diff --git a/events/models.py b/events/models.py
index 3dbbf4412..3cf7634ea 100644
--- a/events/models.py
+++ b/events/models.py
@@ -14,11 +14,16 @@
import asyncio
from asgiref.sync import sync_to_async
import aiohttp
+import hashlib
+import base64
# Create your models here.
class EventManager(models.Manager):
+ def hashing(self, string):
+ return base64.b64encode(hashlib.blake2b(string.encode(), digest_size=6).hexdigest().encode()).decode()
+
async def read_ical(self, name, file, create_function):
try:
#print("Requesting " + name)
@@ -59,17 +64,22 @@ async def read_wp_events_api(self, name, api, categorize):
print("Failed requesting to " + name)
async def wp_events_api_create_event(self, event_json, api, host, categorize):
- if not await self.filter(event_url=event_json['link']).aexists():
+ if not await self.filter(event_url=event_json['link'], start_time=datetime.fromisoformat(event_json['start']).astimezone(timezone.get_current_timezone())).aexists():
event = await self.acreate(
title=event_json['title'],
event_url=event_json['link'],
+ hash=self.hashing(event_json['link'] + str(event_json['start']))
)
else:
- event = await self.filter(event_url=event_json['link']).afirst()
+ event = await self.filter(event_url=event_json['link'], start_time=datetime.fromisoformat(event_json['start']).astimezone(timezone.get_current_timezone())).afirst()
if event.update_mode != 2:
return None
event.title = str(event_json['title']['rendered'].encode('utf-8'), 'UTF-8')
+
+ if event.hash == "":
+ event.hash = self.hashing(event_json['link'] + str(event_json['start']))
+
event.description = str(event_json['excerpt']['rendered'].encode('utf-8'), 'UTF-8')
event.start_time = datetime.fromisoformat(event_json['start']).astimezone(timezone.get_current_timezone())
@@ -89,19 +99,43 @@ async def wp_events_api_create_event(self, event_json, api, host, categorize):
event.event_url=event_json['link']
event.category = categorize['default']
+ categories = ['entertainment', 'seminar', 'community', 'sports']
+ for category in categories:
+ categorize_key = category + '_type'
+ if categorize_key in categorize:
+ for event_type in event_json['event-type']:
+
+ for category_type in categorize[categorize_key]:
+ if event_type == category_type:
+ event.category = category
+ break
+
+ if event.category != categorize['default']:
+ break
+
+ if event.category != categorize['default']:
+ break
- if 'seminar_ids' in categorize:
- for id in event_json['event-type']:
+ event.hidden=False
+ if 'hidden_topics' in categorize:
+ for id in event_json['event-topic']:
- for seminar_id in categorize['seminar_ids']:
- if id == seminar_id:
- event.category = "seminar"
+ for topic in categorize['hidden_topics']:
+ if id == topic:
+ event.hidden = True
break
- if event.category != categorize['default']:
+ if event.hidden == True:
break
-
- event.hidden=False
+
+ if event.hidden == False and 'hidden_title_terms' in categorize:
+ for term in categorize['hidden_title_terms']:
+ if term.lower() in event.title.lower():
+ event.hidden = True
+ break
+
+ if timedelta(days=14) < event.end_time - event.start_time:
+ event.hidden=True
req = Request(api, headers={'User-Agent': "The Ubyssey https://ubyssey.ca/"})
if req.host in event_json['link']:
@@ -133,12 +167,17 @@ async def ubcevents_create_event(self, ical_component):
event = await self.acreate(
title=ical_component.get('summary'),
event_url=ical_component.decoded('url'),
+ hash=self.hashing(ical_component.get('summary') + str(ical_component.decoded('dtstart')))
)
else:
event = await self.filter(event_url=ical_component.get('url')).afirst()
if event.update_mode != 2:
return None
+
+ if event.hash == "":
+ event.hash = self.hashing(ical_component.get('summary') + str(ical_component.decoded('dtstart')))
+
# Split location and address
location = ical_component.get('location')
address = ""
@@ -199,9 +238,9 @@ async def ubcevents_judge_hidden(self, event, ical):
return True
# Hide events with certain terms in the title
- # The two listed right now are on an inaccurate repeating schedule
- for i in ['coffee hour', 'advanced research computing summer school']:
- if i in title:
+ # The first two listed right now are on an inaccurate repeating schedule, the last was an advertisment for a sale that lasted too long
+ for i in ['coffee hour', 'advanced research computing summer school', 'Student Indoor Plant Sale at UBC Botanical Garden']:
+ if i.lower() in title.lower():
return True
# Default to showing events when there are no categories listed
@@ -275,16 +314,22 @@ def ubcevents_category(self, event):
async def gothunderbirds_create_event(self, ical_component):
- if not await self.filter(event_url=ical_component.get('url').replace("&", "__AND__")).aexists():
+ if not await self.filter(event_url=ical_component.get('url')).aexists():
event = await self.acreate(
title=ical_component.get('summary'),
- event_url=ical_component.decoded('url').replace("&", "__AND__"),
+ event_url=ical_component.decoded('url'),
+ hash=self.hashing(ical_component.get('summary') + str(ical_component.decoded('dtstart')))
)
else:
- event = await self.filter(event_url=ical_component.get('url').replace("&", "__AND__")).afirst()
+ event = await self.filter(event_url=ical_component.get('url')).afirst()
if event.update_mode != 2:
return None
+
+ if event.hash == "":
+ event.hash = self.hashing(ical_component.get('summary') + str(ical_component.decoded('dtstart')))
+
+
# Split location and address
address = ical_component.get('location')
location = address.replace('Vancouver, B.C., ', '')
@@ -321,7 +366,7 @@ async def gothunderbirds_create_event(self, ical_component):
event.address=address
event.location=location
- event.event_url=ical_component.decoded('url').replace("&", "__AND__")
+ event.event_url=ical_component.decoded('url')
event.category='sports'
event.hidden=self.gothunderbirds_judge_hidden(ical_component)
@@ -395,12 +440,16 @@ async def phas_ubc_create_event(self, event_component):
event = await self.acreate(
title=title,
event_url=event_url,
+ hash=self.hashing(title + str(event_component.find('span', class_='start').get_text(strip=True)))
)
else:
event = await self.filter(event_url=event_url).afirst()
if event.update_mode != 2:
return None
+ if event.hash == "":
+ event.hash = self.hashing(title + str(event_component.find('span', class_='start').get_text(strip=True)))
+
# Extract start time
start_time_str = event_component.find('span', class_='start').get_text(strip=True)
parsed_start_time = datetime.fromisoformat(start_time_str)
@@ -450,6 +499,7 @@ async def cs_ubc_create_event(self, ical_component):
event = await self.acreate(
title=ical_component.get('summary'),
event_url=ical_component.decoded('url'),
+ hash=self.hashing(ical_component.get('summary') + str(ical_component.decoded('dtstart')))
)
else:
event = await self.filter(event_url=ical_component.get('url')).afirst()
@@ -457,6 +507,10 @@ async def cs_ubc_create_event(self, ical_component):
return None
event.title=ical_component.get('summary')
+
+ if event.hash == "":
+ event.hash = self.hashing(ical_component.get('summary') + str(ical_component.decoded('dtstart')))
+
event.description= "
" + ical_component.get('description').replace("&", "&")
if "
Name:" in event.description and "\nTitle" in event.description:
if event.description.index("
Name:") < event.description.index("\nTitle"):
@@ -526,6 +580,7 @@ async def stats_ubc_create_event(self, ical_component):
event = await self.acreate(
title=ical_component.get('summary'),
event_url=ical_component.decoded('url'),
+ hash=self.hashing(ical_component.get('summary') + str(ical_component.decoded('dtstart')))
)
else:
event = await self.filter(event_url=ical_component.get('url')).afirst()
@@ -536,6 +591,9 @@ async def stats_ubc_create_event(self, ical_component):
event.title=ical_component.get('summary')
+ if event.hash == "":
+ event.hash = self.hashing(ical_component.get('summary') + str(ical_component.decoded('dtstart')))
+
# Clean up event description because they are so messy and have unnecessary information
description = str(ical_component.decoded('description'), 'UTF-8')
safety = 10
@@ -639,6 +697,12 @@ class Event(models.Model):
null=True,
blank=True,
)
+ hash = models.CharField(
+ max_length=50,
+ blank=False,
+ null=True,
+ default=''
+ )
image = models.CharField(
max_length=255,
blank=True,
@@ -672,6 +736,7 @@ class Event(models.Model):
FieldPanel("address"),
FieldPanel("host"),
FieldPanel("event_url"),
+ FieldPanel("hash"),
FieldPanel("image"),
FieldPanel(
"category",
diff --git a/events/views.py b/events/views.py
index 9bf086f5c..c5582b54b 100644
--- a/events/views.py
+++ b/events/views.py
@@ -72,6 +72,18 @@ def react(self, request):
'description': "Events Around Campus collected by The Ubyssey",
'url': 'https://ubyssey.ca/events/',
}
+
+ if request.GET.get("event"):
+ if Event.objects.filter(hash=request.GET.get("event")).exists():
+ event = Event.objects.filter(hash=request.GET.get("event")).first()
+
+ meta = {
+ 'title': event.title,
+ 'description': event.description,
+ 'url': "https://ubyssey.ca/events/?event=" + event.hash,
+ 'noindex': True,
+ }
+
return render(request, "events/event_page_react.html", {'ical':ical, 'rss':rss, 'meta':meta})
def landing(self, request):
@@ -259,7 +271,8 @@ async def update_events(request):
'api': 'https://anth.ubc.ca/wp-json/wp/v2/',
'categorize': {
'default': 'community',
- 'seminar_ids': [633, 632, 634, 528, 530],
+ 'seminar_type': [633, 632, 634, 528, 530],
+ 'hidden_title_terms': ['coffee hour']
},
},
@@ -267,7 +280,7 @@ async def update_events(request):
'api': 'https://asia.ubc.ca/wp-json/wp/v2/',
'categorize': {
'default': 'community',
- 'seminar_ids': [570, 572, 571, 574, 739],
+ 'seminar_type': [570, 572, 571, 574, 739],
},
},
@@ -275,7 +288,8 @@ async def update_events(request):
'api': 'https://cenes.ubc.ca/wp-json/wp/v2/',
'categorize': {
'default': 'community',
- 'seminar_ids': [552, 554, 559, 553, 677, 558]
+ 'seminar_type': [552, 554, 559, 553, 677, 558],
+ 'hidden_title_terms': ['fika', 'plauder', 'kaffeestunde']
},
},
@@ -283,7 +297,7 @@ async def update_events(request):
'api': 'https://english.ubc.ca/wp-json/wp/v2/',
'categorize': {
'default': 'community',
- 'seminar_ids': [512, 515, 510, 513]
+ 'seminar_type': [512, 515, 510, 513]
},
},
@@ -291,7 +305,7 @@ async def update_events(request):
'api': 'http://fhis.ubc.ca/wp-json/wp/v2/',
'categorize': {
'default': 'community',
- 'seminar_ids': [534, 537, 532]
+ 'seminar_type': [534, 537, 532]
},
},
@@ -299,7 +313,7 @@ async def update_events(request):
'api': 'https://grsj.arts.ubc.ca/wp-json/wp/v2/',
'categorize': {
'default': 'community',
- 'seminar_ids': [512, 514, 632]
+ 'seminar_type': [512, 514, 632]
},
},
@@ -307,7 +321,7 @@ async def update_events(request):
'api': 'https://history.ubc.ca/wp-json/wp/v2/',
'categorize': {
'default': 'community',
- 'seminar_ids': [531, 525, 527, 526, 530]
+ 'seminar_type': [531, 525, 527, 526, 530]
},
},
@@ -322,7 +336,7 @@ async def update_events(request):
'api': 'https://psych.ubc.ca/wp-json/wp/v2/',
'categorize': {
'default': 'community',
- 'seminar_ids': [433, 384, 906, 792, 377, 931, 560, 559]
+ 'seminar_type': [433, 384, 906, 792, 377, 931, 560, 559]
},
},
@@ -330,7 +344,92 @@ async def update_events(request):
'api': 'https://socialwork.ubc.ca/wp-json/wp/v2/',
'categorize': {
'default': 'community',
- 'seminar_ids': [520, 527, 525]
+ 'seminar_type': [520, 527, 525]
+ },
+ },
+
+ {'name': 'UBC Faculty of Arts',
+ 'api': 'https://www.arts.ubc.ca/wp-json/wp/v2/',
+ 'categorize': {
+ 'default': 'community',
+ 'entertainment_type': [802],
+ 'seminar_type': [1962, 1785],
+ 'hidden_topics': [1783, 1950, 1996, 2378, 2379, 1995, 2375]
+ },
+ },
+
+ {'name': 'UBC School of Information',
+ 'api': 'https://ischool.ubc.ca/wp-json/wp/v2/',
+ 'categorize': {
+ 'default': 'seminar',
+ },
+ },
+
+ {'name': 'UBC Art History, Visual Art & Theory',
+ 'api': 'https://ahva.ubc.ca/wp-json/wp/v2/',
+ 'categorize': {
+ 'default': 'community',
+ 'seminar_type': [820, 926, 817, 930, 824, 825]
+ },
+ },
+
+ {'name': 'UBC Ancient Mediterranean and Near Eastern Studies',
+ 'api': 'https://amne.ubc.ca/wp-json/wp/v2/',
+ 'categorize': {
+ 'default': 'community',
+ 'seminar_type': [718, 568, 570, 569]
+ },
+ },
+
+ {'name': 'UBC Coordinated Arts Programs',
+ 'api': 'https://cap.arts.ubc.ca/wp-json/wp/v2/',
+ 'categorize': {
+ 'default': 'seminar',
+ },
+ },
+
+ {'name': 'UBC School of Public Policy and Global Affairs',
+ 'api': 'https://sppga.ubc.ca/wp-json/wp/v2/',
+ 'categorize': {
+ 'default': 'seminar',
+ },
+ },
+
+ {'name': 'UBC Geography',
+ 'api': 'https://geog.ubc.ca/wp-json/wp/v2/',
+ 'categorize': {
+ 'default': 'seminar',
+ 'hidden_title_terms': ['green day'],
+ },
+ },
+
+ {'name': 'UBC Linguistics',
+ 'api': 'https://linguistics.ubc.ca/wp-json/wp/v2/',
+ 'categorize': {
+ 'default': 'seminar',
+ },
+ },
+
+ {'name': 'UBC Philosophy',
+ 'api': 'https://philosophy.ubc.ca/wp-json/wp/v2/',
+ 'categorize': {
+ 'default': 'seminar',
+ },
+ },
+
+ {'name': 'UBC Political Science',
+ 'api': 'https://politics.ubc.ca/wp-json/wp/v2/',
+ 'categorize': {
+ 'default': 'seminar',
+ 'community_type': [544, 546, 549]
+ },
+ },
+
+ {'name': 'UBC Theatre & Film',
+ 'api': 'https://politics.ubc.ca/wp-json/wp/v2/',
+ 'categorize': {
+ 'default': 'entertainment',
+ 'seminar_type': [1262, 1263, 1265]
},
},
]
@@ -339,6 +438,10 @@ async def update_events(request):
for a in wp_apis:
# Event.objects.wp_events_api_get_type_ids(a['api'], terms) # Uncomment to print the event-type id for types wuth the terms above in their name. Used for categorizing the events
tasks.append(asyncio.create_task(Event.objects.read_wp_events_api(a['name'], a['api'], a['categorize'])))
+ if len(tasks) >= 15:
+ await asyncio.gather(*tasks)
+ tasks = []
+
ical_files = [
@@ -361,6 +464,9 @@ async def update_events(request):
for f in ical_files:
tasks.append(asyncio.create_task(Event.objects.read_ical(f['name'], f['file'], f['create_function'])))
+ if len(tasks) >= 15:
+ await asyncio.gather(*tasks)
+ tasks = []
await asyncio.gather(*tasks)
@@ -499,7 +605,7 @@ def item_link(self, item):
class EventsSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Event
- fields = ['id', 'title', 'description', 'start_time', 'end_time', 'location', 'address', 'host', 'email', 'event_url', 'category']
+ fields = ['id', 'title', 'description', 'start_time', 'end_time', 'location', 'address', 'host', 'email', 'event_url', 'hash', 'category']
class EventsViewSet(viewsets.ModelViewSet):
serializer_class = EventsSerializer
diff --git a/home/templates/home/stream_blocks/links.html b/home/templates/home/stream_blocks/links.html
index 308c38325..02268b6af 100644
--- a/home/templates/home/stream_blocks/links.html
+++ b/home/templates/home/stream_blocks/links.html
@@ -21,7 +21,7 @@