<commit_before>(function() {
  'use strict';
  angular.module('civic.services')
    .factory('GenesResource', GenesResource)
    .factory('Genes', GenesService);

  // @ngInject
  function GenesResource($resource, $cacheFactory) {
    // ngResource normally automatically handles caches but we need
    // to manually remove records in the update/delete
    // custom functions on this resource
    var cache = $cacheFactory('genesCache');
    var cacheInterceptor = function(response) {
      cache.remove(response.config.url);
      return response;
    };

    return $resource('/api/genes/:geneId',
      {
        geneId: '@entrez_id'
      },
      {
        add: {
          method: 'POST',
          cache: cache
        },
        query: { // get list of genes
          method: 'GET',
          isArray: true,
          cache: cache
        },
        get: { // get a single gene
          method: 'GET',
          isArray: false,
          cache: cache
        },
        update: {
          method: 'PATCH',
          interceptor: {
            response: cacheInterceptor
          }
        },
        refresh: { // get gene, force cache
          method: 'GET',
          isArray: false,
          cache: false
        },
        delete: { // delete a single gene
          method: 'DELETE',
          interceptor: {
            response: cacheInterceptor
          }
        },
        getVariants: {
          isArray: true,
          method: 'GET',
          url: '/api/genes/:geneId/variants',
          cache: cache
        },
        queryVariantGroups: {
          method: 'GET',
          url: '/api/genes/:geneId/variant_groups',
          isArray: true,
          cache: cache
        },
        getComments: {
          method: 'GET',
          url: '/api/genes/:geneId/comments',
          isArray: true,
          cache: cache
        },
        getComment: {
          method: 'GET',
          url: '/api/genes/:geneId/comments/:commentId',
          params: {
            geneId: '@geneId',
            commentId: '@commentId'
          },
          isArray: false,
          cache: cache
        },
        addComment: {
          method: 'POST',
          url: '/api/genes/:geneId/comments',
          params: {
            geneId: '@geneId'
          },
          cache: cache
        },
        updateComment: {
          method: 'PATCH',
          url: '/api/genes/:geneId/comments/:commentId',
          params: {
            geneId: '@geneId',
            commentId: '@commentId'
          },
          interceptor: {
            response: cacheInterceptor
          }
        },
        deleteComment: {
          method: 'DELETE',
          url: '/api/genes/:geneId/comments/:commentId',
          params: {
            geneId: '@geneId',
            commentId: '@commentId'
          },
          interceptor: {
            response: cacheInterceptor
          }
        },
        getRevisions: {
          method: 'GET',
          url: '/api/genes/:geneId/revisions',
          cache: cache
        },
        getRevision: {
          method: 'GET',
          url: '/api/genes/:geneId/revisions/:revisionId',
          params: {
            geneId: '@geneId',
            revisionId: '@revisionId'
          },
          isArray: false,
          cache: cache
        },
        getLastRevision: {
          method: 'GET',
          url: '/api/genes/:geneId/revisions/last',
          params: {
            geneId: '@geneId'
          },
          isArray: false
        },
        getChanges: {
          method: 'GET',
          url: '/api/genes/:geneId/suggested_changes'
        },
        getChange: {
          method: 'GET',
          url: '/api/genes/:geneId/suggested_changes/:changeId',
          params: {
            geneId: '@geneId',
            changeId: '@changeId'
          },
          isArray: false
        },
        acceptChange: {
          method: 'POST',
          url: '/api/genes/:geneId/suggested_changes/:changeId/accept',
          params: {
            geneId: '@geneId',
            changeId: '@changeId'
          }
        },
        rejectChange: {
          method: 'POST',
          url: '/api/genes/:geneId/suggested_changes/:changeId/reject',
          params: {
            geneId: '@geneId',
            changeId: '@changeId'
          }
        },
        addChangeComment: {
          method: 'POST',
          url: '/api/genes/:geneId/suggested_changes/:changeId/comments',
          params: {
            geneId: '@geneId',
            changeId: '@changeId'
          }
        },
        updateChangeComment: {
          method: 'PATCH',
          url: '/api/genes/:geneId/suggested_changes/:changeId/comments/:commentId',
          params: {
            geneId: '@geneId',
            changeId: '@changeId',
            commentId: '@commentId'
          },
          interceptor: {
            response: cacheInterceptor
          }
        },
        getChangeComments: {
          method: 'GET',
          url: '/api/genes/:geneId/suggested_changes/:changeId/comments',
          params: {
            geneId: '@geneId',
            changeId: '@changeId'
          },
          cache: cache
        },
        getChangeComment: {
          method: 'GET',
          url: '/api/genes/:geneId/suggested_changes/:changeId/comments/:commentId',
          params: {
            geneId: '@geneId',
            changeId: '@changeId',
            commentId: '@commentId'
          },
          cache: cache
        },
        deleteChangeComment: {
          method: 'DELETE',
          url: '/api/genes/:geneId/suggested_changes/:changeId/comments/:commentId',
          params: {
            geneId: '@geneId',
            changeId: '@changeId',
            commentId: '@commentId'
          }
        }
      });
  }

  //ngInject
  function GenesService(GenesResource) {
    return {
      // Gene actions
      add: function(reqObj) {
        return GenesResource.add(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      delete: function(entrez_id) {
        return GenesResource.delete({geneId: entrez_id}).$promise
          .then(function(response) {
            return response;
          });
      },
      get: function(entrez_id) {
        return GenesResource.get({geneId: entrez_id}).$promise
          .then(function(response) {
            return response;
          });
      },
      refresh: function(entrez_id) {
        return GenesResource.refresh({geneId: entrez_id}).$promise
          .then(function(response) {
            return response;
          });
      },
      query: function() {
        return GenesResource.query().$promise
          .then(function(response) {
            return response;
          });
      },
      update: function(reqObj) {
        return GenesResource.update(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      getVariants: function(entrez_id) {
        return GenesResource.getVariants({geneId: entrez_id}).$promise
          .then(function(response) {
            return response;
          });
      },
      getVariantGroups: function(entrez_id) {
        return GenesResource.queryVariantGroups({geneId: entrez_id}).$promise
          .then(function(response) {
            return response;
          });
      },

      // Gene comments
      addComment: function(reqObj) {
        return GenesResource.addComment(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      updateComment: function(reqObj) {
        return GenesResource.updateComment(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      getComments: function(entrez_id) {
        return GenesResource.getComments({geneId: entrez_id}).$promise
          .then(function(response) {
            return response;
          });
      },
      getComment: function(geneId, commentId) {
        return GenesResource.getComment({geneId: geneId, commentId: commentId}).$promise
          .then(function(response) {
            return response;
          });
      },
      deleteComment: function(reqObj) {
        return GenesResource.deleteComment(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },

      // Gene revisions
      getRevisions: function(entrez_id) {
        return GenesResource.getRevisions({geneId: entrez_id}).$promise
          .then(function(response) {
            return response;
          });
      },
      getRevision: function(reqObj) {
        return GenesResource.getRevision(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      getLastRevision: function(reqObj) {
        return GenesResource.getLastRevision(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },

      // Gene suggested changes
      getChanges: function(entrez_id) {
        return GenesResource.getChanges({geneId: entrez_id}).$promise
          .then(function(response) {
            return response;
          });
      },
      getChange: function(reqObj) {
        return GenesResource.getChange(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      acceptChange: function(reqObj) {
        return GenesResource.acceptChange(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      rejectChange: function(reqObj) {
        return GenesResource.rejectChange(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },

      // Gene suggested changes comments
      addChangeComment: function(reqObj) {
        return GenesResource.addChangeComment(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      updateChangeComment: function(reqObj) {
        return GenesResource.updateChangeComment(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      getChangeComments: function(reqObj) {
        return GenesResource.getChangeComments(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      getChangeComment: function(reqObj) {
        return GenesResource.getChangeComment(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      deleteChangeComment: function(reqObj) {
        return GenesResource.deleteChangeComment(reqObj).$promise
          .then(function(response) {
            return response;
          });
      }
    }
  }

})();
<commit_msg>GeneService tweaks<commit_after>(function() {
  'use strict';
  angular.module('civic.services')
    .factory('GenesResource', GenesResource)
    .factory('Genes', GenesService);

  // @ngInject
  function GenesResource($resource, $cacheFactory) {
    // ngResource normally automatically handles caches but we need
    // to manually remove records in the update/delete
    // custom functions on this resource
    var cache = $cacheFactory('genesCache');
    var cacheInterceptor = function(response) {
      cache.remove(response.config.url);
      return response;
    };

    return $resource('/api/genes/:geneId',
      {
        geneId: '@entrez_id'
      },
      {
        add: {
          method: 'POST',
          cache: cache
        },
        query: { // get list of genes
          method: 'GET',
          isArray: true,
          cache: cache
        },
        get: { // get a single gene
          method: 'GET',
          isArray: false,
          cache: cache
        },
        update: {
          method: 'PATCH',
          interceptor: {
            response: cacheInterceptor
          }
        },
        refresh: { // get gene, force cache
          method: 'GET',
          isArray: false,
          cache: false
        },
        delete: { // delete a single gene
          method: 'DELETE',
          interceptor: {
            response: cacheInterceptor
          }
        },
        getVariants: {
          isArray: true,
          method: 'GET',
          url: '/api/genes/:geneId/variants',
          cache: cache
        },
        queryVariantGroups: {
          method: 'GET',
          url: '/api/genes/:geneId/variant_groups',
          isArray: true,
          cache: cache
        },
        getComments: {
          method: 'GET',
          url: '/api/genes/:geneId/comments',
          isArray: true,
          cache: cache
        },
        getComment: {
          method: 'GET',
          url: '/api/genes/:geneId/comments/:commentId',
          params: {
            geneId: '@geneId',
            commentId: '@commentId'
          },
          isArray: false,
          cache: cache
        },
        addComment: {
          method: 'POST',
          url: '/api/genes/:geneId/comments',
          params: {
            geneId: '@geneId'
          },
          cache: cache
        },
        updateComment: {
          method: 'PATCH',
          url: '/api/genes/:geneId/comments/:commentId',
          params: {
            geneId: '@geneId',
            commentId: '@commentId'
          },
          interceptor: {
            response: cacheInterceptor
          }
        },
        deleteComment: {
          method: 'DELETE',
          url: '/api/genes/:geneId/comments/:commentId',
          params: {
            geneId: '@geneId',
            commentId: '@commentId'
          },
          interceptor: {
            response: cacheInterceptor
          }
        },
        getRevisions: {
          method: 'GET',
          url: '/api/genes/:geneId/revisions',
          cache: cache
        },
        getRevision: {
          method: 'GET',
          url: '/api/genes/:geneId/revisions/:revisionId',
          params: {
            geneId: '@geneId',
            revisionId: '@revisionId'
          },
          isArray: false,
          cache: cache
        },
        getLastRevision: {
          method: 'GET',
          url: '/api/genes/:geneId/revisions/last',
          params: {
            geneId: '@geneId'
          },
          isArray: false
        },
        getChanges: {
          method: 'GET',
          url: '/api/genes/:geneId/suggested_changes'
        },
        getChange: {
          method: 'GET',
          url: '/api/genes/:geneId/suggested_changes/:changeId',
          params: {
            geneId: '@geneId',
            changeId: '@changeId'
          },
          isArray: false
        },
        acceptChange: {
          method: 'POST',
          url: '/api/genes/:geneId/suggested_changes/:changeId/accept',
          params: {
            geneId: '@geneId',
            changeId: '@changeId'
          }
        },
        rejectChange: {
          method: 'POST',
          url: '/api/genes/:geneId/suggested_changes/:changeId/reject',
          params: {
            geneId: '@geneId',
            changeId: '@changeId'
          }
        },
        addChangeComment: {
          method: 'POST',
          url: '/api/genes/:geneId/suggested_changes/:changeId/comments',
          params: {
            geneId: '@geneId',
            changeId: '@changeId'
          }
        },
        updateChangeComment: {
          method: 'PATCH',
          url: '/api/genes/:geneId/suggested_changes/:changeId/comments/:commentId',
          params: {
            geneId: '@geneId',
            changeId: '@changeId',
            commentId: '@commentId'
          },
          interceptor: {
            response: cacheInterceptor
          }
        },
        getChangeComments: {
          method: 'GET',
          url: '/api/genes/:geneId/suggested_changes/:changeId/comments',
          params: {
            geneId: '@geneId',
            changeId: '@changeId'
          },
          cache: cache
        },
        getChangeComment: {
          method: 'GET',
          url: '/api/genes/:geneId/suggested_changes/:changeId/comments/:commentId',
          params: {
            geneId: '@geneId',
            changeId: '@changeId',
            commentId: '@commentId'
          },
          cache: cache
        },
        deleteChangeComment: {
          method: 'DELETE',
          url: '/api/genes/:geneId/suggested_changes/:changeId/comments/:commentId',
          params: {
            geneId: '@geneId',
            changeId: '@changeId',
            commentId: '@commentId'
          }
        }
      });
  }

  //ngInject
  function GenesService(GenesResource) {
    return {
      // Gene actions
      add: function(reqObj) {
        return GenesResource.add(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      delete: function(entrez_id) {
        return GenesResource.delete({geneId: entrez_id}).$promise
          .then(function(response) {
            return response;
          });
      },
      get: function(entrez_id) {
        return GenesResource.get({geneId: entrez_id}).$promise
          .then(function(response) {
            return response;
          });
      },
      refresh: function(entrez_id) {
        return GenesResource.refresh({geneId: entrez_id}).$promise
          .then(function(response) {
            return response;
          });
      },
      query: function() {
        return GenesResource.query().$promise
          .then(function(response) {
            return response;
          });
      },
      update: function(reqObj) {
        return GenesResource.update(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      getVariants: function(entrez_id) {
        return GenesResource.getVariants({geneId: entrez_id}).$promise
          .then(function(response) {
            return response;
          });
      },
      getVariantGroups: function(entrez_id) {
        return GenesResource.queryVariantGroups({geneId: entrez_id}).$promise
          .then(function(response) {
            return response;
          });
      },

      // Gene comments
      addComment: function(reqObj) {
        return GenesResource.addComment(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      getComments: function(entrez_id) {
        return GenesResource.getComments({geneId: entrez_id}).$promise
          .then(function(response) {
            return response;
          });
      },
      getComment: function(geneId, commentId) {
        return GenesResource.getComment({geneId: geneId, commentId: commentId}).$promise
          .then(function(response) {
            return response;
          });
      },
      updateComment: function(reqObj) {
        return GenesResource.updateComment(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      deleteComment: function(reqObj) {
        return GenesResource.deleteComment(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },

      // Gene revisions
      getRevisions: function(entrez_id) {
        return GenesResource.getRevisions({geneId: entrez_id}).$promise
          .then(function(response) {
            return response;
          });
      },
      getRevision: function(reqObj) {
        return GenesResource.getRevision(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      getLastRevision: function(reqObj) {
        return GenesResource.getLastRevision(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },

      // Gene suggested changes
      getChanges: function(entrez_id) {
        return GenesResource.getChanges({geneId: entrez_id}).$promise
          .then(function(response) {
            return response;
          });
      },
      getChange: function(reqObj) {
        return GenesResource.getChange(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      acceptChange: function(reqObj) {
        return GenesResource.acceptChange(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      rejectChange: function(reqObj) {
        return GenesResource.rejectChange(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },

      // Gene suggested changes comments
      addChangeComment: function(reqObj) {
        return GenesResource.addChangeComment(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      updateChangeComment: function(reqObj) {
        return GenesResource.updateChangeComment(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      getChangeComments: function(reqObj) {
        return GenesResource.getChangeComments(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      getChangeComment: function(reqObj) {
        return GenesResource.getChangeComment(reqObj).$promise
          .then(function(response) {
            return response;
          });
      },
      deleteChangeComment: function(reqObj) {
        return GenesResource.deleteChangeComment(reqObj).$promise
          .then(function(response) {
            return response;
          });
      }
    }
  }

})();
<|endoftext|>


<commit_before>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var React = require('react');
var sdk = require('matrix-react-sdk');
var Matrix = require("matrix-js-sdk");
var dis = require('matrix-react-sdk/lib/dispatcher');
var MatrixClientPeg = require("matrix-react-sdk/lib/MatrixClientPeg");
var rate_limited_func = require('matrix-react-sdk/lib/ratelimitedfunc');
var Modal = require('matrix-react-sdk/lib/Modal');

module.exports = React.createClass({
    displayName: 'RightPanel',

    propTypes: {
        userId: React.PropTypes.string, // if showing an orphaned MemberInfo page, this is set
        roomId: React.PropTypes.string, // if showing panels for a given room, this is set
        collapsed: React.PropTypes.bool, // currently unused property to request for a minimized view of the panel
    },

    Phase : {
        MemberList: 'MemberList',
        FilePanel: 'FilePanel',
        NotificationPanel: 'NotificationPanel',
        MemberInfo: 'MemberInfo',
    },

    componentWillMount: function() {
        this.dispatcherRef = dis.register(this.onAction);
        var cli = MatrixClientPeg.get();
        cli.on("RoomState.members", this.onRoomStateMember);
    },

    componentWillUnmount: function() {
        dis.unregister(this.dispatcherRef);
        if (MatrixClientPeg.get()) {
            MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember);
        }
    },

    getInitialState: function() {
        if (this.props.userId) {
            var member = new Matrix.RoomMember(null, this.props.userId);
            return {
                phase: this.Phase.MemberInfo,
                member: member,
            }
        }
        else {
            return {
                phase: this.Phase.MemberList
            }
        }
    },

    onMemberListButtonClick: function() {
        if (this.props.collapsed || this.state.phase !== this.Phase.MemberList) {
            this.setState({ phase: this.Phase.MemberList });
            dis.dispatch({
                action: 'show_right_panel',
            });
        }
        else {
            dis.dispatch({
                action: 'hide_right_panel',
            });
        }
    },

    onFileListButtonClick: function() {
        if (this.props.collapsed || this.state.phase !== this.Phase.FilePanel) {
            this.setState({ phase: this.Phase.FilePanel });
            dis.dispatch({
                action: 'show_right_panel',
            });
        }
        else {
            dis.dispatch({
                action: 'hide_right_panel',
            });
        }
    },

    onNotificationListButtonClick: function() {
        if (this.props.collapsed || this.state.phase !== this.Phase.NotificationPanel) {
            this.setState({ phase: this.Phase.NotificationPanel });
            dis.dispatch({
                action: 'show_right_panel',
            });
        }
        else {
            dis.dispatch({
                action: 'hide_right_panel',
            });
        }
    },

    onInviteButtonClick: function() {
        if (MatrixClientPeg.get().isGuest()) {
            var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
            Modal.createDialog(NeedToRegisterDialog, {
                title: "Please Register",
                description: "Guest users can't invite users. Please register to invite."
            });
            return;
        }

        // call ChatInviteDialog
        dis.dispatch({
            action: 'view_invite',
            roomId: this.props.roomId,
        });
    },

    onRoomStateMember: function(ev, state, member) {
        // redraw the badge on the membership list
        if (this.state.phase == this.Phase.MemberList && member.roomId === this.props.roomId) {
            this._delayedUpdate();
        }
        else if (this.state.phase === this.Phase.MemberInfo && member.roomId === this.props.roomId &&
                member.userId === this.state.member.userId) {
            // refresh the member info (e.g. new power level)
            this._delayedUpdate();
        }
    },

    _delayedUpdate: new rate_limited_func(function() {
        this.forceUpdate();
    }, 500),

    onAction: function(payload) {
        if (payload.action === "view_user") {
            dis.dispatch({
                action: 'show_right_panel',
            });
            if (payload.member) {
                this.setState({
                    phase: this.Phase.MemberInfo,
                    member: payload.member,
                });
            }
            else {
                this.setState({
                    phase: this.Phase.MemberList
                });
            }
        }
        else if (payload.action === "view_room") {
            if (this.state.phase === this.Phase.MemberInfo) {
                this.setState({
                    phase: this.Phase.MemberList
                });
            }
        }
    },

    render: function() {
        var MemberList = sdk.getComponent('rooms.MemberList');
        var NotificationPanel = sdk.getComponent('structures.NotificationPanel');
        var FilePanel = sdk.getComponent('structures.FilePanel');
        var TintableSvg = sdk.getComponent("elements.TintableSvg");
        var buttonGroup;
        var inviteGroup;
        var panel;

        var filesHighlight;
        var membersHighlight;
        var notificationsHighlight;
        if (!this.props.collapsed) {
            if (this.state.phase == this.Phase.MemberList || this.state.phase === this.Phase.MemberInfo) {
                membersHighlight =

;
            }
            else if (this.state.phase == this.Phase.FilePanel) {
                filesHighlight =

;
            }
            else if (this.state.phase == this.Phase.NotificationPanel) {
                notificationsHighlight =

;
            }
        }

        var membersBadge;
        if ((this.state.phase == this.Phase.MemberList || this.state.phase === this.Phase.MemberInfo) && this.props.roomId) {
            var cli = MatrixClientPeg.get();
            var room = cli.getRoom(this.props.roomId);
            if (room) {
                membersBadge = room.getJoinedMembers().length;
            }
        }

        if (this.props.roomId) {
            buttonGroup =

{ membersBadge ? membersBadge :  }

                            <TintableSvg src="img/icons-people.svg" width="25" height="25"/>
                            { membersHighlight }

                            <TintableSvg src="img/icons-files.svg" width="25" height="25"/>
                            { filesHighlight }

                            <TintableSvg src="img/icons-notifications.svg" width="25" height="25"/>
                            { notificationsHighlight }

;

            inviteGroup =

                        <TintableSvg src="img/icon-invite-people.svg" width="35" height="35" />

Invite to this room

;
        }

        if (!this.props.collapsed) {
            if(this.props.roomId && this.state.phase == this.Phase.MemberList) {
                panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />
            }
            else if(this.state.phase == this.Phase.MemberInfo) {
                var MemberInfo = sdk.getComponent('rooms.MemberInfo');
                panel = <MemberInfo member={this.state.member} key={this.props.roomId || this.props.userId} />
            }
            else if (this.state.phase == this.Phase.NotificationPanel) {
                panel = <NotificationPanel />
            }
            else if (this.state.phase == this.Phase.FilePanel) {
                panel = <FilePanel roomId={this.props.roomId} />
            }
        }

        if (!panel) {
            panel =

;
        }

        var classes = "mx_RightPanel mx_fadable";
        if (this.props.collapsed) {
            classes += " collapsed";
        }

        return (

                    { buttonGroup }

                { panel }

                    { inviteGroup }

        );
    }
});

<commit_msg>only show invite button for rooms you're in<commit_after>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var React = require('react');
var sdk = require('matrix-react-sdk');
var Matrix = require("matrix-js-sdk");
var dis = require('matrix-react-sdk/lib/dispatcher');
var MatrixClientPeg = require("matrix-react-sdk/lib/MatrixClientPeg");
var rate_limited_func = require('matrix-react-sdk/lib/ratelimitedfunc');
var Modal = require('matrix-react-sdk/lib/Modal');

module.exports = React.createClass({
    displayName: 'RightPanel',

    propTypes: {
        userId: React.PropTypes.string, // if showing an orphaned MemberInfo page, this is set
        roomId: React.PropTypes.string, // if showing panels for a given room, this is set
        collapsed: React.PropTypes.bool, // currently unused property to request for a minimized view of the panel
    },

    Phase : {
        MemberList: 'MemberList',
        FilePanel: 'FilePanel',
        NotificationPanel: 'NotificationPanel',
        MemberInfo: 'MemberInfo',
    },

    componentWillMount: function() {
        this.dispatcherRef = dis.register(this.onAction);
        var cli = MatrixClientPeg.get();
        cli.on("RoomState.members", this.onRoomStateMember);
    },

    componentWillUnmount: function() {
        dis.unregister(this.dispatcherRef);
        if (MatrixClientPeg.get()) {
            MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember);
        }
    },

    getInitialState: function() {
        if (this.props.userId) {
            var member = new Matrix.RoomMember(null, this.props.userId);
            return {
                phase: this.Phase.MemberInfo,
                member: member,
            }
        }
        else {
            return {
                phase: this.Phase.MemberList
            }
        }
    },

    onMemberListButtonClick: function() {
        if (this.props.collapsed || this.state.phase !== this.Phase.MemberList) {
            this.setState({ phase: this.Phase.MemberList });
            dis.dispatch({
                action: 'show_right_panel',
            });
        }
        else {
            dis.dispatch({
                action: 'hide_right_panel',
            });
        }
    },

    onFileListButtonClick: function() {
        if (this.props.collapsed || this.state.phase !== this.Phase.FilePanel) {
            this.setState({ phase: this.Phase.FilePanel });
            dis.dispatch({
                action: 'show_right_panel',
            });
        }
        else {
            dis.dispatch({
                action: 'hide_right_panel',
            });
        }
    },

    onNotificationListButtonClick: function() {
        if (this.props.collapsed || this.state.phase !== this.Phase.NotificationPanel) {
            this.setState({ phase: this.Phase.NotificationPanel });
            dis.dispatch({
                action: 'show_right_panel',
            });
        }
        else {
            dis.dispatch({
                action: 'hide_right_panel',
            });
        }
    },

    onInviteButtonClick: function() {
        if (MatrixClientPeg.get().isGuest()) {
            var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
            Modal.createDialog(NeedToRegisterDialog, {
                title: "Please Register",
                description: "Guest users can't invite users. Please register to invite."
            });
            return;
        }

        // call ChatInviteDialog
        dis.dispatch({
            action: 'view_invite',
            roomId: this.props.roomId,
        });
    },

    onRoomStateMember: function(ev, state, member) {
        // redraw the badge on the membership list
        if (this.state.phase == this.Phase.MemberList && member.roomId === this.props.roomId) {
            this._delayedUpdate();
        }
        else if (this.state.phase === this.Phase.MemberInfo && member.roomId === this.props.roomId &&
                member.userId === this.state.member.userId) {
            // refresh the member info (e.g. new power level)
            this._delayedUpdate();
        }
    },

    _delayedUpdate: new rate_limited_func(function() {
        this.forceUpdate();
    }, 500),

    onAction: function(payload) {
        if (payload.action === "view_user") {
            dis.dispatch({
                action: 'show_right_panel',
            });
            if (payload.member) {
                this.setState({
                    phase: this.Phase.MemberInfo,
                    member: payload.member,
                });
            }
            else {
                this.setState({
                    phase: this.Phase.MemberList
                });
            }
        }
        else if (payload.action === "view_room") {
            if (this.state.phase === this.Phase.MemberInfo) {
                this.setState({
                    phase: this.Phase.MemberList
                });
            }
        }
    },

    render: function() {
        var MemberList = sdk.getComponent('rooms.MemberList');
        var NotificationPanel = sdk.getComponent('structures.NotificationPanel');
        var FilePanel = sdk.getComponent('structures.FilePanel');
        var TintableSvg = sdk.getComponent("elements.TintableSvg");
        var buttonGroup;
        var inviteGroup;
        var panel;

        var filesHighlight;
        var membersHighlight;
        var notificationsHighlight;
        if (!this.props.collapsed) {
            if (this.state.phase == this.Phase.MemberList || this.state.phase === this.Phase.MemberInfo) {
                membersHighlight =

;
            }
            else if (this.state.phase == this.Phase.FilePanel) {
                filesHighlight =

;
            }
            else if (this.state.phase == this.Phase.NotificationPanel) {
                notificationsHighlight =

;
            }
        }

        var membersBadge;
        if ((this.state.phase == this.Phase.MemberList || this.state.phase === this.Phase.MemberInfo) && this.props.roomId) {
            var cli = MatrixClientPeg.get();
            var room = cli.getRoom(this.props.roomId);
            var user_is_in_room;
            if (room) {
                membersBadge = room.getJoinedMembers().length;
                user_is_in_room = room.hasMembershipState(
                    MatrixClientPeg.get().credentials.userId, 'join'
                );
            }

            if (user_is_in_room) {
                inviteGroup =

                            <TintableSvg src="img/icon-invite-people.svg" width="35" height="35" />

Invite to this room

;
            }

        }

        if (this.props.roomId) {
            buttonGroup =

{ membersBadge ? membersBadge :  }

                            <TintableSvg src="img/icons-people.svg" width="25" height="25"/>
                            { membersHighlight }

                            <TintableSvg src="img/icons-files.svg" width="25" height="25"/>
                            { filesHighlight }

                            <TintableSvg src="img/icons-notifications.svg" width="25" height="25"/>
                            { notificationsHighlight }

;
        }

        if (!this.props.collapsed) {
            if(this.props.roomId && this.state.phase == this.Phase.MemberList) {
                panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />
            }
            else if(this.state.phase == this.Phase.MemberInfo) {
                var MemberInfo = sdk.getComponent('rooms.MemberInfo');
                panel = <MemberInfo member={this.state.member} key={this.props.roomId || this.props.userId} />
            }
            else if (this.state.phase == this.Phase.NotificationPanel) {
                panel = <NotificationPanel />
            }
            else if (this.state.phase == this.Phase.FilePanel) {
                panel = <FilePanel roomId={this.props.roomId} />
            }
        }

        if (!panel) {
            panel =

;
        }

        var classes = "mx_RightPanel mx_fadable";
        if (this.props.collapsed) {
            classes += " collapsed";
        }

        return (

                    { buttonGroup }

                { panel }

                    { inviteGroup }

        );
    }
});

<|endoftext|>


<commit_before>/* global Affiliation, Authorship, ResearchEntity, Document, TagLabel, SqlService, DocumentOrigins */
'use strict';

/**
 * ResearchEntity.js
 *
 * @description :: TODO: You might write a short summary of how this model works and what it represents here.
 * @docs        :: http://sailsjs.org/#!documentation/models
 */

const exec = require('child_process').exec;
const Promise = require("bluebird");
const _ = require("lodash");
const BaseModel = require("./BaseModel.js");
const request = require('request-promise');

module.exports = _.merge({}, BaseModel, {
    attributes: {
        getUrlSection: function () {
            return this.getType() + 's';
        }
    },
    createDraft: async function (ResearchEntityModel, researchEntityId, draftData) {
        const selectedDraftData = Document.selectData(draftData);
        selectedDraftData.kind = DocumentKinds.DRAFT;
        const documentType = await DocumentType.findOneByKey(selectedDraftData.type);
        selectedDraftData.documenttype = documentType;
        const researchEntity = await ResearchEntityModel.findOneById(researchEntityId).populate('drafts');
        const draft = await Document.create(selectedDraftData);
        researchEntity.drafts.add(draft);
        await researchEntity.savePromise();
        await Authorship.createEmptyAuthorships(draft, draftData.authorships);
        const completeDraft = await Document.findOneById(draft.id)
            .populate('authorships')
            .populate('affiliations')
            .populate('authors')
            .populate('source');
        return completeDraft;
    },
    copyDocument: async function (Model, researchEntityId, documentId) {
        const document = await Document.findOneById(documentId);

        if (!document)
            throw 'Document not found';

        const documentData = Document.selectData(document);
        documentData.authorships = await Authorship.find({document: document.id}).populate('affiliations');
        return await Model.createDraft(Model, researchEntityId, documentData);
    },
    copyDocuments: async function (Model, researchEntityId, documentIds) {
        const results = [];
        for (const documentId of documentIds) {
            const res = await Model.copyDocument(Model, researchEntityId, documentId);
            results.push(res);
        }
        return results;
    },
    unverifyDocument: async function (ResearchEntityModel, researchEntityId, documentId) {
        await this.doUnverifyDocument(ResearchEntityModel, researchEntityId, documentId);
        return await Document.deleteIfNotVerified(documentId);
    },
    doUnverifyDocument: async function (ResearchEntityModel, researchEntityId, documentId) {
        const authorshipModel = getAuthorshipModel(ResearchEntityModel);
        const authorship = await authorshipModel.findOne({researchEntity: researchEntityId, document: documentId});
        if (!authorship)
            return;
        return authorship.unverify();
    },
    undiscardDocument: async function (Model, researchEntityId, documentId) {
        const DiscardedModel = getDiscardedModel(Model);
        await DiscardedModel.destroy({document: documentId, researchEntity: researchEntityId});
        return await Document.deleteIfNotVerified(documentId);
    },
    discardDocument: async function (Model, researchEntityId, documentId) {
        const DiscardedModel = getDiscardedModel(Model);
        const AuthorshipModel = getAuthorshipModel(Model);
        const authorships = await AuthorshipModel.find({document: documentId, researchEntity: researchEntityId});
        if (authorships.length > 0) {
            return {
                error: 'Document verified, must be unverified',
                item: documentId
            };
        }
        const alreadyDiscarded = await DiscardedModel.find({researchEntity: researchEntityId, document: documentId});
        if (alreadyDiscarded.length > 0) {
            sails.log.info(`${Model.identity} ${researchEntityId} tried to discard document ${documentId} but was already discarded`);
            return alreadyDiscarded[0];
        }
        const newDiscarded = await DiscardedModel.create({researchEntity: researchEntityId, document: documentId});
        return newDiscarded;
    },
    discardDocuments: async function (Model, researchEntityId, documentIds) {
        const results = [];
        for (let documentId of documentIds) {
            const res = await Model.discardDocument(Model, researchEntityId, documentId);
            results.push(res);
        }
        return results;
    },
    verifyDrafts: async function (ResearchEntityModel, researchEntityId, draftIds) {
        const results = [];
        for (let draftId of draftIds) {
            const res = await ResearchEntityModel.verifyDraft(ResearchEntityModel, researchEntityId, draftId);
            results.push(res);
        }
        return results;
    },
    verifyDraft: async function (ResearchEntityModel, researchEntityId, draftId, verificationData) {
        const draft = await Document.findOneById(draftId)
            .populate('authorships')
            .populate('affiliations');

        if (!draft || draft.kind !== DocumentKinds.DRAFT)
            return {
                error: 'Draft not found',
                item: draftId
            };
        if (!draft.isValid())
            return {
                error: 'Draft not valid for verification',
                item: draft
            };
        if (draft.scopusId) {
            const alreadyVerifiedDocuments = (await ResearchEntityModel
                .findOne(researchEntityId)
                .populate('documents', {
                    scopusId: draft.scopusId
                })).documents;
            if (alreadyVerifiedDocuments.length)
                return {
                    error: 'Draft already verified (duplicated scopusId)',
                    item: draft
                };
        }

        const authorshipData = await ResearchEntityModel.getAuthorshipsData(draft, researchEntityId, verificationData);

        if (!authorshipData.isVerifiable)
            return {
                error: authorshipData.error,
                item: authorshipData.document
            };

        const documentCopies = await Document.findCopies(draft, authorshipData.position);

        const n = documentCopies.length;
        let docToVerify;
        if (n === 0) {
            docToVerify = await draft.draftToDocument();
        }
        else {
            if (n > 1)
                sails.log.debug('Too many similar documents to ' + draft.id + ' ( ' + n + ')');
            docToVerify = documentCopies[0];

            if (docToVerify.isPositionVerified(authorshipData.position)) {
                const authorName = docToVerify.authorsStr.split(', ')[authorshipData.position];
                return {
                    error: `You cannot verify this document as ${authorName} because someone else already claimed to be that author`,
                    item: docToVerify
                };
            }
            await Document.addMissingAffiliation(docToVerify, draft, authorshipData.position);
            sails.log.debug('Draft ' + draft.id + ' will be deleted and substituted by ' + docToVerify.id);
            await Document.destroy({id: draft.id});
        }

        return await ResearchEntityModel.doVerifyDocument(docToVerify, researchEntityId, authorshipData);
    },
    verifyDocuments: async function (Model, researchEntityId, documentIds) {
        const results = [];
        for (let documentId of documentIds) {
            const res = await Model.verifyDocument(Model, researchEntityId, documentId);
            results.push(res);
        }
        return results;
    },
    verifyDocument: async function (Model, researchEntityId, documentId, verificationData, check = true) {
        const AuthorshipModel = getAuthorshipModel(Model);
        const alreadyVerifiedDocuments = await AuthorshipModel.find({
            document: documentId,
            researchEntity: researchEntityId
        });
        if (alreadyVerifiedDocuments.length)
            return {
                error: 'Document already verified',
                item: researchEntityId
            };

        const DiscardedModel = getDiscardedModel(Model);
        await  DiscardedModel.destroy({document: documentId, researchEntity: researchEntityId});
        const document = await Document.findOneById(documentId)
            .populate('affiliations')
            .populate('authorships');
        if (!document || document.kind !== DocumentKinds.VERIFIED)
            return {
                error: 'Document not found',
                item: researchEntityId
            };
        if (check && document.scopusId) {
            const alreadyVerifiedDocuments = (await Model
                .findOne(researchEntityId)
                .populate('documents', {
                    scopusId: document.scopusId
                })).documents;
            if (alreadyVerifiedDocuments.length)
                return {
                    error: 'Document already verified (duplicated scopusId)',
                    item: document
                };
        }
        const authorshipData = await Model.getAuthorshipsData(document, researchEntityId, verificationData);

        if (!authorshipData.isVerifiable)
            return {
                error: authorshipData.error,
                item: authorshipData.document
            };

        if (authorshipData.document.isPositionVerified(authorshipData.position))
            return {
                error: "The position is already verified",
                item: authorshipData.document
            };

        return await Model.doVerifyDocument(authorshipData.document, researchEntityId, authorshipData);
    },
    updateDraft: async function (ResearchEntityModel, draftId, draftData) {
        const d = await Document.findOneById(draftId);
        if (!d.kind || d.kind !== DocumentKinds.DRAFT)
            throw "Draft not found";
        const documentFields = Document.getFields();
        const selectedDraftData = _.pick(draftData, documentFields);
        selectedDraftData.kind = DocumentKinds.DRAFT;
        selectedDraftData.synchronized = false;
        const updatedDraft = await Document.update({id: draftId}, selectedDraftData);
        return updatedDraft[0];
    },
    deleteDraft: function (Model, draftId) {
        return Document.destroy({id: draftId});
    },
    deleteDrafts: async function (Model, draftIds) {
        const results = [];
        for (let draftId of draftIds) {
            const res = await Document.destroy({id: draftId});
            results.push(res);
        }
        return results;
    },
    addTags: function (TagModel, userId, documentId, tags) {
        return TagModel.destroy({researchEntity: userId, document: documentId})
            .then(() =>
                tags.forEach(t =>
                    TagLabel
                        .findOrCreate({value: t})
                        .then(tl => TagModel.create({
                            document: documentId,
                            researchEntity: userId,
                            tagLabel: tl.id
                        }))
                )
            )
    },
    makeInternalRequest: async function (researchEntityModel, researchEntitySearchCriteria, baseUrl, qs, attribute) {
        const researchEntity = await researchEntityModel.findOne(researchEntitySearchCriteria);
        if (!researchEntity)
            return {
                error: "404 not found",
                item: researchEntitySearchCriteria
            };
        const path = `/api/v1/${researchEntity.getUrlSection()}/${researchEntity.id}/${attribute}`;
        qs.populate = ['source', 'affiliations', 'authorships', 'institutes', 'documenttype'];
        const reqOptions = {
            uri: baseUrl + path,
            json: true,
            qs: qs
        };
        const r = await request(reqOptions);
        return r;
    },

    _config: {
        actions: false,
        shortcuts: false,
        rest: false
    }
});

function getThroughModel(ResearchEntityModel, fieldName) {
    const throughModelName = ResearchEntityModel._attributes[fieldName].through;
    return sails.models[throughModelName];
}

function getAuthorshipModel(ResearchEntityModel) {
    return getThroughModel(ResearchEntityModel, 'documents');
}

function getDiscardedModel(ResearchEntityModel) {
    return getThroughModel(ResearchEntityModel, 'discardedDocuments');
}<commit_msg>Added populate on makeInternalRequest<commit_after>/* global Affiliation, Authorship, ResearchEntity, Document, TagLabel, SqlService, DocumentOrigins */
'use strict';

/**
 * ResearchEntity.js
 *
 * @description :: TODO: You might write a short summary of how this model works and what it represents here.
 * @docs        :: http://sailsjs.org/#!documentation/models
 */

const exec = require('child_process').exec;
const Promise = require("bluebird");
const _ = require("lodash");
const BaseModel = require("./BaseModel.js");
const request = require('request-promise');

module.exports = _.merge({}, BaseModel, {
    attributes: {
        getUrlSection: function () {
            return this.getType() + 's';
        }
    },
    createDraft: async function (ResearchEntityModel, researchEntityId, draftData) {
        const selectedDraftData = Document.selectData(draftData);
        selectedDraftData.kind = DocumentKinds.DRAFT;
        const documentType = await DocumentType.findOneByKey(selectedDraftData.type);
        selectedDraftData.documenttype = documentType;
        const researchEntity = await ResearchEntityModel.findOneById(researchEntityId).populate('drafts');
        const draft = await Document.create(selectedDraftData);
        researchEntity.drafts.add(draft);
        await researchEntity.savePromise();
        await Authorship.createEmptyAuthorships(draft, draftData.authorships);
        const completeDraft = await Document.findOneById(draft.id)
            .populate('authorships')
            .populate('affiliations')
            .populate('authors')
            .populate('source');
        return completeDraft;
    },
    copyDocument: async function (Model, researchEntityId, documentId) {
        const document = await Document.findOneById(documentId);

        if (!document)
            throw 'Document not found';

        const documentData = Document.selectData(document);
        documentData.authorships = await Authorship.find({document: document.id}).populate('affiliations');
        return await Model.createDraft(Model, researchEntityId, documentData);
    },
    copyDocuments: async function (Model, researchEntityId, documentIds) {
        const results = [];
        for (const documentId of documentIds) {
            const res = await Model.copyDocument(Model, researchEntityId, documentId);
            results.push(res);
        }
        return results;
    },
    unverifyDocument: async function (ResearchEntityModel, researchEntityId, documentId) {
        await this.doUnverifyDocument(ResearchEntityModel, researchEntityId, documentId);
        return await Document.deleteIfNotVerified(documentId);
    },
    doUnverifyDocument: async function (ResearchEntityModel, researchEntityId, documentId) {
        const authorshipModel = getAuthorshipModel(ResearchEntityModel);
        const authorship = await authorshipModel.findOne({researchEntity: researchEntityId, document: documentId});
        if (!authorship)
            return;
        return authorship.unverify();
    },
    undiscardDocument: async function (Model, researchEntityId, documentId) {
        const DiscardedModel = getDiscardedModel(Model);
        await DiscardedModel.destroy({document: documentId, researchEntity: researchEntityId});
        return await Document.deleteIfNotVerified(documentId);
    },
    discardDocument: async function (Model, researchEntityId, documentId) {
        const DiscardedModel = getDiscardedModel(Model);
        const AuthorshipModel = getAuthorshipModel(Model);
        const authorships = await AuthorshipModel.find({document: documentId, researchEntity: researchEntityId});
        if (authorships.length > 0) {
            return {
                error: 'Document verified, must be unverified',
                item: documentId
            };
        }
        const alreadyDiscarded = await DiscardedModel.find({researchEntity: researchEntityId, document: documentId});
        if (alreadyDiscarded.length > 0) {
            sails.log.info(`${Model.identity} ${researchEntityId} tried to discard document ${documentId} but was already discarded`);
            return alreadyDiscarded[0];
        }
        const newDiscarded = await DiscardedModel.create({researchEntity: researchEntityId, document: documentId});
        return newDiscarded;
    },
    discardDocuments: async function (Model, researchEntityId, documentIds) {
        const results = [];
        for (let documentId of documentIds) {
            const res = await Model.discardDocument(Model, researchEntityId, documentId);
            results.push(res);
        }
        return results;
    },
    verifyDrafts: async function (ResearchEntityModel, researchEntityId, draftIds) {
        const results = [];
        for (let draftId of draftIds) {
            const res = await ResearchEntityModel.verifyDraft(ResearchEntityModel, researchEntityId, draftId);
            results.push(res);
        }
        return results;
    },
    verifyDraft: async function (ResearchEntityModel, researchEntityId, draftId, verificationData) {
        const draft = await Document.findOneById(draftId)
            .populate('authorships')
            .populate('affiliations');

        if (!draft || draft.kind !== DocumentKinds.DRAFT)
            return {
                error: 'Draft not found',
                item: draftId
            };
        if (!draft.isValid())
            return {
                error: 'Draft not valid for verification',
                item: draft
            };
        if (draft.scopusId) {
            const alreadyVerifiedDocuments = (await ResearchEntityModel
                .findOne(researchEntityId)
                .populate('documents', {
                    scopusId: draft.scopusId
                })).documents;
            if (alreadyVerifiedDocuments.length)
                return {
                    error: 'Draft already verified (duplicated scopusId)',
                    item: draft
                };
        }

        const authorshipData = await ResearchEntityModel.getAuthorshipsData(draft, researchEntityId, verificationData);

        if (!authorshipData.isVerifiable)
            return {
                error: authorshipData.error,
                item: authorshipData.document
            };

        const documentCopies = await Document.findCopies(draft, authorshipData.position);

        const n = documentCopies.length;
        let docToVerify;
        if (n === 0) {
            docToVerify = await draft.draftToDocument();
        }
        else {
            if (n > 1)
                sails.log.debug('Too many similar documents to ' + draft.id + ' ( ' + n + ')');
            docToVerify = documentCopies[0];

            if (docToVerify.isPositionVerified(authorshipData.position)) {
                const authorName = docToVerify.authorsStr.split(', ')[authorshipData.position];
                return {
                    error: `You cannot verify this document as ${authorName} because someone else already claimed to be that author`,
                    item: docToVerify
                };
            }
            await Document.addMissingAffiliation(docToVerify, draft, authorshipData.position);
            sails.log.debug('Draft ' + draft.id + ' will be deleted and substituted by ' + docToVerify.id);
            await Document.destroy({id: draft.id});
        }

        return await ResearchEntityModel.doVerifyDocument(docToVerify, researchEntityId, authorshipData);
    },
    verifyDocuments: async function (Model, researchEntityId, documentIds) {
        const results = [];
        for (let documentId of documentIds) {
            const res = await Model.verifyDocument(Model, researchEntityId, documentId);
            results.push(res);
        }
        return results;
    },
    verifyDocument: async function (Model, researchEntityId, documentId, verificationData, check = true) {
        const AuthorshipModel = getAuthorshipModel(Model);
        const alreadyVerifiedDocuments = await AuthorshipModel.find({
            document: documentId,
            researchEntity: researchEntityId
        });
        if (alreadyVerifiedDocuments.length)
            return {
                error: 'Document already verified',
                item: researchEntityId
            };

        const DiscardedModel = getDiscardedModel(Model);
        await  DiscardedModel.destroy({document: documentId, researchEntity: researchEntityId});
        const document = await Document.findOneById(documentId)
            .populate('affiliations')
            .populate('authorships');
        if (!document || document.kind !== DocumentKinds.VERIFIED)
            return {
                error: 'Document not found',
                item: researchEntityId
            };
        if (check && document.scopusId) {
            const alreadyVerifiedDocuments = (await Model
                .findOne(researchEntityId)
                .populate('documents', {
                    scopusId: document.scopusId
                })).documents;
            if (alreadyVerifiedDocuments.length)
                return {
                    error: 'Document already verified (duplicated scopusId)',
                    item: document
                };
        }
        const authorshipData = await Model.getAuthorshipsData(document, researchEntityId, verificationData);

        if (!authorshipData.isVerifiable)
            return {
                error: authorshipData.error,
                item: authorshipData.document
            };

        if (authorshipData.document.isPositionVerified(authorshipData.position))
            return {
                error: "The position is already verified",
                item: authorshipData.document
            };

        return await Model.doVerifyDocument(authorshipData.document, researchEntityId, authorshipData);
    },
    updateDraft: async function (ResearchEntityModel, draftId, draftData) {
        const d = await Document.findOneById(draftId);
        if (!d.kind || d.kind !== DocumentKinds.DRAFT)
            throw "Draft not found";
        const documentFields = Document.getFields();
        const selectedDraftData = _.pick(draftData, documentFields);
        selectedDraftData.kind = DocumentKinds.DRAFT;
        selectedDraftData.synchronized = false;
        const updatedDraft = await Document.update({id: draftId}, selectedDraftData);
        return updatedDraft[0];
    },
    deleteDraft: function (Model, draftId) {
        return Document.destroy({id: draftId});
    },
    deleteDrafts: async function (Model, draftIds) {
        const results = [];
        for (let draftId of draftIds) {
            const res = await Document.destroy({id: draftId});
            results.push(res);
        }
        return results;
    },
    addTags: function (TagModel, userId, documentId, tags) {
        return TagModel.destroy({researchEntity: userId, document: documentId})
            .then(() =>
                tags.forEach(t =>
                    TagLabel
                        .findOrCreate({value: t})
                        .then(tl => TagModel.create({
                            document: documentId,
                            researchEntity: userId,
                            tagLabel: tl.id
                        }))
                )
            )
    },
    makeInternalRequest: async function (researchEntityModel, researchEntitySearchCriteria, baseUrl, qs, attribute) {
        const researchEntity = await researchEntityModel.findOne(researchEntitySearchCriteria);
        if (!researchEntity)
            return {
                error: "404 not found",
                item: researchEntitySearchCriteria
            };
        const path = `/api/v1/${researchEntity.getUrlSection()}/${researchEntity.id}/${attribute}`;
        if (!_.isArray(qs.populate)) qs.populate = [qs.populate];
        qs.populate = _.union(['source', 'affiliations', 'authorships', 'institutes', 'documenttype'], qs.populate);
        const reqOptions = {
            uri: baseUrl + path,
            json: true,
            qs: qs
        };
        const r = await request(reqOptions);
        return r;
    },

    _config: {
        actions: false,
        shortcuts: false,
        rest: false
    }
});

function getThroughModel(ResearchEntityModel, fieldName) {
    const throughModelName = ResearchEntityModel._attributes[fieldName].through;
    return sails.models[throughModelName];
}

function getAuthorshipModel(ResearchEntityModel) {
    return getThroughModel(ResearchEntityModel, 'documents');
}

function getDiscardedModel(ResearchEntityModel) {
    return getThroughModel(ResearchEntityModel, 'discardedDocuments');
}<|endoftext|>


<commit_before>import React, { Component } from "react";
import gql from "graphql-tag";
import { graphql, withApollo } from "react-apollo";
import {
  Container,
  Row,
  Col,
  Button,
  Input,
  Card,
  ButtonDropdown,
  DropdownToggle,
  DropdownMenu,
  DropdownItem,
  InputGroup,
  InputGroupButton
} from "reactstrap";
import "./style.css";

const MESSAGING_SUB = gql`
  subscription GotMessage($simulatorId: ID!, $station: String) {
    sendMessage(simulatorId: $simulatorId, station: $station) {
      id
      sender
      content
      timestamp
      simulatorId
      destination
    }
  }
`;

const TEAMS_SUB = gql`
  subscription TeamsUpdate($simulatorId: ID) {
    teamsUpdate(simulatorId: $simulatorId) {
      id
      name
      type
    }
  }
`;

class Messaging extends Component {
  subscription = null;
  teamSub = null;
  state = {
    messageInput: "",
    stationsShown: false,
    selectedConversation: null
  };
  componentWillReceiveProps(nextProps) {
    if (!this.subscription && !nextProps.data.loading) {
      this.subscription = nextProps.data.subscribeToMore({
        document: MESSAGING_SUB,
        variables: {
          simulatorId: nextProps.simulator.id,
          station: nextProps.station.name
        },
        updateQuery: (previousResult, { subscriptionData }) => {
          if (!subscriptionData.data.sendMessage) return previousResult;
          setTimeout(this.scrollElement, 100);
          return Object.assign({}, previousResult, {
            messages: previousResult.messages.concat(
              subscriptionData.data.sendMessage
            )
          });
        }
      });
    }
    if (!this.teamSub && !nextProps.data.loading) {
      this.teamSub = nextProps.data.subscribeToMore({
        document: TEAMS_SUB,
        variables: {
          simulatorId: nextProps.simulator.id
        },
        updateQuery: (previousResult, { subscriptionData }) => {
          return Object.assign({}, previousResult, {
            teams: subscriptionData.data.teamsUpdate
          });
        }
      });
    }
  }
  componentDidUpdate() {
    const el = this.refs.messageHolder;
    if (el) {
      el.scrollTop = el.scrollHeight;
    }
  }
  componentWillUnmount() {
    this.subscription();
    this.teamSub();
  }
  sendMessage = () => {
    const mutation = gql`
      mutation SendMessage($message: MessageInput!) {
        sendMessage(message: $message)
      }
    `;
    const { messageInput, selectedConversation } = this.state;
    const variables = {
      message: {
        simulatorId: this.props.simulator.id,
        destination: selectedConversation,
        sender: this.props.station.name,
        content: messageInput
      }
    };
    this.props.client.mutate({
      mutation,
      variables
    });
    this.setState({ messageInput: "" });
  };
  scrollElement = () => {
    const el = this.refs.messageHolder;
    if (el) {
      scrollTo(el, el.scrollHeight, 600);
    }
  };
  toggleStations = () => {
    this.setState({
      stationsShown: !this.state.stationsShown
    });
  };
  render() {
    const { messages, simulators, teams } = this.props.data.loading
      ? { messages: [], teams: [], simulators: [{ stations: [] }] }
      : this.props.data;
    if (!simulators | !messages | !teams) return null;
    const stations = simulators[0].stations.filter(
      s => s.name !== this.props.station.name
    );
    const messageGroups = this.props.station.messageGroups;
    const { messageInput, stationsShown, selectedConversation } = this.state;
    const convoObj = messages.reduce((prev, next) => {
      if (next.sender === this.props.station.name) {
        prev[next.destination] = Object.assign({}, next, {
          convo: next.destination
        });
      } else if (messageGroups.indexOf(next.destination) > -1) {
        prev[next.destination] = Object.assign({}, next, {
          convo: next.destination
        });
      } else {
        prev[next.sender] = Object.assign({}, next, { convo: next.sender });
      }
      return prev;
    }, {});
    const conversations = Object.keys(convoObj)
      .map(c => convoObj[c])
      .sort((a, b) => {
        if (new Date(a.timestamp) > new Date(b.timestamp)) return -1;
        if (new Date(a.timestamp) < new Date(b.timestamp)) return 1;
        return 0;
      });
    return (
      <Container className="messages">
        <Row>
          <Col sm={3}>

Conversations

            <Card className="convoList">
              {conversations.map(c => (

                    this.setState({ selectedConversation: c.convo })
                  }
                >

{c.convo}

                      {`${c.content.substr(0, 25)}${
                        c.content.length > 25 ? "..." : ""
                      }`}

              ))}
            </Card>
            <ButtonDropdown
              className="btn-block"
              isOpen={stationsShown}
              toggle={this.toggleStations}
              dropup
            >
              <DropdownToggle caret size="lg" block color="primary">
                New Message
              </DropdownToggle>
              <DropdownMenu className="messages-destinations">
                {stations.map(s => (
                  <DropdownItem
                    key={s.name}
                    onClick={() =>
                      this.setState({ selectedConversation: s.name })
                    }
                  >
                    {s.name}
                  </DropdownItem>
                ))}
                <DropdownItem disabled>--------------</DropdownItem>
                {messageGroups &&
                  messageGroups.map(g => (
                    <DropdownItem
                      key={g}
                      onClick={() => this.setState({ selectedConversation: g })}
                    >
                      {g}
                    </DropdownItem>
                  ))}
                <DropdownItem disabled>--------------</DropdownItem>
                {teams &&
                  teams
                    .filter(
                      t =>
                        messageGroups.findIndex(
                          m =>
                            m.toLowerCase().indexOf(t.type.toLowerCase()) > -1
                        ) > -1
                    )
                    .map(g => (
                      <DropdownItem
                        key={g.name}
                        onClick={() =>
                          this.setState({ selectedConversation: g.name })
                        }
                      >
                        {g.name}
                      </DropdownItem>
                    ))}
              </DropdownMenu>
            </ButtonDropdown>
          </Col>
          <Col sm={9}>

Messages

            <Card>

                {selectedConversation && (

                    Conversation with {selectedConversation}

                )}
                {messages
                  .filter(
                    m =>
                      m.sender === selectedConversation ||
                      m.destination === selectedConversation
                  )
                  .map(m => (

                      {m.sender}: {m.content}

                  ))}

            </Card>
            <form
              // eslint-disable-next-line
              action={"javascript:void(0);"}
              onSubmit={this.sendMessage}
            >
              <InputGroup>
                <Input
                  disabled={!selectedConversation}
                  onChange={evt =>
                    this.setState({ messageInput: evt.target.value })
                  }
                  value={messageInput}
                />
                <InputGroupButton>
                  <Button
                    disabled={!selectedConversation}
                    type="submit"
                    color="primary"
                  >
                    Send Message
                  </Button>
                </InputGroupButton>
              </InputGroup>
            </form>
          </Col>
        </Row>
      </Container>
    );
  }
}

const MESSAGING_QUERY = gql`
  query Messages($simulatorId: ID!, $simId: String, $station: String) {
    messages(simulatorId: $simulatorId, station: $station) {
      id
      sender
      content
      timestamp
      simulatorId
      destination
    }
    teams(simulatorId: $simulatorId) {
      id
      name
      type
    }
    simulators(id: $simId) {
      stations {
        name
        messageGroups
      }
    }
  }
`;
export default graphql(MESSAGING_QUERY, {
  options: ownProps => ({
    fetchPolicy: "cache-and-network",
    variables: {
      simulatorId: ownProps.simulator.id,
      simId: ownProps.simulator.id,
      station: ownProps.station.name
    }
  })
})(withApollo(Messaging));

function scrollTo(element, to, duration) {
  if (duration <= 0) return;
  let difference = to - element.scrollTop;
  let perTick = difference / duration * 10;

  setTimeout(function() {
    element.scrollTop = element.scrollTop + perTick;
    if (element.scrollTop === to) return;
    scrollTo(element, to, duration - 10);
  }, 10);
}
<commit_msg>Fixes the error that breaks the messaging. Closes #501 and Closes #514<commit_after>import React, { Component } from "react";
import gql from "graphql-tag";
import { graphql, withApollo } from "react-apollo";
import {
  Container,
  Row,
  Col,
  Button,
  Input,
  Card,
  ButtonDropdown,
  DropdownToggle,
  DropdownMenu,
  DropdownItem,
  InputGroup,
  InputGroupButton
} from "reactstrap";
import "./style.css";

const MESSAGING_SUB = gql`
  subscription GotMessage($simulatorId: ID!, $station: String) {
    sendMessage(simulatorId: $simulatorId, station: $station) {
      id
      sender
      content
      timestamp
      simulatorId
      destination
    }
  }
`;

const TEAMS_SUB = gql`
  subscription TeamsUpdate($simulatorId: ID) {
    teamsUpdate(simulatorId: $simulatorId) {
      id
      name
      type
    }
  }
`;

class Messaging extends Component {
  subscription = null;
  teamSub = null;
  state = {
    messageInput: "",
    stationsShown: false,
    selectedConversation: null
  };
  componentWillReceiveProps(nextProps) {
    if (!this.subscription && !nextProps.data.loading) {
      this.subscription = nextProps.data.subscribeToMore({
        document: MESSAGING_SUB,
        variables: {
          simulatorId: nextProps.simulator.id,
          station: nextProps.station.name
        },
        updateQuery: (previousResult, { subscriptionData }) => {
          if (!subscriptionData.data.sendMessage) return previousResult;
          setTimeout(this.scrollElement, 100);
          return Object.assign({}, previousResult, {
            messages: previousResult.messages.concat(
              subscriptionData.data.sendMessage
            )
          });
        }
      });
    }
    if (!this.teamSub && !nextProps.data.loading) {
      this.teamSub = nextProps.data.subscribeToMore({
        document: TEAMS_SUB,
        variables: {
          simulatorId: nextProps.simulator.id
        },
        updateQuery: (previousResult, { subscriptionData }) => {
          return Object.assign({}, previousResult, {
            teams: subscriptionData.data.teamsUpdate
          });
        }
      });
    }
  }
  componentDidUpdate() {
    const el = this.refs.messageHolder;
    if (el) {
      el.scrollTop = el.scrollHeight;
    }
  }
  componentWillUnmount() {
    this.subscription();
    this.teamSub();
  }
  sendMessage = () => {
    const mutation = gql`
      mutation SendMessage($message: MessageInput!) {
        sendMessage(message: $message)
      }
    `;
    const { messageInput, selectedConversation } = this.state;
    const variables = {
      message: {
        simulatorId: this.props.simulator.id,
        destination: selectedConversation,
        sender: this.props.station.name,
        content: messageInput
      }
    };
    this.props.client.mutate({
      mutation,
      variables
    });
    this.setState({ messageInput: "" });
  };
  scrollElement = () => {
    const el = this.refs.messageHolder;
    if (el) {
      scrollTo(el, el.scrollHeight, 600);
    }
  };
  toggleStations = () => {
    this.setState({
      stationsShown: !this.state.stationsShown
    });
  };
  render() {
    const { messages, simulators, teams } = this.props.data.loading
      ? { messages: [], teams: [], simulators: [{ stations: [] }] }
      : this.props.data;
    if (!simulators | !messages | !teams) return null;
    const stations = simulators[0].stations.filter(
      s => s.name !== this.props.station.name
    );
    const messageGroups = this.props.station.messageGroups;
    const { messageInput, stationsShown, selectedConversation } = this.state;
    const convoObj = messages.reduce((prev, next) => {
      if (next.sender === this.props.station.name) {
        prev[next.destination] = Object.assign({}, next, {
          convo: next.destination
        });
      } else if (messageGroups.indexOf(next.destination) > -1) {
        prev[next.destination] = Object.assign({}, next, {
          convo: next.destination
        });
      } else {
        prev[next.sender] = Object.assign({}, next, { convo: next.sender });
      }
      return prev;
    }, {});
    const conversations = Object.keys(convoObj)
      .map(c => convoObj[c])
      .sort((a, b) => {
        if (new Date(a.timestamp) > new Date(b.timestamp)) return -1;
        if (new Date(a.timestamp) < new Date(b.timestamp)) return 1;
        return 0;
      });
    return (
      <Container className="messages">
        <Row>
          <Col sm={3}>

Conversations

            <Card className="convoList">
              {conversations.map(c => (

                    this.setState({ selectedConversation: c.convo })
                  }
                >

{c.convo}

                      {c.content
                        ? `${c.content.substr(0, 25)}${
                            c.content.length > 25 ? "..." : ""
                          }`
                        : null}

              ))}
            </Card>
            <ButtonDropdown
              className="btn-block"
              isOpen={stationsShown}
              toggle={this.toggleStations}
              dropup
            >
              <DropdownToggle caret size="lg" block color="primary">
                New Message
              </DropdownToggle>
              <DropdownMenu className="messages-destinations">
                {stations.map(s => (
                  <DropdownItem
                    key={s.name}
                    onClick={() =>
                      this.setState({ selectedConversation: s.name })
                    }
                  >
                    {s.name}
                  </DropdownItem>
                ))}
                {messageGroups && (
                  <DropdownItem disabled>--------------</DropdownItem>
                )}
                {messageGroups &&
                  messageGroups.map(g => (
                    <DropdownItem
                      key={g}
                      onClick={() => this.setState({ selectedConversation: g })}
                    >
                      {g}
                    </DropdownItem>
                  ))}
                {teams &&
                  teams.filter(
                    t =>
                      messageGroups.findIndex(
                        m => m.toLowerCase().indexOf(t.type.toLowerCase()) > -1
                      ) > -1
                  ) && <DropdownItem disabled>--------------</DropdownItem>}
                {teams &&
                  teams
                    .filter(
                      t =>
                        messageGroups.findIndex(
                          m =>
                            m.toLowerCase().indexOf(t.type.toLowerCase()) > -1
                        ) > -1
                    )
                    .map(g => (
                      <DropdownItem
                        key={g.name}
                        onClick={() =>
                          this.setState({ selectedConversation: g.name })
                        }
                      >
                        {g.name}
                      </DropdownItem>
                    ))}
              </DropdownMenu>
            </ButtonDropdown>
          </Col>
          <Col sm={9}>

Messages

            <Card>

                {selectedConversation && (

                    Conversation with {selectedConversation}

                )}
                {messages
                  .filter(
                    m =>
                      m.sender === selectedConversation ||
                      m.destination === selectedConversation
                  )
                  .map(m => (

                      {m.sender}: {m.content}

                  ))}

            </Card>
            <form
              // eslint-disable-next-line
              action={"javascript:void(0);"}
              onSubmit={this.sendMessage}
            >
              <InputGroup>
                <Input
                  disabled={!selectedConversation}
                  onChange={evt =>
                    this.setState({ messageInput: evt.target.value })
                  }
                  value={messageInput}
                />
                <InputGroupButton>
                  <Button
                    disabled={!selectedConversation}
                    type="submit"
                    color="primary"
                  >
                    Send Message
                  </Button>
                </InputGroupButton>
              </InputGroup>
            </form>
          </Col>
        </Row>
      </Container>
    );
  }
}

const MESSAGING_QUERY = gql`
  query Messages($simulatorId: ID!, $simId: String, $station: String) {
    messages(simulatorId: $simulatorId, station: $station) {
      id
      sender
      content
      timestamp
      simulatorId
      destination
    }
    teams(simulatorId: $simulatorId) {
      id
      name
      type
    }
    simulators(id: $simId) {
      stations {
        name
        messageGroups
      }
    }
  }
`;
export default graphql(MESSAGING_QUERY, {
  options: ownProps => ({
    fetchPolicy: "cache-and-network",
    variables: {
      simulatorId: ownProps.simulator.id,
      simId: ownProps.simulator.id,
      station: ownProps.station.name
    }
  })
})(withApollo(Messaging));

function scrollTo(element, to, duration) {
  if (duration <= 0) return;
  let difference = to - element.scrollTop;
  let perTick = difference / duration * 10;

  setTimeout(function() {
    element.scrollTop = element.scrollTop + perTick;
    if (element.scrollTop === to) return;
    scrollTo(element, to, duration - 10);
  }, 10);
}
<|endoftext|>


<commit_before>/*
Copyright 2015 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var React = require('react');
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
var sdk = require('matrix-react-sdk');
var classNames = require('classnames');

module.exports = React.createClass({
    displayName: 'SearchBar',

    getInitialState: function() {
        return ({
            scope: 'Room'
        });
    },

    onThisRoomClick: function() {
        this.setState({ scope: 'Room' });
    },

    onAllRoomsClick: function() {
        this.setState({ scope: 'All' });
    },

    onSearchChange: function(e) {
        if (e.keyCode === 13) { // on enter...
            this.onSearch();
        }
    },

    onSearch: function() {
        this.props.onSearch(this.refs.search_term.value, this.state.scope);
    },

    render: function() {
        var searchButtonClasses = classNames({ mx_SearchBar_searchButton : true, mx_SearchBar_searching: this.props.searchInProgress });
        var thisRoomClasses = classNames({ mx_SearchBar_button : true, mx_SearchBar_unselected : this.state.scope !== 'Room' });
        var allRoomsClasses = classNames({ mx_SearchBar_button : true, mx_SearchBar_unselected : this.state.scope !== 'All' });

        return (

                <input ref="search_term" className="mx_SearchBar_input" type="text" autoFocus={true} placeholder="Search..." onKeyDown={this.onSearchChange}/>

This Room

All Rooms

        );
    }
});
<commit_msg>escape key to cancel search box<commit_after>/*
Copyright 2015 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var React = require('react');
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
var sdk = require('matrix-react-sdk');
var classNames = require('classnames');

module.exports = React.createClass({
    displayName: 'SearchBar',

    getInitialState: function() {
        return ({
            scope: 'Room'
        });
    },

    onThisRoomClick: function() {
        this.setState({ scope: 'Room' });
    },

    onAllRoomsClick: function() {
        this.setState({ scope: 'All' });
    },

    onSearchChange: function(e) {
        if (e.keyCode === 13) { // on enter...
            this.onSearch();
        }
        if (e.keyCode === 27) { // escape...
            this.props.onCancelClick();
        }
    },

    onSearch: function() {
        this.props.onSearch(this.refs.search_term.value, this.state.scope);
    },

    render: function() {
        var searchButtonClasses = classNames({ mx_SearchBar_searchButton : true, mx_SearchBar_searching: this.props.searchInProgress });
        var thisRoomClasses = classNames({ mx_SearchBar_button : true, mx_SearchBar_unselected : this.state.scope !== 'Room' });
        var allRoomsClasses = classNames({ mx_SearchBar_button : true, mx_SearchBar_unselected : this.state.scope !== 'All' });

        return (

                <input ref="search_term" className="mx_SearchBar_input" type="text" autoFocus={true} placeholder="Search..." onKeyDown={this.onSearchChange}/>

This Room

All Rooms

        );
    }
});
<|endoftext|>


<commit_before>var fs = require('fs');

describe("step-templates", function() {
  beforeEach(function(){
    jasmine.addMatchers({
      toHaveValidLastModified: function() {
        return {
          compare: function(template){
            if(typeof template.LastModifiedOn == 'undefined')  {
              return { pass: false, message: 'Expected template "' + template.Name + '" to have a valid LastModifiedOn date, but it was undefined.' }
            } else if(typeof template.LastModifiedBy == 'undefined')  {
              return { pass: false, message: 'Expected template "' + template.Name + '" to have a valid LastModifiedBy field, but it was undefined.' }
            } else {
              return { pass: true, message: 'Expected template "' + template.Name + '" to have a valid LastModified details.' }
            }
          }
        }
      }
    });
  });

  it("step templates have valid last modified details", function(done) {
    var filenameCounter = 0;
    var stepTemplateCount = 0;
    var dirname = './step-templates/';

    fs.readdir(dirname, function(err, filenames) {
      if (err) {
        console.log('error listing files in dir: ' + err);
        return;
      }
      stepTemplateCount = filenames.length;
      filenames.forEach(function(filename) {
        fs.readFile(dirname + filename, 'utf-8', function(err, content) {
          if (err) {
            console.log('error reading file ' + filename + ': ' + err);
            return;
          }
          try {
            var template = JSON.parse(content);
            expect(template).toHaveValidLastModified();
          }
          catch(e) {
            console.log('error reading file ' + dirname + filename + ': ' + e + ' - it might be UTF 8 with a BOM. Please resave without the BOM.')
          }
          if (filenameCounter++ == stepTemplateCount) {
            done();
          };
        });
      });
    });
  });
});
<commit_msg>Only check for presence of LastModifiedBy field<commit_after>var fs = require('fs');

describe("step-templates", function() {
  beforeEach(function(){
    jasmine.addMatchers({
      toHaveValidLastModified: function() {
        return {
          compare: function(template){
            if(typeof template.LastModifiedBy == 'undefined')  {
              return { pass: false, message: 'Expected template "' + template.Name + '" to have a valid LastModifiedBy field, but it was undefined.' }
            } else {
              return { pass: true, message: 'Expected template "' + template.Name + '" to have a valid LastModifiedBy field.' }
            }
          }
        }
      }
    });
  });

  it("step templates have valid last modified details", function(done) {
    var filenameCounter = 0;
    var stepTemplateCount = 0;
    var dirname = './step-templates/';

    fs.readdir(dirname, function(err, filenames) {
      if (err) {
        console.log('error listing files in dir: ' + err);
        return;
      }
      stepTemplateCount = filenames.length;
      filenames.forEach(function(filename) {
        fs.readFile(dirname + filename, 'utf-8', function(err, content) {
          if (err) {
            console.log('error reading file ' + filename + ': ' + err);
            return;
          }
          try {
            var template = JSON.parse(content);
            expect(template).toHaveValidLastModified();
          }
          catch(e) {
            console.log('error reading file ' + dirname + filename + ': ' + e + ' - it might be UTF 8 with a BOM. Please resave without the BOM.')
          }
          if (filenameCounter++ == stepTemplateCount) {
            done();
          };
        });
      });
    });
  });
});
<|endoftext|>


<commit_before>/*
 * This plugin parses goog.exportSymbol and goog.exportProperty calls to build
 * a list of API symbols and properties. Everything else is marked undocumented,
 * which will remove it from the docs.
 */

var api = [];

function collectExports(source) {
  var i, ii, symbol, property;
  var syms = source.match(/goog\.exportSymbol\([^\)]*\)/g);
  if (syms) {
    i = 0; ii = syms.length;
    for (; i < ii; ++i) {
      symbol = syms[i].match(/'([^']*)'/)[1];
      api.push(symbol);
    }
  }
  var props = source.match(/goog\.exportProperty\([^\)]*\)/g);
  if (props) {
    i = 0; ii = props.length;
    for (; i < ii; ++i) {
      property = props[i].match(/[^,]*,[^,]*,\r?\n? *([^\)]*)\)/)[1]
          .replace('.prototype.', '#');
      api.push(property);
    }
  }
}

var encoding = env.conf.encoding || 'utf8';
var fs = require('jsdoc/fs');
collectExports(fs.readFileSync('build/src/external/src/exports.js', encoding));
collectExports(fs.readFileSync('build/src/external/src/types.js', encoding));

exports.handlers = {

  beforeParse: function(e) {
    if (/\.js$/.test(e.filename)) {
      collectExports(e.source);
    }
  },

  newDoclet: function(e) {
    if (api.indexOf(e.doclet.longname) > -1) {
      // Add params of API symbols to the API
      var names, name;
      var params = e.doclet.params;
      if (params) {
        for (var i = 0, ii = params.length; i < ii; ++i) {
          names = params[i].type.names;
          if (names) {
            for (var j = 0, jj=names.length; j < jj; ++j) {
              name = names[j];
              if (api.indexOf(name) === -1) {
                api.push(name);
              }
            }
          }
        }
      }
    }
  }

};

function filter(e) {
  if (e.doclet) {
    var fqn = e.doclet.longname;
    if (fqn) {
      e.doclet.undocumented = (api.indexOf(fqn) === -1);
      // Remove parents that are not part of the API
      var parent;
      var parents = e.doclet.augments;
      if (parents) {
        for (var i = parents.length - 1; i >= 0; --i) {
          parent = parents[i];
          if (api.indexOf(parent) === -1) {
            parents.splice(i, 1);
          }
        }
      }
    }
  }
}

exports.nodeVisitor = {

  visitNode: function(node, e, parser, currentSourceName) {
    // filter out non-API symbols before the addDocletRef finisher is called
    e.finishers.unshift(filter);
  }
};
<commit_msg>external/src/types.js file no longer exists<commit_after>/*
 * This plugin parses goog.exportSymbol and goog.exportProperty calls to build
 * a list of API symbols and properties. Everything else is marked undocumented,
 * which will remove it from the docs.
 */

var api = [];

function collectExports(source) {
  var i, ii, symbol, property;
  var syms = source.match(/goog\.exportSymbol\([^\)]*\)/g);
  if (syms) {
    i = 0; ii = syms.length;
    for (; i < ii; ++i) {
      symbol = syms[i].match(/'([^']*)'/)[1];
      api.push(symbol);
    }
  }
  var props = source.match(/goog\.exportProperty\([^\)]*\)/g);
  if (props) {
    i = 0; ii = props.length;
    for (; i < ii; ++i) {
      property = props[i].match(/[^,]*,[^,]*,\r?\n? *([^\)]*)\)/)[1]
          .replace('.prototype.', '#');
      api.push(property);
    }
  }
}

var encoding = env.conf.encoding || 'utf8';
var fs = require('jsdoc/fs');
collectExports(fs.readFileSync('build/src/external/src/exports.js', encoding));

exports.handlers = {

  beforeParse: function(e) {
    if (/\.js$/.test(e.filename)) {
      collectExports(e.source);
    }
  },

  newDoclet: function(e) {
    if (api.indexOf(e.doclet.longname) > -1) {
      // Add params of API symbols to the API
      var names, name;
      var params = e.doclet.params;
      if (params) {
        for (var i = 0, ii = params.length; i < ii; ++i) {
          names = params[i].type.names;
          if (names) {
            for (var j = 0, jj=names.length; j < jj; ++j) {
              name = names[j];
              if (api.indexOf(name) === -1) {
                api.push(name);
              }
            }
          }
        }
      }
    }
  }

};

function filter(e) {
  if (e.doclet) {
    var fqn = e.doclet.longname;
    if (fqn) {
      e.doclet.undocumented = (api.indexOf(fqn) === -1);
      // Remove parents that are not part of the API
      var parent;
      var parents = e.doclet.augments;
      if (parents) {
        for (var i = parents.length - 1; i >= 0; --i) {
          parent = parents[i];
          if (api.indexOf(parent) === -1) {
            parents.splice(i, 1);
          }
        }
      }
    }
  }
}

exports.nodeVisitor = {

  visitNode: function(node, e, parser, currentSourceName) {
    // filter out non-API symbols before the addDocletRef finisher is called
    e.finishers.unshift(filter);
  }
};
<|endoftext|>