first commit
This commit is contained in:
0
events/__init__.py
Normal file
0
events/__init__.py
Normal file
30
events/admin.py
Normal file
30
events/admin.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from django.contrib import admin
|
||||
from .models import *
|
||||
|
||||
|
||||
class ScraperAdmin(admin.ModelAdmin):
|
||||
# prepopulated_fields = {"slug": ("shortname",)}
|
||||
list_display = ("name", "items", "new_items", "last_ran")
|
||||
|
||||
class OrganizationAdmin(admin.ModelAdmin):
|
||||
# prepopulated_fields = {"slug": ("shortname",)}
|
||||
list_display = ( "name", "city",)
|
||||
# list_filter = ("promo_type",)
|
||||
|
||||
class EventAdmin(admin.ModelAdmin):
|
||||
# prepopulated_fields = {"slug": ("shortname",)}
|
||||
list_display = ( "show_title", "event_type", "show_date",)
|
||||
list_filter = ("venue", "event_type")
|
||||
|
||||
class PromoAdmin(admin.ModelAdmin):
|
||||
# prepopulated_fields = {"slug": ("shortname",)}
|
||||
list_display = ("title", "organization", "promo_type", "published")
|
||||
list_filter = ("promo_type",)
|
||||
|
||||
|
||||
# Register your models here.
|
||||
admin.site.register(Scraper, ScraperAdmin)
|
||||
admin.site.register(Event, EventAdmin)
|
||||
admin.site.register(Organization, OrganizationAdmin)
|
||||
admin.site.register(Promo, PromoAdmin)
|
||||
admin.site.register(Calendar)
|
||||
6
events/apps.py
Normal file
6
events/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class EventsConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'events'
|
||||
258
events/digitools.py
Normal file
258
events/digitools.py
Normal file
@@ -0,0 +1,258 @@
|
||||
import os, sys
|
||||
from datetime import datetime
|
||||
from dateutil import relativedelta
|
||||
from time import sleep
|
||||
import pytz
|
||||
from lxml import html
|
||||
from pprint import pprint as ppr
|
||||
|
||||
import django
|
||||
sys.path.append('../')
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'ds_events.settings'
|
||||
django.setup()
|
||||
|
||||
from xvfbwrapper import Xvfb
|
||||
from selenium import webdriver as wd
|
||||
|
||||
from events.models import Event as DSEvent, Organization, Promo, Scraper, Calendar
|
||||
|
||||
tz = pytz.timezone("US/Central")
|
||||
td = relativedelta.relativedelta(months=1)
|
||||
odt = datetime.now() + td
|
||||
|
||||
|
||||
def getScraper(venue):
|
||||
try:
|
||||
scraper, created = Scraper.objects.get_or_create(
|
||||
name=venue.name,
|
||||
website=venue.website,
|
||||
calendar = Calendar.objects.get(id=1),
|
||||
items = 0,
|
||||
new_items = 0,
|
||||
last_ran = datetime.now(),
|
||||
)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
scraper = Scraper.objects.get(name=venue.name)
|
||||
num_of_events = DSEvent.objects.filter(scraper=scraper)
|
||||
scraper.items = len(num_of_events)
|
||||
scraper.save()
|
||||
print("Scraper: ", scraper)
|
||||
pass
|
||||
return scraper, scraper.items
|
||||
|
||||
def updateScraper(scraper, item_count_start):
|
||||
num_of_events = DSEvent.objects.filter(scraper=scraper)
|
||||
scraper.items = len(num_of_events)
|
||||
scraper.new_items = len(num_of_events) - item_count_start
|
||||
scraper.last_ran = datetime.now()
|
||||
scraper.save()
|
||||
return
|
||||
|
||||
def getSource(browser, link):
|
||||
browser.get(link)
|
||||
sleep(5)
|
||||
ps = html.fromstring(browser.page_source)
|
||||
return ps
|
||||
|
||||
def getBrowser(run_env):
|
||||
if run_env == 'dev':
|
||||
print("Chrome is a go!")
|
||||
# chromeOptions = wd.ChromeOptions()
|
||||
# chromeOptions.binary_location = "/Application/Google\ Chrome.app"
|
||||
# chromeDriver = "/opt/homebrew/bin/chromedriver"
|
||||
# br = wd.Chrome(chromeDriver, options=chromeOptions)
|
||||
br = wd.Chrome()
|
||||
return br
|
||||
elif run_env == "def":
|
||||
print("Firefox go vroom")
|
||||
br = wd.Firefox()
|
||||
return br
|
||||
elif run_env == "prod":
|
||||
start_cmd = "Xvfb :91 && export DISPLAY=:91 &"
|
||||
xvfb = Xvfb()
|
||||
os.system(start_cmd)
|
||||
xvfb.start()
|
||||
print("started Xvfb")
|
||||
br = wd.Firefox()
|
||||
return br
|
||||
else:
|
||||
print("Failed", sys.argv, arg1)
|
||||
quit()
|
||||
|
||||
def createBasicURL(site_url):
|
||||
month = datetime.now().month
|
||||
next_month = odt.month
|
||||
year = datetime.now().year
|
||||
links = [
|
||||
site_url + str(month) + "/" + str(year),
|
||||
site_url + str(next_month) + "/" + str(year)
|
||||
]
|
||||
return links
|
||||
|
||||
def createURLNoZero(site_url):
|
||||
month = datetime.now().month
|
||||
next_month = odt.month
|
||||
year = datetime.now().year
|
||||
links = [
|
||||
site_url + str(year) + "/" + str(month),
|
||||
]
|
||||
if next_month == "1":
|
||||
links.append(site_url + str(int(year)+1) + "/" + str(next_month))
|
||||
else:
|
||||
links.append(site_url + str(year) + "/" + str(next_month))
|
||||
return links
|
||||
|
||||
def createURL(site_url):
|
||||
month = datetime.now().month
|
||||
if month < 10:
|
||||
month = "0" + str(month)
|
||||
else:
|
||||
month = str(month)
|
||||
next_month = odt.month
|
||||
if next_month < 10:
|
||||
next_month = "0" + str(next_month)
|
||||
else:
|
||||
next_month = str(next_month)
|
||||
year = datetime.now().year
|
||||
links = [
|
||||
site_url + str(year) + "/" + month,
|
||||
]
|
||||
if next_month == "01":
|
||||
links.append(site_url + str(int(year)+1) + "/" + next_month)
|
||||
else:
|
||||
links.append(site_url + str(year) + "/" + next_month)
|
||||
return links
|
||||
|
||||
def createDashURL(site_url):
|
||||
month = datetime.now().month
|
||||
if month < 10:
|
||||
month = "0" + str(month)
|
||||
else:
|
||||
month = str(month)
|
||||
next_month = odt.month
|
||||
if next_month < 10:
|
||||
next_month = "0" + str(next_month)
|
||||
else:
|
||||
next_month = str(next_month)
|
||||
year = datetime.now().year
|
||||
links = [
|
||||
site_url + month + "-" + str(year),
|
||||
site_url + next_month + "-" + str(year)
|
||||
]
|
||||
print(links)
|
||||
return links
|
||||
|
||||
def createBasicEvent(event, event_type, venue):
|
||||
new_event, created = DSEvent.objects.update_or_create(
|
||||
event_type = event_type,
|
||||
show_title = event['title'],
|
||||
show_link = event['link'],
|
||||
show_date = event['dateStamp'],
|
||||
show_day = event['dateStamp'],
|
||||
calendar = event['calendar'],
|
||||
scraper = event['scraper'],
|
||||
venue = venue
|
||||
)
|
||||
return new_event, created
|
||||
|
||||
def createBasiciCalEvent(event, event_type, venue):
|
||||
print("starting create")
|
||||
ppr(event)
|
||||
new_event, created = DSEvent.objects.update_or_create(
|
||||
event_type = event_type,
|
||||
show_title = event['title'][0],
|
||||
show_link = event['link'],
|
||||
show_date = datetime.strptime(str(event['dateStamp'][0]), '%Y-%m-%d %H:%M:%S'),
|
||||
show_day = datetime.strptime(str(event['dateStamp'][0]), '%Y-%m-%d %H:%M:%S'),
|
||||
calendar = event['calendar'],
|
||||
scraper = event['scraper'],
|
||||
venue = venue
|
||||
)
|
||||
print("created")
|
||||
return new_event, created
|
||||
|
||||
def createDetailedEvent(event, event_type, venue, scraper):
|
||||
new_event, created = DSEvent.objects.update_or_create(
|
||||
event_type = event_type,
|
||||
show_title = event["show_title"],
|
||||
show_link = event["link"],
|
||||
show_date = event["dateStamp"],
|
||||
show_day = event["dateStamp"],
|
||||
guests = " ".join(event["guests"]),
|
||||
more_details = event["details"],
|
||||
calendar = event['calendar'],
|
||||
scraper = event['scraper'],
|
||||
venue = venue
|
||||
)
|
||||
return new_event, created
|
||||
|
||||
def createBasicArticle(article, event_type, organization):
|
||||
new_article, created = Promo.objects.update_or_create(
|
||||
promo_type = 'Ja',
|
||||
title = article['title'],
|
||||
target_link = article['link'],
|
||||
published = True,
|
||||
organization = organization
|
||||
)
|
||||
return new_article, created
|
||||
|
||||
def getiCalEvents(gcal, scraper):
|
||||
for component in gcal.walk():
|
||||
event = {}
|
||||
event['scraper'] = scraper
|
||||
event['calendar'] = scraper.calendar
|
||||
event['strSummary'] = f"{(component.get('SUMMARY'))}"
|
||||
event['strDesc'] = component.get('DESCRIPTION')
|
||||
event['strLocation'] = component.get('LOCATION')
|
||||
event['dateStart'] = component.get('DTSTART')
|
||||
event['dateStamp'] = component.get('DTSTAMP')
|
||||
if event['dateStamp'] is not None:
|
||||
event['dateStamp'] = event['dateStamp'].dt
|
||||
if event['dateStart'] is not None:
|
||||
try:
|
||||
event['dateStart'] = event['dateStart'].dt
|
||||
except Exception as e:
|
||||
event['dateStart'] = event['dateStart'].dt
|
||||
|
||||
event['dateEnd'] = (component.get('DTEND'))
|
||||
if event['dateEnd'] is not None:
|
||||
event['dateEnd'] = event['dateEnd'].dt
|
||||
else:
|
||||
event['dateEnd'] = event['dateStart']
|
||||
if event['strSummary'] != 'None':
|
||||
event['details'] = {
|
||||
"description" : event['strDesc'],
|
||||
"Location" : event['strLocation'],
|
||||
}
|
||||
now_now = datetime.today().date()
|
||||
try:
|
||||
print("1Event: ", event['dateStart'])
|
||||
if event['dateStart'] > now_now:
|
||||
new_date = event['dateStart']-td
|
||||
new_event = {}
|
||||
new_event['scraper'] = scraper
|
||||
new_event['calendar'] = scraper.calendar
|
||||
new_event['title'] = event['strSummary'],
|
||||
new_event['date'] = str(new_date),
|
||||
new_event['dateStamp'] = str(new_date),
|
||||
new_event['link'] = venue.website
|
||||
createBasiciCalEvent(new_event, "Mu", venue)
|
||||
except Exception as e:
|
||||
try:
|
||||
event['dateStart'] = event['dateStart'].date()
|
||||
print("1Event: ", event['dateStart'])
|
||||
if event['dateStart'] > now_now:
|
||||
new_date = event['dateStart']-td
|
||||
print("The new Date: ", new_date, type(new_date))
|
||||
new_event = {}
|
||||
new_event['scraper'] = scraper
|
||||
new_event['calendar'] = scraper.calendar
|
||||
new_event['title'] = event['strSummary'],
|
||||
new_event['date'] = new_date,
|
||||
new_event['dateStamp'] = new_date,
|
||||
new_event['link'] = venue.website
|
||||
createBasiciCalEvent(new_event, "Mu", venue)
|
||||
except Exception as e:
|
||||
print("The Error: ", e)
|
||||
pass
|
||||
1118
events/fixtures/organizations.json
Normal file
1118
events/fixtures/organizations.json
Normal file
File diff suppressed because it is too large
Load Diff
452
events/fixtures/promo.2.json
Normal file
452
events/fixtures/promo.2.json
Normal file
@@ -0,0 +1,452 @@
|
||||
[
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 1,
|
||||
"fields": {
|
||||
"title": "DreamFreely",
|
||||
"organization": 1,
|
||||
"promo_type": "Jo",
|
||||
"overlay_image": "promo/SOL_Sign.png",
|
||||
"short_text": "And intro to the operation.",
|
||||
"long_text": "<p>Alright, I guess this is it. This is the game, these are the plays.</p>\r\n\r\n<p>Lots of work, for sure; but it's a blessing to help people. Now to continue to expand the support and stability.</p>",
|
||||
"target_link": "https://www.dreamfreely.org",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"title": "Comuna Andina",
|
||||
"organization": 1,
|
||||
"promo_type": "Fo",
|
||||
"overlay_image": "promo/pa_cover.jpg",
|
||||
"short_text": "Authentic products from the Andes Mountains and surrounding regions, mochilas, cafe y panella.",
|
||||
"long_text": "<p>These are all products from my travels.</p>\r\n<p>From hand-woven mochilas, to organic mountain farmed coffee and panela and more.</p>\r\n<p>All of these products are direct from the producer, while nearly all proceeds are also returned to the producer.</p>",
|
||||
"target_link": "https://www.comunandina.com",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 3,
|
||||
"fields": {
|
||||
"title": "idioke",
|
||||
"organization": 1,
|
||||
"promo_type": "Ev",
|
||||
"overlay_image": "promo/soltoken.png",
|
||||
"short_text": "We're starting with English, but soon you will be able to practice Spanish as well.",
|
||||
"long_text": "We're starting with English, but soon you will be able to practice Spanish as well.We're starting with English, but soon you will be able to practice Spanish as well.We're starting with English, but soon you will be able to practice Spanish as well.",
|
||||
"target_link": "https://www.idioke.com",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 4,
|
||||
"fields": {
|
||||
"title": "Manifesting Empathy",
|
||||
"organization": 1,
|
||||
"promo_type": "Fo",
|
||||
"overlay_image": "promo/manifestingempathy.png",
|
||||
"short_text": "Help humans find their roots.",
|
||||
"long_text": "Help humans find their roots.",
|
||||
"target_link": "https://www.manifestingempathy.com",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 5,
|
||||
"fields": {
|
||||
"title": "DigiSnaxx LIVE!",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "promo/cover.png",
|
||||
"short_text": "@ the Acadia. Every Monday. 4pm.",
|
||||
"long_text": "This is a brave space to converse, relax, listen to music and begin to navigate a path forward.<br/><br/>This is going to be a process.",
|
||||
"target_link": "https://canin.dreamfreely.org/digisnaxx/",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 6,
|
||||
"fields": {
|
||||
"title": "AI & the Last Question",
|
||||
"organization": 1,
|
||||
"promo_type": "Fo",
|
||||
"overlay_image": "promo/cover.png",
|
||||
"short_text": "A short story by Isaac Asimov",
|
||||
"long_text": "A short story by Isaac AsimovA short story by Isaac AsimovA short story by Isaac Asimov",
|
||||
"target_link": "https://canin.dreamfreely.org/the-last-question/",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 7,
|
||||
"fields": {
|
||||
"title": "idioke",
|
||||
"organization": 1,
|
||||
"promo_type": "Ev",
|
||||
"overlay_image": "promo/soltoken.png",
|
||||
"short_text": "We're starting with English, but soon you will be able to practice Spanish as well.",
|
||||
"long_text": "We're starting with English, but soon you will be able to practice Spanish as well.We're starting with English, but soon you will be able to practice Spanish as well.We're starting with English, but soon you will be able to practice Spanish as well.",
|
||||
"target_link": "https://www.idioke.com",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 8,
|
||||
"fields": {
|
||||
"title": "AI & the Last Question",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "promo/cover.png",
|
||||
"short_text": "A short story by Isaac Asimov",
|
||||
"long_text": "A short story by Isaac AsimovA short story by Isaac AsimovA short story by Isaac Asimov",
|
||||
"target_link": "https://canin.dreamfreely.org/the-last-question/",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 9,
|
||||
"fields": {
|
||||
"title": "Comuna Andina",
|
||||
"organization": 1,
|
||||
"promo_type": "Ev",
|
||||
"overlay_image": "promo/pa_cover.jpg",
|
||||
"short_text": "Authentic products from the Andes Mountains and surrounding regions, mochilas, cafe y panella.",
|
||||
"long_text": "<p>These are all products from my travels.</p>\r\n<p>From hand-woven mochilas, to organic mountain farmed coffee and panela and more.</p>\r\n<p>All of these products are direct from the producer, while nearly all proceeds are also returned to the producer.</p>",
|
||||
"target_link": "https://www.comunandina.com",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 10,
|
||||
"fields": {
|
||||
"title": "DreamFreely",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "promo/SOL_Sign.png",
|
||||
"short_text": "And intro to the operation.",
|
||||
"long_text": "<p>Alright, I guess this is it. This is the game, these are the plays.</p>\r\n\r\n<p>Lots of work, for sure; but it's a blessing to help people. Now to continue to expand the support and stability.</p>",
|
||||
"target_link": "https://www.dreamfreely.org",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 11,
|
||||
"fields": {
|
||||
"title": "Manifesting Empathy",
|
||||
"organization": 1,
|
||||
"promo_type": "Ev",
|
||||
"overlay_image": "promo/manifestingempathy.png",
|
||||
"short_text": "Help humans find their roots.",
|
||||
"long_text": "Help humans find their roots.",
|
||||
"target_link": "https://www.manifestingempathy.com",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 12,
|
||||
"fields": {
|
||||
"title": "DigiSnaxx & the DBC",
|
||||
"organization": 1,
|
||||
"promo_type": "Ev",
|
||||
"overlay_image": "promo/cover.png",
|
||||
"short_text": "More info about the project DigiSnaxx.",
|
||||
"long_text": "<p>After seeing the City Pages fall down the drain, followed by the dissolution of the MetroIBA.</p>\r\n<p>Anywho, it's time for something different, and that's what DigiSnaxx and DreamFreely is all about.</p>\r\n<p>DigiSnaxx is not trying to replace either of the aforementioned entities; we are rather looking to be an evolution, of sorts.</p>\r\n</p>We're not trying to be everything either ...</p>\r\n<p>We're trying to be an accessible, community-centered, directory.</p>",
|
||||
"target_link": "https://canin.dreamfreely.org/digisnaxx/",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 13,
|
||||
"fields": {
|
||||
"title": "Complimentary Street Harrassment",
|
||||
"organization": 1,
|
||||
"promo_type": "An",
|
||||
"overlay_image": "",
|
||||
"short_text": "It's cultural right?",
|
||||
"long_text": "I learn about the creation of gender in public space through the lens of a PhD student studying pidopo's, in Colombia.\r\n\r\n<iframe style='border-radius:12px' src='https://open.spotify.com/embed/episode/4V3V9lAS4FRz7apdfj1qsV?utm_source=generator' width='100%' height='352' frameBorder='0' allowfullscreen='' allow='autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture' loading='lazy'></iframe>",
|
||||
"target_link": "https://creators.spotify.com/pod/show/digisnaxx/episodes/Complimentary-Street-Harassment-et9h5d",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 14,
|
||||
"fields": {
|
||||
"title": "DigiSnaxx & the DBC",
|
||||
"organization": 1,
|
||||
"promo_type": "Fo",
|
||||
"overlay_image": "promo/cover.png",
|
||||
"short_text": "More info about the project DigiSnaxx.",
|
||||
"long_text": "<p>After seeing the City Pages fall down the drain, followed by the dissolution of the MetroIBA.</p>\r\n<p>Anywho, it's time for something different, and that's what DigiSnaxx and DreamFreely is all about.</p>\r\n<p>DigiSnaxx is not trying to replace either of the aforementioned entities; we are rather looking to be an evolution, of sorts.</p>\r\n</p>We're not trying to be everything either ...</p>\r\n<p>We're trying to be an accessible, community-centered, directory.</p>",
|
||||
"target_link": "https://canin.dreamfreely.org/digisnaxx/",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 15,
|
||||
"fields": {
|
||||
"title": "DreamFreely Library",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "",
|
||||
"short_text": "It's like having an open notebook ...",
|
||||
"long_text": "It's a work in progress, but you get the idea; and there's still some useful information.",
|
||||
"target_link": "https://library.dreamfreely.org",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 16,
|
||||
"fields": {
|
||||
"title": "Talkin' w/ DiViNCi",
|
||||
"organization": 1,
|
||||
"promo_type": "Fo",
|
||||
"overlay_image": "promo/soltoken.png",
|
||||
"short_text": "Canin converses with DiViNCi.",
|
||||
"long_text": "We met a great many number of years ago; before the hills were hills and the trees mere saplings. Haha ... I dunno, but it was definitely a fun conversation.\r\n\r\n<iframe style='border-radius:12px' src='https://open.spotify.com/embed/episode/2gdzy6TjXd3QEj8WRSeZSD?utm_source=generator' width='100%' height='352' frameBorder='0' allowfullscreen='' allow='autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture' loading='lazy'></iframe>",
|
||||
"target_link": "https://creators.spotify.com/pod/show/digisnaxx/episodes/DiViNCi-egm90v",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 17,
|
||||
"fields": {
|
||||
"title": "Mpls Stp Mag Calendar",
|
||||
"organization": 1,
|
||||
"promo_type": "Ev",
|
||||
"overlay_image": "",
|
||||
"short_text": "They got a great list of events.",
|
||||
"long_text": "They've got a great collection of events; we just don't have the time/resources to parse them all at present; and so pass the link directly on to you.",
|
||||
"target_link": "https://calendar.mspmag.com/calendars/all-events",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 19,
|
||||
"fields": {
|
||||
"title": "Academia Nuts",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "promo/SOL_Sign.png",
|
||||
"short_text": "Abstacts coming soon; gotta catch 'em all.",
|
||||
"long_text": "I've always wanted to make academia more accessible, so here's my go at that!\r\n\r\n<iframe class='airtable-embed' src='https://airtable.com/embed/appzQxsifc8AnD1zA/shr3SATN1OTsY47it' frameborder='0' onmousewheel='' width='100%' height='533' style='background: transparent; border: 1px solid #ccc;'></iframe>",
|
||||
"target_link": "https://www.academianuts.net",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 20,
|
||||
"fields": {
|
||||
"title": "Talkin' w/ DiViNCi",
|
||||
"organization": 1,
|
||||
"promo_type": "Fo",
|
||||
"overlay_image": "promo/soltoken.png",
|
||||
"short_text": "Canin converses with DiViNCi.",
|
||||
"long_text": "We met a great many number of years ago; before the hills were hills and the trees mere saplings. Haha ... I dunno, but it was definitely a fun conversation.\r\n\r\n<iframe style='border-radius:12px' src='https://open.spotify.com/embed/episode/2gdzy6TjXd3QEj8WRSeZSD?utm_source=generator' width='100%' height='352' frameBorder='0' allowfullscreen='' allow='autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture' loading='lazy'></iframe>",
|
||||
"target_link": "https://creators.spotify.com/pod/show/digisnaxx/episodes/DiViNCi-egm90v",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 21,
|
||||
"fields": {
|
||||
"title": "Rebel Coding",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "",
|
||||
"short_text": "Enough knowledge to be dangerous.",
|
||||
"long_text": "<p>Just covering the basics, we'll be hosting webinars.</p>\r\n<p>HTML, CSS, JavaScript & Python.</p>",
|
||||
"target_link": "https://www.rebelcoding.com",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 22,
|
||||
"fields": {
|
||||
"title": "Add a Calendar",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "",
|
||||
"short_text": "Got a calendar for us?",
|
||||
"long_text": "<iframe class='airtable-embed' src='https://airtable.com/embed/appzQxsifc8AnD1zA/shrfUvOiFdaHI8xoz' frameborder='0' onmousewheel='' width='100%'' height='533' style='background: transparent; border: 1px solid #ccc;'></iframe>",
|
||||
"target_link": "",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 23,
|
||||
"fields": {
|
||||
"title": "Add a Calendar",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "",
|
||||
"short_text": "Got a calendar for us?",
|
||||
"long_text": "<iframe class='airtable-embed' src='https://airtable.com/embed/appzQxsifc8AnD1zA/shrfUvOiFdaHI8xoz' frameborder='0' onmousewheel='' width='100%'' height='533' style='background: transparent; border: 1px solid #ccc;'></iframe>",
|
||||
"target_link": "",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 24,
|
||||
"fields": {
|
||||
"title": "Academia Nuts",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "promo/SOL_Sign.png",
|
||||
"short_text": "Abstacts coming soon; gotta catch 'em all.",
|
||||
"long_text": "I've always wanted to make academia more accessible, so here's my go at that!\r\n\r\n<iframe class='airtable-embed' src='https://airtable.com/embed/appzQxsifc8AnD1zA/shr3SATN1OTsY47it' frameborder='0' onmousewheel='' width='100%' height='533' style='background: transparent; border: 1px solid #ccc;'></iframe>",
|
||||
"target_link": "https://www.academianuts.net",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 25,
|
||||
"fields": {
|
||||
"title": "Rebel Coding",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "",
|
||||
"short_text": "Enough knowledge to be dangerous.",
|
||||
"long_text": "<p>Just covering the basics, we'll be hosting webinars.</p>\r\n<p>HTML, CSS, JavaScript & Python.</p>",
|
||||
"target_link": "https://www.rebelcoding.com",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 26,
|
||||
"fields": {
|
||||
"title": "Comuna Andina",
|
||||
"organization": 1,
|
||||
"promo_type": "Fo",
|
||||
"overlay_image": "promo/pa_cover.jpg",
|
||||
"short_text": "Authentic products from the Andes Mountains and surrounding regions, mochilas, cafe y panella.",
|
||||
"long_text": "<p>These are all products from my travels.</p>\r\n<p>From hand-woven mochilas, to organic mountain farmed coffee and panela and more.</p>\r\n<p>All of these products are direct from the producer, while nearly all proceeds are also returned to the producer.</p>",
|
||||
"target_link": "https://www.comunandina.com",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 27,
|
||||
"fields": {
|
||||
"title": "Add a Calendar",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "",
|
||||
"short_text": "Got a calendar for us?",
|
||||
"long_text": "<iframe class='airtable-embed' src='https://airtable.com/embed/appzQxsifc8AnD1zA/shrfUvOiFdaHI8xoz' frameborder='0' onmousewheel='' width='100%'' height='533' style='background: transparent; border: 1px solid #ccc;'></iframe>",
|
||||
"target_link": "",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 28,
|
||||
"fields": {
|
||||
"title": "Complimentary Street Harrassment",
|
||||
"organization": 1,
|
||||
"promo_type": "An",
|
||||
"overlay_image": "",
|
||||
"short_text": "It's cultural right?",
|
||||
"long_text": "I learn about the creation of gender in public space through the lens of a PhD student studying pidopo's, in Colombia.\r\n\r\n<iframe style='border-radius:12px' src='https://open.spotify.com/embed/episode/4V3V9lAS4FRz7apdfj1qsV?utm_source=generator' width='100%' height='352' frameBorder='0' allowfullscreen='' allow='autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture' loading='lazy'></iframe>",
|
||||
"target_link": "https://creators.spotify.com/pod/show/digisnaxx/episodes/Complimentary-Street-Harassment-et9h5d",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 29,
|
||||
"fields": {
|
||||
"title": "Saint Wich Burgers",
|
||||
"organization": 1,
|
||||
"promo_type": "Fo",
|
||||
"overlay_image": "promo/soltoken.png",
|
||||
"short_text": "Serving handcrafted gourmet burgers made with love.",
|
||||
"long_text": "Welcome to Saint Wich Burgers, located on Selby Avenue in Saint Paul, Minnesota, where our love for food and dedication to quality come together in every burger we serve. We don’t believe in shortcuts. Our burgers are made from scratch with premium ingredients, served fresh, and customized to suit your unique tastes.\r\n<br/><br/>\r\nFrom our hand-crafted patties to our delicious signature sauces, everything is designed to make each bite something special. Whether you like your burger simple or stacked with all the toppings, we offer a variety of options to satisfy every craving.\r\n<br/><br/>\r\nCome see what makes us different. At Saint Wich Burgers, it's all about great burgers, good times, and lasting memories.\r\n<br/><br/>\r\nWhether you're in the mood for a simple, classic burger or a sandwich with sides, we’ve got you covered. Enjoy the perfect meal in our inviting space, where you can savor your burger and enjoy time with family and friends.\r\n<br/><br/>\r\nOur atmosphere is laid-back, our service is friendly, and our burgers are unforgettable. Stop by today and taste what makes us different!",
|
||||
"target_link": "https://www.stwichburgers.com/",
|
||||
"notes": "",
|
||||
"published": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 30,
|
||||
"fields": {
|
||||
"title": "Arepas, Las de Queso",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "promo/SOL_Sign.png",
|
||||
"short_text": "If you're lookin' for the tastiest arepa in Medellin.",
|
||||
"long_text": "For those who may travel, check out my friends :)",
|
||||
"target_link": "https://www.dreamfreely.org",
|
||||
"notes": "",
|
||||
"published": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 31,
|
||||
"fields": {
|
||||
"title": "Vigs Guitars",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "promo/VigGuitarsLogo.sm.jpg",
|
||||
"short_text": "A luthier-owned music shop.",
|
||||
"long_text": "<b>“The Player’s Store”</b>\r\n<br/><br/>\r\nWe are an independent, full service, luthier-owned shop serving the working musicians in the Minneapolis/St. Paul metro area since September 2014. Ted Vig’s expert repair is the cornerstone of our business. We specialize in repair and customization, and carry a variety of guitars, basses, mandolins, ukuleles, and accessories.\r\n<br/><br/>\r\nWith EXPERT repair, a large stock of parts and interesting, unique and fun instruments, both new and used, you won’t be afraid to come in here, and it’s a big part of the reason that we’ve been coined as “The Players Store.”\r\n<br/><br/>\r\nTed Vig has been working full time and building his audience through music stores since 1988. He has a long list of devoted repair clients…this just doesn’t happen overnight! His Custom Vig Handwound Pickups are flying out the door! *SATURDAYS ARE THE BEST DAYS TO COME IN AND TALK TO TED ABOUT THE PICKUPS*\r\n<br/><br/>\r\nThis store is Indigenous Female Owned and run by local musicians who SUPPORT local musicians! We have ample street parking in front of the shop and a big parking lot.\r\n<br/><br/>\r\nWinner of “Star Tribune’s Readers Choice Best of”\r\nBest Music Instrument Shop\r\n<br/><br/>\r\n2021 – SILVER! 2023 – SILVER!\r\n<br/>\r\n2022 – GOLD 2024 GOLD!!!!",
|
||||
"target_link": "https://vigguitarshop.com/",
|
||||
"notes": "",
|
||||
"published": false
|
||||
}
|
||||
}
|
||||
]
|
||||
452
events/fixtures/promo.json
Normal file
452
events/fixtures/promo.json
Normal file
@@ -0,0 +1,452 @@
|
||||
[
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 1,
|
||||
"fields": {
|
||||
"title": "DreamFreely",
|
||||
"organization": 1,
|
||||
"promo_type": "Jo",
|
||||
"overlay_image": "promo/SOL_Sign.png",
|
||||
"short_text": "And intro to the operation.",
|
||||
"long_text": "<p>Alright, I guess this is it. This is the game, these are the plays.</p>\r\n\r\n<p>Lots of work, for sure; but it's a blessing to help people. Now to continue to expand the support and stability.</p>",
|
||||
"target_link": "https://www.dreamfreely.org",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"title": "Comuna Andina",
|
||||
"organization": 1,
|
||||
"promo_type": "Fo",
|
||||
"overlay_image": "promo/pa_cover.jpg",
|
||||
"short_text": "Authentic products from the Andes Mountains and surrounding regions, mochilas, cafe y panella.",
|
||||
"long_text": "<p>These are all products from my travels.</p>\r\n<p>From hand-woven mochilas, to organic mountain farmed coffee and panela and more.</p>\r\n<p>All of these products are direct from the producer, while nearly all proceeds are also returned to the producer.</p>",
|
||||
"target_link": "https://www.comunandina.com",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 3,
|
||||
"fields": {
|
||||
"title": "idioke",
|
||||
"organization": 1,
|
||||
"promo_type": "Ev",
|
||||
"overlay_image": "promo/soltoken.png",
|
||||
"short_text": "We're starting with English, but soon you will be able to practice Spanish as well.",
|
||||
"long_text": "We're starting with English, but soon you will be able to practice Spanish as well.We're starting with English, but soon you will be able to practice Spanish as well.We're starting with English, but soon you will be able to practice Spanish as well.",
|
||||
"target_link": "https://www.idioke.com",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 4,
|
||||
"fields": {
|
||||
"title": "Manifesting Empathy",
|
||||
"organization": 1,
|
||||
"promo_type": "Fo",
|
||||
"overlay_image": "promo/manifestingempathy.png",
|
||||
"short_text": "Help humans find their roots.",
|
||||
"long_text": "Help humans find their roots.",
|
||||
"target_link": "https://www.manifestingempathy.com",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 5,
|
||||
"fields": {
|
||||
"title": "AI & the Last Question",
|
||||
"organization": 1,
|
||||
"promo_type": "Fo",
|
||||
"overlay_image": "promo/cover.png",
|
||||
"short_text": "A short story by Isaac Asimov",
|
||||
"long_text": "A short story by Isaac AsimovA short story by Isaac AsimovA short story by Isaac Asimov",
|
||||
"target_link": "https://canin.dreamfreely.org/the-last-question/",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 6,
|
||||
"fields": {
|
||||
"title": "AI & the Last Question",
|
||||
"organization": 1,
|
||||
"promo_type": "Fo",
|
||||
"overlay_image": "promo/cover.png",
|
||||
"short_text": "A short story by Isaac Asimov",
|
||||
"long_text": "A short story by Isaac AsimovA short story by Isaac AsimovA short story by Isaac Asimov",
|
||||
"target_link": "https://canin.dreamfreely.org/the-last-question/",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 7,
|
||||
"fields": {
|
||||
"title": "idioke",
|
||||
"organization": 1,
|
||||
"promo_type": "Ev",
|
||||
"overlay_image": "promo/soltoken.png",
|
||||
"short_text": "We're starting with English, but soon you will be able to practice Spanish as well.",
|
||||
"long_text": "We're starting with English, but soon you will be able to practice Spanish as well.We're starting with English, but soon you will be able to practice Spanish as well.We're starting with English, but soon you will be able to practice Spanish as well.",
|
||||
"target_link": "https://www.idioke.com",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 8,
|
||||
"fields": {
|
||||
"title": "AI & the Last Question",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "promo/cover.png",
|
||||
"short_text": "A short story by Isaac Asimov",
|
||||
"long_text": "A short story by Isaac AsimovA short story by Isaac AsimovA short story by Isaac Asimov",
|
||||
"target_link": "https://canin.dreamfreely.org/the-last-question/",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 9,
|
||||
"fields": {
|
||||
"title": "Comuna Andina",
|
||||
"organization": 1,
|
||||
"promo_type": "Ev",
|
||||
"overlay_image": "promo/pa_cover.jpg",
|
||||
"short_text": "Authentic products from the Andes Mountains and surrounding regions, mochilas, cafe y panella.",
|
||||
"long_text": "<p>These are all products from my travels.</p>\r\n<p>From hand-woven mochilas, to organic mountain farmed coffee and panela and more.</p>\r\n<p>All of these products are direct from the producer, while nearly all proceeds are also returned to the producer.</p>",
|
||||
"target_link": "https://www.comunandina.com",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 10,
|
||||
"fields": {
|
||||
"title": "DreamFreely",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "promo/SOL_Sign.png",
|
||||
"short_text": "And intro to the operation.",
|
||||
"long_text": "<p>Alright, I guess this is it. This is the game, these are the plays.</p>\r\n\r\n<p>Lots of work, for sure; but it's a blessing to help people. Now to continue to expand the support and stability.</p>",
|
||||
"target_link": "https://www.dreamfreely.org",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 11,
|
||||
"fields": {
|
||||
"title": "Manifesting Empathy",
|
||||
"organization": 1,
|
||||
"promo_type": "Ev",
|
||||
"overlay_image": "promo/manifestingempathy.png",
|
||||
"short_text": "Help humans find their roots.",
|
||||
"long_text": "Help humans find their roots.",
|
||||
"target_link": "https://www.manifestingempathy.com",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 12,
|
||||
"fields": {
|
||||
"title": "DigiSnaxx & the DBC",
|
||||
"organization": 1,
|
||||
"promo_type": "Ev",
|
||||
"overlay_image": "promo/cover.png",
|
||||
"short_text": "More info about the project DigiSnaxx.",
|
||||
"long_text": "<p>After seeing the City Pages fall down the drain, followed by the dissolution of the MetroIBA.</p>\r\n<p>Anywho, it's time for something different, and that's what DigiSnaxx and DreamFreely is all about.</p>\r\n<p>DigiSnaxx is not trying to replace either of the aforementioned entities; we are rather looking to be an evolution, of sorts.</p>\r\n</p>We're not trying to be everything either ...</p>\r\n<p>We're trying to be an accessible, community-centered, directory.</p>",
|
||||
"target_link": "https://canin.dreamfreely.org/digisnaxx/",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 13,
|
||||
"fields": {
|
||||
"title": "Complimentary Street Harrassment",
|
||||
"organization": 1,
|
||||
"promo_type": "An",
|
||||
"overlay_image": "",
|
||||
"short_text": "It's cultural right?",
|
||||
"long_text": "I learn about the creation of gender in public space through the lens of a PhD student studying pidopo's, in Colombia.\r\n\r\n<iframe style='border-radius:12px' src='https://open.spotify.com/embed/episode/4V3V9lAS4FRz7apdfj1qsV?utm_source=generator' width='100%' height='352' frameBorder='0' allowfullscreen='' allow='autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture' loading='lazy'></iframe>",
|
||||
"target_link": "https://creators.spotify.com/pod/show/digisnaxx/episodes/Complimentary-Street-Harassment-et9h5d",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 14,
|
||||
"fields": {
|
||||
"title": "DigiSnaxx & the DBC",
|
||||
"organization": 1,
|
||||
"promo_type": "Fo",
|
||||
"overlay_image": "promo/cover.png",
|
||||
"short_text": "More info about the project DigiSnaxx.",
|
||||
"long_text": "<p>After seeing the City Pages fall down the drain, followed by the dissolution of the MetroIBA.</p>\r\n<p>Anywho, it's time for something different, and that's what DigiSnaxx and DreamFreely is all about.</p>\r\n<p>DigiSnaxx is not trying to replace either of the aforementioned entities; we are rather looking to be an evolution, of sorts.</p>\r\n</p>We're not trying to be everything either ...</p>\r\n<p>We're trying to be an accessible, community-centered, directory.</p>",
|
||||
"target_link": "https://canin.dreamfreely.org/digisnaxx/",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 15,
|
||||
"fields": {
|
||||
"title": "DreamFreely Library",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "",
|
||||
"short_text": "It's like having an open notebook ...",
|
||||
"long_text": "It's a work in progress, but you get the idea; and there's still some useful information.",
|
||||
"target_link": "https://library.dreamfreely.org",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 16,
|
||||
"fields": {
|
||||
"title": "Talkin' w/ DiViNCi",
|
||||
"organization": 1,
|
||||
"promo_type": "Fo",
|
||||
"overlay_image": "promo/soltoken.png",
|
||||
"short_text": "Canin converses with DiViNCi.",
|
||||
"long_text": "We met a great many number of years ago; before the hills were hills and the trees mere saplings. Haha ... I dunno, but it was definitely a fun conversation.\r\n\r\n<iframe style='border-radius:12px' src='https://open.spotify.com/embed/episode/2gdzy6TjXd3QEj8WRSeZSD?utm_source=generator' width='100%' height='352' frameBorder='0' allowfullscreen='' allow='autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture' loading='lazy'></iframe>",
|
||||
"target_link": "https://creators.spotify.com/pod/show/digisnaxx/episodes/DiViNCi-egm90v",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 17,
|
||||
"fields": {
|
||||
"title": "Mpls Stp Mag Calendar",
|
||||
"organization": 1,
|
||||
"promo_type": "Ev",
|
||||
"overlay_image": "",
|
||||
"short_text": "They got a great list of events.",
|
||||
"long_text": "They've got a great collection of events; we just don't have the time/resources to parse them all at present; and so pass the link directly on to you.",
|
||||
"target_link": "https://calendar.mspmag.com/calendars/all-events",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 19,
|
||||
"fields": {
|
||||
"title": "Academia Nuts",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "promo/SOL_Sign.png",
|
||||
"short_text": "Abstacts coming soon; gotta catch 'em all.",
|
||||
"long_text": "I've always wanted to make academia more accessible, so here's my go at that!\r\n\r\n<iframe class='airtable-embed' src='https://airtable.com/embed/appzQxsifc8AnD1zA/shr3SATN1OTsY47it' frameborder='0' onmousewheel='' width='100%' height='533' style='background: transparent; border: 1px solid #ccc;'></iframe>",
|
||||
"target_link": "https://www.academianuts.net",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 20,
|
||||
"fields": {
|
||||
"title": "Talkin' w/ DiViNCi",
|
||||
"organization": 1,
|
||||
"promo_type": "Fo",
|
||||
"overlay_image": "promo/soltoken.png",
|
||||
"short_text": "Canin converses with DiViNCi.",
|
||||
"long_text": "We met a great many number of years ago; before the hills were hills and the trees mere saplings. Haha ... I dunno, but it was definitely a fun conversation.\r\n\r\n<iframe style='border-radius:12px' src='https://open.spotify.com/embed/episode/2gdzy6TjXd3QEj8WRSeZSD?utm_source=generator' width='100%' height='352' frameBorder='0' allowfullscreen='' allow='autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture' loading='lazy'></iframe>",
|
||||
"target_link": "https://creators.spotify.com/pod/show/digisnaxx/episodes/DiViNCi-egm90v",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 21,
|
||||
"fields": {
|
||||
"title": "Rebel Coding",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "",
|
||||
"short_text": "Enough knowledge to be dangerous.",
|
||||
"long_text": "<p>Just covering the basics, we'll be hosting webinars.</p>\r\n<p>HTML, CSS, JavaScript & Python.</p>",
|
||||
"target_link": "https://www.rebelcoding.com",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 22,
|
||||
"fields": {
|
||||
"title": "Add a Calendar",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "",
|
||||
"short_text": "Got a calendar for us?",
|
||||
"long_text": "<iframe class='airtable-embed' src='https://airtable.com/embed/appzQxsifc8AnD1zA/shrfUvOiFdaHI8xoz' frameborder='0' onmousewheel='' width='100%'' height='533' style='background: transparent; border: 1px solid #ccc;'></iframe>",
|
||||
"target_link": "",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 23,
|
||||
"fields": {
|
||||
"title": "Add a Calendar",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "",
|
||||
"short_text": "Got a calendar for us?",
|
||||
"long_text": "<iframe class='airtable-embed' src='https://airtable.com/embed/appzQxsifc8AnD1zA/shrfUvOiFdaHI8xoz' frameborder='0' onmousewheel='' width='100%'' height='533' style='background: transparent; border: 1px solid #ccc;'></iframe>",
|
||||
"target_link": "",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 24,
|
||||
"fields": {
|
||||
"title": "Academia Nuts",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "promo/SOL_Sign.png",
|
||||
"short_text": "Abstacts coming soon; gotta catch 'em all.",
|
||||
"long_text": "I've always wanted to make academia more accessible, so here's my go at that!\r\n\r\n<iframe class='airtable-embed' src='https://airtable.com/embed/appzQxsifc8AnD1zA/shr3SATN1OTsY47it' frameborder='0' onmousewheel='' width='100%' height='533' style='background: transparent; border: 1px solid #ccc;'></iframe>",
|
||||
"target_link": "https://www.academianuts.net",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 25,
|
||||
"fields": {
|
||||
"title": "Rebel Coding",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "",
|
||||
"short_text": "Enough knowledge to be dangerous.",
|
||||
"long_text": "<p>Just covering the basics, we'll be hosting webinars.</p>\r\n<p>HTML, CSS, JavaScript & Python.</p>",
|
||||
"target_link": "https://www.rebelcoding.com",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 26,
|
||||
"fields": {
|
||||
"title": "Comuna Andina",
|
||||
"organization": 1,
|
||||
"promo_type": "Fo",
|
||||
"overlay_image": "promo/pa_cover.jpg",
|
||||
"short_text": "Authentic products from the Andes Mountains and surrounding regions, mochilas, cafe y panella.",
|
||||
"long_text": "<p>These are all products from my travels.</p>\r\n<p>From hand-woven mochilas, to organic mountain farmed coffee and panela and more.</p>\r\n<p>All of these products are direct from the producer, while nearly all proceeds are also returned to the producer.</p>",
|
||||
"target_link": "https://www.comunandina.com",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 27,
|
||||
"fields": {
|
||||
"title": "Add a Calendar",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "",
|
||||
"short_text": "Got a calendar for us?",
|
||||
"long_text": "<iframe class='airtable-embed' src='https://airtable.com/embed/appzQxsifc8AnD1zA/shrfUvOiFdaHI8xoz' frameborder='0' onmousewheel='' width='100%'' height='533' style='background: transparent; border: 1px solid #ccc;'></iframe>",
|
||||
"target_link": "",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 28,
|
||||
"fields": {
|
||||
"title": "Complimentary Street Harrassment",
|
||||
"organization": 1,
|
||||
"promo_type": "An",
|
||||
"overlay_image": "",
|
||||
"short_text": "It's cultural right?",
|
||||
"long_text": "I learn about the creation of gender in public space through the lens of a PhD student studying pidopo's, in Colombia.\r\n\r\n<iframe style='border-radius:12px' src='https://open.spotify.com/embed/episode/4V3V9lAS4FRz7apdfj1qsV?utm_source=generator' width='100%' height='352' frameBorder='0' allowfullscreen='' allow='autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture' loading='lazy'></iframe>",
|
||||
"target_link": "https://creators.spotify.com/pod/show/digisnaxx/episodes/Complimentary-Street-Harassment-et9h5d",
|
||||
"notes": "",
|
||||
"published": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 29,
|
||||
"fields": {
|
||||
"title": "Saint Wich Burgers",
|
||||
"organization": 1,
|
||||
"promo_type": "Fo",
|
||||
"overlay_image": "promo/soltoken.png",
|
||||
"short_text": "Serving handcrafted gourmet burgers made with love.",
|
||||
"long_text": "Welcome to Saint Wich Burgers, located on Selby Avenue in Saint Paul, Minnesota, where our love for food and dedication to quality come together in every burger we serve. We don’t believe in shortcuts. Our burgers are made from scratch with premium ingredients, served fresh, and customized to suit your unique tastes.\r\n<br/><br/>\r\nFrom our hand-crafted patties to our delicious signature sauces, everything is designed to make each bite something special. Whether you like your burger simple or stacked with all the toppings, we offer a variety of options to satisfy every craving.\r\n<br/><br/>\r\nCome see what makes us different. At Saint Wich Burgers, it's all about great burgers, good times, and lasting memories.\r\n<br/><br/>\r\nWhether you're in the mood for a simple, classic burger or a sandwich with sides, we’ve got you covered. Enjoy the perfect meal in our inviting space, where you can savor your burger and enjoy time with family and friends.\r\n<br/><br/>\r\nOur atmosphere is laid-back, our service is friendly, and our burgers are unforgettable. Stop by today and taste what makes us different!",
|
||||
"target_link": "https://www.stwichburgers.com/",
|
||||
"notes": "",
|
||||
"published": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 30,
|
||||
"fields": {
|
||||
"title": "Arepas, Las de Queso",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "promo/SOL_Sign.png",
|
||||
"short_text": "If you're lookin' for the tastiest arepa in Medellin.",
|
||||
"long_text": "For those who may travel, check out my friends :)",
|
||||
"target_link": "https://www.dreamfreely.org",
|
||||
"notes": "",
|
||||
"published": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "events.promo",
|
||||
"pk": 31,
|
||||
"fields": {
|
||||
"title": "Vigs Guitars",
|
||||
"organization": 1,
|
||||
"promo_type": "Re",
|
||||
"overlay_image": "promo/VigGuitarsLogo.sm.jpg",
|
||||
"short_text": "A luthier-owned music shop.",
|
||||
"long_text": "<b>“The Player’s Store”</b>\r\n<br/><br/>\r\nWe are an independent, full service, luthier-owned shop serving the working musicians in the Minneapolis/St. Paul metro area since September 2014. Ted Vig’s expert repair is the cornerstone of our business. We specialize in repair and customization, and carry a variety of guitars, basses, mandolins, ukuleles, and accessories.\r\n<br/><br/>\r\nWith EXPERT repair, a large stock of parts and interesting, unique and fun instruments, both new and used, you won’t be afraid to come in here, and it’s a big part of the reason that we’ve been coined as “The Players Store.”\r\n<br/><br/>\r\nTed Vig has been working full time and building his audience through music stores since 1988. He has a long list of devoted repair clients…this just doesn’t happen overnight! His Custom Vig Handwound Pickups are flying out the door! *SATURDAYS ARE THE BEST DAYS TO COME IN AND TALK TO TED ABOUT THE PICKUPS*\r\n<br/><br/>\r\nThis store is Indigenous Female Owned and run by local musicians who SUPPORT local musicians! We have ample street parking in front of the shop and a big parking lot.\r\n<br/><br/>\r\nWinner of “Star Tribune’s Readers Choice Best of”\r\nBest Music Instrument Shop\r\n<br/><br/>\r\n2021 – SILVER! 2023 – SILVER!\r\n<br/>\r\n2022 – GOLD 2024 GOLD!!!!",
|
||||
"target_link": "https://vigguitarshop.com/",
|
||||
"notes": "",
|
||||
"published": false
|
||||
}
|
||||
}
|
||||
]
|
||||
1
events/fixtures/venues.json
Normal file
1
events/fixtures/venues.json
Normal file
@@ -0,0 +1 @@
|
||||
[{"model": "events.venue", "pk": 1, "fields": {"name": "Acme Comedy Club", "website": "https://acmecomedycompany.com/the-club/calendar/", "phone_number": null, "address": null, "city": "Minneapolis", "state": "Minnesota", "zip_code": null}}, {"model": "events.venue", "pk": 2, "fields": {"name": "Amsterdam Bar & Hall", "website": "https://www.amsterdambarandhall.com/events-new/", "phone_number": null, "address": null, "city": "St. Paul", "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 3, "fields": {"name": "Birchbark Books", "website": "https://birchbarkbooks.com/pages/events", "phone_number": null, "address": null, "city": "Minneapolis", "state": "Minnesota", "zip_code": null}}, {"model": "events.venue", "pk": 4, "fields": {"name": "Cedar Cultural Center", "website": "https://www.thecedar.org/listing", "phone_number": null, "address": null, "city": "Minneapolis", "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 5, "fields": {"name": "331 Club", "website": null, "phone_number": null, "address": null, "city": null, "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 6, "fields": {"name": "Comedy Corner", "website": "https://comedycornerunderground.com/calendar", "phone_number": null, "address": null, "city": "Minneapolis", "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 7, "fields": {"name": "Eastside Freedom Library", "website": "https://eastsidefreedomlibrary.org/events/", "phone_number": null, "address": null, "city": "Minneapolis", "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 30, "fields": {"name": "7th St Entry", "website": null, "phone_number": null, "address": null, "city": null, "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 34, "fields": {"name": "Fine Line", "website": null, "phone_number": null, "address": null, "city": null, "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 35, "fields": {"name": "The Fitzgerald Theater", "website": null, "phone_number": null, "address": null, "city": null, "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 36, "fields": {"name": "Turf Club", "website": null, "phone_number": null, "address": null, "city": null, "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 37, "fields": {"name": "Palace Theatre", "website": null, "phone_number": null, "address": null, "city": null, "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 38, "fields": {"name": "First Avenue", "website": null, "phone_number": null, "address": null, "city": null, "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 39, "fields": {"name": "The Cedar Cultural Center", "website": null, "phone_number": null, "address": null, "city": null, "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 40, "fields": {"name": "Pantages Theatre", "website": null, "phone_number": null, "address": null, "city": null, "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 41, "fields": {"name": "Xcel Energy Center", "website": null, "phone_number": null, "address": null, "city": null, "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 42, "fields": {"name": "State Theatre", "website": null, "phone_number": null, "address": null, "city": null, "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 43, "fields": {"name": "Hook & Ladder", "website": null, "phone_number": null, "address": null, "city": null, "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 44, "fields": {"name": "Magers & Quinn", "website": "https://www.magersandquinn.com/events", "phone_number": null, "address": null, "city": "Minneapolis", "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 45, "fields": {"name": "Uptown VFW", "website": null, "phone_number": null, "address": null, "city": "Minneapolis", "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 46, "fields": {"name": "Palmer's Bar", "website": "https://palmers-bar.com", "phone_number": null, "address": null, "city": "Minneapolis", "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 47, "fields": {"name": "Parkway Theater", "website": "https://theparkwaytheater.com", "phone_number": null, "address": null, "city": "Minneapolis", "state": null, "zip_code": null}}, {"model": "events.venue", "pk": 48, "fields": {"name": "White Squirrel", "website": "https://whitesquirrelbar.com", "phone_number": null, "address": null, "city": "St. Paul", "state": null, "zip_code": null}}]
|
||||
42
events/migrations/0001_initial.py
Normal file
42
events/migrations/0001_initial.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# Generated by Django 4.1.7 on 2023-02-28 16:07
|
||||
|
||||
import django.core.files.storage
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Venue',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=64)),
|
||||
('website', models.CharField(max_length=128)),
|
||||
('phone_number', models.CharField(max_length=200)),
|
||||
('address', models.CharField(max_length=64)),
|
||||
('city', models.CharField(max_length=32)),
|
||||
('state', models.CharField(max_length=16)),
|
||||
('zip_code', models.CharField(max_length=16)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Event',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('show_title', models.CharField(max_length=128)),
|
||||
('show_link', models.URLField()),
|
||||
('guests', models.CharField(max_length=256)),
|
||||
('show_date', models.DateTimeField()),
|
||||
('flyer_img', models.ImageField(upload_to=django.core.files.storage.FileSystemStorage(location='/media/flyers'))),
|
||||
('more_details', models.JSONField()),
|
||||
('venue', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.venue')),
|
||||
],
|
||||
),
|
||||
]
|
||||
19
events/migrations/0002_event_event_type.py
Normal file
19
events/migrations/0002_event_event_type.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.1.7 on 2023-03-01 07:10
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='event',
|
||||
name='event_type',
|
||||
field=models.CharField(default='Mu', max_length=128),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,82 @@
|
||||
# Generated by Django 4.1.7 on 2023-03-01 08:13
|
||||
|
||||
import django.core.files.storage
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0002_event_event_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='event',
|
||||
options={'ordering': ['show_title'], 'verbose_name_plural': 'Events'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='venue',
|
||||
options={'ordering': ['name'], 'verbose_name_plural': 'Venues'},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='event_type',
|
||||
field=models.CharField(choices=[('Mu', 'Music'), ('Va', 'Visual Art'), ('Gv', 'Government'), ('Ce', 'Civic Engagement'), ('Ed', 'Educational')], default='0', max_length=16),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='flyer_img',
|
||||
field=models.ImageField(blank=True, null=True, upload_to=django.core.files.storage.FileSystemStorage(location='/media/flyers')),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='guests',
|
||||
field=models.CharField(blank=True, max_length=256, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='more_details',
|
||||
field=models.JSONField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='show_link',
|
||||
field=models.URLField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='show_title',
|
||||
field=models.CharField(blank=True, max_length=128, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='venue',
|
||||
name='address',
|
||||
field=models.CharField(blank=True, max_length=64, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='venue',
|
||||
name='city',
|
||||
field=models.CharField(blank=True, max_length=32, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='venue',
|
||||
name='phone_number',
|
||||
field=models.CharField(blank=True, max_length=200, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='venue',
|
||||
name='state',
|
||||
field=models.CharField(blank=True, max_length=16, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='venue',
|
||||
name='website',
|
||||
field=models.CharField(blank=True, max_length=128, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='venue',
|
||||
name='zip_code',
|
||||
field=models.CharField(blank=True, max_length=16, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,27 @@
|
||||
# Generated by Django 4.1.7 on 2023-03-06 01:45
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0003_alter_event_options_alter_venue_options_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='event',
|
||||
options={'ordering': ['show_date', 'show_title'], 'verbose_name_plural': 'Events'},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='event',
|
||||
name='show_day',
|
||||
field=models.DateField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='event_type',
|
||||
field=models.CharField(choices=[('Mu', 'Music'), ('Va', 'Visual Art'), ('Gv', 'Government'), ('Ce', 'Civic Engagement'), ('Ed', 'Educational'), ('Co', 'Comedy'), ('Ma', 'Mutual Aid')], default='0', max_length=16),
|
||||
),
|
||||
]
|
||||
18
events/migrations/0005_event_img_link.py
Normal file
18
events/migrations/0005_event_img_link.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.1.7 on 2023-03-23 03:50
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0004_alter_event_options_event_show_day_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='event',
|
||||
name='img_link',
|
||||
field=models.CharField(blank=True, max_length=256, null=True),
|
||||
),
|
||||
]
|
||||
18
events/migrations/0006_alter_event_event_type.py
Normal file
18
events/migrations/0006_alter_event_event_type.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.1.7 on 2023-03-25 13:43
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0005_event_img_link'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='event_type',
|
||||
field=models.CharField(choices=[('Mu', 'Music'), ('Va', 'Visual Art'), ('Gv', 'Government'), ('Ce', 'Civic Engagement'), ('Ed', 'Educational'), ('Co', 'Comedy'), ('Ma', 'Mutual Aid'), ('Th', 'Theater')], default='0', max_length=16),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,39 @@
|
||||
# Generated by Django 4.1.7 on 2023-05-07 21:41
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('events', '0006_alter_event_event_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='event_type',
|
||||
field=models.CharField(choices=[('Mu', 'Music'), ('Ot', 'Other'), ('Va', 'Visual Art'), ('Gv', 'Government'), ('Ce', 'Civic Engagement'), ('Ed', 'Educational'), ('Co', 'Comedy'), ('Ma', 'Mutual Aid'), ('Th', 'Theater')], default='0', max_length=16),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserThrottle',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('scope', models.CharField(choices=[('admin', 'Admin'), ('platinum', 'Platinum'), ('gold', 'Gold'), ('silver', 'Silver'), ('free', 'Free')], max_length=20)),
|
||||
('calls', models.IntegerField(default=0)),
|
||||
('limit', models.IntegerField(default=0)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserScope',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('scope', models.CharField(choices=[('admin', 'Admin'), ('platinum', 'Platinum'), ('gold', 'Gold'), ('silver', 'Silver'), ('free', 'Free')], max_length=20)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,59 @@
|
||||
# Generated by Django 5.1.1 on 2024-11-24 06:03
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0007_alter_event_event_type_userthrottle_userscope'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Organization',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=64)),
|
||||
('website', models.CharField(blank=True, max_length=128, null=True)),
|
||||
('is_venue', models.BooleanField(default=False)),
|
||||
('is_501c', models.BooleanField(default=False)),
|
||||
('contact_name', models.CharField(blank=True, max_length=64, null=True)),
|
||||
('contact_email', models.CharField(blank=True, max_length=64, null=True)),
|
||||
('phone_number', models.CharField(blank=True, max_length=200, null=True)),
|
||||
('address', models.CharField(blank=True, max_length=64, null=True)),
|
||||
('city', models.CharField(blank=True, max_length=32, null=True)),
|
||||
('state', models.CharField(blank=True, max_length=16, null=True)),
|
||||
('zip_code', models.CharField(blank=True, max_length=16, null=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Organizations',
|
||||
'ordering': ['name'],
|
||||
},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='venue',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.organization'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Promo',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=64)),
|
||||
('promo_type', models.CharField(choices=[('Jo', 'Job Opening'), ('Re', 'Retail'), ('Fo', 'Food'), ('Ev', 'Event')], default='0', max_length=16)),
|
||||
('image', models.ImageField(blank=True, null=True, upload_to='')),
|
||||
('promo_text', models.TextField(blank=True, null=True)),
|
||||
('target_link', models.URLField(blank=True, null=True)),
|
||||
('notes', models.TextField(blank=True, null=True)),
|
||||
('organization', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.organization')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Promo',
|
||||
},
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Venue',
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,27 @@
|
||||
# Generated by Django 5.1.1 on 2024-11-24 08:28
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0008_organization_alter_event_venue_promo_delete_venue'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='promo',
|
||||
name='image',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='promo',
|
||||
name='desk_image',
|
||||
field=models.ImageField(blank=True, upload_to='promo/desk'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='promo',
|
||||
name='mobile_image',
|
||||
field=models.ImageField(blank=True, upload_to='promo/mobile'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,27 @@
|
||||
# Generated by Django 5.1.1 on 2024-12-01 22:45
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0009_remove_promo_image_promo_desk_image_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='promo',
|
||||
old_name='promo_text',
|
||||
new_name='promo_text_short',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='promo',
|
||||
name='desk_image',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='promo',
|
||||
name='promo_text_long',
|
||||
field=models.TextField(blank=True, max_length=127, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,32 @@
|
||||
# Generated by Django 5.1.1 on 2024-12-11 07:07
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0010_rename_promo_text_promo_promo_text_short_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='promo',
|
||||
old_name='promo_text_long',
|
||||
new_name='long_text',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='promo',
|
||||
old_name='promo_text_short',
|
||||
new_name='short_text',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='promo',
|
||||
name='mobile_image',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='promo',
|
||||
name='image',
|
||||
field=models.ImageField(blank=True, upload_to='promo'),
|
||||
),
|
||||
]
|
||||
18
events/migrations/0012_alter_promo_long_text.py
Normal file
18
events/migrations/0012_alter_promo_long_text.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.1.1 on 2024-12-11 07:15
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0011_rename_promo_text_long_promo_long_text_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='promo',
|
||||
name='long_text',
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
17
events/migrations/0013_alter_organization_unique_together.py
Normal file
17
events/migrations/0013_alter_organization_unique_together.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# Generated by Django 5.1.1 on 2025-01-19 18:50
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0012_alter_promo_long_text'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterUniqueTogether(
|
||||
name='organization',
|
||||
unique_together={('name', 'is_venue')},
|
||||
),
|
||||
]
|
||||
18
events/migrations/0014_promo_published.py
Normal file
18
events/migrations/0014_promo_published.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.1.1 on 2025-02-11 19:38
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0013_alter_organization_unique_together'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='promo',
|
||||
name='published',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,33 @@
|
||||
# Generated by Django 5.1.1 on 2025-02-12 01:39
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0014_promo_published'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='userthrottle',
|
||||
name='user',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='membership',
|
||||
field=models.CharField(choices=[('Nm', 'Non-Member'), ('Na', 'Nano Member'), ('Mm', 'Micro Member'), ('Sm', 'Small Business Member'), ('Lb', 'Local Business Member'), ('Rb', 'Regional Business Member')], default='0', max_length=24),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='promo',
|
||||
name='promo_type',
|
||||
field=models.CharField(choices=[('Jo', 'Job Opening'), ('Re', 'Retail'), ('Fo', 'Food'), ('Ev', 'Event'), ('An', 'Academia Nuts'), ('Su', 'Survey Questions')], default='0', max_length=16),
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='UserScope',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='UserThrottle',
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,32 @@
|
||||
# Generated by Django 5.1.1 on 2025-02-25 01:27
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0015_remove_userthrottle_user_organization_membership_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='promo',
|
||||
options={'ordering': ['published', 'organization', 'title'], 'verbose_name_plural': 'Promo'},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='promo',
|
||||
name='art_image',
|
||||
field=models.ImageField(blank=True, upload_to='art'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='promo',
|
||||
name='embed_link',
|
||||
field=models.CharField(blank=True, max_length=127, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='promo',
|
||||
name='promo_type',
|
||||
field=models.CharField(choices=[('Jo', 'Job Opening'), ('Re', 'Retail'), ('Fo', 'Food'), ('Ev', 'Event'), ('Ma', 'Mutual Aid'), ('Ja', 'Journal Article'), ('Sp', 'Startup Pitch'), ('Ar', 'Art'), ('An', 'Academia Nuts'), ('Su', 'Survey Questions')], default='0', max_length=16),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,70 @@
|
||||
# Generated by Django 5.1.1 on 2025-02-28 00:37
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0016_alter_promo_options_promo_art_image_promo_embed_link_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='promo',
|
||||
name='art_image',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='promo',
|
||||
name='image',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='ein',
|
||||
field=models.CharField(blank=True, max_length=16, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='long_desc',
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='org_type',
|
||||
field=models.CharField(choices=[('Fo', 'Food'), ('Re', 'Retail'), ('Se', 'Service'), ('Ud', 'Undefined')], default='3', max_length=24),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='short_desc',
|
||||
field=models.CharField(blank=True, max_length=63, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='stripe_email',
|
||||
field=models.CharField(blank=True, max_length=64, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='promo',
|
||||
name='classified_image',
|
||||
field=models.ImageField(blank=True, upload_to='classifieds'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='promo',
|
||||
name='overlay_image',
|
||||
field=models.ImageField(blank=True, upload_to='overlays'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='event_type',
|
||||
field=models.CharField(choices=[('Ot', 'Other'), ('Mu', 'Music'), ('Va', 'Visual Art'), ('Gv', 'Government'), ('Ce', 'Civic Engagement'), ('Ed', 'Educational'), ('Ma', 'Mutual Aid'), ('Th', 'Theater'), ('Co', 'Comedy')], default='0', max_length=16),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='promo',
|
||||
name='promo_type',
|
||||
field=models.CharField(choices=[('Ar', 'Art'), ('Fo', 'Food'), ('Ev', 'Event'), ('Re', 'Retail'), ('Ma', 'Mutual Aid'), ('Ca', 'Classifieds'), ('Jo', 'Job Opening'), ('Sp', 'Startup Pitch'), ('An', 'Academia Nuts'), ('Ja', 'Journal Article'), ('Su', 'Survey Questions')], default='0', max_length=16),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='event',
|
||||
unique_together={('show_title', 'show_date', 'venue')},
|
||||
),
|
||||
]
|
||||
33
events/migrations/0018_scraper_event_scraper.py
Normal file
33
events/migrations/0018_scraper_event_scraper.py
Normal file
@@ -0,0 +1,33 @@
|
||||
# Generated by Django 5.1.1 on 2025-02-28 01:07
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0017_remove_promo_art_image_remove_promo_image_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Scraper',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=64)),
|
||||
('items', models.IntegerField()),
|
||||
('last_run', models.DateTimeField()),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Scrapers',
|
||||
'ordering': ['name'],
|
||||
'unique_together': {('name',)},
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='event',
|
||||
name='scraper',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='events.scraper'),
|
||||
),
|
||||
]
|
||||
18
events/migrations/0019_scraper_website.py
Normal file
18
events/migrations/0019_scraper_website.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.1.1 on 2025-02-28 01:09
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0018_scraper_event_scraper'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='scraper',
|
||||
name='website',
|
||||
field=models.CharField(blank=True, max_length=64, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,26 @@
|
||||
# Generated by Django 5.1.1 on 2025-03-01 12:37
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0019_scraper_website'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='scraper',
|
||||
old_name='last_run',
|
||||
new_name='last_ran',
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='event',
|
||||
unique_together=set(),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='organization',
|
||||
unique_together=set(),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 5.1.1 on 2025-03-01 12:38
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0020_rename_last_run_scraper_last_ran_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='scraper',
|
||||
name='items',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='scraper',
|
||||
name='last_ran',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,21 @@
|
||||
# Generated by Django 5.1.1 on 2025-03-02 00:49
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0021_alter_scraper_items_alter_scraper_last_ran'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterUniqueTogether(
|
||||
name='organization',
|
||||
unique_together={('name', 'is_venue')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='scraper',
|
||||
unique_together={('name', 'website')},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,22 @@
|
||||
# Generated by Django 5.1.1 on 2025-03-02 01:08
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0022_alter_organization_unique_together_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterUniqueTogether(
|
||||
name='scraper',
|
||||
unique_together=set(),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='scraper',
|
||||
name='name',
|
||||
field=models.CharField(max_length=64, unique=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,36 @@
|
||||
# Generated by Django 5.1.1 on 2025-03-21 01:27
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0023_alter_scraper_unique_together_alter_scraper_name'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Tags',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=31, unique=True)),
|
||||
('desc', models.TextField(blank=True, null=True)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='event',
|
||||
name='tags',
|
||||
field=models.ManyToManyField(blank=True, null=True, to='events.tags'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='tags',
|
||||
field=models.ManyToManyField(blank=True, null=True, to='events.tags'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='promo',
|
||||
name='tags',
|
||||
field=models.ManyToManyField(blank=True, null=True, to='events.tags'),
|
||||
),
|
||||
]
|
||||
26
events/migrations/0025_calendars_organization_calendars.py
Normal file
26
events/migrations/0025_calendars_organization_calendars.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# Generated by Django 5.1.1 on 2025-10-05 07:56
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0024_tags_event_tags_organization_tags_promo_tags'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Calendars',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=31, unique=True)),
|
||||
('desc', models.TextField(blank=True, null=True)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='calendars',
|
||||
field=models.ManyToManyField(blank=True, null=True, to='events.calendars'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,151 @@
|
||||
# Generated by Django 5.1.1 on 2025-10-11 02:11
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0025_calendars_organization_calendars'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Calendar',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=31, unique=True)),
|
||||
('shortcode', models.CharField(max_length=3, unique=True)),
|
||||
('desc', models.TextField(blank=True, null=True)),
|
||||
],
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='organization',
|
||||
name='calendars',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='event_type',
|
||||
field=models.CharField(choices=[('Ot', 'Other'), ('Mu', 'Music'), ('Va', 'Visual Art'), ('Gv', 'Government'), ('Ce', 'Civic Engagement'), ('Ed', 'Educational'), ('Ma', 'Mutual Aid'), ('Th', 'Theater'), ('Co', 'Comedy')], default='0', max_length=15),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='guests',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='img_link',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='show_title',
|
||||
field=models.CharField(blank=True, max_length=127, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='organization',
|
||||
name='address',
|
||||
field=models.CharField(blank=True, max_length=63, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='organization',
|
||||
name='city',
|
||||
field=models.CharField(blank=True, max_length=31, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='organization',
|
||||
name='contact_email',
|
||||
field=models.CharField(blank=True, max_length=63, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='organization',
|
||||
name='contact_name',
|
||||
field=models.CharField(blank=True, max_length=63, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='organization',
|
||||
name='ein',
|
||||
field=models.CharField(blank=True, max_length=15, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='organization',
|
||||
name='membership',
|
||||
field=models.CharField(choices=[('Nm', 'Non-Member'), ('Na', 'Nano Member'), ('Mm', 'Micro Member'), ('Sm', 'Small Business Member'), ('Lb', 'Local Business Member'), ('Rb', 'Regional Business Member')], default='0', max_length=31),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='organization',
|
||||
name='name',
|
||||
field=models.CharField(max_length=63),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='organization',
|
||||
name='org_type',
|
||||
field=models.CharField(choices=[('Fo', 'Food'), ('Re', 'Retail'), ('Se', 'Service'), ('Ud', 'Undefined')], default='3', max_length=31),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='organization',
|
||||
name='phone_number',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='organization',
|
||||
name='state',
|
||||
field=models.CharField(blank=True, max_length=15, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='organization',
|
||||
name='stripe_email',
|
||||
field=models.CharField(blank=True, max_length=63, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='organization',
|
||||
name='website',
|
||||
field=models.CharField(blank=True, max_length=126, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='organization',
|
||||
name='zip_code',
|
||||
field=models.CharField(blank=True, max_length=15, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='promo',
|
||||
name='embed_link',
|
||||
field=models.CharField(blank=True, max_length=126, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='promo',
|
||||
name='promo_type',
|
||||
field=models.CharField(choices=[('Ar', 'Art'), ('Fo', 'Food'), ('Ev', 'Event'), ('Re', 'Retail'), ('Ma', 'Mutual Aid'), ('Ca', 'Classifieds'), ('Jo', 'Job Opening'), ('Sp', 'Startup Pitch'), ('An', 'Academia Nuts'), ('Ja', 'Journal Article'), ('Su', 'Survey Questions')], default='0', max_length=15),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='promo',
|
||||
name='title',
|
||||
field=models.CharField(max_length=63),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='scraper',
|
||||
name='name',
|
||||
field=models.CharField(max_length=63, unique=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='scraper',
|
||||
name='website',
|
||||
field=models.CharField(blank=True, max_length=63, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='event',
|
||||
name='calendar',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='events.calendar'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='scraper',
|
||||
name='calendar',
|
||||
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='events.calendar'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Calendars',
|
||||
),
|
||||
]
|
||||
18
events/migrations/0027_scraper_new_items.py
Normal file
18
events/migrations/0027_scraper_new_items.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.1.1 on 2025-10-11 02:41
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0026_calendar_remove_organization_calendars_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='scraper',
|
||||
name='new_items',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
0
events/migrations/__init__.py
Normal file
0
events/migrations/__init__.py
Normal file
206
events/models.py
Normal file
206
events/models.py
Normal file
@@ -0,0 +1,206 @@
|
||||
from django.db import models
|
||||
from django.core.files.storage import FileSystemStorage
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
fs = FileSystemStorage(location='/media/flyers')
|
||||
# Create your models here.
|
||||
|
||||
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)
|
||||
|
||||
def __unicode__(self):
|
||||
return "%s" % self.shortcode
|
||||
|
||||
def __str__(self):
|
||||
return u'%s' % self.shortcode
|
||||
|
||||
|
||||
class Scraper(models.Model):
|
||||
name = models.CharField(max_length=63, unique=True)
|
||||
website = models.CharField(max_length=63, blank=True, null=True)
|
||||
calendar = models.ForeignKey(Calendar, on_delete=models.CASCADE)
|
||||
items = models.IntegerField(blank=True, null=True)
|
||||
new_items = models.IntegerField(blank=True, null=True)
|
||||
last_ran = models.DateTimeField(blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "Scrapers"
|
||||
ordering = ['name',]
|
||||
|
||||
def __unicode__(self):
|
||||
return "%s" % self.name
|
||||
|
||||
def __str__(self):
|
||||
return u'%s' % self.name
|
||||
|
||||
|
||||
class Tags(models.Model):
|
||||
name = models.CharField(max_length=31, unique=True)
|
||||
desc = models.TextField(blank=True, null=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return "%s" % self.name
|
||||
|
||||
def __str__(self):
|
||||
return u'%s' % self.name
|
||||
|
||||
|
||||
class Organization(models.Model):
|
||||
MEMBER_TYPE = (
|
||||
('Nm', 'Non-Member'),
|
||||
('Na', 'Nano Member'),
|
||||
('Mm', 'Micro Member'),
|
||||
('Sm', 'Small Business Member'),
|
||||
('Lb', 'Local Business Member'),
|
||||
('Rb', 'Regional Business Member'),
|
||||
)
|
||||
ORG_TYPE = (
|
||||
('Fo', 'Food'),
|
||||
('Re', 'Retail'),
|
||||
('Se', 'Service'),
|
||||
('Ud', 'Undefined'),
|
||||
)
|
||||
name = models.CharField(max_length=63)
|
||||
website = models.CharField(max_length=126, blank=True, null=True)
|
||||
membership = models.CharField(max_length=31, choices=MEMBER_TYPE, default='0')
|
||||
org_type = models.CharField(max_length=31, choices=ORG_TYPE, default='3')
|
||||
|
||||
stripe_email = models.CharField(max_length=63, blank=True, null=True)
|
||||
ein = models.CharField(max_length=15, blank=True, null=True)
|
||||
is_venue= models.BooleanField(default=False)
|
||||
is_501c = models.BooleanField(default=False)
|
||||
|
||||
short_desc = models.CharField(max_length=63, blank=True, null=True)
|
||||
long_desc = models.TextField(blank=True, null=True)
|
||||
|
||||
contact_name = models.CharField(max_length=63, blank=True, null=True)
|
||||
contact_email = models.CharField(max_length=63, blank=True, null=True)
|
||||
|
||||
phone_number = models.CharField(max_length=255, blank=True, null=True)
|
||||
address = models.CharField(max_length=63, blank=True, null=True)
|
||||
city = models.CharField(max_length=31, blank=True, null=True)
|
||||
state = models.CharField(max_length=15, blank=True, null=True)
|
||||
zip_code = models.CharField(max_length=15, blank=True, null=True)
|
||||
|
||||
tags = models.ManyToManyField(Tags, blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
unique_together = ("name", "is_venue")
|
||||
verbose_name_plural = "Organizations"
|
||||
ordering = ['name']
|
||||
|
||||
def __unicode__(self):
|
||||
return "%s" % self.name
|
||||
|
||||
def __str__(self):
|
||||
return u'%s' % self.name
|
||||
|
||||
|
||||
class Event(models.Model):
|
||||
EVENT_TYPE = (
|
||||
('Ot', 'Other'),
|
||||
('Mu', 'Music'),
|
||||
('Va', 'Visual Art'),
|
||||
('Gv', 'Government'),
|
||||
('Ce', 'Civic Engagement'),
|
||||
('Ed', 'Educational'),
|
||||
('Ma', 'Mutual Aid'),
|
||||
('Th', 'Theater'),
|
||||
('Co', 'Comedy'),
|
||||
)
|
||||
calendar = models.ForeignKey(Calendar, on_delete=models.CASCADE, blank=True, null=True)
|
||||
scraper = models.ForeignKey(Scraper, on_delete=models.CASCADE, null=True)
|
||||
venue = models.ForeignKey(Organization, on_delete=models.CASCADE)
|
||||
event_type = models.CharField(max_length=15, choices=EVENT_TYPE, default='0')
|
||||
show_title = models.CharField(max_length=127, blank=True, null=True)
|
||||
show_link = models.URLField(blank=True, null=True)
|
||||
guests = models.CharField(max_length=255, blank=True, null=True)
|
||||
show_date = models.DateTimeField()
|
||||
show_day = models.DateField(blank=True, null=True)
|
||||
img_link = models.CharField(max_length=255, blank=True, null=True)
|
||||
flyer_img = models.ImageField(upload_to=fs, blank=True, null=True)
|
||||
more_details = models.JSONField(blank=True, null=True)
|
||||
|
||||
tags = models.ManyToManyField(Tags, blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "Events"
|
||||
# unique_together = ("show_title", "show_date", "venue")
|
||||
ordering = ['show_date', 'show_title']
|
||||
|
||||
def __unicode__(self):
|
||||
return "%s" % self.show_title
|
||||
|
||||
def __str__(self):
|
||||
return u'%s' % self.show_title
|
||||
|
||||
|
||||
class Promo(models.Model):
|
||||
PROMO_TYPE = (
|
||||
('Ar', 'Art'),
|
||||
('Fo', 'Food'),
|
||||
('Ev', 'Event'),
|
||||
('Re', 'Retail'),
|
||||
('Ma', 'Mutual Aid'),
|
||||
('Ca', 'Classifieds'),
|
||||
('Jo', 'Job Opening'),
|
||||
('Sp', 'Startup Pitch'),
|
||||
('An', 'Academia Nuts'),
|
||||
('Ja', 'Journal Article'),
|
||||
('Su', 'Survey Questions')
|
||||
)
|
||||
title = models.CharField(max_length=63)
|
||||
organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
|
||||
promo_type = models.CharField(max_length=15, choices=PROMO_TYPE, default='0')
|
||||
overlay_image = models.ImageField(upload_to="overlays", blank=True)
|
||||
classified_image = models.ImageField(upload_to="classifieds", blank=True)
|
||||
embed_link = models.CharField(max_length=126, blank=True, null=True)
|
||||
short_text = models.TextField(blank=True, null=True)
|
||||
long_text = models.TextField(blank=True, null=True)
|
||||
target_link = models.URLField(blank=True, null=True)
|
||||
notes = models.TextField(blank=True, null=True)
|
||||
published = models.BooleanField(default=False)
|
||||
|
||||
tags = models.ManyToManyField(Tags, blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "Promo"
|
||||
ordering = ['published', 'organization', 'title',]
|
||||
|
||||
def __unicode__(self):
|
||||
return "%s" % self.title
|
||||
|
||||
def __str__(self):
|
||||
return u'%s' % self.title
|
||||
|
||||
|
||||
# class UserThrottle(models.Model):
|
||||
# user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
# scope = models.CharField(max_length=20, choices=(
|
||||
# ('admin', 'Admin'),
|
||||
# ('platinum', 'Platinum'),
|
||||
# ('gold', 'Gold'),
|
||||
# ('silver', 'Silver'),
|
||||
# ('free', 'Free'),
|
||||
# ))
|
||||
# calls = models.IntegerField(default=0)
|
||||
# limit = models.IntegerField(default=0)
|
||||
|
||||
# def __str__(self):
|
||||
# return f"{self.user.username}: {self.scope}"
|
||||
|
||||
|
||||
# class UserScope(models.Model):
|
||||
# user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
# scope = models.CharField(max_length=20, choices=(
|
||||
# ('admin', 'Admin'),
|
||||
# ('platinum', 'Platinum'),
|
||||
# ('gold', 'Gold'),
|
||||
# ('silver', 'Silver'),
|
||||
# ('free', 'Free'),
|
||||
# ))
|
||||
|
||||
# def __str__(self):
|
||||
# return f"{self.user.username}: {self.scope}"
|
||||
62
events/serializers.py
Normal file
62
events/serializers.py
Normal file
@@ -0,0 +1,62 @@
|
||||
from rest_framework import serializers
|
||||
from .models import Event, Organization, Promo
|
||||
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from rest_framework.permissions import BasePermission
|
||||
|
||||
class ScopesPermission(BasePermission):
|
||||
scopes_map = {
|
||||
'admin': [],
|
||||
'platinum': ['gold', 'silver', 'free'],
|
||||
'gold': ['silver', 'free'],
|
||||
'silver': ['free'],
|
||||
'free': [],
|
||||
}
|
||||
|
||||
def has_permission(self, request, view):
|
||||
if not request.user.is_authenticated:
|
||||
return False
|
||||
|
||||
# Check if the user has an associated scope
|
||||
try:
|
||||
user_scope = UserScope.objects.get(user=request.user)
|
||||
except UserScope.DoesNotExist:
|
||||
return False
|
||||
|
||||
# Check if the user's scope has the required permission level
|
||||
if user_scope.scope not in self.scopes_map:
|
||||
return False
|
||||
|
||||
allowed_scopes = self.scopes_map[user_scope.scope]
|
||||
return request.scope in allowed_scopes or request.scope == user_scope.scope
|
||||
|
||||
############
|
||||
## Events ##
|
||||
############
|
||||
|
||||
class OrganizationSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Organization
|
||||
fields = ('id', 'name', 'website', 'city')
|
||||
# fields = '__all__'
|
||||
|
||||
|
||||
class EventSerializer(serializers.ModelSerializer):
|
||||
venue = OrganizationSerializer(many=False)
|
||||
event_type = serializers.CharField(source='get_event_type_display')
|
||||
# target_language = serializers.SerializerMethodField()
|
||||
class Meta:
|
||||
model = Event
|
||||
fields = '__all__'
|
||||
depth = 2
|
||||
# fields = ('id', 'name',)
|
||||
|
||||
class PromoSerializer(serializers.ModelSerializer):
|
||||
organization = OrganizationSerializer(many=False)
|
||||
# event_type = serializers.CharField(source='get_event_type_display')
|
||||
class Meta:
|
||||
model = Promo
|
||||
fields = ('id', 'title', 'organization', 'promo_type', 'long_text', 'short_text', 'overlay_image', 'classified_image', 'target_link')
|
||||
# fields = '__all__'
|
||||
depth = 2
|
||||
3
events/tests.py
Normal file
3
events/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
25
events/urls.py
Normal file
25
events/urls.py
Normal file
@@ -0,0 +1,25 @@
|
||||
"""ds_events URL Configuration
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/4.1/topics/http/urls/
|
||||
Examples:
|
||||
Function views
|
||||
1. Add an import: from my_app import views
|
||||
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||
Class-based views
|
||||
1. Add an import: from other_app.views import Home
|
||||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||
Including another URLconf
|
||||
1. Import the include() function: from django.urls import include, path
|
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import path, include, re_path
|
||||
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'^events-token/', EventsTokenAPIView.as_view(), name="get-token-events"),
|
||||
|
||||
]
|
||||
52
events/views.py
Normal file
52
events/views.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from django.shortcuts import render
|
||||
from datetime import datetime, timedelta
|
||||
import pytz, random
|
||||
|
||||
from .models import *
|
||||
from .serializers import *
|
||||
|
||||
from django.db.models import Q
|
||||
|
||||
from rest_framework import generics
|
||||
from rest_framework.decorators import authentication_classes, permission_classes
|
||||
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
|
||||
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
# from durin.auth import TokenAuthentication
|
||||
|
||||
# from durin.views import APIAccessTokenView
|
||||
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework import filters
|
||||
|
||||
from rest_framework.response import Response
|
||||
|
||||
td = timedelta(hours=7)
|
||||
odt = datetime.now() - td
|
||||
|
||||
# Create your views here.
|
||||
class EventsAPIView(generics.ListAPIView):
|
||||
serializer_class = EventSerializer
|
||||
queryset = Event.objects.filter(show_date__gte=odt).order_by('show_date')
|
||||
filter_backends = [DjangoFilterBackend, filters.SearchFilter]
|
||||
filterset_fields = ['show_title', 'event_type', 'venue__name', 'calendar__shortcode']
|
||||
search_fields = ['show_title', 'event_type', 'venue__name']
|
||||
|
||||
|
||||
class PromoAPIView(generics.ListAPIView):
|
||||
serializer_class = PromoSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
promo_objects = list(Promo.objects.filter(published=True))
|
||||
print(len(promo_objects))
|
||||
queryset = random.sample(promo_objects, 21)
|
||||
return queryset
|
||||
|
||||
# class EventsTokenAPIView(APIAccessTokenView):
|
||||
# serializer_class = EventSerializer
|
||||
# authentication_classes = (TokenAuthentication, BasicAuthentication,)
|
||||
# permission_classes = (IsAuthenticated,)
|
||||
# queryset = Event.objects.filter(show_date__gte=odt).order_by('show_date')
|
||||
# filter_backends = [DjangoFilterBackend, filters.SearchFilter]
|
||||
# filterset_fields = ['show_title', 'event_type', 'show_date', 'show_day', 'venue__name']
|
||||
# search_fields = ['show_title', 'event_type']
|
||||
Reference in New Issue
Block a user