class GroupManager(object): def __init__(self, assignment_id, group_id=None): self.assignment_id = assignment_id if group_id: self.group = AssignmentGroup.objects.get(parentnode_id=assignment_id, id=group_id) else: self.group = AssignmentGroup(parentnode_id=assignment_id) self.serializer = GroupSerializer(self.group) def get_group_from_db(self): return AssignmentGroup.objects.get(id=self.group.id) def update_group(self, name, is_open): self.group.name = name self.group.is_open = is_open self.group.save() def _create_tag(self, tag): self.group.tags.create(tag=tag) def update_tags(self, tagdicts): AssignmentGroupTag.objects.filter(assignment_group=self.group).delete() for tagdict in tagdicts: self._create_tag(tag=tagdict["tag"]) def _get_user(self, user_id): try: return User.objects.get(id=user_id) except ObjectDoesNotExist, e: raise ValidationError("User with ID={0} does not exist".format(user_id))
def test_merge_history_meta_data_real_groups(self): test_assignment = mommy.make_recipe( 'devilry.apps.core.assignment_activeperiod_start') group1 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group1') group2 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group2') group3 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group3') group4 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group4') AssignmentGroup.merge_groups([group1, group2, group3]) AssignmentGroup.merge_groups([group1, group4]) meta_data = AssignmentGroupHistory.objects.get( assignment_group__id=group1.id).meta_data self.assertEqual(len(meta_data), 2) self.assertDictContainsSubset({'groups': ['group1', 'group4']}, meta_data[0]) self.assertDictContainsSubset( {'groups': ['group1', 'group2', 'group3']}, meta_data[1])
def get(self, request): devilry_qualifiesforexam_enabled = 'devilry_qualifiesforexam' in settings.INSTALLED_APPS if self.request.GET.get('activeonly', False) == 'true': qry = AssignmentGroup.active_where_is_candidate(self.request.user) else: qry = AssignmentGroup.published_where_is_candidate(self.request.user) return GroupedBySubjectSerialize(qry, devilry_qualifiesforexam_enabled, request.user).serialize()
def test_merge_single_assignment_groups(self): test_assignment = mommy.make_recipe('devilry.apps.core.assignment_activeperiod_start') group1 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group1') group2 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group2') AssignmentGroup.merge_groups([group1, group2]) merge_history = AssignmentGroupHistory.objects.get(assignment_group__id=group1.id).merge_history self.assertEqual(merge_history['groups'][0]['state']['name'], 'group1') self.assertEqual(merge_history['groups'][1]['state']['name'], 'group2')
def form_valid(self, form): try: AssignmentGroup.merge_groups(self.__get_groups_from_form(form)) except ValidationError as e: messages.warning(self.request, ugettext_lazy(str(e.message))) else: messages.success( self.request, ugettext_lazy("A group with {} has been created!".format( self.__get_merged_candidates_short_name( self.target_group)))) return super(MergeGroupsView, self).form_valid(form)
def post(self, request, id): self.assignment_id = id source_group_ids = self.CONTENT['source_group_ids'] target_group_id = self.CONTENT['target_group_id'] sources = [self._get_group(groupdct['id']) for groupdct in source_group_ids] target = self._get_group(target_group_id) logger.info('User %s merging %r into %r', request.user.username, sources, target) AssignmentGroup.merge_many_groups(sources, target) logger.info('User %s successfully merged groups %s into %r', request.user.username, source_group_ids, target) return {'success': True, 'source_group_ids': source_group_ids, 'target_group_id': target_group_id}
def form_valid(self, form): try: AssignmentGroup.merge_groups(self.__get_groups_from_form(form)) except ValidationError as e: messages.warning( self.request, ugettext_lazy(str(e.message))) else: candidates_short_name = self.__get_merged_candidates_short_name(self.target_group) messages.success( self.request, ugettext_lazy("A group with %(what)s has been created!") % {'what': candidates_short_name} ) return super(MergeGroupsView, self).form_valid(form)
def get_queryset(self): querystring = self.request.GET.get('query', '').strip() if not querystring: return EmptyQuerySet() qry = None for word in querystring.split(): wordqry = Q(Q(name__icontains=word) | # Assignment Q(parentnode__short_name__icontains=word) | Q(parentnode__long_name__icontains=word) | # Period Q(parentnode__parentnode__short_name__icontains=word) | Q(parentnode__parentnode__long_name__icontains=word) | # Subject Q(parentnode__parentnode__parentnode__short_name__icontains=word) | Q(parentnode__parentnode__parentnode__long_name__icontains=word)) if qry: qry &= wordqry else: qry = wordqry assignments = AssignmentGroup.published_where_is_candidate(self.request.user) assignments = assignments.filter(qry) assignments = assignments.select_related('parentnode', 'parentnode__parentnode', 'parentnode__parentnode__parentnode') assignments = assignments.order_by('-parentnode__publishing_time') return assignments[:50]
def get_queryset(self): qry = AssignmentGroup.active_where_is_candidate(self.request.user) qry = qry.filter(is_open=True) qry = qry.filter( parentnode__delivery_types=0 ) # Only include ELECTRONIC - for now this makes sense, and if we need NON-ELECTRONIC, we make a new API, or add an option to this API. qry = qry.annotate(newest_deadline=Max("deadlines__deadline")) qry = qry.annotate(deadline_count=Count("deadlines__deadline")) qry = qry.filter(deadline_count__gt=0) # Only include assignments with one of: # - SOFT deadline handling # - deadline has NOT expired qry = qry.filter(Q(parentnode__deadline_handling=0) | Q(newest_deadline__gt=datetime.now())) only = self.request.GET.get("only", "") if only: if only == "deadline_not_expired": qry = qry.filter(newest_deadline__gte=datetime.now()) elif only == "deadline_expired": qry = qry.filter(newest_deadline__lt=datetime.now()) else: raise BadRequestError( "Invalid value for ``only``. Specify one of ``deadline_not_expired`` or ``deadline_expired``." ) qry = qry.order_by("newest_deadline") return qry
def __init__(self, assignment_id, group_id=None): self.assignment_id = assignment_id if group_id: self.group = AssignmentGroup.objects.get(parentnode_id=assignment_id, id=group_id) else: self.group = AssignmentGroup(parentnode_id=assignment_id) self.serializer = GroupSerializer(self.group)
class GroupManager(object): def __init__(self, user, assignment=None, group=None, createmode=False, usercache=None): self.user = user self.createmode = createmode self.usercache = usercache if group: self.group = group elif assignment: self.group = AssignmentGroup(parentnode=assignment) else: raise ValueError("One of assignment or group must be supplied.") self.serializer = GroupSerializer(self.group) def get_group_from_db(self): return AssignmentGroup.objects.get(id=self.group.id) def update_group(self, name, is_open): self.group.name = name self.group.is_open = is_open self.group.save() def create_first_deadline_if_available(self): assignment = self.group.parentnode first_deadline = assignment.first_deadline if first_deadline and assignment.delivery_types != NON_ELECTRONIC: self.group.deadlines.create(deadline=first_deadline) def _create_tag(self, tag): self.group.tags.create(tag=tag) def update_tags(self, tagdicts): if not self.createmode: AssignmentGroupTag.objects.filter(assignment_group=self.group).delete() for tagdict in tagdicts: self._create_tag(tag=tagdict["tag"]) def _get_user(self, user_id): if self.usercache != None: try: return self.usercache[user_id] except KeyError: pass try: user = User.objects.get(id=user_id) except ObjectDoesNotExist, e: raise ValidationError("User with ID={0} does not exist".format(user_id)) else:
def copy_groups_from_another_assignment(self, sourceassignment): """ Copy all AssignmentGroup objects from another assignment. Copies: - The name of the group. """ from devilry.apps.core.models import AssignmentGroup from devilry.apps.core.models import Candidate from devilry.apps.core.models import Examiner if self.assignmentgroups.exists(): raise AssignmentHasGroupsError( _('The assignment has students. You can not ' 'copy use this on assignments with students.')) # Step1: Bulk create the groups with no candidates or examiners, but set copied_from. groups = [] for othergroup in sourceassignment.assignmentgroups.all(): newgroup = AssignmentGroup(parentnode=self, name=othergroup.name, copied_from=othergroup) groups.append(newgroup) AssignmentGroup.objects.bulk_create(groups) # Step2: Bulk create candidate and examiners from group.copied_from.<candidates|examiners>. candidates = [] examiners = [] for group in self.assignmentgroups \ .prefetch_related( models.Prefetch( 'copied_from', to_attr='copied_from_list', queryset=AssignmentGroup.objects.prefetch_related( models.Prefetch('candidates', to_attr='candidatelist', queryset=Candidate.objects.all()), models.Prefetch('examiners', to_attr='examinerlist', queryset=Examiner.objects.all()), ) ) ): for othercandidate in group.copied_from_list.candidatelist: newcandidate = Candidate( assignment_group=group, relatedstudent_id=othercandidate.relatedstudent_id, ) candidates.append(newcandidate) for otherexaminer in group.copied_from_list.examinerlist: newexaminer = Examiner( assignmentgroup=group, relatedexaminer_id=otherexaminer.relatedexaminer_id) examiners.append(newexaminer) Candidate.objects.bulk_create(candidates) Examiner.objects.bulk_create(examiners)
def test_merge_history_meta_data_real_groups(self): test_assignment = mommy.make_recipe('devilry.apps.core.assignment_activeperiod_start') group1 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group1') group2 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group2') group3 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group3') group4 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group4') AssignmentGroup.merge_groups([group1, group2, group3]) AssignmentGroup.merge_groups([group1, group4]) meta_data = AssignmentGroupHistory.objects.get(assignment_group__id=group1.id).meta_data self.assertEqual(len(meta_data), 2) self.assertDictContainsSubset({ 'groups': ['group1', 'group4'] }, meta_data[0]) self.assertDictContainsSubset({ 'groups': ['group1', 'group2', 'group3'] }, meta_data[1])
def _get_assignment_group_from_id(self, assignment_group_id): try: assignment_group = AssignmentGroup.objects.get( id=assignment_group_id) except AssignmentGroup.DoesNotExist(): raise modelimporter.ModelImporterException( 'AssignmentGroup with id {} does not exist.'.format( assignment_group_id)) return assignment_group
def __init__(self, user, assignment=None, group=None, createmode=False, usercache=None): self.user = user self.createmode = createmode self.usercache = usercache if group: self.group = group elif assignment: self.group = AssignmentGroup(parentnode=assignment) else: raise ValueError("One of assignment or group must be supplied.") self.serializer = GroupSerializer(self.group)
def test_is_deleted_after_merge(self): test_assignment = mommy.make_recipe( 'devilry.apps.core.assignment_activeperiod_start') group1 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group1') group2 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group2') group3 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group3') group4 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group4') AssignmentGroup.merge_groups([group1, group2]) historygroup1id = group1.assignmentgrouphistory.id AssignmentGroup.merge_groups([group4, group3]) historygroup4id = group4.assignmentgrouphistory.id AssignmentGroup.merge_groups([group1, group4]) with self.assertRaises(AssignmentGroupHistory.DoesNotExist): AssignmentGroupHistory.objects.get(id=historygroup4id) self.assertTrue( AssignmentGroupHistory.objects.filter(id=historygroup1id).exists())
class GroupManager(object): def __init__(self, user, assignment_id, group_id=None): self.user = user self.assignment_id = assignment_id if group_id: self.group = AssignmentGroup.objects.get(parentnode_id=assignment_id, id=group_id) else: self.group = AssignmentGroup(parentnode_id=assignment_id) self.serializer = GroupSerializer(self.group) def get_group_from_db(self): return AssignmentGroup.objects.get(id=self.group.id) def update_group(self, name, is_open): self.group.name = name self.group.is_open = is_open self.group.save() def create_first_deadline_if_available(self): assignment = self.group.parentnode first_deadline = assignment.first_deadline if first_deadline and assignment.delivery_types != NON_ELECTRONIC: self.group.deadlines.create(deadline=first_deadline) def _create_tag(self, tag): self.group.tags.create(tag=tag) def update_tags(self, tagdicts): AssignmentGroupTag.objects.filter(assignment_group=self.group).delete() for tagdict in tagdicts: self._create_tag(tag=tagdict['tag']) def _get_user(self, user_id): try: return User.objects.get(id=user_id) except ObjectDoesNotExist, e: raise ValidationError('User with ID={0} does not exist'.format(user_id))
def write_authorize(cls, user, obj): """ Checks if the given ``user`` is an student in the given ``obj``, and raises ``PermissionDenied`` if not. :param user: A django user object. :param obj: An object of the type this method is used in. :throws PermissionDenied: """ if not AssignmentGroup.published_where_is_candidate(user).filter(id=obj.deadline.assignment_group.id): raise PermissionDenied() if obj.id != None: current = Delivery.objects.get(id=obj.id) if current.successful: raise PermissionDenied()
def test_examiner_count_filter_after_merge(self): testuser = mommy.make(settings.AUTH_USER_MODEL) testassignment = mommy.make_recipe('devilry.apps.core.assignment_activeperiod_start') group1 = mommy.make('core.AssignmentGroup', parentnode=testassignment) group2 = mommy.make('core.AssignmentGroup', parentnode=testassignment) mommy.make('core.AssignmentGroup', parentnode=testassignment) mommy.make('core.AssignmentGroup', parentnode=testassignment) core_mommy.candidate(group=group1) core_mommy.candidate(group=group1) core_mommy.candidate(group=group2) core_mommy.examiner(group=group2) core_mommy.examiner(group=group1) AssignmentGroup.merge_groups([group1, group2]) mockresponse = self.mock_http200_getrequest_htmls( cradmin_role=testassignment, cradmin_instance=self.__mockinstance_with_devilryrole('departmentadmin'), requestuser=testuser, viewkwargs={ 'filters_string': 'candidatecount-eq-3' }) self.assertEqual( 1, mockresponse.selector.count('.django-cradmin-listbuilder-itemvalue'))
def test_examiner_count_filter_after_merge(self): testuser = mommy.make(settings.AUTH_USER_MODEL) testassignment = mommy.make_recipe('devilry.apps.core.assignment_activeperiod_start') group1 = mommy.make('core.AssignmentGroup', parentnode=testassignment) group2 = mommy.make('core.AssignmentGroup', parentnode=testassignment) mommy.make('core.AssignmentGroup', parentnode=testassignment) mommy.make('core.AssignmentGroup', parentnode=testassignment) core_mommy.candidate(group=group1) core_mommy.candidate(group=group1) core_mommy.candidate(group=group2) core_mommy.examiner(group=group2) core_mommy.examiner(group=group1) AssignmentGroup.merge_groups([group1, group2]) mockresponse = self.mock_http200_getrequest_htmls( cradmin_role=testassignment, cradmin_instance=self.__mockinstance_with_devilryrole('departmentadmin'), requestuser=testuser, viewkwargs={ 'filters_string': 'candidatecount-3' }) self.assertEqual( 1, mockresponse.selector.count('.django-cradmin-listbuilder-itemvalue'))
def test_create_with_related(self): self._create_related_student("student0", tags=["group1"]) self._create_related_student("student1", tags=["group1"]) self._create_related_student("student2", tags=["group1"]) self._create_related_student("student3", tags=["group2"]) self._create_related_examiner("examiner0", tags=["group1"]) created = self.test_success() self.assertEquals(created.assignmentgroups.all().count(), 4) student0group = AssignmentGroup.where_is_candidate(self.testhelper.student0).get(parentnode=created.id) self.assertEquals(student0group.examiners.all()[0].user, self.testhelper.examiner0) self.assertEquals(student0group.deadlines.count(), 1) self.assertEquals(student0group.deadlines.all()[0].deadline.date(), self.tomorrow) self.assertEquals(student0group.deadlines.all()[0].deadline.time().hour, 15) self.assertEquals(student0group.deadlines.all()[0].deadline.time().minute, 0)
def write_authorize(cls, user, obj): """ Checks if the given ``user`` is an student in the given ``obj``, and raises ``PermissionDenied`` if not. :param user: A django user object. :param obj: An object of the type this method is used in. :throws PermissionDenied: """ if not AssignmentGroup.published_where_is_candidate(user).filter( id=obj.deadline.assignment_group.id): raise PermissionDenied() if obj.id != None: current = Delivery.objects.get(id=obj.id) if current.successful: raise PermissionDenied()
def test_is_deleted_after_merge(self): test_assignment = mommy.make_recipe('devilry.apps.core.assignment_activeperiod_start') group1 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group1') group2 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group2') group3 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group3') group4 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group4') AssignmentGroup.merge_groups([group1, group2]) historygroup1id = group1.assignmentgrouphistory.id AssignmentGroup.merge_groups([group4, group3]) historygroup4id = group4.assignmentgrouphistory.id AssignmentGroup.merge_groups([group1, group4]) with self.assertRaises(AssignmentGroupHistory.DoesNotExist): AssignmentGroupHistory.objects.get(id=historygroup4id) self.assertTrue(AssignmentGroupHistory.objects.filter(id=historygroup1id).exists())
def get_queryset(self): qry = AssignmentGroup.active_where_is_candidate(self.request.user) qry = qry.filter(is_open=True) qry = qry.annotate(newest_deadline=Max('deadlines__deadline')) qry = qry.annotate(deadline_count=Count('deadlines__deadline')) qry = qry.filter(deadline_count__gt=0) # Only include assignments with one of: # - SOFT deadline handling # - deadline has NOT expired qry = qry.filter(Q(parentnode__deadline_handling=0) | Q(newest_deadline__gt=datetime.now())) only = self.request.GET.get('only', '') if only: if only == 'deadline_not_expired': qry = qry.filter(newest_deadline__gte=datetime.now()) elif only == 'deadline_expired': qry = qry.filter(newest_deadline__lt=datetime.now()) else: raise BadRequestError('Invalid value for ``only``. Specify one of ``deadline_not_expired`` or ``deadline_expired``.') qry = qry.order_by('newest_deadline') return qry
def test_create_with_related(self): self._create_related_student('student0', tags=['group1']) self._create_related_student('student1', tags=['group1']) self._create_related_student('student2', tags=['group1']) self._create_related_student('student3', tags=['group2']) self._create_related_examiner('examiner0', tags=['group1']) self._load() self._set_values(short_name='sometest', long_name='Test', first_deadline=(self.tomorrow.isoformat(), '15:00')) self._click_createbutton_and_wait_for_reload() created = Assignment.objects.get(parentnode__id=self.period_id, short_name='sometest') self.assertEquals(created.long_name, 'Test') self.assertFalse(created.anonymous) self.assertEquals(created.delivery_types, ELECTRONIC) self.assertEquals(created.assignmentgroups.all().count(), 4) student0group = AssignmentGroup.where_is_candidate(self.testhelper.student0).get(parentnode=created.id) self.assertEquals(student0group.examiners.all()[0].user, self.testhelper.examiner0) self.assertEquals(student0group.deadlines.count(), 1) self.assertEquals(student0group.deadlines.all()[0].deadline.date(), self.tomorrow) self.assertEquals(student0group.deadlines.all()[0].deadline.time().hour, 15) self.assertEquals(student0group.deadlines.all()[0].deadline.time().minute, 0)
def create_groups_from_relatedstudents_on_period(self): """ Create :class:`devilry.apps.core.models.AssignmentGroup` objects for all :class:`devilry.apps.core.models.RelatedStudent` objects on the period owning this assignment. Creates one AssignmentGroup for each RelatedStudent, with a single Candidate in each AssignmentGroup. """ from devilry.apps.core.models import AssignmentGroup from devilry.apps.core.models import Candidate if self.assignmentgroups.exists(): raise AssignmentHasGroupsError( _('The assignment has students. You can not ' 'copy use this on assignments with students.')) # We iterate over relatedstudents twice, so we # use this to avoid multiple queries relatedstudents = list( self.period.relatedstudent_set.filter(active=True)) # Step1: Bulk create empty groups groups = [] for relatedstudent in relatedstudents: newgroup = AssignmentGroup(parentnode=self) groups.append(newgroup) AssignmentGroup.objects.bulk_create(groups) # Step2: Bulk create candidates candidates = [] for group, relatedstudent in zip(self.assignmentgroups.all(), relatedstudents): candidate = Candidate(assignment_group=group, relatedstudent=relatedstudent) candidates.append(candidate) Candidate.objects.bulk_create(candidates)
def test_merge_assignmentgroup_multiple_times(self): test_assignment = mommy.make_recipe('devilry.apps.core.assignment_activeperiod_start') group1 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group1') group2 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group2') group3 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group3') group4 = mommy.make('core.AssignmentGroup', parentnode=test_assignment, name='group4') core_mommy.candidate(group=group1) core_mommy.candidate(group=group1) core_mommy.candidate(group=group2) core_mommy.candidate(group=group3) core_mommy.candidate(group=group4) core_mommy.examiner(group=group1) core_mommy.examiner(group=group2) core_mommy.examiner(group=group2) core_mommy.examiner(group=group3) group1_state = group1.get_current_state() group2_state = group2.get_current_state() group3_state = group3.get_current_state() group4_state = group4.get_current_state() AssignmentGroup.merge_groups([group1, group3]) AssignmentGroup.merge_groups([group2, group4]) group1_merge_history = AssignmentGroupHistory.objects.get(assignment_group__id=group1.id).merge_history group2_merge_history = AssignmentGroupHistory.objects.get(assignment_group__id=group2.id).merge_history self.assertDictEqual(group1_merge_history['groups'][0]['state'], group1_state) self.assertDictEqual(group1_merge_history['groups'][1]['state'], group3_state) self.assertDictEqual(group2_merge_history['groups'][0]['state'], group2_state) self.assertDictEqual(group2_merge_history['groups'][1]['state'], group4_state) group1 = AssignmentGroup.objects.get(id=group1.id) group2 = AssignmentGroup.objects.get(id=group2.id) # Checking one more level in the Btree group1_state = AssignmentGroup.objects.get(id=group1.id).get_current_state() group2_state = AssignmentGroup.objects.get(id=group2.id).get_current_state() AssignmentGroup.merge_groups([group1, group2]) group1_merge_history_new = AssignmentGroupHistory.objects.get(assignment_group__id=group1.id).merge_history self.assertListEqual(group1_merge_history_new['groups'][0]['groups'], group1_merge_history['groups']) self.assertListEqual(group1_merge_history_new['groups'][1]['groups'], group2_merge_history['groups']) self.assertDictEqual(group1_merge_history_new['groups'][0]['state'], group1_state) self.assertDictEqual(group1_merge_history_new['groups'][1]['state'], group2_state)
def _create_assignment_group_qry(self, request, assignment): return AssignmentGroup.where_is_admin_or_superadmin(request.user).filter(parentnode=assignment)
def _create_assignment_group_qry(self, request, assignment): return AssignmentGroup.where_is_admin_or_superadmin( request.user).filter(parentnode=assignment)