Add sharing options #184

This commit is contained in:
Daniel Grams 2021-06-01 16:50:51 +02:00
parent 739ca190e2
commit 4419ea1b93
16 changed files with 376 additions and 32 deletions

View File

@ -1,10 +1,12 @@
from datetime import datetime from datetime import datetime, timedelta
import icalendar
import pytz import pytz
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from dateutil.rrule import rrulestr from dateutil.rrule import rrulestr
berlin_tz = pytz.timezone("Europe/Berlin") berlin_tz = pytz.timezone("Europe/Berlin")
gmt_tz = pytz.timezone("GMT")
def get_now(): def get_now():
@ -195,3 +197,34 @@ def calculate_occurrences(start_date, date_format, rrule_str, start, batch_size)
} }
return {"occurrences": occurrences, "batch": batch_data} return {"occurrences": occurrences, "batch": batch_data}
def create_icalendar() -> icalendar.Calendar:
cal = icalendar.Calendar()
cal.add("prodid", "-//Oveda//oveda.de//")
cal.add("version", "2.0")
cal.add("x-wr-timezone", berlin_tz.zone)
tzc = icalendar.Timezone()
tzc.add("tzid", berlin_tz.zone)
tzc.add("x-lic-location", berlin_tz.zone)
tzs = icalendar.TimezoneStandard()
tzs.add("tzname", "CET")
tzs.add("dtstart", datetime(1970, 10, 25, 3, 0, 0))
tzs.add("rrule", {"freq": "yearly", "bymonth": 10, "byday": "-1su"})
tzs.add("TZOFFSETFROM", timedelta(hours=2))
tzs.add("TZOFFSETTO", timedelta(hours=1))
tzd = icalendar.TimezoneDaylight()
tzd.add("tzname", "CEST")
tzd.add("dtstart", datetime(1970, 3, 29, 2, 0, 0))
tzd.add("rrule", {"freq": "yearly", "bymonth": 3, "byday": "-1su"})
tzd.add("TZOFFSETFROM", timedelta(hours=1))
tzd.add("TZOFFSETTO", timedelta(hours=2))
tzc.add_component(tzs)
tzc.add_component(tzd)
cal.add_component(tzc)
return cal

View File

@ -6,6 +6,8 @@ from project.utils import (
get_event_category_name, get_event_category_name,
get_localized_enum_name, get_localized_enum_name,
get_localized_scope, get_localized_scope,
get_location_str,
get_place_str,
) )
@ -36,6 +38,8 @@ app.jinja_env.filters["quote_plus"] = lambda u: quote_plus(u)
app.jinja_env.filters["is_list"] = is_list app.jinja_env.filters["is_list"] = is_list
app.jinja_env.filters["any_dict_value_true"] = any_dict_value_true app.jinja_env.filters["any_dict_value_true"] = any_dict_value_true
app.jinja_env.filters["ensure_link_scheme"] = lambda s: ensure_link_scheme(s) app.jinja_env.filters["ensure_link_scheme"] = lambda s: ensure_link_scheme(s)
app.jinja_env.filters["place_str"] = lambda p: get_place_str(p)
app.jinja_env.filters["location_str"] = lambda l: get_location_str(l)
@app.context_processor @app.context_processor

View File

@ -1,5 +1,6 @@
from datetime import datetime from datetime import datetime
import icalendar
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from flask import url_for from flask import url_for
from flask_babelex import format_date, format_time from flask_babelex import format_date, format_time
@ -8,7 +9,12 @@ from sqlalchemy.orm import contains_eager, defaultload, joinedload, lazyload
from sqlalchemy.sql import extract from sqlalchemy.sql import extract
from project import db from project import db
from project.dateutils import date_add_time, dates_from_recurrence_rule, get_today from project.dateutils import (
berlin_tz,
date_add_time,
dates_from_recurrence_rule,
get_today,
)
from project.models import ( from project.models import (
AdminUnit, AdminUnit,
Event, Event,
@ -22,7 +28,7 @@ from project.models import (
Image, Image,
Location, Location,
) )
from project.utils import get_pending_changes from project.utils import get_pending_changes, get_place_str
from project.views.utils import truncate from project.views.utils import truncate
@ -350,3 +356,31 @@ def get_meta_data(event: Event, event_date: EventDate = None) -> dict:
meta["image"] = url_for("image", id=event.photo_id, _external=True) meta["image"] = url_for("image", id=event.photo_id, _external=True)
return meta return meta
def create_ical_event_for_date(event_date: EventDate) -> icalendar.Event:
url = url_for("event_date", id=event_date.id, _external=True)
event = icalendar.Event()
event.add("summary", event_date.event.name)
event.add("url", url)
event.add("description", url)
event.add("uid", url)
event.add("dtstart", event_date.start.astimezone(berlin_tz))
if event_date.end:
event.add("dtend", event_date.end.astimezone(berlin_tz))
if event_date.event.created_at:
event.add("dtstamp", event_date.event.created_at)
if event_date.event.updated_at:
event.add("last-modified", event_date.event.updated_at)
if (
event_date.event.attendance_mode
and event_date.event.attendance_mode != EventAttendanceMode.online
):
event.add("location", get_place_str(event_date.event.event_place))
return event

View File

@ -194,6 +194,16 @@ $( function() {
return false; return false;
}); });
$("#copy_input_button").click(function () {
$("#copy_input").select();
document.execCommand("copy");
$(this).tooltip('show');
});
$('#copy_input_button').mouseleave(function () {
$(this).tooltip('hide');
});
$("#geolocation_btn").click(function () { $("#geolocation_btn").click(function () {
if ("geolocation" in navigator){ if ("geolocation" in navigator){
navigator.geolocation.getCurrentPosition(function(position){ navigator.geolocation.getCurrentPosition(function(position){

View File

@ -89,21 +89,8 @@
{{ organizer.name }} {{ organizer.name }}
{% endmacro %} {% endmacro %}
{% macro render_location(location) %} {% macro render_location(location) %}{{ location | location_str }}{% endmacro %}
{%- if location.street -%} {% macro render_place(place) %}{{ place | place_str }}{% endmacro %}
{{ location.street }}, {{ location.postalCode }} {{ location.city }}
{%- elif location.postalCode or location.city -%}
{{ location.postalCode }} {{ location.city }}
{%- endif -%}
{% endmacro %}
{% macro render_place(place) %}
{%- if place.location -%}
{{ place.name }}, {{render_location(place.location)}}
{%- else -%}
{{ place.name }}
{%- endif -%}
{% endmacro %}
{% macro render_events_sub_menu() %} {% macro render_events_sub_menu() %}
{% endmacro %} {% endmacro %}
@ -511,7 +498,7 @@
{% endmacro %} {% endmacro %}
{% macro render_event_props_seo(event, start, end, dates = None, show_rating = False, show_admin_unit = True, user_rights=None) %} {% macro render_event_props_seo(event, start, end, dates = None, show_rating = False, show_admin_unit = True, user_rights=None, share_links=None, calendar_links=None) %}
<div class="w-normal mx-auto"> <div class="w-normal mx-auto">
{% if event.photo_id %} {% if event.photo_id %}
@ -563,7 +550,20 @@
<div class="mt-4" style="white-space:pre-wrap;">{{ event.description|urlize(nofollow=True, target='_blank', rel="nofollow") }}</div> <div class="mt-4" style="white-space:pre-wrap;">{{ event.description|urlize(nofollow=True, target='_blank', rel="nofollow") }}</div>
{% endif %} {% endif %}
<div class="small mt-4"> {% if share_links or calendar_links %}
<div class="mt-4">
{% if share_links %}
<button type="button" class="btn btn-outline-secondary mr-1 mb-1" data-toggle="modal" data-target="#shareModal"><i class="fa fa-share-alt"></i> {{ _('Share') }}</button>
{{ render_share_modal(share_links) }}
{% endif %}
{% if calendar_links %}
<button type="button" class="btn btn-outline-secondary mb-1" data-toggle="modal" data-target="#calendarExportModal"><i class="fa fa-calendar"></i> {{ _('Add to calendar') }}</button>
{{ render_calendar_export_modal(calendar_links) }}
{% endif %}
</div>
{% endif %}
<div class="small mt-2">
{{ render_audit(event, show_rating) }} {{ render_audit(event, show_rating) }}
</div> </div>
</div> </div>
@ -588,7 +588,7 @@
{% if event.attendance_mode and event.attendance_mode.value != 2 %} {% if event.attendance_mode and event.attendance_mode.value != 2 %}
<div class="mt-2"> <div class="mt-2">
<a href="http://www.google.com/maps?q={{ render_place(event.event_place) | quote_plus }}" class="btn btn-secondary" target="_blank" rel="noopener noreferrer">{{ _('Show directions') }}</a> <a href="http://www.google.com/maps?q={{ render_place(event.event_place) | quote_plus }}" class="btn btn-outline-secondary" target="_blank" rel="noopener noreferrer"><i class="fa fa-directions"></i> {{ _('Show directions') }}</a>
</div> </div>
{% endif %} {% endif %}
@ -1248,4 +1248,58 @@ if (URL) {
{% endif %} {% endif %}
</style> </style>
{% endmacro %} {% endmacro %}
{% macro render_share_modal(share_links) %}
<div class="modal fade" id="shareModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{ _('Share event') }}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="input-group mb-3">
<input id="copy_input" type="text" class="form-control" value="{{ share_links["url"] }}" />
<div class="input-group-append">
<button id="copy_input_button" class="btn btn-outline-secondary" type="button" data-toggle="tooltip" data-trigger="manual" data-title="{{ _('Link copied') }}">{{ _('Copy link') }}</button>
</div>
</div>
<div class="list-group">
<a class="list-group-item list-group-item-action" href="{{ share_links["facebook"] }}" target="_blank" rel="noopener noreferrer"><i class="fab fa-facebook"></i> Facebook</a>
<a class="list-group-item list-group-item-action" href="{{ share_links["twitter"] }}" target="_blank" rel="noopener noreferrer"><i class="fab fa-twitter"></i> Twitter</a>
<a class="list-group-item list-group-item-action" href="{{ share_links["email"] }}" target="_blank" rel="noopener noreferrer"><i class="fa fa-envelope"></i> {{ _('Email') }}</a>
<a class="list-group-item list-group-item-action" href="{{ share_links["whatsapp"] }}" target="_blank" rel="noopener noreferrer" data-action="share/whatsapp/share"><i class="fab fa-whatsapp"></i> Whatsapp</a>
<a class="list-group-item list-group-item-action" href="{{ share_links["telegram"] }}" target="_blank" rel="noopener noreferrer"><i class="fab fa-telegram"></i> Telegram</a>
</div>
</div>
</div>
</div>
</div>
{% endmacro %}
{% macro render_calendar_export_modal(calendar_links) %}
<div class="modal fade" id="calendarExportModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{ _('Add to calendar') }}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="list-group">
<a class="list-group-item list-group-item-action" href="{{ calendar_links["ics"] }}"><i class="fab fa-microsoft"></i> Outlook</a>
<a class="list-group-item list-group-item-action" href="{{ calendar_links["google"] }}" target="_blank" rel="noopener noreferrer"><i class="fab fa-google"></i> {{ _('Google calendar') }}</a>
<a class="list-group-item list-group-item-action" href="{{ calendar_links["ics"] }}"><i class="fab fa-apple"></i> {{ _('Apple calendar') }}</a>
<a class="list-group-item list-group-item-action" href="{{ calendar_links["ics"] }}"><i class="fab fa-yahoo"></i> {{ _('Yahoo calendar') }}</a>
<a class="list-group-item list-group-item-action" href="{{ calendar_links["ics"] }}"><i class="fa fa-calendar"></i> {{ _('Other calendar') }}</a>
</div>
</div>
</div>
</div>
</div>
{% endmacro %}

View File

@ -1,5 +1,5 @@
{% extends "layout.html" %} {% extends "layout.html" %}
{% from "_macros.html" import render_event_props %} {% from "_macros.html" import render_share_modal %}
{%- block title -%} {%- block title -%}
{{ _('Actions for event') }} {{ _('Actions for event') }}
{%- endblock -%} {%- endblock -%}
@ -28,6 +28,12 @@
{% endif %} {% endif %}
</div> </div>
<div class="list-group mt-4">
<button type="button" class="list-group-item list-group-item-action" data-toggle="modal" data-target="#shareModal"><i class="fa fa-share-alt"></i> {{ _('Share event') }}</button>
</div>
{{ render_share_modal(share_links) }}
<div class="list-group mt-4"> <div class="list-group mt-4">
{% if user_rights['can_duplicate_event'] %} {% if user_rights['can_duplicate_event'] %}
<a class="list-group-item list-group-item-action" href="{{ url_for('event_create_for_admin_unit_id', id=event.admin_unit_id, template_id=event.id) }}"><i class="fa fa-copy"></i> {{ _('Duplicate event') }}</a> <a class="list-group-item list-group-item-action" href="{{ url_for('event_create_for_admin_unit_id', id=event.admin_unit_id, template_id=event.id) }}"><i class="fa fa-copy"></i> {{ _('Duplicate event') }}</a>
@ -42,7 +48,6 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -6,6 +6,6 @@
{% block content_container_attribs %}{% endblock %} {% block content_container_attribs %}{% endblock %}
{% block content %} {% block content %}
{{ render_event_props_seo(event, event.start, event.end, dates, user_rights['can_update_event'], user_rights=user_rights) }} {{ render_event_props_seo(event, event.start, event.end, dates, user_rights['can_update_event'], user_rights=user_rights, share_links=share_links) }}
{% endblock %} {% endblock %}

View File

@ -7,6 +7,6 @@
{% block content_container_attribs %}{% endblock %} {% block content_container_attribs %}{% endblock %}
{% block content %} {% block content %}
{{ render_event_props_seo(event, event_date.start, event_date.end, dates, user_rights=user_rights) }} {{ render_event_props_seo(event, event_date.start, event_date.end, dates, user_rights=user_rights, share_links=share_links, calendar_links=calendar_links) }}
{% endblock %} {% endblock %}

View File

@ -20,6 +20,29 @@ def get_localized_scope(scope: str) -> str:
return lazy_gettext(loc_key) return lazy_gettext(loc_key)
def get_location_str(location) -> str:
if not location:
return ""
if location.street and not location.street.isspace():
return f"{location.street}, {location.postalCode} {location.city}"
if location.postalCode or location.city:
return f"{location.postalCode} {location.city}".strip()
return ""
def get_place_str(place) -> str:
if not place:
return ""
if place.location:
return f"{place.name}, {get_location_str(place.location)}"
return place.name
def make_dir(path): def make_dir(path):
try: try:
original_umask = os.umask(0) original_umask = os.umask(0)

View File

@ -43,6 +43,7 @@ from project.views.event_suggestion import send_event_suggestion_review_status_m
from project.views.utils import ( from project.views.utils import (
flash_errors, flash_errors,
flash_message, flash_message,
get_share_links,
handleSqlError, handleSqlError,
non_match_for_deletion, non_match_for_deletion,
send_mail, send_mail,
@ -54,6 +55,8 @@ def event(event_id):
event = get_event_with_details_or_404(event_id) event = get_event_with_details_or_404(event_id)
user_rights = get_menu_user_rights(event) user_rights = get_menu_user_rights(event)
dates = get_upcoming_event_dates(event.id) dates = get_upcoming_event_dates(event.id)
url = url_for("event", event_id=event_id, _external=True)
share_links = get_share_links(url, event.name)
structured_datas = list() structured_datas = list()
for event_date in dates: for event_date in dates:
@ -70,6 +73,7 @@ def event(event_id):
meta=get_meta_data(event), meta=get_meta_data(event),
user_rights=user_rights, user_rights=user_rights,
canonical_url=url_for("event", event_id=event_id, _external=True), canonical_url=url_for("event", event_id=event_id, _external=True),
share_links=share_links,
) )
@ -77,8 +81,15 @@ def event(event_id):
def event_actions(event_id): def event_actions(event_id):
event = Event.query.get_or_404(event_id) event = Event.query.get_or_404(event_id)
user_rights = get_user_rights(event) user_rights = get_user_rights(event)
url = url_for("event", event_id=event_id, _external=True)
share_links = get_share_links(url, event.name)
return render_template("event/actions.html", event=event, user_rights=user_rights) return render_template(
"event/actions.html",
event=event,
user_rights=user_rights,
share_links=share_links,
)
@app.route("/admin_unit/<int:id>/events/create", methods=("GET", "POST")) @app.route("/admin_unit/<int:id>/events/create", methods=("GET", "POST"))

View File

@ -1,18 +1,26 @@
import json import json
from flask import redirect, render_template, request, url_for from flask import redirect, render_template, request, url_for
from flask.wrappers import Response
from project import app from project import app
from project.dateutils import create_icalendar
from project.forms.event_date import FindEventDateForm from project.forms.event_date import FindEventDateForm
from project.jsonld import DateTimeEncoder, get_sd_for_event_date from project.jsonld import DateTimeEncoder, get_sd_for_event_date
from project.services.event import ( from project.services.event import (
create_ical_event_for_date,
get_event_date_with_details_or_404, get_event_date_with_details_or_404,
get_meta_data, get_meta_data,
get_upcoming_event_dates, get_upcoming_event_dates,
) )
from project.services.event_search import EventSearchParams from project.services.event_search import EventSearchParams
from project.views.event import get_event_category_choices, get_menu_user_rights from project.views.event import get_event_category_choices, get_menu_user_rights
from project.views.utils import flash_errors, track_analytics from project.views.utils import (
flash_errors,
get_calendar_links,
get_share_links,
track_analytics,
)
def prepare_event_date_form(form): def prepare_event_date_form(form):
@ -53,6 +61,10 @@ def event_date(id):
get_sd_for_event_date(event_date), indent=2, cls=DateTimeEncoder get_sd_for_event_date(event_date), indent=2, cls=DateTimeEncoder
) )
url = url_for("event_date", id=id, _external=True)
share_links = get_share_links(url, event_date.event.name)
calendar_links = get_calendar_links(event_date)
return render_template( return render_template(
"event_date/read.html", "event_date/read.html",
event_date=event_date, event_date=event_date,
@ -61,4 +73,21 @@ def event_date(id):
canonical_url=url_for("event_date", id=id, _external=True), canonical_url=url_for("event_date", id=id, _external=True),
user_rights=get_menu_user_rights(event_date.event), user_rights=get_menu_user_rights(event_date.event),
dates=get_upcoming_event_dates(event_date.event_id), dates=get_upcoming_event_dates(event_date.event_id),
share_links=share_links,
calendar_links=calendar_links,
)
@app.route("/eventdate/<int:id>/ical")
def event_date_ical(id):
event_date = get_event_date_with_details_or_404(id)
event = create_ical_event_for_date(event_date)
cal = create_icalendar()
cal.add_component(event)
return Response(
cal.to_ical(),
mimetype="text/calendar",
headers={"Content-disposition": f"attachment; filename=eventdate_{id}.ics"},
) )

View File

@ -1,3 +1,5 @@
from urllib.parse import quote_plus
from flask import Markup, flash, redirect, render_template, request, url_for from flask import Markup, flash, redirect, render_template, request, url_for
from flask_babelex import gettext from flask_babelex import gettext
from flask_mail import Message from flask_mail import Message
@ -5,7 +7,9 @@ from psycopg2.errorcodes import UNIQUE_VIOLATION
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from project import app, db, mail from project import app, db, mail
from project.models import Analytics from project.dateutils import gmt_tz
from project.models import Analytics, EventAttendanceMode, EventDate
from project.utils import get_place_str
def track_analytics(key, value1, value2): def track_analytics(key, value1, value2):
@ -112,3 +116,52 @@ def truncate(data: str, length: int) -> str:
return data return data
return (data[: length - 2] + "..") if len(data) > length else data return (data[: length - 2] + "..") if len(data) > length else data
def get_share_links(url: str, title: str) -> dict:
share_links = dict()
encoded_url = quote_plus(url)
encoded_title = quote_plus(title)
share_links[
"facebook"
] = f"https://www.facebook.com/sharer/sharer.php?u={encoded_url}"
share_links[
"twitter"
] = f"https://twitter.com/intent/tweet?url={encoded_url}&text={encoded_title}"
share_links["email"] = f"mailto:?subject={encoded_title}&body={encoded_url}"
share_links["whatsapp"] = f"whatsapp://send?text={encoded_url}"
share_links["telegram"] = f"https://t.me/share/url?url={encoded_url}"
share_links["url"] = url
return share_links
def get_calendar_links(event_date: EventDate) -> dict:
calendar_links = dict()
url = url_for("event_date", id=event_date.id, _external=True)
encoded_url = quote_plus(url)
encoded_title = quote_plus(event_date.event.name)
start = event_date.start.astimezone(gmt_tz).strftime("%Y%m%dT%H%M%SZ")
if event_date.end:
end = event_date.end.astimezone(gmt_tz).strftime("%Y%m%dT%H%M%SZ")
else:
end = start
if (
event_date.event.attendance_mode
and event_date.event.attendance_mode != EventAttendanceMode.online
):
location = get_place_str(event_date.event.event_place)
locationParam = f"&location={quote_plus(location)}"
else:
locationParam = ""
calendar_links[
"google"
] = f"http://www.google.com/calendar/event?action=TEMPLATE&text={encoded_title}&dates={start}/{end}&details={encoded_url}{locationParam}"
calendar_links["ics"] = url_for("event_date_ical", id=event_date.id, _external=True)
return calendar_links

View File

@ -4,6 +4,7 @@ apispec==4.0.0
apispec-webframeworks==0.5.2 apispec-webframeworks==0.5.2
appdirs==1.4.4 appdirs==1.4.4
argh==0.26.2 argh==0.26.2
arrow==0.14.7
attrs==20.3.0 attrs==20.3.0
Authlib==0.15.3 Authlib==0.15.3
Babel==2.9.0 Babel==2.9.0
@ -46,6 +47,7 @@ Flask-SQLAlchemy==2.4.4
Flask-WTF==0.14.3 Flask-WTF==0.14.3
GeoAlchemy2==0.8.4 GeoAlchemy2==0.8.4
gunicorn==20.0.4 gunicorn==20.0.4
icalendar==4.0.7
identify==1.5.10 identify==1.5.10
idna==2.10 idna==2.10
importlib-metadata==3.1.1 importlib-metadata==3.1.1
@ -97,6 +99,7 @@ speaklater==1.3
SQLAlchemy==1.3.20 SQLAlchemy==1.3.20
SQLAlchemy-Utils==0.36.8 SQLAlchemy-Utils==0.36.8
swagger-spec-validator==2.7.3 swagger-spec-validator==2.7.3
TatSu==4.4.0
toml==0.10.2 toml==0.10.2
typed-ast==1.4.1 typed-ast==1.4.1
typing-extensions==3.7.4.3 typing-extensions==3.7.4.3

View File

@ -176,8 +176,10 @@ class Seeder(object):
category = get_event_category(category_name) category = get_event_category(category_name)
return category.id return category.id
def create_event(self, admin_unit_id, recurrence_rule="", external_link=""): def create_event(
from project.models import Event self, admin_unit_id, recurrence_rule="", external_link="", end=None
):
from project.models import Event, EventAttendanceMode
from project.services.event import insert_event, upsert_event_category from project.services.event import insert_event, upsert_event_category
with self._app.app_context(): with self._app.app_context():
@ -187,6 +189,7 @@ class Seeder(object):
event.name = "Name" event.name = "Name"
event.description = "Beschreibung" event.description = "Beschreibung"
event.start = self.get_now_by_minute() event.start = self.get_now_by_minute()
event.end = end
event.event_place_id = self.upsert_default_event_place(admin_unit_id) event.event_place_id = self.upsert_default_event_place(admin_unit_id)
event.organizer_id = self.upsert_default_event_organizer(admin_unit_id) event.organizer_id = self.upsert_default_event_organizer(admin_unit_id)
event.recurrence_rule = recurrence_rule event.recurrence_rule = recurrence_rule
@ -194,6 +197,7 @@ class Seeder(object):
event.ticket_link = "" event.ticket_link = ""
event.tags = "" event.tags = ""
event.price_info = "" event.price_info = ""
event.attendance_mode = EventAttendanceMode.offline
insert_event(event) insert_event(event)
self._db.session.commit() self._db.session.commit()
event_id = event.id event_id = event.id

73
tests/test_utils.py Normal file
View File

@ -0,0 +1,73 @@
def test_get_location_str_none(client, seeder, app, utils):
from project.utils import get_location_str
location_str = get_location_str(None)
assert location_str == ""
def test_get_location_str_empty(client, seeder, app, utils):
from project.models import Location
from project.utils import get_location_str
location = Location()
location_str = get_location_str(location)
assert location_str == ""
def test_get_location_str_full(client, seeder, app, utils):
from project.models import Location
from project.utils import get_location_str
location = Location()
location.street = "Strasse"
location.postalCode = "PLZ"
location.city = "Ort"
location_str = get_location_str(location)
assert location_str == "Strasse, PLZ Ort"
def test_get_location_str_no_street(client, seeder, app, utils):
from project.models import Location
from project.utils import get_location_str
location = Location()
location.postalCode = "PLZ"
location.city = "Ort"
location_str = get_location_str(location)
assert location_str == "PLZ Ort"
def test_get_place_str_full(client, seeder, app, utils):
from project.models import EventPlace, Location
from project.utils import get_place_str
place = EventPlace()
place.name = "Name"
place.location = Location()
place.location.street = "Strasse"
place.location.postalCode = "PLZ"
place.location.city = "Ort"
place_str = get_place_str(place)
assert place_str == "Name, Strasse, PLZ Ort"
def test_get_place_str_none(client, seeder, app, utils):
from project.utils import get_place_str
place_str = get_place_str(None)
assert place_str == ""
def test_get_place_str_no_location(client, seeder, app, utils):
from project.models import EventPlace
from project.utils import get_place_str
place = EventPlace()
place.name = "Name"
place_str = get_place_str(place)
assert place_str == "Name"

View File

@ -1,6 +1,6 @@
def test_read(client, seeder, utils): def test_read(client, seeder, utils):
user_id, admin_unit_id = seeder.setup_base() user_id, admin_unit_id = seeder.setup_base()
seeder.create_event(admin_unit_id) seeder.create_event(admin_unit_id, end=seeder.get_now_by_minute())
url = utils.get_url("event_date", id=1) url = utils.get_url("event_date", id=1)
utils.get_ok(url) utils.get_ok(url)
@ -10,6 +10,14 @@ def test_read(client, seeder, utils):
utils.assert_response_redirect(response, "event_date", id=1) utils.assert_response_redirect(response, "event_date", id=1)
def test_ical(client, seeder, utils):
user_id, admin_unit_id = seeder.setup_base()
seeder.create_event(admin_unit_id, end=seeder.get_now_by_minute())
url = utils.get_url("event_date_ical", id=1)
utils.get_ok(url)
def test_list(client, seeder, utils): def test_list(client, seeder, utils):
user_id, admin_unit_id = seeder.setup_base() user_id, admin_unit_id = seeder.setup_base()
seeder.create_event(admin_unit_id) seeder.create_event(admin_unit_id)