示例#1
0
    def test_only_for_one_user(self):
        """Make sure the results are available only for the logged-in user,
        no-one else."""
        # prepare a different user
        self.second_user = Person(
            username="******",
            personal="User",
            family="Secondary",
            email="*****@*****.**",
            is_active=True,
            data_privacy_agreement=True,
        )
        self.second_user.set_password('password')
        self.second_user.save()

        # login as first user
        self.client.login(username='******', password='******')

        # retrieve endpoint
        rv = self.client.get(self.url)
        self.assertEqual(rv.status_code, 200)
        # make sure this endpoint returns current user data
        self.assertEqual(rv.json()['username'], 'primary_user')

        # login as second user
        self.client.login(username='******', password='******')
        rv = self.client.get(self.url)
        self.assertEqual(rv.status_code, 200)
        # make sure this endpoint does not return first user data now
        self.assertEqual(rv.json()['username'], 'secondary_user')
 def testCheckForNonContactablePerson(self):
     """Make sure `may_contact` doesn't impede `check()`."""
     # totally fake Task, Role and Event data
     LC_org = Organization.objects.get(domain="librarycarpentry.org")
     e = Event.objects.create(
         slug="test-event",
         host=Organization.objects.first(),
         administrator=LC_org,
         start=date.today() + timedelta(days=7),
         end=date.today() + timedelta(days=8),
         country="GB",
         venue="Ministry of Magic",
         address="Underground",
         latitude=20.0,
         longitude=20.0,
         url="https://test-event.example.com",
     )
     e.tags.set(
         Tag.objects.filter(
             name__in=["SWC", "DC", "LC", "automated-email"]))
     p = Person(personal="Harry",
                family="Potter",
                email="*****@*****.**",
                may_contact=True)  # contact allowed
     r = Role(name="supporting-instructor")
     t = Task(event=e, person=p, role=r)
     self.assertEqual(NewSupportingInstructorAction.check(t), True)
     p.may_contact = False  # contact disallowed
     self.assertEqual(NewSupportingInstructorAction.check(t), True)
示例#3
0
文件: util.py 项目: timtomch/amy
def create_uploaded_persons_tasks(data):
    """
    Create persons and tasks from upload data.
    """

    # Quick sanity check.
    if any([row.get('errors') for row in data]):
        raise InternalError('Uploaded data contains errors, cancelling upload')

    persons_created = []
    tasks_created = []
    events = set()

    with transaction.atomic():
        for row in data:
            try:
                fields = {key: row[key] for key in Person.PERSON_UPLOAD_FIELDS}
                fields['username'] = create_username(row['personal'],
                                                     row['family'])
                if fields['email']:
                    # we should use existing Person or create one
                    p, created = Person.objects.get_or_create(
                        email__iexact=fields['email'], defaults=fields
                    )

                    if created:
                        persons_created.append(p)

                else:
                    # we should create a new Person without any email provided
                    p = Person(**fields)
                    p.save()
                    persons_created.append(p)

                if row['event'] and row['role']:
                    e = Event.objects.get(slug=row['event'])
                    r = Role.objects.get(name=row['role'])

                    # is the number of learners attending the event changed,
                    # we should update ``event.attendance``
                    if row['role'] == 'learner':
                        events.add(e)

                    t, created = Task.objects.get_or_create(person=p, event=e,
                                                            role=r)
                    if created:
                        tasks_created.append(t)

            except IntegrityError as e:
                raise IntegrityError('{0} (for {1})'.format(str(e), row))

            except ObjectDoesNotExist as e:
                raise ObjectDoesNotExist('{0} (for {1})'.format(str(e), row))

    for event in events:
        # if event.attendance is lower than number of learners, then
        # update the attendance
        update_event_attendance_from_tasks(event)

    return persons_created, tasks_created
示例#4
0
文件: util.py 项目: jstofel/amy
def create_uploaded_persons_tasks(data):
    """
    Create persons and tasks from upload data.
    """

    # Quick sanity check.
    if any([row.get('errors') for row in data]):
        raise InternalError('Uploaded data contains errors, cancelling upload')

    persons_created = []
    tasks_created = []
    events = set()

    with transaction.atomic():
        for row in data:
            try:
                fields = {key: row[key] for key in Person.PERSON_UPLOAD_FIELDS}
                fields['username'] = row['username']

                if fields['email']:
                    # we should use existing Person or create one
                    p, created = Person.objects.get_or_create(
                        email__iexact=fields['email'], defaults=fields
                    )

                    if created:
                        persons_created.append(p)

                else:
                    # we should create a new Person without any email provided
                    p = Person(**fields)
                    p.save()
                    persons_created.append(p)

                if row['event'] and row['role']:
                    e = Event.objects.get(slug=row['event'])
                    r = Role.objects.get(name=row['role'])

                    # is the number of learners attending the event changed,
                    # we should update ``event.attendance``
                    if row['role'] == 'learner':
                        events.add(e)

                    t, created = Task.objects.get_or_create(person=p, event=e,
                                                            role=r)
                    if created:
                        tasks_created.append(t)

            except IntegrityError as e:
                raise IntegrityError('{0} (for {1})'.format(str(e), row))

            except ObjectDoesNotExist as e:
                raise ObjectDoesNotExist('{0} (for {1})'.format(str(e), row))

    for event in events:
        # if event.attendance is lower than number of learners, then
        # update the attendance
        update_event_attendance_from_tasks(event)

    return persons_created, tasks_created
示例#5
0
文件: test_export.py 项目: gridl/amy
    def setUp(self):
        # don't remove all badges
        # super().setUp()

        # prepare user
        self.user = Person(
            username="******", personal="User", family="Primary",
            email="*****@*****.**", is_active=True,
            data_privacy_agreement=True,
        )
        self.user.set_password('password')
        self.user.save()

        # save API endpoint URL
        self.url = reverse('api:export-person-data')
示例#6
0
    def test_only_for_one_user(self):
        """Make sure the results are available only for the logged-in user,
        no-one else."""
        # prepare a different user
        self.second_user = Person(
            username="******", personal="User", family="Secondary",
            email="*****@*****.**", is_active=True,
            data_privacy_agreement=True,
        )
        self.second_user.set_password('password')
        self.second_user.save()

        # login as first user
        self.client.login(username='******', password='******')

        # retrieve endpoint
        rv = self.client.get(self.url)
        self.assertEqual(rv.status_code, 200)
        # make sure this endpoint returns current user data
        self.assertEqual(rv.json()['username'], 'primary_user')

        # login as second user
        self.client.login(username='******', password='******')
        rv = self.client.get(self.url)
        self.assertEqual(rv.status_code, 200)
        # make sure this endpoint does not return first user data now
        self.assertEqual(rv.json()['username'], 'secondary_user')
    def testCheckConditions(self):
        """Make sure `check` works for various input data."""
        # totally fake Task, Role and Event data
        LC_org = Organization.objects.get(domain="librarycarpentry.org")
        e = Event.objects.create(
            slug="test-event",
            host=Organization.objects.first(),
            administrator=LC_org,
            start=date.today() + timedelta(days=7),
            end=date.today() + timedelta(days=8),
        )
        e.tags.set(
            Tag.objects.filter(
                name__in=["SWC", "DC", "LC", "automated-email"]))
        p = Person(personal="Harry", family="Potter", email="*****@*****.**")
        r = Role(name="supporting-instructor")
        t = Task(event=e, person=p, role=r)

        # 1st case: everything is good
        self.assertEqual(NewSupportingInstructorAction.check(t), True)

        # 2nd case: event has no start date, but still valid tags
        e.start = None
        e.save()
        self.assertEqual(NewSupportingInstructorAction.check(t), True)

        # 3rd case: event start date in past, but still valid tags
        e.start = date(2000, 1, 1)
        e.save()
        self.assertEqual(NewSupportingInstructorAction.check(t), False)

        # bring back the good date
        e.start = date.today() + timedelta(days=7)
        e.save()
        self.assertEqual(NewSupportingInstructorAction.check(t), True)

        # 4th case: event is tagged with one (or more) excluding tags
        e.tags.add(Tag.objects.get(name="cancelled"))
        self.assertEqual(NewSupportingInstructorAction.check(t), False)
        e.tags.remove(Tag.objects.get(name="cancelled"))

        # 5th case: role is different than 'supporting-instructor'
        r.name = "helper"
        self.assertEqual(NewSupportingInstructorAction.check(t), False)
        r.name = "supporting-instructor"

        # 6th case: no administrator
        e.administrator = None
        e.save()
        self.assertEqual(NewSupportingInstructorAction.check(t), False)
        e.administrator = LC_org

        # 7th case: wrong administrator (self organized or instructor training)
        e.administrator = Organization.objects.get(domain="self-organized")
        e.save()
        self.assertEqual(NewSupportingInstructorAction.check(t), False)
        e.administrator = Organization.objects.get(domain="carpentries.org")
        e.save()
        self.assertEqual(NewSupportingInstructorAction.check(t), False)
示例#8
0
 def parse(self, speaker):
     speaker['name'] = speaker['name'].strip()
     personal = speaker['name'].rsplit(' ', 1)[0]
     family = speaker['name'].rsplit(' ', 1)[-1]
     return Person(
         username=speaker['username'],
         personal=personal,
         family=family,
         email=speaker['email'],
         url=speaker['absolute_url'],
     )
示例#9
0
    def setUp(self):
        # don't remove all badges
        # super().setUp()

        # prepare user
        self.user = Person(
            username="******", personal="User", family="Primary",
            email="*****@*****.**", is_active=True,
            data_privacy_agreement=True,
        )
        self.user.set_password('password')
        self.user.save()

        # save API endpoint URL
        self.url = reverse('api:export-person-data')
示例#10
0
文件: views.py 项目: pyscrape/amy
def _upload_person_task_csv(request, uploaded_file):
    persons_tasks = []
    reader = csv.DictReader(uploaded_file)
    for row in reader:
        person_fields = dict((col, row[col].strip()) for col in PERSON_UPLOAD_FIELDS)
        person = Person(**person_fields)
        entry = {'person': person, 'task' : None}
        if row.get('event', None) and row.get('role', None):
            try:
                event = Event.objects.get(slug=row['event'])
                role = Role.objects.get(name=row['role'])
                entry['task'] = Task(person=person, event=event, role=role)
                import sys
            except Event.DoesNotExist:
                messages.add_message(request, messages.ERROR, \
                                     'Event with slug {} does not exist.'.format(row['event']))
            except Role.DoesNotExist:
                messages.add_message(request, messages.ERROR, \
                                     'Role with name {} does not exist.'.format(row['role']))
            except Role.MultipleObjectsReturned:
                messages.add_message(request, messages.ERROR, \
                                     'More than one role named {} exists.'.format(row['role']))
        persons_tasks.append(entry)
    return persons_tasks
示例#11
0
文件: util.py 项目: mittald781/amy
def create_uploaded_persons_tasks(data, request=None):
    """
    Create persons and tasks from upload data.
    """

    # Quick sanity check.
    if any([row.get("errors") for row in data]):
        raise InternalError("Uploaded data contains errors, cancelling upload")

    persons_created = []
    tasks_created = []
    events = set()

    with transaction.atomic():
        for row in data:
            try:
                row_repr = ("{personal} {family} {username} <{email}>, "
                            "{role} at {event}").format(**row)

                fields = {key: row[key] for key in Person.PERSON_UPLOAD_FIELDS}
                fields["username"] = row["username"]

                if row["person_exists"] and row["existing_person_id"]:
                    # we should use existing Person
                    p = Person.objects.get(pk=row["existing_person_id"])

                elif row["person_exists"] and not row["existing_person_id"]:
                    # we should use existing Person
                    p = Person.objects.get(
                        personal=fields["personal"],
                        family=fields["family"],
                        username=fields["username"],
                        email=fields["email"],
                    )

                else:
                    # we should create a new Person without any email provided
                    p = Person(**fields)
                    p.save()
                    persons_created.append(p)

                if row["event"] and row["role"]:
                    e = Event.objects.get(slug=row["event"])
                    r = Role.objects.get(name=row["role"])

                    # if the number of learners attending the event changed,
                    # we should update ``event.attendance``
                    if row["role"] == "learner":
                        events.add(e)

                    t, created = Task.objects.get_or_create(person=p,
                                                            event=e,
                                                            role=r)
                    if created:
                        tasks_created.append(t)

            except IntegrityError as e:
                raise IntegrityError('{0} (for "{1}")'.format(
                    str(e), row_repr))

            except ObjectDoesNotExist as e:
                raise ObjectDoesNotExist('{0} (for "{1}")'.format(
                    str(e), row_repr))

    jobs_created = []
    rqjobs_created = []

    # for each created task, try to add a new-(supporting)-instructor action
    with transaction.atomic():
        for task in tasks_created:
            # conditions check out
            if NewInstructorAction.check(task):
                objs = dict(task=task, event=task.event)
                # prepare context and everything and create corresponding RQJob
                jobs, rqjobs = ActionManageMixin.add(
                    action_class=NewInstructorAction,
                    logger=logger,
                    scheduler=scheduler,
                    triggers=Trigger.objects.filter(active=True,
                                                    action="new-instructor"),
                    context_objects=objs,
                    object_=task,
                    request=request,
                )
                jobs_created += jobs
                rqjobs_created += rqjobs

            # conditions check out
            if NewSupportingInstructorAction.check(task):
                objs = dict(task=task, event=task.event)
                # prepare context and everything and create corresponding RQJob
                jobs, rqjobs = ActionManageMixin.add(
                    action_class=NewSupportingInstructorAction,
                    logger=logger,
                    scheduler=scheduler,
                    triggers=Trigger.objects.filter(
                        active=True, action="new-supporting-instructor"),
                    context_objects=objs,
                    object_=task,
                    request=request,
                )
                jobs_created += jobs
                rqjobs_created += rqjobs

    return persons_created, tasks_created
示例#12
0
文件: util.py 项目: mittald781/amy
def verify_upload_person_task(data, match=False):
    """
    Verify that uploaded data is correct.  Show errors by populating `errors`
    dictionary item.  This function changes `data` in place.

    If `match` provided, it will try to match with first similar person.
    """

    errors_occur = False
    for item in data:
        errors = []
        info = []

        event = item.get("event", None)
        existing_event = None
        if event:
            try:
                existing_event = Event.objects.get(slug=event)
            except Event.DoesNotExist:
                errors.append(
                    'Event with slug "{0}" does not exist.'.format(event))
            except Event.MultipleObjectsReturned:
                errors.append(
                    'More than one event named "{0}" exists.'.format(event))

        role = item.get("role", None)
        existing_role = None
        if role:
            try:
                existing_role = Role.objects.get(name=role)
            except Role.DoesNotExist:
                errors.append(
                    'Role with name "{0}" does not exist.'.format(role))
            except Role.MultipleObjectsReturned:
                errors.append(
                    'More than one role named "{0}" exists.'.format(role))

        # check if the user exists, and if so: check if existing user's
        # personal and family names are the same as uploaded
        email = item.get("email", "")
        personal = item.get("personal", "")
        family = item.get("family", "")
        person_id = item.get("existing_person_id", None)
        person = None

        # try to match with first similar person
        if match is True:
            try:
                person = Person.objects.get(email=email)
            except (Person.DoesNotExist, Person.MultipleObjectsReturned):
                person = None
            else:
                info.append("Existing record for person will be used.")
                person_id = person.pk

        elif person_id:
            try:
                person = Person.objects.get(id=int(person_id))
            except (ValueError, TypeError, Person.DoesNotExist):
                person = None
                info.append("Could not match selected person. New record will "
                            "be created.")
            else:
                info.append("Existing record for person will be used.")

        elif not person_id:
            try:
                Person.objects.get(email=email)
            except (Person.DoesNotExist, Person.MultipleObjectsReturned):
                pass
            else:
                errors.append("Person with this email address already exists.")

            try:
                if item.get("username"):
                    Person.objects.get(username=item.get("username"))
            except Person.DoesNotExist:
                pass
            else:
                errors.append("Person with this username already exists.")

        if not email and not person:
            info.append("It's highly recommended to add an email address.")

        if person:
            # force details from existing record
            item["personal"] = personal = person.personal
            item["family"] = family = person.family
            item["email"] = email = person.email
            item["username"] = person.username
            item["existing_person_id"] = person_id
            item["person_exists"] = True
        else:
            # force a newly created username
            if not item.get("username"):
                item["username"] = create_username(personal, family)
            item["person_exists"] = False

            info.append("Person and task will be created.")

        # let's check if there's someone else named this way
        similar_persons = Person.objects.filter(
            Q(personal=personal, family=family)
            | Q(email=email) & ~Q(email="") & Q(email__isnull=False))
        # need to cast to list, otherwise it won't JSON-ify
        item["similar_persons"] = list(
            zip(
                similar_persons.values_list("id", flat=True),
                map(lambda x: str(x), similar_persons),
            ))

        if existing_event and person and existing_role:
            # person, their role and a corresponding event exist, so
            # let's check if the task exists
            try:
                Task.objects.get(event=existing_event,
                                 person=person,
                                 role=existing_role)
            except Task.DoesNotExist:
                info.append("Task will be created.")
            else:
                info.append("Task already exists.")

        # let's check what Person model validators want to say
        try:
            p = Person(personal=personal,
                       family=family,
                       email=email,
                       username=item["username"])
            p.clean_fields(exclude=["password"])
        except ValidationError as e:
            for k, v in e.message_dict.items():
                errors.append("{}: {}".format(k, v))

        if not role:
            errors.append("Must have a role.")

        if not event:
            errors.append("Must have an event.")

        item["errors"] = errors
        if errors:
            errors_occur = True

        item["info"] = info

    return errors_occur
示例#13
0
def create_uploaded_persons_tasks(data):
    """
    Create persons and tasks from upload data.
    """

    # Quick sanity check.
    if any([row.get('errors') for row in data]):
        raise InternalError('Uploaded data contains errors, cancelling upload')

    persons_created = []
    tasks_created = []
    events = set()

    with transaction.atomic():
        for row in data:
            try:
                row_repr = ('{personal} {family} {username} <{email}>, '
                            '{role} at {event}').format(**row)

                fields = {key: row[key] for key in Person.PERSON_UPLOAD_FIELDS}
                fields['username'] = row['username']

                if row['person_exists'] and row['existing_person_id']:
                    # we should use existing Person
                    p = Person.objects.get(pk=row['existing_person_id'])

                elif row['person_exists'] and not row['existing_person_id']:
                    # we should use existing Person
                    p = Person.objects.get(
                        personal=fields['personal'], family=fields['family'],
                        username=fields['username'], email=fields['email'],
                    )

                else:
                    # we should create a new Person without any email provided
                    p = Person(**fields)
                    p.save()
                    persons_created.append(p)

                if row['event'] and row['role']:
                    e = Event.objects.get(slug=row['event'])
                    r = Role.objects.get(name=row['role'])

                    # if the number of learners attending the event changed,
                    # we should update ``event.attendance``
                    if row['role'] == 'learner':
                        events.add(e)

                    t, created = Task.objects.get_or_create(person=p, event=e,
                                                            role=r)
                    if created:
                        tasks_created.append(t)

            except IntegrityError as e:
                raise IntegrityError('{0} (for "{1}")'.format(str(e),
                                                              row_repr))

            except ObjectDoesNotExist as e:
                raise ObjectDoesNotExist('{0} (for "{1}")'.format(str(e),
                                                                  row_repr))

    return persons_created, tasks_created
示例#14
0
def verify_upload_person_task(data):
    """
    Verify that uploaded data is correct.  Show errors by populating ``errors``
    dictionary item.  This function changes ``data`` in place.
    """

    errors_occur = False
    for item in data:
        errors = []
        info = []

        event = item.get('event', None)
        existing_event = None
        if event:
            try:
                existing_event = Event.objects.get(slug=event)
            except Event.DoesNotExist:
                errors.append('Event with slug {0} does not exist.'
                              .format(event))

        role = item.get('role', None)
        existing_role = None
        if role:
            try:
                existing_role = Role.objects.get(name=role)
            except Role.DoesNotExist:
                errors.append('Role with name {0} does not exist.'
                              .format(role))
            except Role.MultipleObjectsReturned:
                errors.append('More than one role named {0} exists.'
                              .format(role))

        # check if the user exists, and if so: check if existing user's
        # personal and family names are the same as uploaded
        email = item.get('email', None)
        personal = item.get('personal', None)
        family = item.get('family', None)
        person_id = item.get('existing_person_id', None)
        person = None

        if person_id:
            try:
                person = Person.objects.get(id=int(person_id))
            except (ValueError, TypeError, Person.DoesNotExist):
                person = None
                info.append('Could not match selected person. New record will '
                            'be created.')
            else:
                info.append('Existing record for person will be used.')

        if not email and not person:
            info.append('It\'s highly recommended to add an email address.')

        if person:
            # force details from existing record
            item['personal'] = personal = person.personal
            item['family'] = family = person.family
            item['email'] = email = person.email
            item['username'] = person.username
            item['person_exists'] = True
        else:
            # force a newly created username
            if not item.get('username'):
                item['username'] = create_username(personal, family)
            item['person_exists'] = False

            info.append('Person and task will be created.')

        # let's check if there's someone else named this way
        similar_persons = Person.objects.filter(
            Q(personal=personal, family=family) |
            Q(email=email) & ~Q(email='') & Q(email__isnull=False)
        )
        # need to cast to list, otherwise it won't JSON-ify
        item['similar_persons'] = list(similar_persons.values(
            'id', 'personal', 'middle', 'family', 'email', 'username',
        ))

        if existing_event and person and existing_role:
            # person, their role and a corresponding event exist, so
            # let's check if the task exists
            try:
                Task.objects.get(event=existing_event, person=person,
                                 role=existing_role)
            except Task.DoesNotExist:
                info.append('Task will be created.')
            else:
                info.append('Task already exists.')

        # let's check what Person model validators want to say
        try:
            p = Person(personal=personal, family=family, email=email,
                       username=item['username'])
            p.clean_fields(exclude=['password'])
        except ValidationError as e:
            for k, v in e.message_dict.items():
                errors.append('{}: {}'.format(k, v))

        if not role:
            errors.append('Must have a role.')

        if not event:
            errors.append('Must have an event.')

        if errors:
            errors_occur = True
            item['errors'] = errors

        if info:
            item['info'] = info

    return errors_occur
示例#15
0
class TestExportingPersonData(BaseExportingTest):
    def setUp(self):
        # don't remove all badges
        # super().setUp()

        # prepare user
        self.user = Person(
            username="******",
            personal="User",
            family="Primary",
            email="*****@*****.**",
            is_active=True,
            data_privacy_agreement=True,
        )
        self.user.set_password('password')
        self.user.save()

        # save API endpoint URL
        self.url = reverse('api:export-person-data')

    def login(self):
        """Overwrite BaseExportingTest's login method: instead of loggin in
        as an admin, use a normal user."""
        self.client.login(username='******', password='******')

    def prepare_data(self, user):
        """Populate relational fields for the user."""

        # create and set airport for the user
        airport = Airport.objects.create(
            iata='DDD',
            fullname='Airport 55x105',
            country='CM',
            latitude=55.0,
            longitude=105.0,
        )
        self.user.airport = airport
        self.user.save()

        # create a fake organization
        test_host = Organization.objects.create(domain='example.com',
                                                fullname='Test Organization')

        # create an event that will later be used
        event = Event.objects.create(
            start=datetime.date(2018, 6, 16),
            end=datetime.date(2018, 6, 17),
            slug='2018-06-16-AMY-event',
            host=test_host,
            url='http://example.org/2018-06-16-AMY-event',
        )

        # add a role
        Role.objects.create(name='instructor', verbose_name='Instructor')

        # add an admin user
        self.setup_admin()

        # award user some badges via awards (intermediary model)
        # one badge was awarded for the event
        award1 = Award.objects.create(
            person=self.user,
            badge=Badge.objects.get(name='swc-instructor'),
            event=event,
            awarded=datetime.date(2018, 6, 16),
        )
        # second badge was awarded without any connected event
        award2 = Award.objects.create(
            person=self.user,
            badge=Badge.objects.get(name='dc-instructor'),
            awarded=datetime.date(2018, 6, 16),
        )

        # user took part in the event as an instructor
        self.user.task_set.create(
            event=event,
            role=Role.objects.get(name='instructor'),
        )

        # user knows a couple of languages
        self.user.languages.set(
            Language.objects.filter(name__in=['English', 'French']))

        # add training requests
        training_request = TrainingRequest.objects.create(
            # mixins
            data_privacy_agreement=True,
            code_of_conduct_agreement=True,
            state='p',  # pending
            person=self.user,
            group_name='Mosquitos',
            personal='User',
            middle='',
            family='Primary',
            email='*****@*****.**',
            github='primary_user',
            occupation='undisclosed',
            occupation_other='',
            affiliation='AMY',
            location='Worldwide',
            country='W3',
            underresourced=False,
            # need to set it below
            # domains=KnowledgeDomain.objects.first(),
            domains_other='E-commerce',
            underrepresented='',
            nonprofit_teaching_experience='Voluntary teacher',
            # need to set it below
            # previous_involvement=Role.objects.filter(name='instructor'),
            previous_training='course',
            previous_training_other='',
            previous_training_explanation='A course for voluntary teaching',
            previous_experience='ta',
            previous_experience_other='',
            previous_experience_explanation='After the course I became a TA',
            programming_language_usage_frequency='weekly',
            teaching_frequency_expectation='monthly',
            max_travelling_frequency='not-at-all',
            max_travelling_frequency_other='',
            reason='I want to became an instructor',
            comment='I like trains',
            training_completion_agreement=True,
            workshop_teaching_agreement=True,
            notes='Admin notes invisible to the user',
        )
        training_request.domains.set([KnowledgeDomain.objects.first()])
        training_request.previous_involvement.set(
            Role.objects.filter(name='instructor'))

        # add some training progress
        TrainingProgress.objects.create(
            trainee=self.user,
            requirement=TrainingRequirement.objects.get(name='Discussion'),
            state='p',  # passed
            event=event,
            evaluated_by=None,
            discarded=False,
            url=None,
        )
        TrainingProgress.objects.create(
            trainee=self.user,
            requirement=TrainingRequirement.objects.get(name='DC Homework'),
            state='f',  # failed
            event=None,
            evaluated_by=self.admin,
            discarded=False,
            url='http://example.org/homework',
        )

    def test_unauthorized_access(self):
        """Make sure only authenticated users can access."""
        # logout
        self.client.logout()

        # retrieve endpoint
        rv = self.client.get(self.url)

        # make sure it's inaccessible
        self.assertEqual(rv.status_code, 401)

    def test_only_for_one_user(self):
        """Make sure the results are available only for the logged-in user,
        no-one else."""
        # prepare a different user
        self.second_user = Person(
            username="******",
            personal="User",
            family="Secondary",
            email="*****@*****.**",
            is_active=True,
            data_privacy_agreement=True,
        )
        self.second_user.set_password('password')
        self.second_user.save()

        # login as first user
        self.client.login(username='******', password='******')

        # retrieve endpoint
        rv = self.client.get(self.url)
        self.assertEqual(rv.status_code, 200)
        # make sure this endpoint returns current user data
        self.assertEqual(rv.json()['username'], 'primary_user')

        # login as second user
        self.client.login(username='******', password='******')
        rv = self.client.get(self.url)
        self.assertEqual(rv.status_code, 200)
        # make sure this endpoint does not return first user data now
        self.assertEqual(rv.json()['username'], 'secondary_user')

    def test_all_related_objects_shown(self):
        """Test if all related fields are present in data output."""
        self.login()

        # retrieve endpoint
        rv = self.client.get(self.url)
        self.assertEqual(rv.status_code, 200)

        # API results parsed as JSON
        user_data = rv.json()
        user_data_keys = user_data.keys()

        # make sure these fields are NOT in the API output
        missing_fields = [
            'password',
            'is_active',
            'notes',
        ]

        # simple (non-relational) fields expected in API output
        expected_fields = [
            'data_privacy_agreement',
            'personal',
            'middle',
            'family',
            'email',
            'username',
            'gender',
            'may_contact',
            'publish_profile',
            'github',
            'twitter',
            'url',
            'user_notes',
            'affiliation',
            'occupation',
            'orcid',
        ]

        # relational fields expected in API output
        expected_relational = [
            'airport',
            'badges',
            'lessons',
            'domains',
            'languages',
            'tasks',  # renamed in serializer (was: task_set)
            'awards',  # renamed in serializer (was: award_set)
            'training_requests',  # renamed from "trainingrequest_set"
            'training_progresses',  # renamed from "trainingprogress_set"
        ]

        # ensure missing fields are not to be found in API output
        for field in missing_fields:
            self.assertNotIn(field, user_data_keys)

        # ensure required fields are present
        for field in expected_fields + expected_relational:
            self.assertIn(field, user_data_keys)

    def test_relational_fields_structure(self):
        """Make sure relational fields available via API endpoints
        retain a specific structure."""
        self.prepare_data(user=self.user)
        self.login()

        # retrieve endpoint
        rv = self.client.get(self.url)
        self.assertEqual(rv.status_code, 200)

        # API results parsed as JSON
        data = rv.json()

        # expected data dict
        expected = dict()

        # test expected Airport output
        expected['airport'] = {
            'iata': 'DDD',
            'fullname': 'Airport 55x105',
            'country': 'CM',
            'latitude': 55.0,
            'longitude': 105.0,
        }
        self.assertEqual(data['airport'], expected['airport'])

        # test expected Badges output
        expected['badges'] = [
            {
                'name':
                'swc-instructor',
                'title':
                'Software Carpentry Instructor',
                'criteria':
                'Teaching at Software Carpentry workshops or'
                ' online',
            },
            {
                'name': 'dc-instructor',
                'title': 'Data Carpentry Instructor',
                'criteria': 'Teaching at Data Carpentry workshops or'
                ' online',
            },
        ]
        self.assertEqual(data['badges'], expected['badges'])

        # test expected Awards output
        expected['awards'] = [
            {
                'badge': 'swc-instructor',
                'awarded': '2018-06-16',
                'event': {
                    'slug': '2018-06-16-AMY-event',
                    'start': '2018-06-16',
                    'end': '2018-06-17',
                    'tags': [],
                    'website_url': 'http://example.org/2018-06-16-AMY-event',
                    'venue': '',
                    'address': '',
                    'country': '',
                    'latitude': None,
                    'longitude': None,
                }
            },
            {
                'badge': 'dc-instructor',
                'awarded': '2018-06-16',
                'event': None,
            },
        ]
        self.assertEqual(data['awards'], expected['awards'])

        # test expected Tasks output
        expected['tasks'] = [
            {
                'event': {
                    'slug': '2018-06-16-AMY-event',
                    'start': '2018-06-16',
                    'end': '2018-06-17',
                    'tags': [],
                    'website_url': 'http://example.org/2018-06-16-AMY-event',
                    'venue': '',
                    'address': '',
                    'country': '',
                    'latitude': None,
                    'longitude': None,
                },
                'role': 'instructor',
            },
        ]
        self.assertEqual(data['tasks'], expected['tasks'])

        # test expected Languages output
        expected['languages'] = [
            'English',
            'French',
        ]
        self.assertEqual(data['languages'], expected['languages'])

        # test expected TrainingRequests output
        expected['training_requests'] = [{
            # these are generated by Django, so we borrow them from the
            # output
            'created_at':
            data['training_requests'][0]['created_at'],
            'last_updated_at':
            data['training_requests'][0]['last_updated_at'],
            'state':
            'Pending',
            'group_name':
            'Mosquitos',
            'personal':
            'User',
            'middle':
            '',
            'family':
            'Primary',
            'email':
            '*****@*****.**',
            'github':
            'primary_user',
            'occupation':
            'undisclosed',
            'occupation_other':
            '',
            'affiliation':
            'AMY',
            'location':
            'Worldwide',
            'country':
            'W3',
            'underresourced':
            False,
            'domains': ['Chemistry'],
            'domains_other':
            'E-commerce',
            'underrepresented':
            '',
            'nonprofit_teaching_experience':
            'Voluntary teacher',
            'previous_involvement': ['instructor'],
            'previous_training':
            'A certification or short course',
            'previous_training_other':
            '',
            'previous_training_explanation':
            'A course for voluntary teaching',
            'previous_experience':
            'Teaching assistant for a full course',
            'previous_experience_other':
            '',
            'previous_experience_explanation':
            'After the course I became a TA',
            'programming_language_usage_frequency':
            'A few times a week',
            'teaching_frequency_expectation':
            'Several times a year',
            'teaching_frequency_expectation_other':
            '',
            'max_travelling_frequency':
            'Not at all',
            'max_travelling_frequency_other':
            '',
            'reason':
            'I want to became an instructor',
            'comment':
            'I like trains',
            'training_completion_agreement':
            True,
            'workshop_teaching_agreement':
            True,
            'data_privacy_agreement':
            True,
            'code_of_conduct_agreement':
            True,
        }]

        self.assertEqual(len(data['training_requests']), 1)
        self.assertEqual(data['training_requests'][0],
                         expected['training_requests'][0])

        # test expected TrainingProgress output
        expected['training_progresses'] = [
            {
                # these are generated by Django, so we borrow them from the
                # output
                'created_at':
                data['training_progresses'][0]['created_at'],
                'last_updated_at':
                data['training_progresses'][0]['last_updated_at'],
                'requirement': {
                    'name': 'Discussion',
                    'url_required': False,
                    'event_required': False,
                },
                'state':
                'Passed',
                'discarded':
                False,
                'evaluated_by':
                None,
                'event': {
                    'slug': '2018-06-16-AMY-event',
                    'start': '2018-06-16',
                    'end': '2018-06-17',
                    'tags': [],
                    'website_url': 'http://example.org/2018-06-16-AMY-event',
                    'venue': '',
                    'address': '',
                    'country': '',
                    'latitude': None,
                    'longitude': None,
                },
                'url':
                None,
            },
            {
                # these are generated by Django, so we borrow them from the
                # output
                'created_at':
                data['training_progresses'][1]['created_at'],
                'last_updated_at':
                data['training_progresses'][1]['last_updated_at'],
                'requirement': {
                    'name': 'DC Homework',
                    'url_required': True,
                    'event_required': False,
                },
                'state':
                'Failed',
                'discarded':
                False,
                'evaluated_by': {
                    'name': 'Super User',
                },
                'event':
                None,
                'url':
                'http://example.org/homework',
            },
        ]
        self.assertEqual(len(data['training_progresses']), 2)
        self.assertEqual(data['training_progresses'][0],
                         expected['training_progresses'][0])
        self.assertEqual(data['training_progresses'][1],
                         expected['training_progresses'][1])
示例#16
0
def person_bulk_add_confirmation(request):
    """
    This view allows for manipulating and saving session-stored upload data.
    """
    persons_tasks = request.session.get('bulk-add-people')

    # if the session is empty, add message and redirect
    if not persons_tasks:
        messages.warning(
            request, "Could not locate CSV data, please try the upload again.")
        return redirect('person_bulk_add')

    if request.method == 'POST':
        # update values if user wants to change them
        personals = request.POST.getlist("personal")
        middles = request.POST.getlist("middle")
        families = request.POST.getlist("family")
        emails = request.POST.getlist("email")
        events = request.POST.getlist("event")
        roles = request.POST.getlist("role")
        data_update = zip(personals, middles, families, emails, events, roles)
        for k, record in enumerate(data_update):
            personal, middle, family, email, event, role = record
            persons_tasks[k]['person'] = {
                'personal': personal,
                'middle': middle,
                'family': family,
                'email': email
            }
            # when user wants to drop related event they will send empty string
            # so we should unconditionally accept new value for event even if
            # it's an empty string
            persons_tasks[k]['event'] = event
            persons_tasks[k]['role'] = role
            persons_tasks[k]['errors'] = None  # reset here

        # save updated data to the session
        request.session['bulk-add-people'] = persons_tasks

        # check if user wants to verify or save, or cancel

        if request.POST.get('verify', None):
            # if there's "verify" in POST, then do only verification
            any_errors = verify_upload_person_task(persons_tasks)
            if any_errors:
                messages.add_message(
                    request, messages.ERROR,
                    "Please make sure to fix all errors "
                    "listed below.")

            context = {
                'title': 'Confirm uploaded data',
                'persons_tasks': persons_tasks
            }
            return render(request, 'workshops/person_bulk_add_results.html',
                          context)

        elif (request.POST.get('confirm', None)
              and not request.POST.get('cancel', None)):
            # there must be "confirm" and no "cancel" in POST in order to save

            try:
                records = 0
                with transaction.atomic():
                    for row in persons_tasks:
                        # create person
                        p = Person(**row['person'])
                        p.save()
                        records += 1

                        # create task if data supplied
                        if row['event'] and row['role']:
                            e = Event.objects.get(slug=row['event'])
                            r = Role.objects.get(name=row['role'])
                            t = Task(person=p, event=e, role=r)
                            t.save()
                            records += 1

            except (IntegrityError, ObjectDoesNotExist) as e:
                messages.add_message(
                    request, messages.ERROR,
                    "Error saving data to the database: {}. "
                    "Please make sure to fix all errors "
                    "listed below.".format(e))
                verify_upload_person_task(persons_tasks)
                context = {
                    'title': 'Confirm uploaded data',
                    'persons_tasks': persons_tasks
                }
                return render(request,
                              'workshops/person_bulk_add_results.html',
                              context)

            else:
                request.session['bulk-add-people'] = None
                messages.add_message(
                    request, messages.SUCCESS,
                    "Successfully bulk-loaded {} records.".format(records))
                return redirect('person_bulk_add')

        else:
            # any "cancel" or no "confirm" in POST cancels the upload
            request.session['bulk-add-people'] = None
            return redirect('person_bulk_add')

    else:
        # alters persons_tasks via reference
        verify_upload_person_task(persons_tasks)

        context = {
            'title': 'Confirm uploaded data',
            'persons_tasks': persons_tasks
        }
        return render(request, 'workshops/person_bulk_add_results.html',
                      context)
示例#17
0
    def testCheckConditions(self):
        """Make sure `check` works for various input data."""
        # totally fake Task, Role and Event data
        LC_org = Organization.objects.get(domain="librarycarpentry.org")
        e = Event.objects.create(
            slug="test-event",
            host=Organization.objects.first(),
            administrator=LC_org,
            start=date.today() + timedelta(days=7),
            end=date.today() + timedelta(days=8),
            # 2019-12-24: we no longer require published conditions met for
            #             the event, so the values below were commented out
            # country='GB',
            # venue='Ministry of Magic',
            # address='Underground',
            # latitude=20.0,
            # longitude=20.0,
            # url='https://test-event.example.com',
        )
        e.tags.set(Tag.objects.filter(name__in=["SWC", "DC", "LC", "automated-email"]))
        p = Person(personal="Harry", family="Potter", email="*****@*****.**")
        r = Role(name="instructor")
        t = Task(event=e, person=p, role=r)

        # 1st case: everything is good
        self.assertEqual(NewInstructorAction.check(t), True)

        # 2nd case: event has no start date, but still valid tags
        e.start = None
        e.save()
        self.assertEqual(NewInstructorAction.check(t), True)

        # 3rd case: event start date in past, but still valid tags
        e.start = date(2000, 1, 1)
        e.save()
        self.assertEqual(NewInstructorAction.check(t), False)

        # bring back the good date
        e.start = date.today() + timedelta(days=7)
        e.save()
        self.assertEqual(NewInstructorAction.check(t), True)

        # 4th case: event is tagged with one (or more) excluding tags
        e.tags.add(Tag.objects.get(name="cancelled"))
        self.assertEqual(NewInstructorAction.check(t), False)
        e.tags.remove(Tag.objects.get(name="cancelled"))

        # 5th case: role is different than 'instructor'
        r.name = "helper"
        self.assertEqual(NewInstructorAction.check(t), False)
        r.name = "instructor"

        # 6th case: no administrator
        e.administrator = None
        e.save()
        self.assertEqual(NewInstructorAction.check(t), False)
        e.administrator = LC_org

        # 7th case: wrong administrator (self organized or instructor training)
        e.administrator = Organization.objects.get(domain="self-organized")
        e.save()
        self.assertEqual(NewInstructorAction.check(t), False)
        e.administrator = Organization.objects.get(domain="carpentries.org")
        e.save()
        self.assertEqual(NewInstructorAction.check(t), False)
示例#18
0
class TestExportingPersonData(BaseExportingTest):
    def setUp(self):
        # don't remove all badges
        # super().setUp()

        # prepare user
        self.user = Person(
            username="******", personal="User", family="Primary",
            email="*****@*****.**", is_active=True,
            data_privacy_agreement=True,
        )
        self.user.set_password('password')
        self.user.save()

        # save API endpoint URL
        self.url = reverse('api:export-person-data')

    def login(self):
        """Overwrite BaseExportingTest's login method: instead of loggin in
        as an admin, use a normal user."""
        self.client.login(username='******', password='******')

    def prepare_data(self, user):
        """Populate relational fields for the user."""

        # create and set airport for the user
        airport = Airport.objects.create(
            iata='DDD', fullname='Airport 55x105',
            country='CM',
            latitude=55.0, longitude=105.0,
        )
        self.user.airport = airport
        self.user.save()

        # create a fake organization
        test_host = Organization.objects.create(
            domain='example.com', fullname='Test Organization')

        # create an event that will later be used
        event = Event.objects.create(
            start=datetime.date(2018, 6, 16),
            end=datetime.date(2018, 6, 17),
            slug='2018-06-16-AMY-event',
            host=test_host,
            url='http://example.org/2018-06-16-AMY-event',
        )

        # add a role
        Role.objects.create(name='instructor', verbose_name='Instructor')

        # add an admin user
        self.setup_admin()

        # award user some badges via awards (intermediary model)
        # one badge was awarded for the event
        award1 = Award.objects.create(
            person=self.user,
            badge=Badge.objects.get(name='swc-instructor'),
            event=event,
            awarded=datetime.date(2018, 6, 16),
        )
        # second badge was awarded without any connected event
        award2 = Award.objects.create(
            person=self.user,
            badge=Badge.objects.get(name='dc-instructor'),
            awarded=datetime.date(2018, 6, 16),
        )

        # user took part in the event as an instructor
        self.user.task_set.create(
            event=event, role=Role.objects.get(name='instructor'),
        )

        # user knows a couple of languages
        self.user.languages.set(
            Language.objects.filter(name__in=['English', 'French'])
        )

        # add training requests
        training_request = TrainingRequest.objects.create(
            # mixins
            data_privacy_agreement=True,
            code_of_conduct_agreement=True,
            state='p',  # pending

            person=self.user,
            group_name='Mosquitos',
            personal='User',
            middle='',
            family='Primary',
            email='*****@*****.**',
            github='primary_user',
            occupation='undisclosed',
            occupation_other='',
            affiliation='AMY',
            location='Worldwide',
            country='W3',
            underresourced=False,
            # need to set it below
            # domains=KnowledgeDomain.objects.first(),
            domains_other='E-commerce',
            underrepresented='yes',
            underrepresented_details='LGBTQ',
            nonprofit_teaching_experience='Voluntary teacher',
            # need to set it below
            # previous_involvement=Role.objects.filter(name='instructor'),
            previous_training='course',
            previous_training_other='',
            previous_training_explanation='A course for voluntary teaching',
            previous_experience='ta',
            previous_experience_other='',
            previous_experience_explanation='After the course I became a TA',
            programming_language_usage_frequency='weekly',
            teaching_frequency_expectation='monthly',
            max_travelling_frequency='not-at-all',
            max_travelling_frequency_other='',
            reason='I want to became an instructor',
            user_notes='I like trains',
            training_completion_agreement=True,
            workshop_teaching_agreement=True,
        )
        training_request.domains.set([KnowledgeDomain.objects.first()])
        training_request.previous_involvement.set(
            Role.objects.filter(name='instructor'))

        # add some training progress
        TrainingProgress.objects.create(
            trainee=self.user,
            requirement=TrainingRequirement.objects.get(name='Discussion'),
            state='p',  # passed
            event=event,
            evaluated_by=None,
            discarded=False,
            url=None,
        )
        TrainingProgress.objects.create(
            trainee=self.user,
            requirement=TrainingRequirement.objects.get(name='DC Homework'),
            state='f',  # failed
            event=None,
            evaluated_by=self.admin,
            discarded=False,
            url='http://example.org/homework',
        )

    def test_unauthorized_access(self):
        """Make sure only authenticated users can access."""
        # logout
        self.client.logout()

        # retrieve endpoint
        rv = self.client.get(self.url)

        # make sure it's inaccessible
        self.assertEqual(rv.status_code, 401)

    def test_only_for_one_user(self):
        """Make sure the results are available only for the logged-in user,
        no-one else."""
        # prepare a different user
        self.second_user = Person(
            username="******", personal="User", family="Secondary",
            email="*****@*****.**", is_active=True,
            data_privacy_agreement=True,
        )
        self.second_user.set_password('password')
        self.second_user.save()

        # login as first user
        self.client.login(username='******', password='******')

        # retrieve endpoint
        rv = self.client.get(self.url)
        self.assertEqual(rv.status_code, 200)
        # make sure this endpoint returns current user data
        self.assertEqual(rv.json()['username'], 'primary_user')

        # login as second user
        self.client.login(username='******', password='******')
        rv = self.client.get(self.url)
        self.assertEqual(rv.status_code, 200)
        # make sure this endpoint does not return first user data now
        self.assertEqual(rv.json()['username'], 'secondary_user')

    def test_all_related_objects_shown(self):
        """Test if all related fields are present in data output."""
        self.login()

        # retrieve endpoint
        rv = self.client.get(self.url)
        self.assertEqual(rv.status_code, 200)

        # API results parsed as JSON
        user_data = rv.json()
        user_data_keys = user_data.keys()

        # make sure these fields are NOT in the API output
        missing_fields = [
            'password',
            'is_active',
        ]

        # simple (non-relational) fields expected in API output
        expected_fields = [
            'data_privacy_agreement',
            'personal',
            'middle',
            'family',
            'email',
            'username',
            'gender',
            'may_contact',
            'publish_profile',
            'github',
            'twitter',
            'url',
            'user_notes',
            'affiliation',
            'occupation',
            'orcid',
        ]

        # relational fields expected in API output
        expected_relational = [
            'airport',
            'badges',
            'lessons',
            'domains',
            'languages',
            'tasks',  # renamed in serializer (was: task_set)
            'awards',  # renamed in serializer (was: award_set)
            'training_requests',  # renamed from "trainingrequest_set"
            'training_progresses',  # renamed from "trainingprogress_set"
        ]

        # ensure missing fields are not to be found in API output
        for field in missing_fields:
            self.assertNotIn(field, user_data_keys)

        # ensure required fields are present
        for field in expected_fields + expected_relational:
            self.assertIn(field, user_data_keys)

    def test_relational_fields_structure(self):
        """Make sure relational fields available via API endpoints
        retain a specific structure."""
        self.prepare_data(user=self.user)
        self.login()

        # retrieve endpoint
        rv = self.client.get(self.url)
        self.assertEqual(rv.status_code, 200)

        # API results parsed as JSON
        data = rv.json()

        # expected data dict
        expected = dict()

        # test expected Airport output
        expected['airport'] = {
            'iata': 'DDD',
            'fullname': 'Airport 55x105',
            'country': 'CM',
            'latitude': 55.0,
            'longitude': 105.0,
        }
        self.assertEqual(data['airport'], expected['airport'])

        # test expected Badges output
        expected['badges'] = [
            {
                'name': 'swc-instructor',
                'title': 'Software Carpentry Instructor',
                'criteria': 'Teaching at Software Carpentry workshops or'
                            ' online',
            },
            {
                'name': 'dc-instructor',
                'title': 'Data Carpentry Instructor',
                'criteria': 'Teaching at Data Carpentry workshops or'
                            ' online',
            },
        ]
        self.assertEqual(data['badges'], expected['badges'])

        # test expected Awards output
        expected['awards'] = [
            {
                'badge': 'swc-instructor',
                'awarded': '2018-06-16',
                'event': {
                    'slug': '2018-06-16-AMY-event',
                    'start': '2018-06-16',
                    'end': '2018-06-17',
                    'tags': [],
                    'website_url': 'http://example.org/2018-06-16-AMY-event',
                    'venue': '',
                    'address': '',
                    'country': '',
                    'latitude': None,
                    'longitude': None,
                }
            },
            {
                'badge': 'dc-instructor',
                'awarded': '2018-06-16',
                'event': None,
            },
        ]
        self.assertEqual(data['awards'], expected['awards'])

        # test expected Tasks output
        expected['tasks'] = [
            {
                'event': {
                    'slug': '2018-06-16-AMY-event',
                    'start': '2018-06-16',
                    'end': '2018-06-17',
                    'tags': [],
                    'website_url': 'http://example.org/2018-06-16-AMY-event',
                    'venue': '',
                    'address': '',
                    'country': '',
                    'latitude': None,
                    'longitude': None,
                },
                'role': 'instructor',
            },
        ]
        self.assertEqual(data['tasks'], expected['tasks'])

        # test expected Languages output
        expected['languages'] = [
            'English',
            'French',
        ]
        self.assertEqual(data['languages'], expected['languages'])

        # test expected TrainingRequests output
        expected['training_requests'] = [
            {
                # these are generated by Django, so we borrow them from the
                # output
                'created_at': data['training_requests'][0]['created_at'],
                'last_updated_at':
                    data['training_requests'][0]['last_updated_at'],
                'state': 'Pending',
                'group_name': 'Mosquitos',
                'personal': 'User',
                'middle': '',
                'family': 'Primary',
                'email': '*****@*****.**',
                'github': 'primary_user',
                'occupation': 'undisclosed',
                'occupation_other': '',
                'affiliation': 'AMY',
                'location': 'Worldwide',
                'country': 'W3',
                'underresourced': False,
                'domains': ['Chemistry'],
                'domains_other': 'E-commerce',
                'underrepresented': 'yes',
                'underrepresented_details': 'LGBTQ',
                'nonprofit_teaching_experience': 'Voluntary teacher',
                'previous_involvement': ['instructor'],
                'previous_training': 'A certification or short course',
                'previous_training_other': '',
                'previous_training_explanation':
                    'A course for voluntary teaching',
                'previous_experience': 'Teaching assistant for a full course',
                'previous_experience_other': '',
                'previous_experience_explanation':
                    'After the course I became a TA',
                'programming_language_usage_frequency': 'A few times a week',
                'teaching_frequency_expectation': 'Several times a year',
                'teaching_frequency_expectation_other': '',
                'max_travelling_frequency': 'Not at all',
                'max_travelling_frequency_other': '',
                'reason': 'I want to became an instructor',
                'user_notes': 'I like trains',
                'training_completion_agreement': True,
                'workshop_teaching_agreement': True,
                'data_privacy_agreement': True,
                'code_of_conduct_agreement': True,
            }
        ]

        self.assertEqual(len(data['training_requests']), 1)
        self.assertEqual(data['training_requests'][0],
                         expected['training_requests'][0])

        # test expected TrainingProgress output
        expected['training_progresses'] = [
            {
                # these are generated by Django, so we borrow them from the
                # output
                'created_at': data['training_progresses'][0]['created_at'],
                'last_updated_at':
                    data['training_progresses'][0]['last_updated_at'],
                'requirement': {
                    'name': 'Discussion',
                    'url_required': False,
                    'event_required': False,
                },
                'state': 'Passed',
                'discarded': False,
                'evaluated_by': None,
                'event': {
                    'slug': '2018-06-16-AMY-event',
                    'start': '2018-06-16',
                    'end': '2018-06-17',
                    'tags': [],
                    'website_url': 'http://example.org/2018-06-16-AMY-event',
                    'venue': '',
                    'address': '',
                    'country': '',
                    'latitude': None,
                    'longitude': None,
                },
                'url': None,
            },
            {
                # these are generated by Django, so we borrow them from the
                # output
                'created_at': data['training_progresses'][1]['created_at'],
                'last_updated_at':
                    data['training_progresses'][1]['last_updated_at'],
                'requirement': {
                    'name': 'DC Homework',
                    'url_required': True,
                    'event_required': False,
                },
                'state': 'Failed',
                'discarded': False,
                'evaluated_by': {
                    'name': 'Super User',
                },
                'event': None,
                'url': 'http://example.org/homework',
            },
        ]
        self.assertEqual(len(data['training_progresses']), 2)
        self.assertEqual(data['training_progresses'][0],
                         expected['training_progresses'][0])
        self.assertEqual(data['training_progresses'][1],
                         expected['training_progresses'][1])
示例#19
0
文件: util.py 项目: jstofel/amy
def verify_upload_person_task(data):
    """
    Verify that uploaded data is correct.  Show errors by populating ``errors``
    dictionary item.  This function changes ``data`` in place.
    """

    errors_occur = False
    for item in data:
        errors = []
        info = []

        event = item.get('event', None)
        existing_event = None
        if event:
            try:
                existing_event = Event.objects.get(slug=event)
            except Event.DoesNotExist:
                errors.append('Event with slug {0} does not exist.'
                              .format(event))

        role = item.get('role', None)
        existing_role = None
        if role:
            try:
                existing_role = Role.objects.get(name=role)
            except Role.DoesNotExist:
                errors.append('Role with name {0} does not exist.'
                              .format(role))
            except Role.MultipleObjectsReturned:
                errors.append('More than one role named {0} exists.'
                              .format(role))

        # check if the user exists, and if so: check if existing user's
        # personal and family names are the same as uploaded
        email = item.get('email', None)
        personal = item.get('personal', None)
        family = item.get('family', None)
        person = None

        if email:
            try:
                # check if first and last name matches person in the database
                person = Person.objects.get(email__iexact=email)

                for which, actual, uploaded in (
                        ('personal', person.personal, personal),
                        ('family', person.family, family)
                ):
                    if (actual == uploaded) or (not actual and not uploaded):
                        pass
                    else:
                        errors.append('{0} mismatch: database "{1}" '
                                      'vs uploaded "{2}".'
                                      .format(which, actual, uploaded))

            except Person.DoesNotExist:
                # in this case we need to add a new person
                pass

            else:
                if existing_event and person and existing_role:
                    # person, their role and a corresponding event exist, so
                    # let's check if the task exists
                    try:
                        Task.objects.get(event=existing_event, person=person,
                                         role=existing_role)
                    except Task.DoesNotExist:
                        info.append('Task will be created.')
                    else:
                        info.append('Task already exists.')
        else:
            info.append('It\'s highly recommended to add an email address.')

        if person:
            # force username from existing record
            item['username'] = person.username
            item['person_exists'] = True

        else:
            # force a newly created username
            if not item.get('username'):
                item['username'] = create_username(personal, family)
            item['person_exists'] = False

            info.append('Person and task will be created.')

            try:
                # let's check if there's someone else named this way
                similar_person = Person.objects.get(personal=personal,
                                                    family=family)

            except Person.DoesNotExist:
                pass

            except Person.MultipleObjectsReturned:
                persons = [
                    str(person) for person in
                    Person.objects.filter(personal=personal, family=family)
                ]
                info.append('There\'s a couple of matching persons in the '
                            'database: {}. '
                            'Use email to merge.'.format(', '.join(persons)))

            else:
                info.append('There\'s a matching person in the database: {}. '
                            'Use their email to merge.'.format(similar_person))

        # let's check what Person model validators want to say
        try:
            p = Person(personal=personal, family=family, email=email,
                       username=item['username'])
            p.clean_fields(exclude=['password'])
        except ValidationError as e:
            for k, v in e.message_dict.items():
                errors.append('{}: {}'.format(k, v))

        if not role:
            errors.append('Must have a role.')

        if not event:
            errors.append('Must have an event.')

        if errors:
            errors_occur = True
            item['errors'] = errors

        if info:
            item['info'] = info

    return errors_occur
示例#20
0
def profileupdaterequest_accept(request, request_id, person_id=None):
    """
    Accept the profile update by rewriting values to selected user's profile.

    IMPORTANT: we do not rewrite all of the data users input (like
    other gender, or other lessons).  All of it is still in
    the database model ProfileUpdateRequest, but does not get written to the
    Person model object.
    """
    profileupdate = get_object_or_404(ProfileUpdateRequest, active=True,
                                      pk=request_id)
    airport = get_object_or_404(Airport,
                                iata__iexact=profileupdate.airport_iata)

    if person_id is None:
        person = Person()
        # since required perms change depending on `person_id`, we have to
        # check the perms programmatically; here user is required
        # `workshops.add_person` in order to add a new person
        if not request.user.has_perm('workshops.add_person'):
            raise PermissionDenied
    else:
        person = get_object_or_404(Person, pk=person_id)
        person_name = str(person)
        # since required perms change depending on `person_id`, we have to
        # check the perms programmatically; here user is required
        # `workshops.change_person` in order to set existing person's fields
        if not request.user.has_perm('workshops.change_person'):
            raise PermissionDenied

    person.personal = profileupdate.personal
    person.middle = profileupdate.middle
    person.family = profileupdate.family
    person.email = profileupdate.email
    person.affiliation = profileupdate.affiliation
    person.country = profileupdate.country
    person.airport = airport
    person.github = profileupdate.github
    person.twitter = profileupdate.twitter
    person.url = profileupdate.website
    # if occupation is "Other", simply save the `occupation_other` field,
    # otherwise get full display of occupation (since it's a choice field)
    if profileupdate.occupation == '':
        person.occupation = profileupdate.occupation_other
    else:
        person.occupation = profileupdate.get_occupation_display()
    person.orcid = profileupdate.orcid
    person.gender = profileupdate.gender
    person.user_notes = profileupdate.notes

    with transaction.atomic():
        # we need person to exist in the database in order to set domains and
        # lessons
        if not person.id:
            try:
                person.username = create_username(person.personal,
                                                  person.family)
                person.save()
            except IntegrityError:
                messages.error(
                    request,
                    'Cannot update profile: some database constraints weren\'t'
                    ' fulfilled. Make sure that user name, GitHub user name,'
                    ' Twitter user name, or email address are unique.'
                )
                return redirect(profileupdate.get_absolute_url())

        person.domains.set(list(profileupdate.domains.all()))
        person.languages.set(profileupdate.languages.all())

        try:
            person.save()
        except IntegrityError:
            messages.error(
                request,
                'Cannot update profile: some database constraints weren\'t'
                'fulfilled. Make sure that user name, GitHub user name,'
                'Twitter user name, or email address are unique.'
            )
            return redirect(profileupdate.get_absolute_url())

        # Since Person.lessons uses a intermediate model Qualification, we
        # ought to operate on Qualification objects instead of using
        # Person.lessons as a list.

        # erase old lessons
        Qualification.objects.filter(person=person).delete()
        # add new
        Qualification.objects.bulk_create([
            Qualification(person=person, lesson=L)
            for L in profileupdate.lessons.all()
        ])

        profileupdate.active = False
        profileupdate.save()

    if person_id is None:
        messages.success(request,
                         'New person was added successfully.')
    else:
        messages.success(request,
                         '{} was updated successfully.'.format(person_name))

    return redirect(person.get_absolute_url())