def delete(self, project_id=None): if self.request.get('token_id') is None: raise HttpErrorException.bad_request('no token id') self.user.current_token_id = self.request.get('token_id') if not project_id and not Project.valid_id(project_id): raise HttpErrorException.bad_request('no project id') project = Project.get_by_id(project_id) if not project: raise HttpErrorException.bad_request('invaild project id') if not project.has_permission_delete(self.user): raise HttpErrorException.forbidden() trans = Transaction(action='pro_del', user=self.user.key, artifact=project.key, project=project.key) trans.put() self.get_channel_token() channel_tokens = ChannelToken.get_by_project_key( project.key, self.user_channel_token) channel_tokens = ChannelToken.remove_unauthorized_users( channel_tokens, [project]) message = { 'user': self.get_user_channel_data(), 'transaction': trans.to_dict(self.user) } ChannelToken.broadcast_message(channel_tokens, message) project.delete(self.user)
def _set_title(self): title = self.json_request.get('title') if title.rstrip() == '': raise HttpErrorException.bad_request('empty title given') if not self.project.has_permission_write(self.user): raise HttpErrorException.forbidden() self.project.title = title action_data = {'title': title} trans = Transaction(action='pro_title', user=self.user.key, artifact=self.project.key, project=self.project.key, action_data=action_data) trans.put() self.get_channel_token() channel_tokens = ChannelToken.get_by_project_key( self.project.key, self.user_channel_token) channel_tokens = ChannelToken.remove_unauthorized_users( channel_tokens, [self.project]) message = { 'user': self.get_user_channel_data(), 'transaction': trans.to_dict(self.user) } ChannelToken.broadcast_message(channel_tokens, message)
def run(self): try: log.info('Publisher Stated') self.set_lock() org = self.user.organization.get( ) if self.user.organization else None publisher = DocumentPublisherEngine(self.project, self.document, self.group, organization=org) publisher.render() pubs = self.document.get_published(group=self.group) version_int = PublishDocument.get_largest_version(pubs) if version_int is None: version_int = 1 else: version_int += 1 pub_doc = PublishDocument(key=PublishDocument.create_key()) pub_doc.project = self.project.key pub_doc.document = self.document.key pub_doc.group = self.group.key pub_doc.version = self.version pub_doc.version_int = version_int pub_doc.html = publisher.html pub_doc.owner.append(self.user.key) if self.user.organization: pub_doc.organization = self.user.organization pub_doc.put() pub_doc.cache(latest=True) self.document.published.append(pub_doc.key) self.document.put() action_data = {'publish': pub_doc.to_dict(html=False)} trans = Transaction(action='doc_published', user=self.user.key, artifact=self.document.key, project=self.project.key, action_data=action_data) trans.put() self.project.pw_modified_ts = datetime.now() self.project.put() self.cache_publish(pub_doc) except: self.cache_error('500') raise finally: self.release_lock() log.info('Publisher Finished')
def _add_perm(self): group, required = self.project.validate_add_perm_request( self.json_request, self.user) self.project.add_group_perm(group, self.json_request.get('operation'), self.json_request.get('permission'), required) if self.json_request.get('operation') == 'read': self.project.record_analytic('pro_perm', self.analytic_session) action_data = { 'group': group.key.id(), 'operation': self.json_request.get('operation'), 'permission': self.json_request.get('permission'), 'type': 'required' if required else 'shared', 'hidden': False, } trans = Transaction(action='pro_perm_add', user=self.user.key, artifact=self.project.key, project=self.project.key, action_data=action_data) trans.put() org = self.project.organization.get() # Get project channel tokens channel_tokens = ChannelToken.get_by_project_key( self.project.key, self.user_channel_token) # Loop through each channel token to test permissions on next sibling for channel_token in channel_tokens: ach_user = channel_token.user.get() if (not self.project.has_permission_read(channel_token.user.get()) and not self.project.had_permission_read( channel_token.user.get())): continue if not ach_user.is_super_admin and not \ (ach_user.is_org_admin and org.key == ach_user.organization) and \ org.is_hidden_group(group): fake_id = memcache.get(group.key.id() + '_fake_id') if fake_id is None: fake_id = server.create_uuid() memcache.add(key=group.key.id() + '_fake_id', value=fake_id) trans.action_data['group'] = fake_id trans.action_data['hidden'] = True message = { 'user': self.get_user_channel_data(), 'transaction': trans.to_dict(self.user) } ChannelToken.broadcast_message([channel_token], message)
def _remove_group(self): group = self.phrasing.validate_rm_group_request( self.json_request, self.user) for op in self.phrasing.operations_list: self.phrasing.remove_group_perm(group, op) self.phrasing.remove_group_perm(group, op, required=True) project = self.phrasing.concept.get().project.get() self.phrasing.broadcast_rm_grp(project, group, self.user, 'phr_rm_grp') action_data = { 'group': group.key.id(), 'hidden': False, } trans = Transaction(action='phr_grp_rmv', user=self.user.key, artifact=self.phrasing.key, project=project.key, action_data=action_data) trans.put() org = project.organization.get() # Get project channel tokens channel_tokens = ChannelToken.get_by_project_key( project.key, self.user_channel_token) # Loop through each channel token to test permissions on next sibling for channel_token in channel_tokens: ach_user = channel_token.user.get() if (not self.phrasing.has_permission_read(channel_token.user.get()) and not self.phrasing.had_permission_read( channel_token.user.get())): continue if not ach_user.is_super_admin and not \ (ach_user.is_org_admin and org.key == ach_user.organization) and \ org.is_hidden_group(group): fake_id = memcache.get(group.key.id() + '_fake_id') if fake_id is None: fake_id = server.create_uuid() memcache.add(key=group.key.id() + '_fake_id', value=fake_id) trans.action_data['group'] = fake_id trans.action_data['hidden'] = True message = { 'user': self.get_user_channel_data(), 'transaction': trans.to_dict(self.user) } ChannelToken.broadcast_message([channel_token], message)
def _up_vote(self): if not self.project.has_permission_write(self.user): raise HttpErrorException.forbidden() vote_changed = True pvote = self.project.get_user_vote(self.user) # If there is no previous vote, they can vote up or down if pvote is None: self.project.project_score += 1 uvote = ProjectUserVotes(project=self.project.key, user=self.user.key, direction='up') uvote.put() # If there was a previous vote and its down. We remove their vote, otherwise they are trying # to vote up again and we disallow that. elif pvote is not None and pvote.direction == 'down': self.project.project_score += 1 pvote.key.delete() else: vote_changed = False if vote_changed: cost = spectra.calculate_cost('pro_up_vote', user=self.user, artifact=self.project) if not spectra.has_sufficient_points(cost, self.user): raise HttpErrorException.forbidden() self.user.sub_spectra_cost(cost) action_data = {'project_score': self.project.project_score} trans = Transaction(action='pro_up_vote', user=self.user.key, artifact=self.project.key, project=self.project.key, action_data=action_data) trans.put() self.get_channel_token() channel_tokens = ChannelToken.get_by_project_key( self.project.key, self.user_channel_token) channel_tokens = ChannelToken.remove_unauthorized_users( channel_tokens, [self.project]) message = { 'user': self.get_user_channel_data(), 'transaction': trans.to_dict(self.user) } ChannelToken.broadcast_message(channel_tokens, message)
def _activate_document(self): trans = Transaction(action='doc_act', user=self.user.key, artifact=self.document.key, project=self.document.project) trans.put() channel_tokens = ChannelToken.get_by_project_key( self.project.key, self.user_channel_token) channel_tokens = ChannelToken.remove_unauthorized_users( channel_tokens, [self.document]) message = { 'user': self.get_user_channel_data(), 'transaction': trans.to_dict(self.user) } ChannelToken.broadcast_message(channel_tokens, message)
def _set_text(self): if not self.phrasing.has_permission_write(self.user): raise HttpErrorException.forbidden() self.get_analytic_session() concept = self.phrasing.concept.get() project = concept.project.get() if concept.is_image(project.distilled_document ) and self.phrasing.text.rstrip() == '': raise HttpErrorException.bad_request( 'can not override this phrasing') old_text = self.phrasing.text self.phrasing.text = self.json_request.get('text') index = self.user.get_put_index() self.phrasing.index(index, concept=concept) concept.record_analytic('con_phr_edit', self.analytic_session) action_data = { 'old_text': old_text, 'text': self.phrasing.text, } trans = Transaction(action='phr_edt', user=self.user.key, artifact=self.phrasing.key, project=project.key, action_data=action_data) trans.put() self.get_channel_token() channel_tokens = ChannelToken.get_by_project_key( project.key, self.user_channel_token) channel_tokens = ChannelToken.remove_unauthorized_users( channel_tokens, [concept, self.phrasing]) message = { 'user': self.get_user_channel_data(), 'transaction': trans.to_dict(self.user) } ChannelToken.broadcast_message(channel_tokens, message)
def delete(self, phrasing_id=None): if not phrasing_id: raise HttpErrorException.bad_request('no phrasing_id given') phrasing = Phrasing.get_by_id(phrasing_id) if not phrasing: raise HttpErrorException.bad_request('invalid phrasing_id given') if not phrasing.has_permission_write(self.user): raise HttpErrorException.forbidden() concept = phrasing.concept.get() if phrasing.key == concept.distilled_phrasing: raise HttpErrorException.forbidden() project = phrasing.project.get() project.pw_modified_ts = datetime.datetime.now() project.put() trans = Transaction(action='phr_del', user=self.user.key, artifact=phrasing.key, project=project.key) trans.put() self.get_channel_token() channel_tokens = ChannelToken.get_by_project_key( project.key, self.user_channel_token) channel_tokens = ChannelToken.remove_unauthorized_users( channel_tokens, [concept, phrasing]) message = { 'user': self.get_user_channel_data(), 'transaction': trans.to_dict(self.user) } ChannelToken.broadcast_message(channel_tokens, message) phrasing.delete(concept, self.user) self.get_analytic_session() concept.record_analytic('con_phr_del', self.analytic_session)
def delete(self, document_id=None): if not document_id and not Document.valid_id(document_id): raise HttpErrorException.bad_request('invalid document id') self.document = Document.get_by_id(document_id) if not self.document: raise HttpErrorException.bad_request('invalid document id') if not self.document.has_permission_write(self.user): raise HttpErrorException.forbidden() if self.document.is_distilled_document(): raise HttpErrorException.bad_request( 'can not delete distilled document') trans = Transaction(action='doc_del', user=self.user.key, artifact=self.document.key, project=self.document.project) trans.put() self.get_channel_token() channel_tokens = ChannelToken.get_by_project_key( self.document.project, self.user_channel_token) channel_tokens = ChannelToken.remove_unauthorized_users( channel_tokens, [self.document]) message = { 'user': self.get_user_channel_data(), 'transaction': trans.to_dict(self.user) } ChannelToken.broadcast_message(channel_tokens, message) self._delete_document() project = self.document.project.get() project.modified_ts = datetime.datetime.now() project.pw_modified_ts = datetime.datetime.now() project.put()
def put(self, phrasing_id=None): self.get_analytic_session() phrasing_text = self.json_request.get('text') if not phrasing_text: raise HttpErrorException.bad_request('invalid phrasing text') if not self.json_request.get('concept') and not Concept.valid_id( self.json_request.get('concept')): raise HttpErrorException.bad_request('invalid concept id') concept = Concept.get_by_id(self.json_request.get('concept')) if not concept: raise HttpErrorException.bad_request('invalid concept id') if not self.json_request.get('document') and not Document.valid_id( self.json_request.get('document')): raise HttpErrorException.bad_request('invalid document id') document = Document.get_by_id(self.json_request.get('document')) if not document: raise HttpErrorException.bad_request('invalid document id') sum_doc = None if self.json_request.get('summary', False): if not document.summary_document: HttpErrorException.bad_request( 'no document does not have summary') sum_doc = document.summary_document.get() if not sum_doc: HttpErrorException.bad_request( 'no document does not have summary') pres_doc = None if self.json_request.get('presentation', False): if not document.presentation_document: HttpErrorException.bad_request( 'no document does not have presentation') pres_doc = document.presentation_document.get() if not pres_doc: HttpErrorException.bad_request( 'no document does not have presentation') phr_perm = Permission(permissions=Permission.init_perm_struct( Phrasing.operations_list), key=Permission.create_key(), project=document.project) phrasing = Phrasing(key=Phrasing.create_key(), text=phrasing_text, concept=concept.key, owner=[self.user.key], permissions=phr_perm.key, project=document.project) phr_perm.artifact = phrasing.key concept.phrasings.append(phrasing.key) sel_phr = None if (document.is_distilled_document() and document.project == concept.project and sum_doc is None and pres_doc is None): concept.distilled_phrasing = phrasing.key else: if sum_doc is not None: if concept.has_summary_selected_phrasing(document=sum_doc): sel_phr = concept.get_summary_selected_phrasing(sum_doc) sel_phr.phrasing = phrasing.key else: sel_phr = SummarySelectedPhrasing( key=SummarySelectedPhrasing.create_key(), project=concept.project, document=sum_doc.key, phrasing=phrasing.key) concept.summary_selected_phrasings.append(sel_phr.key) elif pres_doc is not None: if concept.has_presentation_selected_phrasing( document=pres_doc): sel_phr = concept.get_presentation_selected_phrasing( pres_doc) sel_phr.phrasing = phrasing.key else: sel_phr = PresentationSelectedPhrasing( key=PresentationSelectedPhrasing.create_key(), project=concept.project, document=pres_doc.key, phrasing=phrasing.key) concept.presentation_selected_phrasings.append(sel_phr.key) else: if concept.has_selected_phrasing(document=document): sel_phr = concept.get_selected_phrasing(document=document) sel_phr.phrasing = phrasing.key else: sel_phr = SelectedPhrasing( key=SelectedPhrasing.create_key(), document=document.key, phrasing=phrasing.key, project=document.project) concept.selected_phrasings.append(sel_phr.key) sel_phr.put() phrasing.originating_document = document.key project = phrasing.project.get() project.pw_modified_ts = datetime.datetime.now() ndb.put_multi([phr_perm, phrasing, concept, project]) index = self.user.get_put_index() phrasing.index(index, concept=concept) concept.record_analytic('con_phr_new', self.analytic_session) self.write_json_response({ 'phrasing': phrasing.to_dict(self.user), 'selected_phrasing': sel_phr.to_dict() if sel_phr else None }) action_data = { 'concept': concept.key.id(), 'document': document.key.id(), 'phrasing': phrasing.to_dict(self.user) } trans = Transaction(action='phr_new', user=self.user.key, artifact=phrasing.key, project=project.key, action_data=action_data) trans.put() self.get_channel_token() channel_tokens = ChannelToken.get_by_project_key( project.key, self.user_channel_token) channel_tokens = ChannelToken.remove_unauthorized_users( channel_tokens, [concept, phrasing, document]) message = { 'user': self.get_user_channel_data(), 'transaction': trans.to_dict(self.user) } ChannelToken.broadcast_message(channel_tokens, message)
def put(self, document_id=None): if not self.json_request.get('project') and not Project.valid_id( self.json_request.get('project')): raise HttpErrorException.bad_request('invalid project id') pro = Project.get_by_id(self.json_request.get('project')) if not pro: raise HttpErrorException.bad_request('invalid project id') if not pro.has_permission_read(self.user): raise HttpErrorException.forbidden() if not self.json_request.get('title'): raise HttpErrorException.bad_request('invalid title') doc = Document(key=Document.create_key()) doc.project = pro.key doc.title = self.json_request.get('title') doc.subtitle = self.json_request.get('subtitle') doc.author = self.json_request.get('author') doc.version = self.json_request.get('version') doc.date = self.json_request.get('date') doc.copyright_text = self.json_request.get('copyright') doc.description = self.json_request.get('description') doc.owner.append(self.user.key) doc_perm = Permission(permissions=Permission.init_perm_struct( Document.operations_list), key=Permission.create_key(), project=pro.key) doc_perm.artifact = doc.key doc_perm.put() doc.permissions = doc_perm.key if self.user.in_org(): doc.organization = self.user.organization doc.parent_perms = [ pro.permissions, pro.distilled_document.get().permissions ] doc.put() pro.documents.append(doc.key) indexes = self.user.get_put_index() doc.index(indexes) pro.pw_modified_ts = datetime.datetime.now() pro.put() self.write_json_response(doc.to_dict(self.user)) action_data = {'document': doc.to_dict(self.user)} trans = Transaction(action='doc_new', user=self.user.key, artifact=doc.key, project=pro.key, action_data=action_data) trans.put() self.get_channel_token() channel_tokens = ChannelToken.get_by_project_key( pro.key, self.user_channel_token) channel_tokens = ChannelToken.remove_unauthorized_users( channel_tokens, [doc]) for channel_token in channel_tokens: trans.action_data['document'] = doc.to_dict( channel_token.user.get()) message = { 'user': self.get_user_channel_data(), 'transaction': trans.to_dict(self.user) } ChannelToken.broadcast_message([channel_token], message)
def post(self, document_id=None): self.get_channel_token() modify_ts = True if not document_id and not Document.valid_id(document_id): raise HttpErrorException.bad_request('invalid document id') self.document = Document.get_by_id(document_id) if not self.document: raise HttpErrorException.bad_request('invalid document id') self.project = self.document.project.get() if not self.document.has_permission_read(self.user): raise HttpErrorException.forbidden() if self.json_request.get('active_document'): modify_ts = False self._activate_document() else: if not self.document.has_permission_write(self.user): raise HttpErrorException.forbidden() if self.json_request.get('permission'): self._add_perm() values = {} values_changed = False if not self.json_request.get( 'permission') and self.json_request.get('group_id'): self._rm_perm() if self.json_request.get('remove_group'): self._remove_group() if self.json_request.get('title') is not None: self._set_title() values_changed = True values['title'] = self.json_request.get('title', '') if self.json_request.get('subtitle') is not None: self._set_subtitle() values_changed = True values['subtitle'] = self.json_request.get('subtitle', '') if self.json_request.get('author') is not None: self._set_author() values_changed = True values['author'] = self.json_request.get('author', '') if self.json_request.get('date') is not None: self._set_date() values_changed = True values['date'] = self.json_request.get('date', '') if self.json_request.get('version') is not None: self._set_version() values_changed = True values['version'] = self.json_request.get('version', '') if self.json_request.get('copyright') is not None: self._set_copyright() values_changed = True values['copyright'] = self.json_request.get('copyright', '') if self.json_request.get('description') is not None: self._set_description() values_changed = True values['description'] = self.json_request.get( 'description', '') if values_changed: action_data = {'values': values} trans = Transaction(action='doc_edit', user=self.user.key, artifact=self.document.key, project=self.document.project, action_data=action_data) trans.put() self.get_channel_token() channel_tokens = ChannelToken.get_by_project_key( self.document.project, self.user_channel_token) channel_tokens = ChannelToken.remove_unauthorized_users( channel_tokens, [self.document]) message = { 'user': self.get_user_channel_data(), 'transaction': trans.to_dict(self.user) } ChannelToken.broadcast_message(channel_tokens, message) if modify_ts: project = self.document.project.get() project.pw_modified_ts = datetime.datetime.now() project.put() self.document.put()
def post(self, concept_id=None): if not concept_id and not Concept.valid_id(concept_id): raise HttpErrorException.bad_request('invalid concept id') concept = Concept.get_by_id(concept_id) if not concept: raise HttpErrorException.bad_request('invalid concept id') if not self.json_request.get('document_id') and not Document.valid_id( self.json_request.get('document_id')): raise HttpErrorException.bad_request('invalid document id') document = Document.get_by_id(self.json_request.get('document_id')) if not document: raise HttpErrorException.bad_request('invalid document id') if not document.has_permission_set_crawlcontext(self.user): raise HttpErrorException.forbidden() project = document.project.get() if not isinstance(self.json_request.get('crawl'), bool): raise HttpErrorException.bad_request('invalid crawl') crawlcontexts = ndb.get_multi(concept.crawlcontext) for crawl in crawlcontexts: if crawl.document == document.key: crawl.crawl = self.json_request.get('crawl') crawl.put() crawlcontext = crawl break else: crawl = CrawlContext(key=CrawlContext.create_key(), project=project.key, document=document.key, crawl=self.json_request.get('crawl')) crawl.put() concept.crawlcontext.append(crawl.key) concept.put() crawlcontext = crawl project.pw_modified_ts = datetime.datetime.now() project.put() self.get_analytic_session() if crawl.crawl: concept.record_analytic('con_cc_t', self.analytic_session) else: concept.record_analytic('con_cc_f', self.analytic_session) action = 'con_hid' if self.json_request.get('crawl'): action = 'con_shw' action_data = { 'concept': concept.key.id(), 'document': document.key.id() } trans = Transaction(action=action, user=self.user.key, artifact=crawlcontext.key, project=project.key, document=document, action_data=action_data) trans.put() self.get_channel_token() channel_tokens = ChannelToken.get_by_project_key( project.key, self.user_channel_token) channel_tokens = ChannelToken.remove_unauthorized_users( channel_tokens, [concept, document]) message = { 'user': self.get_user_channel_data(), 'transaction': trans.to_dict(self.user) } ChannelToken.broadcast_message(channel_tokens, message)
def post(self, phrasing_id=None): if not phrasing_id: raise HttpErrorException.bad_request('no phrasing_id given') phrasing = Phrasing.get_by_id(phrasing_id) if not phrasing: raise HttpErrorException.bad_request('invalid phrasing_id given') if not self.json_request.get('document'): raise HttpErrorException.bad_request('no document given') document = Document.get_by_id(self.json_request.get('document')) if not document: raise HttpErrorException.bad_request('invalid document given') if not document.has_permission(self.user, 'manage_phrasings'): lr = tt_logging.construct_log( msg_short='User does not have manage_phrasing perm', log_type=tt_logging.SECURITY, request=self.request, artifact=document, request_user=self.user) log.info(lr['dict_msg']['msg'], extra=lr) raise HttpErrorException.forbidden() concept = phrasing.concept.get() project = concept.project.get() selected_phrasing = None if document.is_distilled_document( ) and project.key == document.project: concept.distilled_phrasing = phrasing.key concept.put() else: if concept.has_selected_phrasing(document=document): selected_phrasing = concept.get_selected_phrasing(document) selected_phrasing.phrasing = phrasing.key selected_phrasing.put() else: selected_phrasing = SelectedPhrasing(id=Phrasing.create_uuid(), project=concept.project, document=document.key, phrasing=phrasing.key) selected_phrasing.put() concept.selected_phrasings.append(selected_phrasing.key) concept.put() project = document.project.get( ) # Don't want concept's project, this could be a linked concept project.pw_modified_ts = datetime.datetime.now() project.put() self.get_analytic_session() concept.record_analytic('con_phr_cha', self.analytic_session) if selected_phrasing: self.write_json_response(selected_phrasing.to_dict()) action_data = {'document': document.key.id()} trans = Transaction(action='phr_chg', user=self.user.key, artifact=phrasing.key, project=project.key, action_data=action_data) trans.put() self.get_channel_token() channel_tokens = ChannelToken.get_by_project_key( project.key, self.user_channel_token) channel_tokens = ChannelToken.remove_unauthorized_users( channel_tokens, [concept, document, phrasing]) message = { 'user': self.get_user_channel_data(), 'transaction': trans.to_dict(self.user) } ChannelToken.broadcast_message(channel_tokens, message)
def _add_attribute(self): r_attr = self.json_request.get('add_attribute') if not r_attr: raise ValueError('no attribute given') if not isinstance(r_attr, basestring): raise ValueError('attributes must be a string') if not self.json_request.get('document'): raise ValueError('no document id given') if not Document.valid_id(self.json_request.get('document')): raise HttpErrorException.bad_request('invalid document id') doc = Document.get_by_id(self.json_request.get('document')) if not doc.has_permission_write(self.user): raise HttpErrorException.forbidden() if not doc: raise ValueError('invalid document id given') attr = self.project.get_attr(doc.key) if attr: if r_attr == 'h' and 'noh' in attr.attributes: attr.attributes.remove('noh') if r_attr == 'noh' and 'h' in attr.attributes: attr.attributes.remove('h') if r_attr == 'ol' and 'nol' in attr.attributes: attr.attributes.remove('nol') if r_attr == 'ol' and 'ul' in attr.attributes: attr.attributes.remove('ul') if r_attr == 'ul' and 'nol' in attr.attributes: attr.attributes.remove('nol') if r_attr == 'il' and 'ol' in attr.attributes: attr.attributes.remove('ol') if r_attr == 'nol' and 'ol' in attr.attributes: attr.attributes.remove('ol') if r_attr == 'nol' and 'ul' in attr.attributes: attr.attributes.remove('ul') if r_attr not in attr.attributes: attr.attributes.append(r_attr) attr.put() else: attr = [r_attr] if r_attr != 'attr' else [] attr = Attributes(project=self.project.project, document=doc.key, attributes=attr) attr.put() self.project.attributes.append(attr.key) action_data = {'attribute': r_attr, 'document': doc.key.id()} trans = Transaction(action='pro_attr_add', user=self.user.key, artifact=self.project.key, project=self.project.key, action_data=action_data) trans.put() channel_tokens = ChannelToken.get_by_project_key( self.project.key, self.user_channel_token) channel_tokens = ChannelToken.remove_unauthorized_users( channel_tokens, [self.project, doc]) message = { 'user': self.get_user_channel_data(), 'transaction': trans.to_dict(self.user) } ChannelToken.broadcast_message(channel_tokens, message)