<commit_before>import uuid

from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils.text import slugify
from guardian.shortcuts import assign_perm
from transitions.extensions import GraphMachine as Machine
from django.contrib.postgres.fields import ArrayField

from accounts.models import DemographicData, Organization, Child, User
from project.fields.datetime_aware_jsonfield import DateTimeAwareJSONField
from . import workflow


class Study(models.Model):
    uuid = models.UUIDField(default=uuid.uuid4, unique=True)
    name = models.CharField(max_length=255, blank=False, null=False)
    date_modified = models.DateTimeField(auto_now=True)
    short_description = models.TextField()
    long_description = models.TextField()
    criteria = models.TextField()
    duration = models.TextField()
    contact_info = models.TextField()
    max_age = models.TextField(default='')
    min_age = models.TextField(default='')
    image = models.ImageField(null=True)
    comments = models.TextField(blank=True, null=True)
    organization = models.ForeignKey(
        Organization,
        on_delete=models.DO_NOTHING,
        related_name='studies',
        related_query_name='study'
    )
    structure = DateTimeAwareJSONField(default=dict)
    display_full_screen = models.BooleanField(default=True)
    exit_url = models.URLField(default="https://lookit.mit.edu/")
    state = models.CharField(
        choices=workflow.STATE_CHOICES,
        max_length=25,
        default=workflow.STATE_CHOICES.created
    )
    public = models.BooleanField(default=False)
    creator = models.ForeignKey(User)

    def __init__(self, *args, **kwargs):
        super(Study, self).__init__(*args, **kwargs)
        self.machine = Machine(
            self,
            states=workflow.states,
            transitions=workflow.transitions,
            initial=self.state,
            send_event=True,
            before_state_change='check_permission',
            after_state_change='_finalize_state_change'
        )

    def __str__(self):
        return f'<Study: {self.name}>'

    class Meta:
        permissions = (
            ('can_view_study', 'Can View Study'),
            ('can_create_study', 'Can Create Study'),
            ('can_edit_study', 'Can Edit Study'),
            ('can_remove_study', 'Can Remove Study'),
            ('can_activate_study', 'Can Activate Study'),
            ('can_deactivate_study', 'Can Deactivate Study'),
            ('can_pause_study', 'Can Pause Study'),
            ('can_resume_study', 'Can Resume Study'),
            ('can_approve_study', 'Can Approve Study'),
            ('can_submit_study', 'Can Submit Study'),
            ('can_retract_study', 'Can Retract Study'),
            ('can_resubmit_study', 'Can Resubmit Study'),
            ('can_edit__study_permissions', 'Can Edit Study Permissions'),
            ('can_view_study_permissions', 'Can View Study Permissions'),
            ('can_view_study_responses', 'Can View Study Responses'),
            ('can_view_study_video_responses', 'Can View Study Video Responses'),
            ('can_view_study_demographics', 'Can View Study Demographics'),
        )

    @property
    def begin_date(self):
        active_logs = self.logs.filter(action='active')
        if active_logs.exists():
            return active_logs.latest('action').created_at
        else:
            return None

    @property
    def end_date(self):
        begin_date = self.begin_date
        deactivated_logs = self.logs.filter(action='deactivated')
        if deactivated_logs.exists() and begin_date:
            end_date = deactivated_logs.latest('action').created_at
        else:
            return None;
        return end_date if end_date > begin_date else None

    @property
    def completed_responses_count(self):
        return self.responses.filter(completed=True).count();

    @property
    def incomplete_responses_count(self):
        return self.responses.filter(completed=False).count();

    # WORKFLOW CALLBACKS
    def check_permission(self, ev):
        user = ev.kwargs.get('user')
        if user.is_superuser:
            return
        raise

    def notify_administrators_of_submission(self, ev):
        # TODO
        pass

    def notify_submitter_of_approval(self, ev):
        # TODO
        pass

    def notify_submitter_of_rejection(self, ev):
        # TODO
        pass

    def notify_administrators_of_retraction(self, ev):
        # TODO
        pass

    def notify_administrators_of_activation(self, ev):
        # TODO
        pass

    def notify_administrators_of_pause(self, ev):
        # TODO
        pass

    def notify_administrators_of_deactivation(self, ev):
        # TODO
        pass

    # Runs for every transition to log action
    def _log_action(self, ev):
        StudyLog.objects.create(
            action=ev.state.name,
            study=ev.model,
            user=ev.kwargs.get('user')
        )

    # Runs for every transition to save state and log action
    def _finalize_state_change(self, ev):
        ev.model.save()
        self._log_action(ev)

# TODO Need a post_save hook for edit that pulls studies out of approved state
# TODO or disallows editing in pre_save if they are approved


@receiver(post_save, sender=Study)
def study_post_save(sender, **kwargs):
    """
    Add study permissions to organization groups and
    create groups for all newly created Study instances. We only
    run on study creation to avoid having to check for existence
    on each call to Study.save.
    """
    study, created = kwargs['instance'], kwargs['created']
    if created:
        from django.contrib.auth.models import Group

        organization_groups = Group.objects.filter(
            name__startswith=f'{slugify(study.organization.name)}_ORG_'.upper()
        )
        # assign study permissions to organization groups
        for group in organization_groups:
            for perm, _ in Study._meta.permissions:
                if 'ADMIN' in group.name:
                    assign_perm(perm, group, obj=study)
                elif 'READ' in group.name and 'view' in perm:
                    assign_perm(perm, group, obj=study)

        # create study groups and assign permissions
        for group in ['read', 'admin']:
            study_group_instance = Group.objects.create(
                name=f'{slugify(study.organization.name)}_{slugify(study.name)}_STUDY_{group}'.upper()  # noqa
            )<commit_msg>Use. build_study_group_name method.<commit_after>import uuid

from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils.text import slugify
from guardian.shortcuts import assign_perm
from transitions.extensions import GraphMachine as Machine
from django.contrib.postgres.fields import ArrayField

from accounts.utils import build_study_group_name
from accounts.models import DemographicData, Organization, Child, User
from project.fields.datetime_aware_jsonfield import DateTimeAwareJSONField
from . import workflow


class Study(models.Model):
    uuid = models.UUIDField(default=uuid.uuid4, unique=True)
    name = models.CharField(max_length=255, blank=False, null=False)
    date_modified = models.DateTimeField(auto_now=True)
    short_description = models.TextField()
    long_description = models.TextField()
    criteria = models.TextField()
    duration = models.TextField()
    contact_info = models.TextField()
    max_age = models.TextField(default='')
    min_age = models.TextField(default='')
    image = models.ImageField(null=True)
    comments = models.TextField(blank=True, null=True)
    organization = models.ForeignKey(
        Organization,
        on_delete=models.DO_NOTHING,
        related_name='studies',
        related_query_name='study'
    )
    structure = DateTimeAwareJSONField(default=dict)
    display_full_screen = models.BooleanField(default=True)
    exit_url = models.URLField(default="https://lookit.mit.edu/")
    state = models.CharField(
        choices=workflow.STATE_CHOICES,
        max_length=25,
        default=workflow.STATE_CHOICES.created
    )
    public = models.BooleanField(default=False)
    creator = models.ForeignKey(User)

    def __init__(self, *args, **kwargs):
        super(Study, self).__init__(*args, **kwargs)
        self.machine = Machine(
            self,
            states=workflow.states,
            transitions=workflow.transitions,
            initial=self.state,
            send_event=True,
            before_state_change='check_permission',
            after_state_change='_finalize_state_change'
        )

    def __str__(self):
        return f'<Study: {self.name}>'

    class Meta:
        permissions = (
            ('can_view_study', 'Can View Study'),
            ('can_create_study', 'Can Create Study'),
            ('can_edit_study', 'Can Edit Study'),
            ('can_remove_study', 'Can Remove Study'),
            ('can_activate_study', 'Can Activate Study'),
            ('can_deactivate_study', 'Can Deactivate Study'),
            ('can_pause_study', 'Can Pause Study'),
            ('can_resume_study', 'Can Resume Study'),
            ('can_approve_study', 'Can Approve Study'),
            ('can_submit_study', 'Can Submit Study'),
            ('can_retract_study', 'Can Retract Study'),
            ('can_resubmit_study', 'Can Resubmit Study'),
            ('can_edit__study_permissions', 'Can Edit Study Permissions'),
            ('can_view_study_permissions', 'Can View Study Permissions'),
            ('can_view_study_responses', 'Can View Study Responses'),
            ('can_view_study_video_responses', 'Can View Study Video Responses'),
            ('can_view_study_demographics', 'Can View Study Demographics'),
        )

    @property
    def begin_date(self):
        active_logs = self.logs.filter(action='active')
        if active_logs.exists():
            return active_logs.latest('action').created_at
        else:
            return None

    @property
    def end_date(self):
        begin_date = self.begin_date
        deactivated_logs = self.logs.filter(action='deactivated')
        if deactivated_logs.exists() and begin_date:
            end_date = deactivated_logs.latest('action').created_at
        else:
            return None;
        return end_date if end_date > begin_date else None

    @property
    def completed_responses_count(self):
        return self.responses.filter(completed=True).count();

    @property
    def incomplete_responses_count(self):
        return self.responses.filter(completed=False).count();

    # WORKFLOW CALLBACKS
    def check_permission(self, ev):
        user = ev.kwargs.get('user')
        if user.is_superuser:
            return
        raise

    def notify_administrators_of_submission(self, ev):
        # TODO
        pass

    def notify_submitter_of_approval(self, ev):
        # TODO
        pass

    def notify_submitter_of_rejection(self, ev):
        # TODO
        pass

    def notify_administrators_of_retraction(self, ev):
        # TODO
        pass

    def notify_administrators_of_activation(self, ev):
        # TODO
        pass

    def notify_administrators_of_pause(self, ev):
        # TODO
        pass

    def notify_administrators_of_deactivation(self, ev):
        # TODO
        pass

    # Runs for every transition to log action
    def _log_action(self, ev):
        StudyLog.objects.create(
            action=ev.state.name,
            study=ev.model,
            user=ev.kwargs.get('user')
        )

    # Runs for every transition to save state and log action
    def _finalize_state_change(self, ev):
        ev.model.save()
        self._log_action(ev)

# TODO Need a post_save hook for edit that pulls studies out of approved state
# TODO or disallows editing in pre_save if they are approved


@receiver(post_save, sender=Study)
def study_post_save(sender, **kwargs):
    """
    Add study permissions to organization groups and
    create groups for all newly created Study instances. We only
    run on study creation to avoid having to check for existence
    on each call to Study.save.
    """
    study, created = kwargs['instance'], kwargs['created']
    if created:
        from django.contrib.auth.models import Group

        organization_groups = Group.objects.filter(
            name__startswith=f'{slugify(study.organization.name)}_ORG_'.upper()
        )
        # assign study permissions to organization groups
        for group in organization_groups:
            for perm, _ in Study._meta.permissions:
                if 'ADMIN' in group.name:
                    assign_perm(perm, group, obj=study)
                elif 'READ' in group.name and 'view' in perm:
                    assign_perm(perm, group, obj=study)

        # create study groups and assign permissions
        for group in ['read', 'admin']:
            study_group_instance = Group.objects.create(
                name=build_study_group_name(study.organization.name, study.name, group)
            )
{'fraction_non_alphanumeric': 0.09358105535673494, 'fraction_numerical': 0.000913728774842001, 'mean_word_length': 2.718573046432616, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1602290', 'n_tokens_mistral': 3744, 'n_tokens_neox': 3603, 'n_words': 881}