def test_clean_invalid_value(): field = RecurrenceField() value = "RRULE:FREQS=WEEKLY" with pytest.raises(forms.ValidationError) as e: field.clean(value) assert e.value.messages[0] == "bad parameter: FREQS"
def test_none_fieldvalue(): field = RecurrenceField() value = None return_obj = field.clean(value) assert isinstance(return_obj, Recurrence) or return_obj is None
def test_dt_start_and_dtend_converts_to_utc(self): """Convert the values for dtstart and dtend to UTC.""" tz = pytz.timezone('America/Adak') limits = Recurrence( dtstart=datetime(2014, 1, 1, 0, 0, 0, tzinfo=tz), dtend=datetime(2014, 2, 3, 0, 0, 0, tzinfo=tz), ) value = recurrence.serialize(limits) field = RecurrenceField() cleaned_value = field.clean(value) assert cleaned_value.dtstart == datetime(2014, 1, 1, 0, 0, 0, tzinfo=tz).astimezone( pytz.utc) assert cleaned_value.dtend == datetime(2014, 2, 3, 0, 0, 0, tzinfo=tz).astimezone(pytz.utc) assert cleaned_value.dtstart.tzname() == 'UTC' assert cleaned_value.dtend.tzname() == 'UTC'
def test_strip_dtstart_and_dtend_if_required(self): """Test that naive datetimes will get converted to UTC and returned as UTC.""" rule = Rule( recurrence.WEEKLY ) limits = Recurrence( dtstart=datetime(2014, 1, 1, 0, 0, 0), dtend=datetime(2014, 2, 3, 0, 0, 0), rrules=[rule] ) value = recurrence.serialize(limits) field = RecurrenceField() cleaned_value = field.clean(value) assert cleaned_value.rrules == [rule] assert cleaned_value.dtstart == datetime(2014, 1, 1, 0, 0, 0, tzinfo=pytz.utc) assert cleaned_value.dtend == datetime(2014, 2, 3, 0, 0, 0, tzinfo=pytz.utc) field = RecurrenceField(accept_dtstart=False, accept_dtend=False) cleaned_value = field.clean(value) assert cleaned_value != limits assert cleaned_value.dtstart is None assert cleaned_value.dtend is None
def test_check_allowable_frequencies(): rule = Rule( recurrence.WEEKLY ) limits = Recurrence( rrules=[rule] ) value = recurrence.serialize(limits) field = RecurrenceField(frequencies=[ recurrence.WEEKLY ]) field.clean(value) field = RecurrenceField(frequencies=[ recurrence.YEARLY ]) with pytest.raises(forms.ValidationError) as e: field.clean(value) assert e.value.messages[0] == "Invalid frequency." limits = Recurrence( exrules=[rule] ) value = recurrence.serialize(limits) with pytest.raises(forms.ValidationError) as e: field.clean(value) assert e.value.messages[0] == "Invalid frequency."
def test_clean_normal_value(): field = RecurrenceField() value = "RRULE:FREQ=WEEKLY;BYDAY=TU" obj = field.clean(value) assert len(obj.rrules) == 1 assert obj.rrules[0].to_text() == "weekly, each Tuesday"
def test_aware_until_gets_converted_to_utc(self): tz = pytz.timezone('America/Adak') until = datetime(2014, 1, 1, 0, 0, 0, tzinfo=tz) recurs = Recurrence(rrules=[Rule(recurrence.DAILY, until=until)], ) value = recurrence.serialize(recurs) field = RecurrenceField() cleaned_value = field.clean(value) assert cleaned_value.rrules[0].until == until.astimezone(pytz.utc)
def test_check_max_rrules(): rule = Rule(recurrence.WEEKLY) limits = Recurrence(rrules=[rule]) value = recurrence.serialize(limits) field = RecurrenceField(max_rrules=0) with pytest.raises(forms.ValidationError) as e: field.clean(value) assert e.value.messages[0] == "Max rules exceeded. The limit is 0"
def test_naive_until_gets_converted_to_utc(self): recurs = Recurrence( rrules=[Rule( recurrence.DAILY, until=datetime(2014, 1, 1, 0, 0, 0)) ], ) value = recurrence.serialize(recurs) field = RecurrenceField() cleaned_value = field.clean(value) assert cleaned_value.rrules[0].until == datetime(2014, 1, 1, 0, 0, 0, tzinfo=pytz.utc)
def test_aware_until_gets_converted_to_utc(self): tz = pytz.timezone('America/Adak') until = datetime(2014, 1, 1, 0, 0, 0, tzinfo=tz) recurs = Recurrence( rrules=[Rule( recurrence.DAILY, until=until) ], ) value = recurrence.serialize(recurs) field = RecurrenceField() cleaned_value = field.clean(value) assert cleaned_value.rrules[0].until == until.astimezone(pytz.utc)
def test_naive_until_gets_converted_to_utc(self): recurs = Recurrence(rrules=[ Rule(recurrence.DAILY, until=datetime(2014, 1, 1, 0, 0, 0)) ], ) value = recurrence.serialize(recurs) field = RecurrenceField() cleaned_value = field.clean(value) assert cleaned_value.rrules[0].until == datetime(2014, 1, 1, 0, 0, 0, tzinfo=pytz.utc)
def test_check_max_rrules(): rule = Rule( recurrence.WEEKLY ) limits = Recurrence( rrules=[rule] ) value = recurrence.serialize(limits) field = RecurrenceField(max_rrules=0) with pytest.raises(forms.ValidationError) as e: field.clean(value) assert e.value.messages[0] == "Max rules exceeded. The limit is 0"
class Form(forms.Form): name = forms.CharField() description = forms.CharField(required=False, initial='', widget=forms.Textarea) recurrence_enabled = forms.BooleanField(required=False, initial=True) recurrence_start = forms.DateTimeField( initial=timezone.now, help_text= _('The recurrence defined below is applied from this date and time onwards.<br/>' 'Eg. for daily recurrence the actions would be scheduled for the time set here.<br/>' 'The set time zone is %s.<br/>' 'Note that this date is <em>always</em> included in the schedule, even if it ' 'doesn\'t match the criteria.') % settings.TIME_ZONE) recurrence = RecurrenceField(required=False) def __init__(self, data, *args, **kwargs): super().__init__(data, *args, **kwargs) if 'recurrence' in self.initial: self.initial['recurrence_start'] = self.initial[ 'recurrence'].dtstart def clean(self): super().clean() if not self.errors: dtstart = self.cleaned_data.pop('recurrence_start') self.cleaned_data['recurrence'].dtstart = dtstart return self.cleaned_data
def test_naive_rdates_converted_to_utc(self): limits = Recurrence(rdates=[ datetime(2014, 1, 1, 0, 0, 0), datetime(2014, 1, 2, 0, 0, 0), ], ) value = recurrence.serialize(limits) field = RecurrenceField() cleaned_value = field.clean(value) assert cleaned_value.rdates == [ datetime(2014, 1, 1, 0, 0, 0, tzinfo=pytz.utc), datetime(2014, 1, 2, 0, 0, 0, tzinfo=pytz.utc), ] for rdate in cleaned_value.rdates: assert rdate.tzname() == 'UTC'
def test_dt_start_and_dtend_converts_to_utc(self): """Convert the values for dtstart and dtend to UTC.""" tz = pytz.timezone('America/Adak') limits = Recurrence( dtstart=datetime(2014, 1, 1, 0, 0, 0, tzinfo=tz), dtend=datetime(2014, 2, 3, 0, 0, 0, tzinfo=tz), ) value = recurrence.serialize(limits) field = RecurrenceField(required=False) cleaned_value = field.clean(value) assert cleaned_value.dtstart == datetime(2014, 1, 1, 0, 0, 0, tzinfo=tz).astimezone(pytz.utc) assert cleaned_value.dtend == datetime(2014, 2, 3, 0, 0, 0, tzinfo=tz).astimezone(pytz.utc) assert cleaned_value.dtstart.tzname() == 'UTC' assert cleaned_value.dtend.tzname() == 'UTC'
def test_aware_rdates_converted_to_utc(self): tz = pytz.timezone('America/Adak') limits = Recurrence(rdates=[ datetime(2014, 1, 1, 0, 0, 0, tzinfo=tz), datetime(2014, 1, 2, 0, 0, 0, tzinfo=tz), ], ) value = recurrence.serialize(limits) field = RecurrenceField() cleaned_value = field.clean(value) assert cleaned_value.rdates == [ datetime(2014, 1, 1, 0, 0, 0, tzinfo=tz).astimezone(pytz.utc), datetime(2014, 1, 2, 0, 0, 0, tzinfo=tz).astimezone(pytz.utc), ] for rdate in cleaned_value.rdates: assert rdate.tzname() == 'UTC'
class GeneratePermanenceForm(forms.Form): # repeat_counter = forms.IntegerField(label=_("Number of permanence(s)"), min_value=0, max_value=54) # repeat_step = forms.IntegerField(label=_("Number of week(s) between two permanences"), min_value=0, max_value=12) recurrences = RecurrenceField() def __init__(self, *args, **kwargs): self.request = kwargs.pop("request", None) super(GeneratePermanenceForm, self).__init__(*args, **kwargs)
def test_naive_rdates_converted_to_utc(self): limits = Recurrence( rdates=[ datetime(2014, 1, 1, 0, 0, 0), datetime(2014, 1, 2, 0, 0, 0), ], ) value = recurrence.serialize(limits) field = RecurrenceField() cleaned_value = field.clean(value) assert cleaned_value.rdates == [ datetime(2014, 1, 1, 0, 0, 0, tzinfo=pytz.utc), datetime(2014, 1, 2, 0, 0, 0, tzinfo=pytz.utc), ] for rdate in cleaned_value.rdates: assert rdate.tzname() == 'UTC'
class EventDuplicationForm(forms.Form): start_date = forms.DateField( widget=CustomDateInput(format="%Y-%m-%d"), initial=date.today(), help_text= _("This date will be used as the start date for recurring events that you create below, e.g. daily events will be created from this date onwards." ), ) recurrence = RecurrenceField(required=False)
def test_aware_rdates_converted_to_utc(self): tz = pytz.timezone('America/Adak') limits = Recurrence( rdates=[ datetime(2014, 1, 1, 0, 0, 0, tzinfo=tz), datetime(2014, 1, 2, 0, 0, 0, tzinfo=tz), ], ) value = recurrence.serialize(limits) field = RecurrenceField() cleaned_value = field.clean(value) assert cleaned_value.rdates == [ datetime(2014, 1, 1, 0, 0, 0, tzinfo=tz).astimezone(pytz.utc), datetime(2014, 1, 2, 0, 0, 0, tzinfo=tz).astimezone(pytz.utc), ] for rdate in cleaned_value.rdates: assert rdate.tzname() == 'UTC'
def test_strip_dtstart_and_dtend_if_required(self): """Test that naive datetimes will get converted to UTC and returned as UTC.""" rule = Rule(recurrence.WEEKLY) limits = Recurrence(dtstart=datetime(2014, 1, 1, 0, 0, 0), dtend=datetime(2014, 2, 3, 0, 0, 0), rrules=[rule]) value = recurrence.serialize(limits) field = RecurrenceField() cleaned_value = field.clean(value) assert cleaned_value.rrules == [rule] assert cleaned_value.dtstart == datetime(2014, 1, 1, 0, 0, 0, tzinfo=pytz.utc) assert cleaned_value.dtend == datetime(2014, 2, 3, 0, 0, 0, tzinfo=pytz.utc) field = RecurrenceField(accept_dtstart=False, accept_dtend=False) cleaned_value = field.clean(value) assert cleaned_value != limits assert cleaned_value.dtstart is None assert cleaned_value.dtend is None
def post(self, *args, **kwargs): try: recurrence = RecurrenceField().clean( self.request.POST["recurrence_string"]) return HttpResponse( json.dumps( recurrence.between( datetime.now() - timedelta(days=1), datetime.now() + timedelta( days=730 ), # allow dates up to two years in the future inc=True, dtstart=datetime.combine( DateField().to_python( self.request.POST["dtstart"]), datetime.min.time()), ), default=lambda obj: date_format( obj, format="SHORT_DATE_FORMAT"), )) except (TypeError, KeyError, ValidationError): return HttpResponse()
def test_check_max_rdates(): limits = Recurrence(rdates=[ datetime(2014, 1, 1, 0, 0, 0), datetime(2014, 1, 2, 0, 0, 0), ]) value = recurrence.serialize(limits) field = RecurrenceField(max_rdates=2) field.clean(value) field = RecurrenceField(max_rdates=1) with pytest.raises(forms.ValidationError) as e: field.clean(value) assert e.value.messages[0] == "Max dates exceeded. The limit is 1"
def test_strip_dtstart_and_dtend_if_required(): rule = Rule( recurrence.WEEKLY ) limits = Recurrence( dtstart=datetime(2014, 1, 1, 0, 0, 0), dtend=datetime(2014, 2, 3, 0, 0, 0), rrules=[rule] ) value = recurrence.serialize(limits) field = RecurrenceField() cleaned_value = field.clean(value) assert cleaned_value == limits assert cleaned_value.dtstart == datetime(2014, 1, 1, 0, 0, 0) assert cleaned_value.dtend == datetime(2014, 2, 3, 0, 0, 0) field = RecurrenceField(accept_dtstart=False, accept_dtend=False) cleaned_value = field.clean(value) assert cleaned_value != limits assert cleaned_value.dtstart is None assert cleaned_value.dtend is None
def test_check_max_rdates(): limits = Recurrence( rdates=[ datetime(2014, 1, 1, 0, 0, 0), datetime(2014, 1, 2, 0, 0, 0), ] ) value = recurrence.serialize(limits) field = RecurrenceField(max_rdates=2) field.clean(value) field = RecurrenceField(max_rdates=1) with pytest.raises(forms.ValidationError) as e: field.clean(value) assert e.value.messages[0] == "Max dates exceeded. The limit is 1"
def test_strip_dtstart_and_dtend_if_required(): rule = Rule(recurrence.WEEKLY) limits = Recurrence(dtstart=datetime(2014, 1, 1, 0, 0, 0), dtend=datetime(2014, 2, 3, 0, 0, 0), rrules=[rule]) value = recurrence.serialize(limits) field = RecurrenceField() cleaned_value = field.clean(value) assert cleaned_value == limits assert cleaned_value.dtstart == datetime(2014, 1, 1, 0, 0, 0) assert cleaned_value.dtend == datetime(2014, 2, 3, 0, 0, 0) field = RecurrenceField(accept_dtstart=False, accept_dtend=False) cleaned_value = field.clean(value) assert cleaned_value != limits assert cleaned_value.dtstart is None assert cleaned_value.dtend is None
class ResourceSearchForm(SearchForm): """ Main search form. Ordering of results is computed according to the following: """ def __init__(self, *args, **kwargs): kwargs['auto_id'] = True kwargs['label_suffix'] = '' super(ResourceSearchForm, self).__init__(*args, **kwargs) #q = forms.CharField(label=__(u'Quoi?'), initial='',required=True) q = AutoCompleteField('resource', help_text='', label=__(u'Quoi?'), initial='', required=True) a = AutoCompleteField('location', help_text='', label=__(u'Où?'), initial='', required=False) t = RecurrenceField(label=__(u'Quand?'), initial='', required=False, max_rdates=0, max_exdates=0) d = forms.CharField(label=__(u'Quand?'), initial='', required=False) def search(self): # First, store the SearchQuerySet received from other processing. sqs = super(ResourceSearchForm, self).search() address = self.cleaned_data.get('a') if (address): g = geocoders.Nominatim( ) # this should be changed to openstreetmap try: place, (lat, lng) = g.geocode(address) print "address: %s, lat : %g, lng : %g" % (address, lat, lng) loc = Point(lng, lat) max_dist = D(km=10) #sqs = sqs.dwithin('location',loc,max_dist).distance('location',loc) except geopy.exc.GeocoderServiceError: pass time = self.cleaned_data.get('t') if (time): # extract serialized events from search query set index events = sqs.exclude(event='toto') excluded = list() for e in events: if e.event: # we only check if we can go to the next upcoming occurrence # checking all occurrences would be too costly ev = deserialize(e.event).after(datetime.now()) if not ev in time.occurrences(dtstart=ev): excluded.append(e.pk) if (excluded): sqs = sqs.exclude(id__in=excluded) return sqs def no_query_found(self): return self.searchqueryset.all()
class ActionTriggerForm(forms.ModelForm): """A form for creating a default trigger while creating an action.""" recurrences = RecurrenceField( help_text="Select the rules to define how this reminder should repeat." ) class Meta: model = Trigger fields = [ 'time_of_day', 'frequency', 'start_when_selected', 'stop_on_complete', 'time', 'trigger_date', 'relative_value', 'relative_units', 'recurrences', ] widgets = { "time": TimeSelectWidget(include_empty=True), "trigger_date": forms.TextInput(attrs={'class': 'datepicker'}), } labels = { "time": "Reminder Time", "trigger_date": "Reminder Date", } class Media: js = ( "foundation/js/vendor/jquery.js", "js/action_trigger_form.js", ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # If there's a trigger instance, include a button to disable it. This # should be handled in the template. try: if self.instance.action_default: disable_button = HTML( '<button type="button" id="disable-trigger-button" ' ' class="button info tiny pull-right">' '<i class="fa fa-bell-slash"></i> Remove Trigger</button><hr/>' ) except ObjectDoesNotExist: disable_button = HTML('') self.fields['time'].help_text = ( "Set the time at which the notification should be sent") self.fields['trigger_date'].help_text = ( "The date on which notifications should start") # Better label names for the Relative Reminders self.fields['relative_value'].label = 'Relative Reminder' self.fields['relative_units'].label = ' ' self.helper = FormHelper() self.helper.form_tag = False self.helper.layout = Layout( Fieldset( _("Reminder Details"), disable_button, 'time_of_day', 'frequency', # NOTE: advanced options are hidden by default and may # override the above dynamic/automatic notifications. # ------------------------------------------------------------- HTML('<hr/><strong>Advanced Options</strong>'), HTML('<a class="button tiny secondary right" id="advanced" ' 'data-status="hidden"><i class="fa fa-chevron-right"></i>' ' Show</a>'), Div(HTML("<hr/><p class='alert-box warning'>" "<i class='fa fa-warning'></i> These options may " "override any options set above</p>"), Div( Div('time', css_class="large-6 columns"), Div('trigger_date', css_class="large-6 columns"), ), Div( Field('stop_on_complete', data_tooltip=None, aria_haspopup="true", title=( "Reminders will cease to fire once the user " "has completed this action."), css_class="has-tip tip-top"), ), Field( 'start_when_selected', data_tooltip=None, aria_haspopup="true", title= ("If selected the reminder date will be automatically " "be set when the user adds this action."), css_class="has-tip tip-top"), Div(Div('relative_value', css_class="large-6 columns"), Div('relative_units', css_class="large-6 columns"), css_class="row"), Div(Div(HTML( '<div class="hint">Relative reminders will fire ' 'based on when the user adopts an action. Select ' 'the amount time after the user adds the action ' 'that this reminder should start</div>'), css_class="large-12 columns"), css_class="row"), 'recurrences', css_class="trigger-form-advanced"))) def save(self, *args, **kwargs): obj = super().save(*args, **kwargs) obj.name = date_hash() return obj def clean(self): data = super().clean() recurrences = data.get('recurrences') date = data.get('trigger_date') rel_value = data.get('relative_value') rel_units = data.get('relative_units') start_when_selected = data.get('start_when_selected', False) # Require BOTH relative_value and relative_units if (rel_value or rel_units) and not all([rel_value, rel_units]): self.add_error( 'relative_value', ValidationError( "Both a value and units are required for Relative Reminders", code="required_for_relative_reminders")) if not start_when_selected and not date: # Intervals (e.g. every other day) need a starting date. if recurrences and 'INTERVAL' in serialize_recurrences( recurrences): self.add_error( 'trigger_date', ValidationError( "A Trigger Date is required for recurrences that contain an " "interval (such as every 2 days)", code="required_for_intervals")) elif recurrences and 'COUNT' in serialize_recurrences(recurrences): self.add_error( 'trigger_date', ValidationError( "A Trigger Date is required for recurrences that occur a set " "number of times", code="required_for_count")) return data