예제 #1
0
파일: forms.py 프로젝트: ekr/ietfdb
class SearchLiaisonForm(forms.Form):
    '''Expects initial keyword argument queryset which then gets filtered based on form data'''
    text = forms.CharField(required=False)
    scope = forms.ChoiceField(choices=(("all", "All text fields"), ("title", "Title field")), required=False, initial='title', widget=forms.RadioSelect(renderer=RadioRenderer))
    source = forms.CharField(required=False)
    destination = forms.CharField(required=False)
    start_date = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1" }, label='Start date', required=False)
    end_date = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1" }, label='End date', required=False)

    def __init__(self, *args, **kwargs):
        self.queryset = kwargs.pop('queryset')
        super(SearchLiaisonForm, self).__init__(*args, **kwargs)

    def get_results(self):
        results = self.queryset
        if self.is_bound:
            query = self.cleaned_data.get('text')
            if query:
                q = (Q(title__icontains=query) |
                    Q(from_contact__address__icontains=query) |
                    Q(to_contacts__icontains=query) |
                    Q(other_identifiers__icontains=query) |
                    Q(body__icontains=query) |
                    Q(attachments__title__icontains=query,liaisonstatementattachment__removed=False) |
                    Q(technical_contacts__icontains=query) | 
                    Q(action_holder_contacts__icontains=query) |
                    Q(cc_contacts=query) |
                    Q(response_contacts__icontains=query))
                results = results.filter(q)

            source = self.cleaned_data.get('source')
            if source:
                source_list = source.split(',')
                if len(source_list) > 1:
                    results = results.filter(Q(from_groups__acronym__in=source_list))
                else:
                    results = results.filter(Q(from_groups__name__icontains=source) | Q(from_groups__acronym__iexact=source))

            destination = self.cleaned_data.get('destination')
            if destination:
                destination_list = destination.split(',')
                if len(destination_list) > 1:
                    results = results.filter(Q(to_groups__acronym__in=destination_list))
                else:
                    results = results.filter(Q(to_groups__name__icontains=destination) | Q(to_groups__acronym__iexact=destination))

            start_date = self.cleaned_data.get('start_date')
            end_date = self.cleaned_data.get('end_date')
            events = None
            if start_date:
                events = LiaisonStatementEvent.objects.filter(type='posted', time__gte=start_date)
                if end_date:
                    events = events.filter(time__lte=end_date)
            elif end_date:
                events = LiaisonStatementEvent.objects.filter(type='posted', time__lte=end_date)
            if events:
                results = results.filter(liaisonstatementevent__in=events)

        results = results.distinct().order_by('title')
        return results
예제 #2
0
    def __init__(self, *args, **kwargs):
        super(AddUnavailablePeriodForm, self).__init__(*args, **kwargs)

        self.fields["start_date"] = DatepickerDateField(
            date_format="yyyy-mm-dd",
            picker_settings={"autoclose": "1"},
            label=self.fields["start_date"].label,
            help_text=self.fields["start_date"].help_text,
            required=self.fields["start_date"].required)
        self.fields["end_date"] = DatepickerDateField(
            date_format="yyyy-mm-dd",
            picker_settings={"autoclose": "1"},
            label=self.fields["end_date"].label,
            help_text=self.fields["end_date"].help_text,
            required=self.fields["end_date"].required)

        self.fields['availability'].widget = forms.RadioSelect(
            choices=UnavailablePeriod.LONG_AVAILABILITY_CHOICES)
예제 #3
0
    def __init__(self, start_date, *args, **kwargs):
        super(EndUnavailablePeriodForm, self).__init__(*args, **kwargs)

        self.fields["end_date"] = DatepickerDateField(
            date_format="yyyy-mm-dd",
            picker_settings={
                "autoclose": "1",
                "start-date": start_date.isoformat() if start_date else ""
            })

        self.start_date = start_date
예제 #4
0
파일: forms.py 프로젝트: ekr/ietfdb
class InterimSessionModelForm(forms.ModelForm):
    date = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1"}, label='Date', required=False)
    time = forms.TimeField(widget=forms.TimeInput(format='%H:%M'), required=True)
    requested_duration = CustomDurationField(required=True)
    end_time = forms.TimeField(required=False)
    remote_instructions = forms.CharField(max_length=1024, required=True)
    agenda = forms.CharField(required=False, widget=forms.Textarea, strip=False)
    agenda_note = forms.CharField(max_length=255, required=False)

    class Meta:
        model = Session
        fields = ('date', 'time', 'requested_duration', 'end_time',
                  'remote_instructions', 'agenda', 'agenda_note')

    def __init__(self, *args, **kwargs):
        if 'user' in kwargs:
            self.user = kwargs.pop('user')
        if 'group' in kwargs:
            self.group = kwargs.pop('group')
        if 'is_approved_or_virtual' in kwargs:
            self.is_approved_or_virtual = kwargs.pop('is_approved_or_virtual')
        super(InterimSessionModelForm, self).__init__(*args, **kwargs)
        self.is_edit = bool(self.instance.pk)
        # setup fields that aren't intrinsic to the Session object
        if self.is_edit:
            self.initial['date'] = self.instance.official_timeslotassignment().timeslot.time
            self.initial['time'] = self.instance.official_timeslotassignment().timeslot.time
            if self.instance.agenda():
                doc = self.instance.agenda()
                path = os.path.join(doc.get_file_path(), doc.filename_with_rev())
                self.initial['agenda'] = get_document_content(os.path.basename(path), path, markup=False)

    def clean_date(self):
        '''Date field validator.  We can't use required on the input because
        it is a datepicker widget'''
        date = self.cleaned_data.get('date')
        if not date:
            raise forms.ValidationError('Required field')
        return date

    def save(self, *args, **kwargs):
        """NOTE: as the baseform of an inlineformset self.save(commit=True)
        never gets called"""
        session = super(InterimSessionModelForm, self).save(commit=kwargs.get('commit', True))
        if self.is_approved_or_virtual:
            session.status_id = 'scheda'
        else:
            session.status_id = 'apprw'
        session.group = self.group
        session.type_id = 'session'
        if not self.instance.pk:
            session.requested_by = self.user.person

        return session

    def save_agenda(self):
        if self.instance.agenda():
            doc = self.instance.agenda()
            doc.rev = str(int(doc.rev) + 1).zfill(2)
            e = NewRevisionDocEvent.objects.create(
                type='new_revision',
                by=self.user.person,
                doc=doc,
                rev=doc.rev,
                desc='New revision available')
            doc.save_with_history([e])
        else:
            filename = get_next_agenda_name(meeting=self.instance.meeting)
            doc = Document.objects.create(
                type_id='agenda',
                group=self.group,
                name=filename,
                rev='00',
                external_url='{}-00.txt'.format(filename))
            doc.set_state(State.objects.get(type__slug=doc.type.slug, slug='active'))
            DocAlias.objects.create(name=doc.name, document=doc)
            self.instance.sessionpresentation_set.create(document=doc, rev=doc.rev)
            NewRevisionDocEvent.objects.create(
                type='new_revision',
                by=self.user.person,
                doc=doc,
                rev=doc.rev,
                desc='New revision available')
        # write file
        path = os.path.join(self.instance.meeting.get_materials_path(), 'agenda', doc.filename_with_rev())
        directory = os.path.dirname(path)
        if not os.path.exists(directory):
            os.makedirs(directory)
        with codecs.open(path, "w", encoding='utf-8') as file:
            file.write(self.cleaned_data['agenda'])
예제 #5
0
파일: forms.py 프로젝트: ekr/ietfdb
class LiaisonModelForm(BetterModelForm):
    '''Specify fields which require a custom widget or that are not part of the model.
    NOTE: from_groups and to_groups are marked as not required because select2 has
    a problem with validating
    '''
    from_groups = forms.ModelMultipleChoiceField(queryset=Group.objects.all(),label=u'Groups',required=False)
    from_contact = forms.EmailField()
    to_contacts = forms.CharField(label="Contacts", widget=forms.Textarea(attrs={'rows':'3', }), strip=False)
    to_groups = forms.ModelMultipleChoiceField(queryset=Group.objects,label=u'Groups',required=False)
    deadline = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1" }, label='Deadline', required=True)
    related_to = SearchableLiaisonStatementsField(label=u'Related Liaison Statement', required=False)
    submitted_date = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1" }, label='Submission date', required=True, initial=datetime.date.today())
    attachments = CustomModelMultipleChoiceField(queryset=Document.objects,label='Attachments', widget=ShowAttachmentsWidget, required=False)
    attach_title = forms.CharField(label='Title', required=False)
    attach_file = forms.FileField(label='File', required=False)
    attach_button = forms.CharField(label='',
                                    widget=ButtonWidget(label='Attach', show_on='id_attachments',
                                                        require=['id_attach_title', 'id_attach_file'],
                                                        required_label='title and file'),
                                    required=False)
    class Meta:
        model = LiaisonStatement
        exclude = ('attachments','state','from_name','to_name')
        fieldsets = [('From', {'fields': ['from_groups','from_contact', 'response_contacts'], 'legend': ''}),
                     ('To', {'fields': ['to_groups','to_contacts'], 'legend': ''}),
                     ('Other email addresses', {'fields': ['technical_contacts','action_holder_contacts','cc_contacts'], 'legend': ''}),
                     ('Purpose', {'fields':['purpose', 'deadline'], 'legend': ''}),
                     ('Reference', {'fields': ['other_identifiers','related_to'], 'legend': ''}),
                     ('Liaison Statement', {'fields': ['title', 'submitted_date', 'body', 'attachments'], 'legend': ''}),
                     ('Add attachment', {'fields': ['attach_title', 'attach_file', 'attach_button'], 'legend': ''})]

    def __init__(self, user, *args, **kwargs):
        super(LiaisonModelForm, self).__init__(*args, **kwargs)
        self.user = user
        self.edit = False
        self.person = get_person_for_user(user)
        self.is_new = not self.instance.pk

        self.fields["from_groups"].widget.attrs["placeholder"] = "Type in name to search for group"
        self.fields["to_groups"].widget.attrs["placeholder"] = "Type in name to search for group"
        self.fields["to_contacts"].label = 'Contacts'
        self.fields["other_identifiers"].widget.attrs["rows"] = 2
        
        # add email validators
        for field in ['from_contact','to_contacts','technical_contacts','action_holder_contacts','cc_contacts']:
            if field in self.fields:
                self.fields[field].validators.append(validate_emails)

        self.set_from_fields()
        self.set_to_fields()

    def clean_from_groups(self):
        from_groups = self.cleaned_data.get('from_groups')
        if not from_groups:
            raise forms.ValidationError('You must specify a From Group')
        return from_groups
        
    def clean_to_groups(self):
        to_groups = self.cleaned_data.get('to_groups')
        if not to_groups:
            raise forms.ValidationError('You must specify a To Group')
        return to_groups
        
    def clean_from_contact(self):
        contact = self.cleaned_data.get('from_contact')
        try:
            email = Email.objects.get(address=contact)
        except ObjectDoesNotExist:
            raise forms.ValidationError('Email address does not exist')
        return email

    def clean_cc_contacts(self):
        '''Return a comma separated list of addresses'''
        cc_contacts = self.cleaned_data.get('cc_contacts')
        cc_contacts = cc_contacts.replace('\r\n',',')
        cc_contacts = cc_contacts.rstrip(',')
        return cc_contacts

    def clean(self):
        if not self.cleaned_data.get('body', None) and not self.has_attachments():
            self._errors['body'] = ErrorList([u'You must provide a body or attachment files'])
            self._errors['attachments'] = ErrorList([u'You must provide a body or attachment files'])

        # if purpose=response there must be a related statement
        purpose = LiaisonStatementPurposeName.objects.get(slug='response')
        if self.cleaned_data.get('purpose') == purpose and not self.cleaned_data.get('related_to'):
            self._errors['related_to'] = ErrorList([u'You must provide a related statement when purpose is In Response'])
        return self.cleaned_data

    def full_clean(self):
        self.set_required_fields()
        super(LiaisonModelForm, self).full_clean()
        self.reset_required_fields()

    def has_attachments(self):
        for key in self.files.keys():
            if key.startswith('attach_file_') and key.replace('file', 'title') in self.data.keys():
                return True
        return False

    def is_approved(self):
        assert NotImplemented

    def save(self, *args, **kwargs):
        super(LiaisonModelForm, self).save(*args,**kwargs)

        # set state for new statements
        if self.is_new:
            self.instance.change_state(state_id='pending',person=self.person)
            if self.is_approved():
                self.instance.change_state(state_id='posted',person=self.person)
        else:
            # create modified event
            LiaisonStatementEvent.objects.create(
                type_id='modified',
                by=self.person,
                statement=self.instance,
                desc='Statement Modified'
            )

        self.save_related_liaisons()
        self.save_attachments()
        self.save_tags()

        return self.instance

    def save_attachments(self):
        '''Saves new attachments.
        Files come in with keys like "attach_file_N" where N is index of attachments
        displayed in the form.  The attachment title is in the corresponding
        request.POST[attach_title_N]
        '''
        written = self.instance.attachments.all().count()
        for key in self.files.keys():
            title_key = key.replace('file', 'title')
            attachment_title = self.data.get(title_key)
            if not key.startswith('attach_file_') or not title_key in self.data.keys():
                continue
            attached_file = self.files.get(key)
            extension=attached_file.name.rsplit('.', 1)
            if len(extension) > 1:
                extension = '.' + extension[1]
            else:
                extension = ''
            written += 1
            name = self.instance.name() + ("-attachment-%s" % written)
            attach, created = Document.objects.get_or_create(
                name = name,
                defaults=dict(
                    title = attachment_title,
                    type_id = "liai-att",
                    external_url = name + extension, # strictly speaking not necessary, but just for the time being ...
                    )
                )
            if created:
                attach.docalias_set.create(name=attach.name)
            LiaisonStatementAttachment.objects.create(statement=self.instance,document=attach)
            attach_file = open(os.path.join(settings.LIAISON_ATTACH_PATH, attach.name + extension), 'w')
            attach_file.write(attached_file.read())
            attach_file.close()

            if not self.is_new:
                # create modified event
                LiaisonStatementEvent.objects.create(
                    type_id='modified',
                    by=self.person,
                    statement=self.instance,
                    desc='Added attachment: {}'.format(attachment_title)
                )

    def save_related_liaisons(self):
        rel = DocRelationshipName.objects.get(slug='refold')
        new_related = self.cleaned_data.get('related_to', [])
        # add new ones
        for stmt in new_related:
            self.instance.source_of_set.get_or_create(target=stmt,relationship=rel)
        # delete removed ones
        for related in self.instance.source_of_set.all():
            if related.target not in new_related:
                related.delete()

    def save_tags(self):
        '''Create tags as needed'''
        if self.instance.deadline and not self.instance.tags.filter(slug='taken'):
            self.instance.tags.add('required')

    def set_from_fields(self):
        assert NotImplemented

    def set_required_fields(self):
        purpose = self.data.get('purpose', None)
        if purpose in ['action', 'comment']:
            self.fields['deadline'].required = True
        else:
            self.fields['deadline'].required = False

    def reset_required_fields(self):
        self.fields['deadline'].required = True

    def set_to_fields(self):
        assert NotImplemented
예제 #6
0
파일: milestones.py 프로젝트: ekr/ietfdb
class MilestoneForm(forms.Form):
    id = forms.IntegerField(required=True, widget=forms.HiddenInput)

    desc = forms.CharField(max_length=500, label="Milestone", required=True)
    due = DatepickerDateField(date_format="MM yyyy",
                              picker_settings={
                                  "min-view-mode": "months",
                                  "autoclose": "1",
                                  "view-mode": "years"
                              },
                              required=True)
    docs = SearchableDocumentsField(
        label="Drafts",
        required=False,
        help_text="Any drafts that the milestone concerns.")
    resolved_checkbox = forms.BooleanField(required=False, label="Resolved")
    resolved = forms.CharField(label="Resolved as",
                               max_length=50,
                               required=False)

    delete = forms.BooleanField(required=False, initial=False)

    review = forms.ChoiceField(
        label="Review action",
        help_text="Choose whether to accept or reject the proposed changes.",
        choices=(("accept", "Accept"), ("reject", "Reject and delete"),
                 ("noaction", "No action")),
        required=False,
        initial="noaction",
        widget=forms.RadioSelect)

    def __init__(self, needs_review, reviewer, *args, **kwargs):
        m = self.milestone = kwargs.pop("instance", None)

        can_review = not needs_review

        if m:
            needs_review = m.state_id == "review"

            if not "initial" in kwargs:
                kwargs["initial"] = {}
            kwargs["initial"].update(
                dict(
                    id=m.pk,
                    desc=m.desc,
                    due=m.due,
                    resolved_checkbox=bool(m.resolved),
                    resolved=m.resolved,
                    docs=m.docs.all(),
                    delete=False,
                    review="noaction" if can_review and needs_review else "",
                ))

            kwargs["prefix"] = "m%s" % m.pk

        super(MilestoneForm, self).__init__(*args, **kwargs)

        self.fields["resolved"].widget.attrs["data-default"] = "Done"

        if needs_review and self.milestone and self.milestone.state_id != "review":
            self.fields["desc"].widget.attrs["readonly"] = True

        self.changed = False

        if not (needs_review and can_review):
            self.fields["review"].widget = forms.HiddenInput()

        self.needs_review = needs_review

    def clean_resolved(self):
        r = self.cleaned_data["resolved"].strip()

        if self.cleaned_data["resolved_checkbox"]:
            if not r:
                raise forms.ValidationError(
                    'Please provide explanation (like "Done") for why the milestone is no longer due.'
                )
        else:
            r = ""

        return r
예제 #7
0
파일: views_review.py 프로젝트: ekr/ietfdb
class RequestReviewForm(forms.ModelForm):
    team = forms.ModelMultipleChoiceField(queryset=Group.objects.all(),
                                          widget=forms.CheckboxSelectMultiple)
    deadline = DatepickerDateField(date_format="yyyy-mm-dd",
                                   picker_settings={
                                       "autoclose": "1",
                                       "start-date": "+0d"
                                   })

    class Meta:
        model = ReviewRequest
        fields = ('requested_by', 'type', 'deadline', 'requested_rev',
                  'comment')

    def __init__(self, user, doc, *args, **kwargs):
        super(RequestReviewForm, self).__init__(*args, **kwargs)

        self.doc = doc

        f = self.fields["team"]
        f.queryset = active_review_teams()
        f.initial = [
            group.pk for group in f.queryset
            if can_manage_review_requests_for_team(
                user, group, allow_personnel_outside_team=False)
        ]

        self.fields['type'].queryset = self.fields['type'].queryset.filter(
            used=True,
            reviewteamsettings__group__in=self.fields["team"].queryset
        ).distinct()
        self.fields['type'].widget = forms.RadioSelect(
            choices=[t for t in self.fields['type'].choices if t[0]])

        self.fields["requested_rev"].label = "Document revision"

        if has_role(user, "Secretariat"):
            self.fields["requested_by"] = SearchablePersonField()
        else:
            self.fields["requested_by"].widget = forms.HiddenInput()
            self.fields["requested_by"].initial = user.person.pk

    def clean_deadline(self):
        v = self.cleaned_data.get('deadline')
        if v < datetime.date.today():
            raise forms.ValidationError(
                "Select today or a date in the future.")
        return v

    def clean_requested_rev(self):
        return clean_doc_revision(self.doc,
                                  self.cleaned_data.get("requested_rev"))

    def clean(self):
        chosen_type = self.cleaned_data.get("type")
        chosen_teams = self.cleaned_data.get("team")

        if chosen_type and chosen_teams:
            for t in chosen_teams:
                if chosen_type not in t.reviewteamsettings.review_types.all():
                    self.add_error(
                        "type", "{} does not use the review type {}.".format(
                            t.name, chosen_type.name))

        return self.cleaned_data
예제 #8
0
파일: views_review.py 프로젝트: ekr/ietfdb
class CompleteReviewForm(forms.Form):
    state = forms.ModelChoiceField(
        queryset=ReviewRequestStateName.objects.filter(
            slug__in=("completed", "part-completed")).order_by("-order"),
        widget=forms.RadioSelect,
        initial="completed")
    reviewed_rev = forms.CharField(label="Reviewed revision", max_length=4)
    result = forms.ModelChoiceField(
        queryset=ReviewResultName.objects.filter(used=True),
        widget=forms.RadioSelect,
        empty_label=None)
    ACTIONS = [
        ("enter",
         "Enter review content (automatically posts to {mailing_list})"),
        ("upload",
         "Upload review content in text file (automatically posts to {mailing_list})"
         ),
        ("link", "Link to review message already sent to {mailing_list}"),
    ]
    review_submission = forms.ChoiceField(choices=ACTIONS,
                                          widget=forms.RadioSelect)

    review_url = forms.URLField(label="Link to message", required=False)
    review_file = forms.FileField(label="Text file to upload", required=False)
    review_content = forms.CharField(widget=forms.Textarea,
                                     required=False,
                                     strip=False)
    completion_date = DatepickerDateField(
        date_format="yyyy-mm-dd",
        picker_settings={"autoclose": "1"},
        initial=datetime.date.today,
        help_text="Date of announcement of the results of this review")
    completion_time = forms.TimeField(widget=forms.HiddenInput,
                                      initial=datetime.time.min)
    cc = MultiEmailField(
        required=False,
        help_text=
        "Email addresses to send to in addition to the review team list")

    def __init__(self, review_req, *args, **kwargs):
        self.review_req = review_req

        super(CompleteReviewForm, self).__init__(*args, **kwargs)

        doc = self.review_req.doc

        known_revisions = NewRevisionDocEvent.objects.filter(doc=doc).order_by(
            "time", "id").values_list("rev", flat=True)

        revising_review = review_req.state_id not in ["requested", "accepted"]

        if not revising_review:
            self.fields["state"].choices = [
                (slug, "{} - extra reviewer is to be assigned".format(label))
                if slug == "part-completed" else (slug, label)
                for slug, label in self.fields["state"].choices
            ]

        self.fields["reviewed_rev"].help_text = mark_safe(" ".join(
            "<a class=\"rev label label-default\">{}</a>".format(r)
            for r in known_revisions))

        self.fields["result"].queryset = self.fields["result"].queryset.filter(
            reviewteamsettings__group=review_req.team)

        def format_submission_choice(label):
            if revising_review:
                label = label.replace(
                    " (automatically posts to {mailing_list})", "")

            return label.format(mailing_list=review_req.team.list_email
                                or "[error: team has no mailing list set]")

        self.fields["review_submission"].choices = [
            (k, format_submission_choice(label))
            for k, label in self.fields["review_submission"].choices
        ]

        if revising_review:
            del self.fields["cc"]
        else:
            del self.fields["completion_date"]
            del self.fields["completion_time"]

    def clean_reviewed_rev(self):
        return clean_doc_revision(self.review_req.doc,
                                  self.cleaned_data.get("reviewed_rev"))

    def clean_review_content(self):
        return self.cleaned_data["review_content"].replace("\r", "")

    def clean_review_file(self):
        return get_cleaned_text_file_content(self.cleaned_data["review_file"])

    def clean(self):
        if "@" in self.review_req.reviewer.person.ascii:
            raise forms.ValidationError(
                "Reviewer name must be filled in (the ASCII version is currently \"{}\" - since it contains an @ sign the name is probably still the original email address)."
                .format(self.review_req.reviewer.person.ascii))

        def require_field(f):
            if not self.cleaned_data.get(f):
                self.add_error(f,
                               ValidationError("You must fill in this field."))

        submission_method = self.cleaned_data.get("review_submission")
        if submission_method == "enter":
            require_field("review_content")
        elif submission_method == "upload":
            require_field("review_file")
        elif submission_method == "link":
            require_field("review_url")
            require_field("review_content")