From aacc0af901246c990a6faad615692e7ae569d214 Mon Sep 17 00:00:00 2001 From: canin carlos Date: Mon, 12 Jan 2026 22:48:08 -0500 Subject: [PATCH] API for Calendars --- events/admin.py | 4 +- events/digitools.py | 27 ++++++------ ...dar_options_calendar_published_and_more.py | 44 +++++++++++++++++++ ...calendar_options_alter_organization_cal.py | 23 ++++++++++ .../migrations/0041_alter_event_calendar.py | 18 ++++++++ events/models.py | 21 +++++---- events/serializers.py | 15 ++++++- events/urls.py | 1 + events/views.py | 9 ++++ 9 files changed, 137 insertions(+), 25 deletions(-) create mode 100644 events/migrations/0039_alter_calendar_options_calendar_published_and_more.py create mode 100644 events/migrations/0040_alter_calendar_options_alter_organization_cal.py create mode 100644 events/migrations/0041_alter_event_calendar.py diff --git a/events/admin.py b/events/admin.py index eeb809d..d9b7b06 100644 --- a/events/admin.py +++ b/events/admin.py @@ -3,12 +3,12 @@ from .models import * class CalendarAdmin(admin.ModelAdmin): # prepopulated_fields = {"slug": ("shortname",)} - list_display = ("name", "shortcode") + list_display = ("name", "shortcode", "published") class ScraperAdmin(admin.ModelAdmin): # prepopulated_fields = {"slug": ("shortname",)} - list_display = ("name", "items", "new_items", "last_ran") + list_display = ("name", "items", "new_items", "last_ran", "calendar") class OrganizationAdmin(admin.ModelAdmin): # prepopulated_fields = {"slug": ("shortname",)} diff --git a/events/digitools.py b/events/digitools.py index 23b7720..811240d 100644 --- a/events/digitools.py +++ b/events/digitools.py @@ -1,5 +1,5 @@ import os, sys -from datetime import datetime +from datetime import datetime, timedelta from dateutil import relativedelta from time import sleep import pytz @@ -19,7 +19,7 @@ odt_next_month = datetime.now() + plus_one_month # Get Scraper name, item count and online_calendar (virtcal) -def getScraper(venue, webite, cal): +def getScraper(venue, website, cal): virtcal = Calendar.objects.get(shortcode='000') try: scraper, created = Scraper.objects.get_or_create( @@ -183,7 +183,7 @@ def createBasicEvent(event, event_type, venue): venue = venue ) new_event = add_calendars(new_event, event) - print("\n+new event+\n") + # print("\n+new event+") return new_event, created # Create iCal Event @@ -198,7 +198,7 @@ def createBasiciCalEvent(event, event_type, venue): venue = venue ) new_event = add_calendars(new_event, event) - print("\n+new event+\n") + print("Success") return new_event, created # Create Detailed Event with Details & Guests @@ -216,7 +216,7 @@ def createDetailedEvent(event, event_type, venue, scraper): venue = venue ) new_event = add_calendars(new_event, event) - print("\n+new event+\n") + print("Success") return new_event, created # Create iCal event from DF_Online & Medellin @@ -260,7 +260,7 @@ def getiCalEvents(gcal, scraper, venue, event_type): return events # Build iCal Events and Send to Create -def buildiCalEvents(events, event_type, scraper): +def buildiCalEvents(events, event_type, scraper, venue): for event in events: e = {} e['calendars'] = event['calendars'] @@ -322,7 +322,7 @@ def getiCalRepeateEvents(gcal, scraper, venue, event_type, cal): try: if rules['FREQ'][0] == 'WEEKLY': if datetime.today().weekday() != 0: - event = digitools.splitLocation(event, "Medellin") + event = splitLocation(event, city="Medellin") date = datetime.today().date() - timedelta(days=datetime.today().weekday()) date = datetime.combine(date, event['dateStart'].time()) days = ["SU", "MO", "TU", "WE", "TH", "FR", "SA"] @@ -333,27 +333,28 @@ def getiCalRepeateEvents(gcal, scraper, venue, event_type, cal): iCalEventRepeatFilter(day, date, event, scraper, event['venue'], "Ed") except Exception as e: - print("Error: ", e, "\n\n\n\n") + print("Error: ", event, e, "\n\n\n\n") pass -def iCalEventRepeatFilterteEvent(day, date, event, scraper, venue, event_type): +def iCalEventRepeatFilter(day, date, event, scraper, venue, event_type): days = [day-1, day+6, day+13] for day in days: event['dateStamp'] = date + timedelta(days=day) event['dateStart'] = event['dateStamp'] - digitools.createCleanIcalEvent(event, scraper, venue, event_type) + createCleanIcalEvent(event, scraper, venue, event_type) return def splitLocation(event, **kwargs): loc_split = event['strLocation'].split(',') + ppr(loc_split) venue_name = loc_split[0] venue, created = Organization.objects.get_or_create( name=venue_name, ) event['venue'] = venue - if city: - venue.city = kwargs['city'] - venue.save() + # if kwargs['city']: + # venue.city = kwargs['city'] + # venue.save() return event # ARCHIVED Methods diff --git a/events/migrations/0039_alter_calendar_options_calendar_published_and_more.py b/events/migrations/0039_alter_calendar_options_calendar_published_and_more.py new file mode 100644 index 0000000..3075fb0 --- /dev/null +++ b/events/migrations/0039_alter_calendar_options_calendar_published_and_more.py @@ -0,0 +1,44 @@ +# Generated by Django 5.1.1 on 2026-01-12 23:30 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('events', '0038_remove_event_calendar_event_calendar'), + ] + + operations = [ + migrations.AlterModelOptions( + name='calendar', + options={'ordering': ['name'], 'verbose_name_plural': 'Calendars'}, + ), + migrations.AddField( + model_name='calendar', + name='published', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='organization', + name='cal', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='events.calendar'), + preserve_default=False, + ), + migrations.AlterField( + model_name='organization', + name='membership', + field=models.CharField(choices=[('Nm', 'Non-Member'), ('Ds', 'DigiSnaxx'), ('Dsp', 'DigiSnaxx +')], default='0', max_length=31), + ), + migrations.AlterField( + model_name='organization', + name='org_type', + field=models.CharField(choices=[('Fb', 'Food & Beverage'), ('Re', 'Retail'), ('Se', 'Service'), ('Vn', 'Venue'), ('Ud', 'Undefined')], default='3', max_length=31), + ), + migrations.AlterField( + model_name='promo', + name='promo_type', + field=models.CharField(choices=[('Ar', 'Art'), ('Fo', 'Food'), ('Ev', 'Event'), ('Re', 'Retail'), ('Sv', 'Service'), ('Ma', 'Mutual Aid'), ('Ca', 'Classified'), ('Jo', 'Job Opening'), ('Ja', 'Journal Article'), ('Sp', 'Startup Pitch'), ('An', 'Academia Nut'), ('Su', 'Survey Question')], default='0', max_length=15), + ), + ] diff --git a/events/migrations/0040_alter_calendar_options_alter_organization_cal.py b/events/migrations/0040_alter_calendar_options_alter_organization_cal.py new file mode 100644 index 0000000..7d80745 --- /dev/null +++ b/events/migrations/0040_alter_calendar_options_alter_organization_cal.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1.1 on 2026-01-12 23:49 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('events', '0039_alter_calendar_options_calendar_published_and_more'), + ] + + operations = [ + migrations.AlterModelOptions( + name='calendar', + options={'ordering': ['-published', 'id'], 'verbose_name_plural': 'Calendars'}, + ), + migrations.AlterField( + model_name='organization', + name='cal', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='cal_events', to='events.calendar'), + ), + ] diff --git a/events/migrations/0041_alter_event_calendar.py b/events/migrations/0041_alter_event_calendar.py new file mode 100644 index 0000000..1e49c8f --- /dev/null +++ b/events/migrations/0041_alter_event_calendar.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.1 on 2026-01-13 00:13 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('events', '0040_alter_calendar_options_alter_organization_cal'), + ] + + operations = [ + migrations.AlterField( + model_name='event', + name='calendar', + field=models.ManyToManyField(blank=True, null=True, related_name='events', to='events.calendar'), + ), + ] diff --git a/events/models.py b/events/models.py index d84e1e7..0b8b691 100644 --- a/events/models.py +++ b/events/models.py @@ -9,10 +9,12 @@ class Calendar(models.Model): name = models.CharField(max_length=31, unique=True) shortcode = models.CharField(max_length=3, unique=True) desc = models.TextField(blank=True, null=True) + published = models.BooleanField(default=False) + class Meta: verbose_name_plural = "Calendars" - ordering = ['name',] + ordering = ['-published', 'id',] def __unicode__(self): return "%s" % self.shortcode @@ -29,6 +31,7 @@ class Scraper(models.Model): new_items = models.IntegerField(blank=True, null=True) last_ran = models.DateTimeField(blank=True, null=True) + class Meta: verbose_name_plural = "Scrapers" ordering = ['name',] @@ -78,7 +81,7 @@ class Organization(models.Model): address_type = models.CharField(max_length=31, blank=True, null=True) address_complete = models.CharField(max_length=63, blank=True, null=True) - + cal = models.ForeignKey(Calendar, on_delete=models.CASCADE, related_name="cal_events") barrio = models.CharField(max_length=127, blank=True, null=True) city = models.CharField(max_length=31, blank=True, null=True) state = models.CharField(max_length=15, blank=True, null=True) @@ -113,15 +116,15 @@ class Organization(models.Model): class Event(models.Model): EVENT_TYPE = ( - ('Ot', 'Other'), - ('Mu', 'Music'), + ('Ot', '🤔'), + ('Mu', '🎶'), ('Va', 'Visual Art'), - ('Gv', 'Government'), + ('Gv', '🛠️'), ('Ce', 'Civic Engagement'), - ('Ed', 'Educational'), + ('Ed', '🍎'), ('Ma', 'Mutual Aid'), - ('Th', 'Theater'), - ('Co', 'Comedy'), + ('Th', '🎭'), + ('Co', '🍿'), ) EVENT_STATE = ( ('live', 'Live & Direct'), @@ -134,7 +137,7 @@ class Event(models.Model): show_date = models.DateTimeField() show_day = models.DateField() - calendar = models.ManyToManyField(Calendar, blank=True, null=True) + calendar = models.ManyToManyField(Calendar, blank=True, null=True, related_name="events") scraper = models.ForeignKey(Scraper, on_delete=models.CASCADE, null=True) venue = models.ForeignKey(Organization, on_delete=models.CASCADE) diff --git a/events/serializers.py b/events/serializers.py index db78c61..d6a97cf 100644 --- a/events/serializers.py +++ b/events/serializers.py @@ -1,5 +1,5 @@ from rest_framework import serializers -from .models import Event, Organization, Promo +from .models import Calendar, Event, Organization, Promo from django.db import models from django.contrib.auth.models import User @@ -35,6 +35,7 @@ class ScopesPermission(BasePermission): ## Events ## ############ + class OrganizationSerializer(serializers.ModelSerializer): class Meta: model = Organization @@ -52,6 +53,18 @@ class EventSerializer(serializers.ModelSerializer): depth = 2 # fields = ('id', 'name',) +class CalSerializer(serializers.ModelSerializer): + events_count = serializers.SerializerMethodField() + class Meta: + model = Calendar + fields = ['id', 'name', 'shortcode', 'events_count', 'published'] + # fields = '__all__' + + + def get_events_count(self, obj): + # obj is the current Tag instance + return obj.events.count() + class PromoSerializer(serializers.ModelSerializer): organization = OrganizationSerializer(many=False) # event_type = serializers.CharField(source='get_event_type_display') diff --git a/events/urls.py b/events/urls.py index f55b1a7..51dccfd 100644 --- a/events/urls.py +++ b/events/urls.py @@ -20,6 +20,7 @@ from .views import * urlpatterns = [ re_path(r'^events/', EventsAPIView.as_view(), name="get-events"), re_path(r'^promo/', PromoAPIView.as_view(), name="get-promo"), + re_path(r'^cals/', CalAPIView.as_view(), name="get-cals"), # re_path(r'^events-token/', EventsTokenAPIView.as_view(), name="get-token-events"), ] diff --git a/events/views.py b/events/views.py index 7b56242..3ac3053 100644 --- a/events/views.py +++ b/events/views.py @@ -6,6 +6,7 @@ from .models import * from .serializers import * from django.db.models import Q +from django.db.models import Count from rest_framework import generics from rest_framework.decorators import authentication_classes, permission_classes @@ -26,6 +27,14 @@ td = timedelta(hours=7) odt = datetime.now() - td # Create your views here. + +class CalAPIView(generics.ListAPIView): + serializer_class = CalSerializer + queryset = Calendar.objects.all() + # queryset = Calendar.objects.filter(published=True) + permission_classes = [HasAPIKey] + + class EventsAPIView(generics.ListAPIView): serializer_class = EventSerializer queryset = Event.objects.filter(show_date__gte=odt).order_by('show_date')