def events_calendar(request, public=True): cache_key = "calendar_%s" % ("public" if public else "private") cached = cache.get(cache_key) if cached: return cached cal = vobject.iCalendar() cal.add("X-WR-CALNAME").value = "Air Mozilla Public Events" if public else "Air Mozilla Private Events" now = datetime.datetime.utcnow().replace(tzinfo=utc) events = list( Event.objects.approved() .filter(start_time__lt=now, public=public) .order_by("-start_time")[: settings.CALENDAR_SIZE] ) events += list( Event.objects.approved() .filter(start_time__gte=now, public=public) .order_by("start_time")[: settings.CALENDAR_SIZE] ) base_url = "%s://%s/" % (request.is_secure() and "https" or "http", RequestSite(request).domain) for event in events: vevent = cal.add("vevent") vevent.add("summary").value = event.title vevent.add("dtstart").value = event.start_time vevent.add("dtend").value = event.start_time + datetime.timedelta(hours=1) vevent.add("description").value = unhtml(short_desc(event)) if event.location: vevent.add("location").value = event.location.name vevent.add("url").value = base_url + event.slug + "/" icalstream = cal.serialize() response = http.HttpResponse(icalstream, mimetype="text/calendar; charset=utf-8") filename = "AirMozillaEvents%s.ics" % ("Public" if public else "Private") response["Content-Disposition"] = "inline; filename=%s" % filename cache.set(cache_key, response) return response
def events_calendar(request, public=True): cache_key = 'calendar_%s' % ('public' if public else 'private') cached = cache.get(cache_key) if cached: return cached cal = vobject.iCalendar() cal.add('X-WR-CALNAME').value = ('Air Mozilla Public Events' if public else 'Air Mozilla Private Events') now = datetime.datetime.utcnow().replace(tzinfo=utc) events = list(Event.objects.approved().filter( start_time__lt=now, public=public).order_by('-start_time')[:settings.CALENDAR_SIZE]) events += list(Event.objects.approved().filter( start_time__gte=now, public=public).order_by('start_time')[:settings.CALENDAR_SIZE]) base_url = '%s://%s/' % (request.is_secure() and 'https' or 'http', RequestSite(request).domain) for event in events: vevent = cal.add('vevent') vevent.add('summary').value = event.title vevent.add('dtstart').value = event.start_time vevent.add('dtend').value = (event.start_time + datetime.timedelta(hours=1)) vevent.add('description').value = unhtml(short_desc(event)) if event.location: vevent.add('location').value = event.location.name vevent.add('url').value = base_url + event.slug + '/' icalstream = cal.serialize() response = http.HttpResponse(icalstream, mimetype='text/calendar; charset=utf-8') filename = 'AirMozillaEvents%s.ics' % ('Public' if public else 'Private') response['Content-Disposition'] = ('inline; filename=%s' % filename) cache.set(cache_key, response) return response
def tweet_new_published_events(verbose=False): """Create EventTweet instances for events that have recently been published and are ready for public consumption.""" now = timezone.now() yesterday = now - datetime.timedelta(hours=24) events = Event.objects.scheduled().filter( created__gt=yesterday, created__lt=now, privacy=Event.PRIVACY_PUBLIC, ).approved().exclude(id__in=EventTweet.objects.values('event_id')) site = Site.objects.get_current() base_url = 'https://%s' % site.domain # yuck! for event in events: if event.channels.filter(no_automated_tweets=True): if verbose: print "Skipping", repr(event.title), "because it's part of" print event.channels.filter(no_automated_tweets=True) continue # we have to try to manually create an appropriate tweet url = reverse('main:event', args=(event.slug, )) abs_url = urlparse.urljoin(base_url, url) try: abs_url = shorten_url(abs_url) except (ImproperlyConfigured, ValueError) as err: # pragma: no cover if verbose: # pragma: no cover print "Failed to shorten URL" print err text = event.title if len(text) > 115: # Why not 140? # We've found that sometimes when you're trying to tweet # a piece of text that actually is less than 140 when # doing text+URL you can get strange errors from Twitter # that it's still too long. text = text[:115] text = unhtml('%s\n%s' % (text, abs_url)) text += '\n' tags = (event.tags.all().extra(select={ 'lower_name': 'lower(name)' }).order_by('lower_name')) for tag in tags: _tag = '#' + tag.name.replace(' ', '') # see comment above why we use 115 instead of 140 if len(text + _tag) + 1 < 115: text += '%s ' % _tag else: break text = text.strip() event_tweet = EventTweet.objects.create( event=event, text=text, include_placeholder=True, ) if verbose: # pragma: no cover print "Created", repr(event_tweet)
def short_desc(event, words=25, strip_html=False): """Takes an event object and returns a shortened description.""" if event.short_description: description = event.short_description else: description = event.description if strip_html: description = unhtml(description) return Truncator(description).words(words)
def event_assignments_ical(request): cache_key = 'event_assignements_ical' assignee = request.GET.get('assignee') if assignee: assignee = get_object_or_404(User, email=assignee) cache_key += str(assignee.pk) cached = cache.get(cache_key) if cached: # additional response headers aren't remembered so add them again cached['Access-Control-Allow-Origin'] = '*' return cached cal = vobject.iCalendar() now = timezone.now() base_qs = EventAssignment.objects.all().order_by('-event__start_time') if assignee: base_qs = base_qs.filter(users=assignee) title = 'Airmo' if assignee: title += ' for %s' % assignee.email cal.add('X-WR-CALNAME').value = title assignments = list( base_qs.filter(event__start_time__lt=now)[:settings.CALENDAR_SIZE]) assignments += list(base_qs.filter(event__start_time__gte=now)) base_url = '%s://%s' % (request.is_secure() and 'https' or 'http', RequestSite(request).domain) for assignment in assignments: event = assignment.event vevent = cal.add('vevent') vevent.add('summary').value = "[AirMo crew] %s" % event.title # Adjusted start times for Event Assignment iCal feeds # to allow staff sufficient time for event set-up. vevent.add('dtstart').value = (event.start_time - datetime.timedelta(minutes=30)) vevent.add('dtend').value = (event.start_time + datetime.timedelta(hours=1)) vevent.add('description').value = unhtml(short_desc(event)) vevent.add('url').value = (base_url + reverse('main:event', args=(event.slug, ))) icalstream = cal.serialize() # response = http.HttpResponse(icalstream, # mimetype='text/plain; charset=utf-8') response = http.HttpResponse(icalstream, mimetype='text/calendar; charset=utf-8') filename = 'AirMozillaEventAssignments' filename += '.ics' response['Content-Disposition'] = ('inline; filename=%s' % filename) cache.set(cache_key, response, 60 * 10) # 10 minutes # https://bugzilla.mozilla.org/show_bug.cgi?id=909516 response['Access-Control-Allow-Origin'] = '*' return response
def new_event_tweet(request, id): data = {} event = get_object_or_404(Event, id=id) if request.method == 'POST': form = forms.EventTweetForm(event, data=request.POST) if form.is_valid(): event_tweet = form.save(commit=False) if event_tweet.send_date: assert event.location, "event must have a location" tz = pytz.timezone(event.location.timezone) event_tweet.send_date = tz_apply(event_tweet.send_date, tz) else: now = timezone.now() event_tweet.send_date = now event_tweet.event = event event_tweet.creator = request.user event_tweet.save() messages.info(request, 'Tweet saved') url = reverse('manage:event_edit', args=(event.pk, )) return redirect(url) else: initial = {} event_url = reverse('main:event', args=(event.slug, )) base_url = ('%s://%s' % (request.is_secure() and 'https' or 'http', RequestSite(request).domain)) abs_url = urlparse.urljoin(base_url, event_url) try: abs_url = shorten_url(abs_url) data['shortener_error'] = None except (ImproperlyConfigured, ValueError) as err: data['shortener_error'] = str(err) # except OtherHttpRelatedErrors? # data['shortener_error'] = "Network error trying to shorten URL" initial['text'] = unhtml('%s\n%s' % (short_desc(event), abs_url)) initial['include_placeholder'] = bool(event.placeholder_img) initial['send_date'] = '' form = forms.EventTweetForm(initial=initial, event=event) data['event'] = event data['form'] = form data['tweets'] = EventTweet.objects.filter(event=event) return render(request, 'manage/new_event_tweet.html', data)
def new_event_tweet(request, id): data = {} event = get_object_or_404(Event, id=id) if request.method == 'POST': form = forms.EventTweetForm(event, data=request.POST) if form.is_valid(): event_tweet = form.save(commit=False) if event_tweet.send_date: assert event.location, "event must have a location" tz = pytz.timezone(event.location.timezone) event_tweet.send_date = tz_apply(event_tweet.send_date, tz) else: now = timezone.now() event_tweet.send_date = now event_tweet.event = event event_tweet.creator = request.user event_tweet.save() messages.info(request, 'Tweet saved') url = reverse('manage:event_edit', args=(event.pk,)) return redirect(url) else: initial = {} event_url = reverse('main:event', args=(event.slug,)) base_url = get_base_url(request) abs_url = urlparse.urljoin(base_url, event_url) try: abs_url = shorten_url(abs_url) data['shortener_error'] = None except (ImproperlyConfigured, ValueError) as err: data['shortener_error'] = str(err) # except OtherHttpRelatedErrors? # data['shortener_error'] = "Network error trying to shorten URL" initial['text'] = unhtml('%s\n%s' % (short_desc(event), abs_url)) initial['include_placeholder'] = bool(event.placeholder_img) initial['send_date'] = '' form = forms.EventTweetForm(initial=initial, event=event) data['event'] = event data['form'] = form data['tweets'] = EventTweet.objects.filter(event=event) return render(request, 'manage/new_event_tweet.html', data)
def events_calendar(request, public=True): cache_key = 'calendar_%s' % ('public' if public else 'private') cached = cache.get(cache_key) if cached: return cached cal = vobject.iCalendar() cal.add('X-WR-CALNAME').value = ('Air Mozilla Public Events' if public else 'Air Mozilla Private Events') now = datetime.datetime.utcnow().replace(tzinfo=utc) base_qs = Event.objects.approved() if public: base_qs = base_qs.filter(privacy=Event.PRIVACY_PUBLIC) else: base_qs = base_qs.exclude(privacy=Event.PRIVACY_PUBLIC) events = list(base_qs .filter(start_time__lt=now) .order_by('-start_time')[:settings.CALENDAR_SIZE]) events += list(base_qs .filter(start_time__gte=now) .order_by('start_time')[:settings.CALENDAR_SIZE]) base_url = '%s://%s/' % (request.is_secure() and 'https' or 'http', RequestSite(request).domain) for event in events: vevent = cal.add('vevent') vevent.add('summary').value = event.title vevent.add('dtstart').value = event.start_time vevent.add('dtend').value = (event.start_time + datetime.timedelta(hours=1)) vevent.add('description').value = unhtml(short_desc(event)) if event.location: vevent.add('location').value = event.location.name vevent.add('url').value = base_url + event.slug + '/' icalstream = cal.serialize() response = http.HttpResponse(icalstream, mimetype='text/calendar; charset=utf-8') filename = 'AirMozillaEvents%s.ics' % ('Public' if public else 'Private') response['Content-Disposition'] = ( 'inline; filename=%s' % filename) cache.set(cache_key, response) return response
def test_unhtml(self): input_ = 'A <a href="">FOO</a> BAR' eq_(utils.unhtml(input_), 'A FOO BAR')
def strip_html(text): return unhtml(text)
def tweet_new_published_events(verbose=False): """Create EventTweet instances for events that have recently been published and are ready for public consumption.""" now = timezone.now() events = Event.objects.scheduled().filter( created__gt=now - datetime.timedelta(days=7), created__lt=now, privacy=Event.PRIVACY_PUBLIC, ).approved().exclude( id__in=EventTweet.objects.values('event_id') ) site = Site.objects.get_current() base_url = 'https://%s' % site.domain # yuck! for event in events: if event.channels.filter(no_automated_tweets=True): if verbose: print "Skipping", repr(event.title), "because it's part of" print event.channels.filter(no_automated_tweets=True) continue # we have to try to manually create an appropriate tweet url = reverse('main:event', args=(event.slug,)) abs_url = urlparse.urljoin(base_url, url) try: abs_url = shorten_url(abs_url) except (ImproperlyConfigured, ValueError) as err: # pragma: no cover if verbose: # pragma: no cover print "Failed to shorten URL" print err text = event.title if len(text) > 115: # Why not 140? # We've found that sometimes when you're trying to tweet # a piece of text that actually is less than 140 when # doing text+URL you can get strange errors from Twitter # that it's still too long. text = text[:115] text = unhtml('%s\n%s' % ( text, abs_url )) text += '\n' tags = ( event.tags.all() .extra( select={'lower_name': 'lower(name)'} ).order_by('lower_name') ) for tag in tags: _tag = '#' + tag.name.replace(' ', '') # see comment above why we use 115 instead of 140 if len(text + _tag) + 1 < 115: text += '%s ' % _tag else: break text = text.strip() if event.start_time > timezone.now(): send_date = event.start_time - datetime.timedelta(minutes=30) else: send_date = timezone.now() # send as soon as possible event_tweet = EventTweet.objects.create( event=event, text=text, include_placeholder=True, send_date=send_date, ) if verbose: # pragma: no cover print "Created", repr(event_tweet)
def events_calendar_ical(request, privacy=None): cache_key = 'calendar' if privacy: cache_key += '_%s' % privacy if request.GET.get('location'): if request.GET.get('location').isdigit(): location = get_object_or_404( Location, pk=request.GET.get('location') ) else: location = get_object_or_404( Location, name=request.GET.get('location') ) cache_key += str(location.pk) cached = None else: location = None cached = cache.get(cache_key) if cached: # additional response headers aren't remembered so add them again cached['Access-Control-Allow-Origin'] = '*' return cached cal = vobject.iCalendar() now = datetime.datetime.utcnow().replace(tzinfo=utc) base_qs = Event.objects.approved() if privacy == 'public': base_qs = base_qs.filter(privacy=Event.PRIVACY_PUBLIC) title = 'Air Mozilla Public Events' elif privacy == 'private': base_qs = base_qs.exclude(privacy=Event.PRIVACY_PUBLIC) title = 'Air Mozilla Private Events' else: title = 'Air Mozilla Events' if location: base_qs = base_qs.filter(location=location) cal.add('X-WR-CALNAME').value = title events = list(base_qs .filter(start_time__lt=now) .order_by('-start_time')[:settings.CALENDAR_SIZE]) events += list(base_qs .filter(start_time__gte=now) .order_by('start_time')) base_url = '%s://%s/' % (request.is_secure() and 'https' or 'http', RequestSite(request).domain) for event in events: vevent = cal.add('vevent') vevent.add('summary').value = event.title vevent.add('dtstart').value = event.start_time vevent.add('dtend').value = (event.start_time + datetime.timedelta(hours=1)) vevent.add('description').value = unhtml(short_desc(event)) if event.location: vevent.add('location').value = event.location.name vevent.add('url').value = base_url + event.slug + '/' icalstream = cal.serialize() #response = http.HttpResponse(icalstream, # mimetype='text/plain; charset=utf-8') response = http.HttpResponse(icalstream, mimetype='text/calendar; charset=utf-8') filename = 'AirMozillaEvents%s' % (privacy and privacy or '') if location: filename += '_%s' % slugify(location.name) filename += '.ics' response['Content-Disposition'] = ( 'inline; filename=%s' % filename) if not location: cache.set(cache_key, response, 60 * 10) # 10 minutes # https://bugzilla.mozilla.org/show_bug.cgi?id=909516 response['Access-Control-Allow-Origin'] = '*' return response
def events_calendar(request, privacy=None): cache_key = 'calendar' if privacy: cache_key += '_%s' % privacy if request.GET.get('location'): location = get_object_or_404(Location, name=request.GET.get('location')) cache_key += str(location.pk) cached = None else: location = None cached = cache.get(cache_key) if cached: return cached cal = vobject.iCalendar() now = datetime.datetime.utcnow().replace(tzinfo=utc) base_qs = Event.objects.approved() if privacy == 'public': base_qs = base_qs.filter(privacy=Event.PRIVACY_PUBLIC) title = 'Air Mozilla Public Events' elif privacy == 'private': base_qs = base_qs.exclude(privacy=Event.PRIVACY_PUBLIC) title = 'Air Mozilla Private Events' else: title = 'Air Mozilla Events' if location: base_qs = base_qs.filter(location=location) cal.add('X-WR-CALNAME').value = title events = list( base_qs.filter(start_time__lt=now).order_by('-start_time') [:settings.CALENDAR_SIZE]) events += list( base_qs.filter(start_time__gte=now).order_by('start_time') [:settings.CALENDAR_SIZE]) base_url = '%s://%s/' % (request.is_secure() and 'https' or 'http', RequestSite(request).domain) for event in events: vevent = cal.add('vevent') vevent.add('summary').value = event.title vevent.add('dtstart').value = event.start_time vevent.add('dtend').value = (event.start_time + datetime.timedelta(hours=1)) vevent.add('description').value = unhtml(short_desc(event)) if event.location: vevent.add('location').value = event.location.name vevent.add('url').value = base_url + event.slug + '/' icalstream = cal.serialize() #response = http.HttpResponse(icalstream, # mimetype='text/plain; charset=utf-8') response = http.HttpResponse(icalstream, mimetype='text/calendar; charset=utf-8') filename = 'AirMozillaEvents%s' % (privacy and privacy or '') if location: filename += '_%s' % slugify(location.name) filename += '.ics' response['Content-Disposition'] = ('inline; filename=%s' % filename) if not location: cache.set(cache_key, response) return response