def acl_feed_task(email, resource_id, with_group=True): if with_group: logger.debug('Adding writing permission to anyone') GoogleDriveHelper.share_to(resource_id, emails=['{0}@unishared.com'.format(settings.GAPPS_GROUP_NAME), email], with_default_entry=True) else: logger.debug('Adding writing permission to {0}'.format(email)) GoogleDriveHelper.share_to(resource_id, emails=[email])
def acl_feed_task(email, resource_id, with_group=True): if with_group: logger.debug('Adding writing permission to anyone') GoogleDriveHelper.share_to(resource_id, emails=[ '{0}@unishared.com'.format( settings.GAPPS_GROUP_NAME), email ], with_default_entry=True) else: logger.debug('Adding writing permission to {0}'.format(email)) GoogleDriveHelper.share_to(resource_id, emails=[email])
def move_document_to_user_folder(resource_id, user): logger = LoggingHelper.getDebugLogger() client = GoogleDriveHelper.get_docs_client() dest_folder = user.get_profile().drive_folder_id if not dest_folder: logger.debug('Creating folder for {0}'.format(user.username)) dest_folder = GoogleDriveHelper.create_unistar_folder(user) user.get_profile().drive_folder_id = dest_folder user.get_profile().save() logger.debug('Moving {0} to {1}'.format(resource_id, GoogleDriveHelper._get_unistar_collection_name(user.username))) client.files().update(fileId=resource_id, body={"parents":[{'id':dest_folder}]}).execute()
def update_informations_task(): logger.debug('Starting update informations') client = GoogleDriveHelper.get_docs_client() params = {} params['includeDeleted'] = False result = client.changes().list(**params).execute() total_updated = 0 for item in result['items']: try: resource_id = GoogleDriveHelper.get_id_from_feed_url(item.id.text) if resource_id: is_updated = False title = item['file']['title'] updated = parser.parse(item['file']['modifiedDate']) updated = calendar.timegm(updated.utctimetuple()) logger.debug('Working on resource {0}'.format(resource_id)) document = Training.objects.get(resource_id=resource_id) if document.last_updated < updated: logger.debug( 'Updating last_updated for resource {0} from {1} to {2}' .format(resource_id, document.last_updated, updated)) document.last_updated = updated is_updated = True if document.title != title: logger.debug( u'Updating title for resource {0} from {1} to {2}'. format(resource_id, document.title, title)) document.title = title is_updated = True if is_updated: total_updated += 1 document.save() except Training.DoesNotExist: logger.debug('Unexisting resource {0}'.format(resource_id)) except Exception: LoggingHelper.getErrorLogger().error( 'An error occured while updating {0}'.format(item.id.text), exc_info=1) logger.debug('{0} resources updated'.format(total_updated))
def test_search_documents(self): response = { 'items': [ { 'id':'abcdef' }, { 'id':'1234' } ] } requestBuilder = RequestMockBuilder( { 'drive.files.list': (None, json.dumps(response)), } ) GoogleDriveHelper.get_docs_client = Mock() GoogleDriveHelper.get_docs_client.return_value = apiclient.discovery.build("drive", "v2", requestBuilder=requestBuilder) creator = User.objects.create_user('test-user') Training.objects.create(resource_id='resource_id_test', title='toto', creator=creator, is_displayed=True, is_deleted=False) Training.objects.create(resource_id='resource_id_test2', title='tata', creator=creator, is_displayed=True, is_deleted=False) search_results = GoogleDriveHelper.search_documents('toto') self.assertGreater(len(search_results), 0) self.assertIn('abcdef', search_results) self.assertIn('1234', search_results) self.assertIn('resource_id_test', search_results) self.assertNotIn('resource_id_test2', search_results)
def test_get_all_documents_max_documents_second_page(self): creator = User.objects.create_user('test-user') other_user = User.objects.create_user('other-user') document = Training.objects.create(resource_id='resource_id_test', title='toto', creator=creator, is_displayed=True, is_deleted=False) document2 = Training.objects.create(resource_id='resource_id_test2', title='toto', creator=other_user, is_displayed=True, is_deleted=False) document3 = Training.objects.create(resource_id='resource_id_test3', title='toto', creator=creator, is_displayed=True, is_deleted=False) total_records, results = GoogleDriveHelper.get_all_documents( max_documents=1, id_page=2) self.assertEqual(total_records, 3) self.assertNotIn(document, results) self.assertIn(document2, results) self.assertNotIn(document3, results)
def test_get_unistar_collection_name(self): username = '******' folder_name = GoogleDriveHelper._get_unistar_collection_name(username) self.assertEqual( folder_name, '[UniShared-{0}] {1}'.format(settings.ENV_NAME, username))
def test_search_documents(self): response = {'items': [{'id': 'abcdef'}, {'id': '1234'}]} requestBuilder = RequestMockBuilder({ 'drive.files.list': (None, json.dumps(response)), }) GoogleDriveHelper.get_docs_client = Mock() GoogleDriveHelper.get_docs_client.return_value = apiclient.discovery.build( "drive", "v2", requestBuilder=requestBuilder) creator = User.objects.create_user('test-user') Training.objects.create(resource_id='resource_id_test', title='toto', creator=creator, is_displayed=True, is_deleted=False) Training.objects.create(resource_id='resource_id_test2', title='tata', creator=creator, is_displayed=True, is_deleted=False) search_results = GoogleDriveHelper.search_documents('toto') self.assertGreater(len(search_results), 0) self.assertIn('abcdef', search_results) self.assertIn('1234', search_results) self.assertIn('resource_id_test', search_results) self.assertNotIn('resource_id_test2', search_results)
def update_informations_task(): logger.debug('Starting update informations') client = GoogleDriveHelper.get_docs_client() params = {} params['includeDeleted'] = False result = client.changes().list(**params).execute() total_updated = 0 for item in result['items']: try: resource_id = GoogleDriveHelper.get_id_from_feed_url(item.id.text) if resource_id: is_updated = False title = item['file']['title'] updated = parser.parse(item['file']['modifiedDate']) updated = calendar.timegm(updated.utctimetuple()) logger.debug('Working on resource {0}'.format(resource_id)) document = Training.objects.get(resource_id=resource_id) if document.last_updated < updated: logger.debug( 'Updating last_updated for resource {0} from {1} to {2}'.format(resource_id, document.last_updated, updated)) document.last_updated = updated is_updated = True if document.title != title: logger.debug( u'Updating title for resource {0} from {1} to {2}'.format(resource_id, document.title, title)) document.title = title is_updated = True if is_updated: total_updated += 1 document.save() except Training.DoesNotExist: logger.debug('Unexisting resource {0}'.format(resource_id)) except Exception: LoggingHelper.getErrorLogger().error('An error occured while updating {0}'.format(item.id.text), exc_info=1) logger.debug('{0} resources updated'.format(total_updated))
def test_get_document_url(self): resource_id = 'toto' url_expected = '{0}{1}'.format( settings.BASE_URL, reverse('website.views.embedded_document', args=[resource_id])) self.assertEqual(GoogleDriveHelper.get_document_url(resource_id), url_expected)
def test_get_documents_max_documents_second_page(self): creator = User.objects.create_user('test-user') document = Training.objects.create(resource_id='resource_id_test', title='toto', creator=creator, is_displayed=True, is_deleted=False) document2 = Training.objects.create(resource_id='resource_id_test2', title='toto', creator=creator, is_displayed=True, is_deleted=False) document3 = Training.objects.create(resource_id='resource_id_test3', title='toto', creator=creator, is_displayed=True, is_deleted=False) results = GoogleDriveHelper.get_documents([document, document2, document3], max_documents=1, id_page=2) self.assertNotIn(document, results) self.assertIn(document2, results) self.assertNotIn(document3, results)
def test_get_all_user_documents(self): creator = User.objects.create_user('test-user') other_user = User.objects.create_user('other-user') document = Training.objects.create(resource_id='resource_id_test', title='toto', creator=creator, is_displayed=True, is_deleted=False) document2 = Training.objects.create(resource_id='resource_id_test2', title='toto', creator=other_user, is_displayed=True, is_deleted=False) total_records, results = GoogleDriveHelper.get_all_user_documents(creator) self.assertEqual(total_records, 1) self.assertIn(document, results) self.assertNotIn(document2, results)
def move_document_to_user_folder(resource_id, user): logger = LoggingHelper.getDebugLogger() client = GoogleDriveHelper.get_docs_client() dest_folder = user.get_profile().drive_folder_id if not dest_folder: logger.debug('Creating folder for {0}'.format(user.username)) dest_folder = GoogleDriveHelper.create_unistar_folder(user) user.get_profile().drive_folder_id = dest_folder user.get_profile().save() logger.debug('Moving {0} to {1}'.format( resource_id, GoogleDriveHelper._get_unistar_collection_name(user.username))) client.files().update(fileId=resource_id, body={ "parents": [{ 'id': dest_folder }] }).execute()
def document_temp_share_task(document, user): logger.debug(u'Looking for a temporary share for training {0} and user {1}'.format(document.resource_id, user)) trainingTempShares = TrainingTempShare.objects.filter( Q(user_invited=user) | Q(facebook_id=user.get_profile().facebook_id) | Q(email=user.email), training=document) if trainingTempShares.exists(): logger.debug(u'Temporary share found for training {0} and user {1}'.format(document.resource_id, user)) for trainingTempShare in trainingTempShares: if trainingTempShare.role == 'cowriters': if document.creator != user and user not in document.cowriters.all(): logger.debug(u'Adding co-writer for training {0} and user {1}'.format(document.resource_id, user)) document.cowriters.add(user) if user in document.participants.all(): logger.debug(u'Remove participant for training {0} and user {1}'.format(document.resource_id, user)) document.participants.remove(user) document.save() else: logger.debug(u'User {0} is already cowriter on training {1}'.format(user, document.resource_id)) elif trainingTempShare.role == 'participants': if document.creator != user and user not in document.participants.all() and user not in document.cowriters.all(): logger.debug(u'Adding participant for training {0} and user {1}'.format(document.resource_id, user)) document.participants.add(user) document.save() else: logger.debug(u'User {0} is already cowriter/participant on training {1}'.format(user, document.resource_id)) trainingTempShare.delete() else: if document.creator != user and user not in document.cowriters.all() and user not in document.participants.all(): logger.debug('Adding participant for training {0} and user {1}'.format(document.resource_id, user)) document.participants.add(user) if Training.objects.filter(participants=user).count() == 1: logger.debug('Sending first participation mail') context = Context({'user': user, 'document': {'url': GoogleDriveHelper.get_document_url(document.resource_id), 'title': document.title}, 'ga_campaign_params': 'utm_source=unishared&utm_content=v1&utm_medium=e-mail&utm_campaign=new_document_participation_mail'}) email_task.apply_async( ["Yihaa, you participated in a collaborative document!", context, "new_document_participation_mail", [user.email]]) document.total_views += 1 document.total_views_open25 += 1 document.save() try: logger.debug('Adding participation for training {0} and user {1}'.format(document.resource_id, user)) participation = TrainingParticipation.objects.get(user=user, training=document) participation.count += 1 participation.save() except TrainingParticipation.DoesNotExist: TrainingParticipation.objects.create(user=user, training=document, count=1)
def test_create_unistar_folder(self): response = {'id': 'abcdef'} requestBuilder = RequestMockBuilder({ 'drive.files.insert': (None, json.dumps(response)), }) GoogleDriveHelper.get_docs_client = Mock() GoogleDriveHelper.get_docs_client.return_value = apiclient.discovery.build( "drive", "v2", requestBuilder=requestBuilder) user = User.objects.create_user('arnaud.breton', '*****@*****.**') self.assertEqual(GoogleDriveHelper.create_unistar_folder(user), 'abcdef')
def test_build_document_json(self): creator_user = User.objects.create_user('test-user') cowriter_user = User.objects.create_user('cowriter-user') participant_user = User.objects.create_user('participant-user') document = Training.objects.create(resource_id='resource_id_test', title='toto', type='document', creator=creator_user, is_displayed=True, is_deleted=False) document.cowriters.add(cowriter_user) document.participants.add(participant_user) creator = ProfileHelper.get_user_json(creator_user) cowriters = [ProfileHelper.get_user_json(cowriter) for cowriter in document.cowriters.all()] participants = [{'id' : participant.id} for participant in document.participants.all()] json_expected = {'resource' : { 'id' : document.resource_id, 'type' : document.type, 'title' : unicode(document.title), 'updated' : document.last_updated}, 'creator' : creator, 'cowriters' : cowriters, 'participants': participants} self.assertEqual(GoogleDriveHelper._build_document_json(document), json_expected)
def test_create_unistar_folder(self): response = { 'id' : 'abcdef' } requestBuilder = RequestMockBuilder( { 'drive.files.insert': (None, json.dumps(response)), } ) GoogleDriveHelper.get_docs_client = Mock() GoogleDriveHelper.get_docs_client.return_value = apiclient.discovery.build("drive", "v2", requestBuilder=requestBuilder) user = User.objects.create_user('arnaud.breton','*****@*****.**') self.assertEqual(GoogleDriveHelper.create_unistar_folder(user), 'abcdef')
def handle(self, *args, **options): self.stdout.write('Executing Remove Docs editors to group command\n') client = GoogleDriveHelper.get_docs_client() trainings = Training.objects.all() for training in trainings: try: self.stdout.write('Entry : {0}\n'.format(training.resource_id)) entry = client.GetResourceById(training.resource_id) acl_feed = client.GetResourceAcl(entry) if acl_feed: for acl in acl_feed.entry: if acl.scope.type == 'user' and acl.role.value != 'owner': self.stdout.write( 'Remove ACL entry : {0}\n'.format( acl.scope.value)) client.DeleteAclEntry(acl) group_mail = '{0}@unishared.com'.format(GAPPS_GROUP_NAME) self.stdout.write('Add {0} as editor\n'.format(group_mail)) acl_entry_user = AclEntry(scope=AclScope(value=group_mail, type='user'), role=AclRole(value='writer')) client.AddAclEntry(entry, acl_entry_user, send_notifications=False) self.stdout.write('Add {0} as editor\n'.format( training.creator.email)) acl_entry_user = AclEntry(scope=AclScope( value=training.creator.email, type='user'), role=AclRole(value='writer')) client.AddAclEntry(entry, acl_entry_user, send_notifications=False) except Exception, e: print e
def test_build_document_json(self): creator_user = User.objects.create_user('test-user') cowriter_user = User.objects.create_user('cowriter-user') participant_user = User.objects.create_user('participant-user') document = Training.objects.create(resource_id='resource_id_test', title='toto', type='document', creator=creator_user, is_displayed=True, is_deleted=False) document.cowriters.add(cowriter_user) document.participants.add(participant_user) creator = ProfileHelper.get_user_json(creator_user) cowriters = [ ProfileHelper.get_user_json(cowriter) for cowriter in document.cowriters.all() ] participants = [{ 'id': participant.id } for participant in document.participants.all()] json_expected = { 'resource': { 'id': document.resource_id, 'type': document.type, 'title': unicode(document.title), 'updated': document.last_updated }, 'creator': creator, 'cowriters': cowriters, 'participants': participants } self.assertEqual(GoogleDriveHelper._build_document_json(document), json_expected)
def test_get_documents_max_documents_second_page(self): creator = User.objects.create_user('test-user') document = Training.objects.create(resource_id='resource_id_test', title='toto', creator=creator, is_displayed=True, is_deleted=False) document2 = Training.objects.create(resource_id='resource_id_test2', title='toto', creator=creator, is_displayed=True, is_deleted=False) document3 = Training.objects.create(resource_id='resource_id_test3', title='toto', creator=creator, is_displayed=True, is_deleted=False) results = GoogleDriveHelper.get_documents( [document, document2, document3], max_documents=1, id_page=2) self.assertNotIn(document, results) self.assertIn(document2, results) self.assertNotIn(document3, results)
def document_temp_share_task(document, user): logger.debug( u'Looking for a temporary share for training {0} and user {1}'.format( document.resource_id, user)) trainingTempShares = TrainingTempShare.objects.filter( Q(user_invited=user) | Q(facebook_id=user.get_profile().facebook_id) | Q(email=user.email), training=document) if trainingTempShares.exists(): logger.debug( u'Temporary share found for training {0} and user {1}'.format( document.resource_id, user)) for trainingTempShare in trainingTempShares: if trainingTempShare.role == 'cowriters': if document.creator != user and user not in document.cowriters.all( ): logger.debug( u'Adding co-writer for training {0} and user {1}'. format(document.resource_id, user)) document.cowriters.add(user) if user in document.participants.all(): logger.debug( u'Remove participant for training {0} and user {1}' .format(document.resource_id, user)) document.participants.remove(user) document.save() else: logger.debug( u'User {0} is already cowriter on training {1}'.format( user, document.resource_id)) elif trainingTempShare.role == 'participants': if document.creator != user and user not in document.participants.all( ) and user not in document.cowriters.all(): logger.debug( u'Adding participant for training {0} and user {1}'. format(document.resource_id, user)) document.participants.add(user) document.save() else: logger.debug( u'User {0} is already cowriter/participant on training {1}' .format(user, document.resource_id)) trainingTempShare.delete() else: if document.creator != user and user not in document.cowriters.all( ) and user not in document.participants.all(): logger.debug( 'Adding participant for training {0} and user {1}'.format( document.resource_id, user)) document.participants.add(user) if Training.objects.filter(participants=user).count() == 1: logger.debug('Sending first participation mail') context = Context({ 'user': user, 'document': { 'url': GoogleDriveHelper.get_document_url( document.resource_id), 'title': document.title }, 'ga_campaign_params': 'utm_source=unishared&utm_content=v1&utm_medium=e-mail&utm_campaign=new_document_participation_mail' }) email_task.apply_async([ "Yihaa, you participated in a collaborative document!", context, "new_document_participation_mail", [user.email] ]) document.total_views += 1 document.total_views_open25 += 1 document.save() try: logger.debug( 'Adding participation for training {0} and user {1}'.format( document.resource_id, user)) participation = TrainingParticipation.objects.get( user=user, training=document) participation.count += 1 participation.save() except TrainingParticipation.DoesNotExist: TrainingParticipation.objects.create(user=user, training=document, count=1)
def test_get_unistar_collection_name(self): username = '******' folder_name = GoogleDriveHelper._get_unistar_collection_name(username) self.assertEqual(folder_name, '[UniShared-{0}] {1}'.format(settings.ENV_NAME, username))
def test_get_document_url(self): resource_id = 'toto' url_expected = '{0}{1}'.format(settings.BASE_URL, reverse('website.views.embedded_document', args=[resource_id])) self.assertEqual(GoogleDriveHelper.get_document_url(resource_id), url_expected)
def live_detection_change_feed(last_result): logger.debug('Starting live detection with change feed') client = GoogleDriveHelper.get_docs_client() params = {'includeDeleted': False} if last_result and last_result['startChangeId']: logger.debug('Last change id : {0}'.format( last_result['startChangeId'])) params['startChangeId'] = last_result['startChangeId'] result = client.changes().list(**params).execute() task_result = { 'startChangeId': int(result['largestChangeId']) + 1, 'items': [] } for item in result['items']: resource_id = item['file']['id'] updated = parser.parse(item['file']['modifiedDate']) title = item['file']['title'] try: last_entries = None if last_result: last_entries = [ last_entry for last_entry in last_result['items'] if last_entry['document_id'] == resource_id ] last_entry = last_entries[0] if last_entries and len( last_entries) > 0 else None document = Training.objects.get(resource_id=resource_id) logger.debug('Document recently modified : %s', resource_id) if document.title != title: logger.debug( 'Updating title of document {0}'.format(resource_id)) document.title = title updated = calendar.timegm(updated.utctimetuple()) document.last_updated = updated if last_entry: logger.debug('Previous entry found') logger.debug('Last entry : {0}'.format(last_entry)) if last_entry['live'] is None: logger.debug('Enabling live in DB for %s', resource_id) document.is_live = True document.is_displayed = True email_task.apply_async([ 'Document live', Context({ 'document_url': GoogleDriveHelper.get_document_url(resource_id) }), 'document_live', [a[1] for a in settings.ADMINS], None, 'gmail' ]) else: logger.debug('Document already live %s', resource_id) task_result['items'].append({ 'document_id': resource_id, 'live': True }) else: logger.debug('No previous entry found') logger.debug('Creating entry %s', resource_id) task_result['items'].append({ 'document_id': resource_id, 'live': None }) document.save() except Training.DoesNotExist: logger.debug('Unexisting resource {0}'.format(resource_id)) except Exception: LoggingHelper.getErrorLogger().error( 'An error occurred while detecting live', exc_info=1) logger.debug('Disabling documents not live anymore') Training.objects.filter( ~Q(resource_id__in=[item['file']['id'] for item in result['items']]), is_live=True).update(is_live=False) logger.debug('Result : %s', task_result) live_detection_change_feed.apply_async([task_result], eta=timezone.now() + timedelta(minutes=5)) return task_result
def live_detection_change_feed(last_result): logger.debug('Starting live detection with change feed') client = GoogleDriveHelper.get_docs_client() params = {'includeDeleted' : False} if last_result and last_result['startChangeId']: logger.debug('Last change id : {0}'.format(last_result['startChangeId'])) params['startChangeId'] = last_result['startChangeId'] result = client.changes().list(**params).execute() task_result = {'startChangeId' : int(result['largestChangeId']) + 1, 'items' : []} for item in result['items']: resource_id = item['file']['id'] updated = parser.parse(item['file']['modifiedDate']) title = item['file']['title'] try: last_entries = None if last_result: last_entries = [last_entry for last_entry in last_result['items'] if last_entry['document_id'] == resource_id] last_entry = last_entries[0] if last_entries and len(last_entries) > 0 else None document = Training.objects.get(resource_id=resource_id) logger.debug('Document recently modified : %s', resource_id) if document.title != title: logger.debug('Updating title of document {0}'.format(resource_id)) document.title=title updated = calendar.timegm(updated.utctimetuple()) document.last_updated = updated if last_entry: logger.debug('Previous entry found') logger.debug('Last entry : {0}'.format(last_entry)) if last_entry['live'] is None: logger.debug('Enabling live in DB for %s', resource_id) document.is_live = True document.is_displayed = True email_task.apply_async( ['Document live', Context({'document_url': GoogleDriveHelper.get_document_url(resource_id)}), 'document_live', [a[1] for a in settings.ADMINS], None, 'gmail']) else: logger.debug('Document already live %s', resource_id) task_result['items'].append({'document_id': resource_id, 'live': True}) else: logger.debug('No previous entry found') logger.debug('Creating entry %s', resource_id) task_result['items'].append({'document_id': resource_id, 'live': None}) document.save() except Training.DoesNotExist: logger.debug('Unexisting resource {0}'.format(resource_id)) except Exception: LoggingHelper.getErrorLogger().error('An error occurred while detecting live', exc_info=1) logger.debug('Disabling documents not live anymore') Training.objects.filter(~Q(resource_id__in=[item['file']['id'] for item in result['items']]), is_live=True).update(is_live=False) logger.debug('Result : %s', task_result) live_detection_change_feed.apply_async([task_result], eta=timezone.now()+timedelta(minutes=5)) return task_result
def run(self): logger = LoggingHelper.getDebugLogger() logger.debug('Looking for a temporary share for training {0} and user {1}'.format(self.training.resource_id, self.user)) trainingShare = TrainingTempShare.objects.filter(Q(facebook_id=self.user.get_profile().facebook_id) | Q(email=self.user.email), training=self.training) if trainingShare.exists(): logger.debug('Temporary share found for training {0} and user {1}'.format(self.training.resource_id, self.user)) if self.training.creator != self.user and self.user not in self.training.cowriters.all(): logger.debug('Adding co-writer for training {0} and user {1}'.format(self.training.resource_id, self.user)) self.training.cowriters.add(self.user) if self.user in self.training.participants.all(): logger.debug('Remove participant for training {0} and user {1}'.format(self.training.resource_id, self.user)) self.training.participants.remove(self.user) trainingShare.delete() elif self.training.creator != self.user and self.user not in self.training.cowriters.all() and self.user not in self.training.participants.all(): logger.debug('Adding participant for training {0} and user {1}'.format(self.training.resource_id, self.user)) self.training.participants.add(self.user) if Training.objects.filter(participants=self.user).count() == 1: logger.debug('Sending first participation mail') context = Context({'username': self.user.username, 'first_name' : self.user.first_name, 'profile_url' : ProfileHelper.get_profile_url(self.user.username), 'document_url' : GoogleDriveHelper.get_document_url(self.training.resource_id), 'document_title' : self.training.title, 'ga_campaign_params' : 'utm_source=unishared&utm_content=v1&utm_medium=e-mail&utm_campaign=new_document_participation_mail'}) email_task.apply_async(["Yihaa, you participated in a collaborative document!", context, "new_document_participation_mail", [self.user.email]]) try: logger.debug('Adding participation for training {0} and user {1}'.format(self.training.resource_id, self.user)) participation = TrainingParticipation.objects.get(user=self.user, training=self.training) participation.count += 1 participation.save() except TrainingParticipation.DoesNotExist: TrainingParticipation.objects.create(user=self.user, training=self.training, count=1)