mirror of
https://github.com/lucaspalomodevelop/eventcally.git
synced 2026-03-13 00:07:22 +00:00
AU mit Mitglieder-Einladungen, die Events anlegen können für Vereine
This commit is contained in:
parent
cbfc4a2669
commit
1f6ff9f2ee
303
app.py
303
app.py
@ -18,6 +18,7 @@ from urllib.parse import quote_plus
|
||||
from dateutil.rrule import rrulestr, rruleset, rrule
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from flask_qrcode import QRcode
|
||||
from flask_mail import Mail, Message
|
||||
|
||||
# Create app
|
||||
app = Flask(__name__)
|
||||
@ -47,6 +48,16 @@ app.jinja_env.filters['quote_plus'] = lambda u: quote_plus(u)
|
||||
# cors
|
||||
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})
|
||||
|
||||
# Mail
|
||||
app.config['MAIL_SERVER'] = 'smtp.gmail.com'
|
||||
app.config['MAIL_PORT'] = 587
|
||||
app.config['MAIL_USE_TLS'] = True
|
||||
app.config['MAIL_USE_SSL'] = False
|
||||
app.config['MAIL_USERNAME'] = 'oveda.app@gmail.com'
|
||||
app.config['MAIL_PASSWORD'] = 'UPF7ujUi2zfa22E-'
|
||||
app.config['MAIL_DEFAULT_SENDER'] = 'oveda.app@gmail.com'
|
||||
mail = Mail(app)
|
||||
|
||||
# create db
|
||||
db = SQLAlchemy(app)
|
||||
|
||||
@ -58,7 +69,7 @@ app.json_encoder = DateTimeEncoder
|
||||
|
||||
# Setup Flask-Security
|
||||
# Define models
|
||||
from models import Analytics, EventRejectionReason, EventReviewStatus, EventPlace, EventOrganizer, EventCategory, Image, OrgOrAdminUnit, Actor, Place, Location, User, Role, AdminUnit, AdminUnitMember, AdminUnitMemberRole, OrgMember, OrgMemberRole, Organization, AdminUnitOrg, AdminUnitOrgRole, Event, EventDate
|
||||
from models import AdminUnitMemberInvitation, Analytics, EventRejectionReason, EventReviewStatus, EventPlace, EventOrganizer, EventCategory, Image, OrgOrAdminUnit, Actor, Place, Location, User, Role, AdminUnit, AdminUnitMember, AdminUnitMemberRole, OrgMember, OrgMemberRole, Organization, AdminUnitOrg, AdminUnitOrgRole, Event, EventDate
|
||||
user_datastore = SQLAlchemySessionUserDatastore(db.session, User, Role)
|
||||
security = Security(app, user_datastore)
|
||||
from oauth import blueprint
|
||||
@ -103,6 +114,8 @@ def print_dynamic_texts():
|
||||
gettext('Event_Sports')
|
||||
gettext('Event_Other')
|
||||
gettext('Typical Age range')
|
||||
gettext('Administrator')
|
||||
gettext('Event expert')
|
||||
|
||||
def handleSqlError(e):
|
||||
message = str(e.__dict__['orig'])
|
||||
@ -120,6 +133,11 @@ def upsert_user(email, password="password"):
|
||||
result = user_datastore.create_user(email=email, password=hash_password(password))
|
||||
return result
|
||||
|
||||
def add_roles_to_user(user_name, role_names):
|
||||
user = upsert_user(user_name)
|
||||
for role_name in role_names:
|
||||
user_datastore.add_role_to_user(user, role_name)
|
||||
|
||||
def upsert_admin_unit(unit_name, short_name = None):
|
||||
admin_unit = AdminUnit.query.filter_by(name = unit_name).first()
|
||||
if admin_unit is None:
|
||||
@ -143,16 +161,28 @@ def upsert_org_member_role(role_name, permissions):
|
||||
result.add_permissions(permissions)
|
||||
return result
|
||||
|
||||
def upsert_admin_unit_member_role(role_name, permissions):
|
||||
def get_admin_unit_member_role(role_name):
|
||||
return AdminUnitMemberRole.query.filter_by(name = role_name).first()
|
||||
|
||||
def upsert_admin_unit_member_role(role_name, role_title, permissions):
|
||||
result = AdminUnitMemberRole.query.filter_by(name = role_name).first()
|
||||
if result is None:
|
||||
result = AdminUnitMemberRole(name = role_name)
|
||||
db.session.add(result)
|
||||
|
||||
result.title = role_title
|
||||
result.remove_permissions(result.get_permissions())
|
||||
result.add_permissions(permissions)
|
||||
return result
|
||||
|
||||
def upsert_user_role(role_name, role_title, permissions):
|
||||
role = user_datastore.find_or_create_role(role_name)
|
||||
role.title = role_title
|
||||
role.remove_permissions(role.get_permissions())
|
||||
role.add_permissions(permissions)
|
||||
return role
|
||||
|
||||
|
||||
def upsert_admin_unit_org_role(role_name, permissions):
|
||||
result = AdminUnitOrgRole.query.filter_by(name = role_name).first()
|
||||
if result is None:
|
||||
@ -179,6 +209,17 @@ def add_user_to_admin_unit(user, admin_unit):
|
||||
db.session.add(result)
|
||||
return result
|
||||
|
||||
def add_user_to_admin_unit_with_roles(user, admin_unit, role_names):
|
||||
member = add_user_to_admin_unit(current_user, admin_unit)
|
||||
add_roles_to_admin_unit_member(member, role_names)
|
||||
|
||||
return member
|
||||
|
||||
def add_roles_to_admin_unit_member(member, role_names):
|
||||
for role_name in role_names:
|
||||
role = get_admin_unit_member_role(role_name)
|
||||
add_role_to_admin_unit_member(member, role)
|
||||
|
||||
def add_organization_to_admin_unit(organization, admin_unit):
|
||||
result = AdminUnitOrg.query.with_parent(admin_unit).filter_by(organization_id = organization.id).first()
|
||||
if result is None:
|
||||
@ -595,18 +636,21 @@ def has_current_user_permissions_for_admin_unit_and_any_org(admin_unit_id, org_m
|
||||
|
||||
# Type permissions
|
||||
|
||||
def can_list_admin_unit_members(admin_unit):
|
||||
def has_current_user_permission_for_admin_unit(admin_unit, permission):
|
||||
if not current_user.is_authenticated:
|
||||
return False
|
||||
|
||||
if has_current_user_permission('admin_unit.members:read'):
|
||||
if has_current_user_permission(permission):
|
||||
return True
|
||||
|
||||
if has_current_user_member_permission_for_admin_unit(admin_unit.id, 'admin_unit.members:read'):
|
||||
if has_current_user_member_permission_for_admin_unit(admin_unit.id, permission):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def can_list_admin_unit_members(admin_unit):
|
||||
return has_current_user_permission_for_admin_unit(admin_unit, 'admin_unit.members:read')
|
||||
|
||||
def can_list_org_members(organization):
|
||||
if not current_user.is_authenticated:
|
||||
return False
|
||||
@ -734,7 +778,27 @@ def get_pagination_urls(pagination, **kwargs):
|
||||
|
||||
@app.before_first_request
|
||||
def create_initial_data():
|
||||
pass
|
||||
admin_permissions = [
|
||||
"admin_unit:update",
|
||||
"admin_unit.members:invite",
|
||||
"admin_unit.members:read",
|
||||
"admin_unit.members:update",
|
||||
"admin_unit.members:delete",
|
||||
"admin_unit.organizations.members:read"]
|
||||
event_permissions = [
|
||||
"event:verify",
|
||||
"event:create",
|
||||
"event_suggestion:read"]
|
||||
|
||||
upsert_admin_unit_member_role('admin', 'Administrator', admin_permissions)
|
||||
upsert_admin_unit_member_role('event_verifier', 'Event expert', event_permissions)
|
||||
|
||||
upsert_user_role('admin', 'Administrator', admin_permissions)
|
||||
upsert_user_role('event_verifier', 'Event expert', event_permissions)
|
||||
add_roles_to_user('grams.daniel@gmail.com', ['admin', 'event_verifier'])
|
||||
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def flash_errors(form):
|
||||
for field, errors in form.errors.items():
|
||||
@ -744,12 +808,20 @@ def flash_errors(form):
|
||||
error
|
||||
), 'danger')
|
||||
|
||||
def send_mail(recipient, subject, template, **context):
|
||||
msg = Message(subject)
|
||||
msg.recipients = [recipient]
|
||||
msg.body = render_template("email/%s.txt" % template, **context)
|
||||
msg.html = render_template("email/%s.html" % template, **context)
|
||||
mail.send(msg)
|
||||
|
||||
# Views
|
||||
@app.route("/")
|
||||
def home():
|
||||
if 'src' in request.args:
|
||||
track_analytics("home", '', request.args['src'])
|
||||
return redirect(url_for('home'))
|
||||
|
||||
return render_template('home.html')
|
||||
|
||||
@app.route("/example")
|
||||
@ -784,6 +856,39 @@ def admin_unit(admin_unit_id):
|
||||
can_list_admin_unit_members=can_list_admin_unit_members(admin_unit),
|
||||
can_update_admin_unit=has_current_user_permission('admin_unit:update'))
|
||||
|
||||
from forms.admin_unit_member import NegotiateAdminUnitMemberInvitationForm
|
||||
|
||||
@app.route('/invitations/<int:id>', methods=('GET', 'POST'))
|
||||
@auth_required()
|
||||
def admin_unit_member_invitation(id):
|
||||
invitation = AdminUnitMemberInvitation.query.get_or_404(id)
|
||||
|
||||
if invitation.email != current_user.email:
|
||||
return permission_missing(url_for('profile'))
|
||||
|
||||
form = NegotiateAdminUnitMemberInvitationForm()
|
||||
|
||||
if form.validate_on_submit():
|
||||
try:
|
||||
if form.accept.data:
|
||||
message = gettext('Invitation successfully accepted')
|
||||
roles = invitation.roles.split(',')
|
||||
add_user_to_admin_unit_with_roles(current_user, invitation.adminunit, roles)
|
||||
else:
|
||||
message = gettext('Invitation successfully declined')
|
||||
|
||||
db.session.delete(invitation)
|
||||
db.session.commit()
|
||||
flash(message, 'success')
|
||||
return redirect(url_for('manage'))
|
||||
except SQLAlchemyError as e:
|
||||
db.session.rollback()
|
||||
flash(handleSqlError(e), 'danger')
|
||||
|
||||
return render_template('invitation/read.html',
|
||||
form=form,
|
||||
invitation=invitation)
|
||||
|
||||
def update_admin_unit_with_form(admin_unit, form):
|
||||
form.populate_obj(admin_unit)
|
||||
|
||||
@ -920,11 +1025,7 @@ def admin_unit_create():
|
||||
upsert_org_or_admin_unit_for_admin_unit(admin_unit)
|
||||
|
||||
# Aktuellen Nutzer als Admin hinzufügen
|
||||
member = add_user_to_admin_unit(current_user, admin_unit)
|
||||
admin_unit_admin_role = upsert_admin_unit_member_role('admin', ["admin_unit.members:read", "admin_unit.organizations.members:read"])
|
||||
admin_unit_event_verifier_role = upsert_admin_unit_member_role('event_verifier', ["event:verify", "event:create", "event_suggestion:read"])
|
||||
add_role_to_admin_unit_member(member, admin_unit_admin_role)
|
||||
add_role_to_admin_unit_member(member, admin_unit_event_verifier_role)
|
||||
add_user_to_admin_unit_with_roles(current_user, admin_unit, ['admin', 'event_verifier'])
|
||||
db.session.commit()
|
||||
|
||||
# Organizer anlegen
|
||||
@ -979,10 +1080,13 @@ def image(id):
|
||||
@app.route("/profile")
|
||||
@auth_required()
|
||||
def profile():
|
||||
admin_unit_members = AdminUnitMember.query.filter_by(user_id = current_user.id).all() if current_user.is_authenticated else None
|
||||
organization_members = OrgMember.query.filter_by(user_id = current_user.id).all() if current_user.is_authenticated else None
|
||||
admin_unit_members = AdminUnitMember.query.filter_by(user_id = current_user.id).all()
|
||||
organization_members = None #OrgMember.query.filter_by(user_id = current_user.id).all()
|
||||
invitations = AdminUnitMemberInvitation.query.filter(AdminUnitMemberInvitation.email == current_user.email).all()
|
||||
|
||||
return render_template('profile.html',
|
||||
admin_unit_members=admin_unit_members,
|
||||
invitations=invitations,
|
||||
organization_members=organization_members)
|
||||
|
||||
@app.route("/places")
|
||||
@ -1201,6 +1305,7 @@ from forms.place import CreatePlaceForm, UpdatePlaceForm
|
||||
from forms.organization import CreateOrganizationForm, UpdateOrganizationForm
|
||||
from forms.organizer import CreateOrganizerForm, UpdateOrganizerForm, DeleteOrganizerForm
|
||||
from forms.admin_unit import CreateAdminUnitForm, UpdateAdminUnitForm
|
||||
from forms.admin_unit_member import InviteAdminUnitMemberForm
|
||||
|
||||
def update_event_with_form(event, form):
|
||||
form.populate_obj(event)
|
||||
@ -1377,16 +1482,17 @@ def admin_admin_units():
|
||||
admin_units=AdminUnit.query.all())
|
||||
|
||||
@app.route("/manage")
|
||||
@auth_required()
|
||||
def manage():
|
||||
admin_units = get_admin_units_for_manage()
|
||||
|
||||
# if len(admin_units) == 1:
|
||||
# return redirect(url_for('manage_admin_unit', id=admin_units[0].id))
|
||||
invitations = AdminUnitMemberInvitation.query.filter(AdminUnitMemberInvitation.email == current_user.email).all()
|
||||
|
||||
return render_template('manage/admin_units.html',
|
||||
invitations=invitations,
|
||||
admin_units=admin_units)
|
||||
|
||||
@app.route('/manage/admin_unit/<int:id>')
|
||||
@auth_required()
|
||||
def manage_admin_unit(id):
|
||||
admin_unit = get_admin_unit_for_manage_or_404(id)
|
||||
|
||||
@ -1396,6 +1502,7 @@ def manage_admin_unit(id):
|
||||
admin_unit=admin_unit)
|
||||
|
||||
@app.route('/manage/admin_unit/<int:id>/organizers')
|
||||
@auth_required()
|
||||
def manage_admin_unit_organizers(id):
|
||||
admin_unit = get_admin_unit_for_manage_or_404(id)
|
||||
organizers = EventOrganizer.query.filter(EventOrganizer.admin_unit_id == admin_unit.id).order_by(func.lower(EventOrganizer.name)).paginate()
|
||||
@ -1405,7 +1512,160 @@ def manage_admin_unit_organizers(id):
|
||||
organizers=organizers.items,
|
||||
pagination=get_pagination_urls(organizers, id=id))
|
||||
|
||||
def permission_missing(redirect_location):
|
||||
flash('You do not have permission for this action', 'danger')
|
||||
return redirect(redirect_location)
|
||||
|
||||
@app.route('/manage/admin_unit/<int:id>/members')
|
||||
@auth_required()
|
||||
def manage_admin_unit_members(id):
|
||||
admin_unit = get_admin_unit_for_manage_or_404(id)
|
||||
|
||||
if not has_current_user_permission_for_admin_unit(admin_unit, 'admin_unit.members:read'):
|
||||
return permission_missing(url_for('manage_admin_unit', id=id))
|
||||
|
||||
members = AdminUnitMember.query.join(User).filter(AdminUnitMember.admin_unit_id == admin_unit.id).order_by(func.lower(User.email)).paginate()
|
||||
invitations = AdminUnitMemberInvitation.query.filter(AdminUnitMember.admin_unit_id == admin_unit.id).order_by(func.lower(AdminUnitMemberInvitation.email)).all()
|
||||
|
||||
return render_template('manage/members.html',
|
||||
admin_unit=admin_unit,
|
||||
can_invite_users=has_current_user_permission_for_admin_unit(admin_unit, 'admin_unit.members:invite'),
|
||||
members=members.items,
|
||||
invitations=invitations,
|
||||
pagination=get_pagination_urls(members, id=id))
|
||||
|
||||
@app.route('/manage/admin_unit/<int:id>/members/invite', methods=('GET', 'POST'))
|
||||
@auth_required()
|
||||
def manage_admin_unit_member_invite(id):
|
||||
admin_unit = get_admin_unit_for_manage_or_404(id)
|
||||
|
||||
if not has_current_user_permission_for_admin_unit(admin_unit, 'admin_unit.members:invite'):
|
||||
return permission_missing(url_for('manage_admin_unit', id=admin_unit.id))
|
||||
|
||||
form = InviteAdminUnitMemberForm()
|
||||
form.roles.choices = [(c.name, gettext(c.title)) for c in AdminUnitMemberRole.query.order_by(AdminUnitMemberRole.id).all()]
|
||||
|
||||
if form.validate_on_submit():
|
||||
invitation = AdminUnitMemberInvitation()
|
||||
invitation.admin_unit_id = admin_unit.id
|
||||
form.populate_obj(invitation)
|
||||
invitation.roles = ','.join(form.roles.data)
|
||||
|
||||
try:
|
||||
db.session.add(invitation)
|
||||
db.session.commit()
|
||||
|
||||
send_mail(invitation.email,
|
||||
gettext('You have received an invitation'),
|
||||
'invitation_notice',
|
||||
invitation=invitation)
|
||||
|
||||
flash(gettext('Invitation successfully sent'), 'success')
|
||||
return redirect(url_for('manage_admin_unit_members', id=admin_unit.id))
|
||||
except SQLAlchemyError as e:
|
||||
db.session.rollback()
|
||||
flash(handleSqlError(e), 'danger')
|
||||
return render_template('admin_unit/invite_member.html',
|
||||
admin_unit=admin_unit,
|
||||
form=form)
|
||||
|
||||
from forms.admin_unit_member import DeleteAdminUnitMemberForm, UpdateAdminUnitMemberForm
|
||||
|
||||
@app.route('/manage/member/<int:id>/update', methods=('GET', 'POST'))
|
||||
@auth_required()
|
||||
def manage_admin_unit_member_update(id):
|
||||
member = AdminUnitMember.query.get_or_404(id)
|
||||
admin_unit = member.adminunit
|
||||
|
||||
if not has_current_user_permission_for_admin_unit(admin_unit, 'admin_unit.members:update'):
|
||||
return permission_missing(url_for('manage_admin_unit', id=admin_unit.id))
|
||||
|
||||
form = UpdateAdminUnitMemberForm()
|
||||
form.roles.choices = [(c.name, gettext(c.title)) for c in AdminUnitMemberRole.query.order_by(AdminUnitMemberRole.id).all()]
|
||||
|
||||
if form.validate_on_submit():
|
||||
member.roles.clear()
|
||||
add_roles_to_admin_unit_member(member, form.roles.data)
|
||||
|
||||
try:
|
||||
db.session.commit()
|
||||
flash(gettext('Member successfully updated'), 'success')
|
||||
return redirect(url_for('manage_admin_unit_members', id=admin_unit.id))
|
||||
except SQLAlchemyError as e:
|
||||
db.session.rollback()
|
||||
flash(handleSqlError(e), 'danger')
|
||||
else:
|
||||
form.roles.data = [c.name for c in member.roles]
|
||||
|
||||
return render_template('admin_unit/update_member.html',
|
||||
admin_unit=admin_unit,
|
||||
member=member,
|
||||
form=form)
|
||||
|
||||
@app.route('/manage/member/<int:id>/delete', methods=('GET', 'POST'))
|
||||
@auth_required()
|
||||
def manage_admin_unit_member_delete(id):
|
||||
member = AdminUnitMember.query.get_or_404(id)
|
||||
admin_unit = member.adminunit
|
||||
|
||||
if not has_current_user_permission_for_admin_unit(admin_unit, 'admin_unit.members:delete'):
|
||||
return permission_missing(url_for('manage_admin_unit', id=admin_unit.id))
|
||||
|
||||
form = DeleteAdminUnitMemberForm()
|
||||
|
||||
if form.validate_on_submit():
|
||||
if form.email.data != member.user.email:
|
||||
flash(gettext('Entered email does not match member email'), 'danger')
|
||||
else:
|
||||
try:
|
||||
db.session.delete(member)
|
||||
db.session.commit()
|
||||
flash(gettext('Member successfully deleted'), 'success')
|
||||
return redirect(url_for('manage_admin_unit_members', id=admin_unit.id))
|
||||
except SQLAlchemyError as e:
|
||||
db.session.rollback()
|
||||
flash(handleSqlError(e), 'danger')
|
||||
else:
|
||||
flash_errors(form)
|
||||
|
||||
return render_template('manage/delete_member.html',
|
||||
form=form,
|
||||
member=member)
|
||||
|
||||
from forms.admin_unit_member import DeleteAdminUnitInvitationForm
|
||||
|
||||
@app.route('/manage/invitation/<int:id>/delete', methods=('GET', 'POST'))
|
||||
@auth_required()
|
||||
def manage_admin_unit_invitation_delete(id):
|
||||
invitation = AdminUnitMemberInvitation.query.get_or_404(id)
|
||||
admin_unit = invitation.adminunit
|
||||
|
||||
if not has_current_user_permission_for_admin_unit(admin_unit, 'admin_unit.members:invite'):
|
||||
return permission_missing(url_for('manage_admin_unit', id=id))
|
||||
|
||||
form = DeleteAdminUnitInvitationForm()
|
||||
|
||||
if form.validate_on_submit():
|
||||
if form.email.data != invitation.email:
|
||||
flash(gettext('Entered email does not match invitation email'), 'danger')
|
||||
else:
|
||||
try:
|
||||
db.session.delete(invitation)
|
||||
db.session.commit()
|
||||
flash(gettext('Invitation successfully deleted'), 'success')
|
||||
return redirect(url_for('manage_admin_unit_members', id=admin_unit.id))
|
||||
except SQLAlchemyError as e:
|
||||
db.session.rollback()
|
||||
flash(handleSqlError(e), 'danger')
|
||||
else:
|
||||
flash_errors(form)
|
||||
|
||||
return render_template('manage/delete_invitation.html',
|
||||
form=form,
|
||||
invitation=invitation)
|
||||
|
||||
@app.route('/manage/admin_unit/<int:id>/event_places')
|
||||
@auth_required()
|
||||
def manage_admin_unit_event_places(id):
|
||||
admin_unit = get_admin_unit_for_manage_or_404(id)
|
||||
organizer = EventOrganizer.query.filter(EventOrganizer.admin_unit_id == admin_unit.id).order_by(func.lower(EventOrganizer.name)).first()
|
||||
@ -1419,6 +1679,7 @@ def manage_admin_unit_event_places(id):
|
||||
from forms.event_place import FindEventPlaceForm
|
||||
|
||||
@app.route('/manage/event_places')
|
||||
@auth_required()
|
||||
def manage_organizer_event_places():
|
||||
organizer = EventOrganizer.query.get_or_404(request.args.get('organizer_id'))
|
||||
admin_unit = get_admin_unit_for_manage_or_404(organizer.admin_unit_id)
|
||||
@ -1436,6 +1697,7 @@ def manage_organizer_event_places():
|
||||
pagination=get_pagination_urls(places))
|
||||
|
||||
@app.route('/manage/admin_unit/<int:id>/events')
|
||||
@auth_required()
|
||||
def manage_admin_unit_events(id):
|
||||
admin_unit = get_admin_unit_for_manage_or_404(id)
|
||||
organizer = EventOrganizer.query.filter(EventOrganizer.admin_unit_id == admin_unit.id).order_by(func.lower(EventOrganizer.name)).first()
|
||||
@ -1449,6 +1711,7 @@ def manage_admin_unit_events(id):
|
||||
from forms.event import FindEventForm
|
||||
|
||||
@app.route('/manage/events')
|
||||
@auth_required()
|
||||
def manage_organizer_events():
|
||||
organizer = EventOrganizer.query.get_or_404(request.args.get('organizer_id'))
|
||||
admin_unit = get_admin_unit_for_manage_or_404(organizer.admin_unit_id)
|
||||
@ -1474,6 +1737,7 @@ def manage_organizer_events():
|
||||
pagination=get_pagination_urls(events))
|
||||
|
||||
@app.route('/manage/admin_unit/<int:id>/reviews')
|
||||
@auth_required()
|
||||
def manage_admin_unit_event_reviews(id):
|
||||
admin_unit = get_admin_unit_for_manage_or_404(id)
|
||||
|
||||
@ -1490,6 +1754,7 @@ def manage_admin_unit_event_reviews(id):
|
||||
pagination = get_pagination_urls(events_paginate, id=id))
|
||||
|
||||
@app.route('/manage/admin_unit/<int:id>/widgets')
|
||||
@auth_required()
|
||||
def manage_admin_unit_widgets(id):
|
||||
admin_unit = get_admin_unit_for_manage_or_404(id)
|
||||
return render_template('manage/widgets.html', admin_unit=admin_unit)
|
||||
@ -1512,6 +1777,7 @@ def update_organizer_with_form(organizer, form):
|
||||
organizer.logo = upsert_image_with_data(organizer.logo, fs.read(), fs.content_type)
|
||||
|
||||
@app.route('/manage/admin_unit/<int:id>/organizers/create', methods=('GET', 'POST'))
|
||||
@auth_required()
|
||||
def manage_admin_unit_organizer_create(id):
|
||||
admin_unit = get_admin_unit_for_manage_or_404(id)
|
||||
|
||||
@ -1527,7 +1793,6 @@ def manage_admin_unit_organizer_create(id):
|
||||
db.session.add(organizer)
|
||||
db.session.commit()
|
||||
flash(gettext('Organizer successfully created'), 'success')
|
||||
#return redirect(url_for('organizer', id=organizer.id))
|
||||
return redirect(url_for('manage_admin_unit_organizers', id=organizer.admin_unit_id))
|
||||
except SQLAlchemyError as e:
|
||||
db.session.rollback()
|
||||
@ -1535,6 +1800,7 @@ def manage_admin_unit_organizer_create(id):
|
||||
return render_template('organizer/create.html', form=form)
|
||||
|
||||
@app.route('/organizer/<int:id>/update', methods=('GET', 'POST'))
|
||||
@auth_required()
|
||||
def organizer_update(id):
|
||||
organizer = EventOrganizer.query.get_or_404(id)
|
||||
|
||||
@ -1560,6 +1826,7 @@ def organizer_update(id):
|
||||
organizer=organizer)
|
||||
|
||||
@app.route('/organizer/<int:id>/delete', methods=('GET', 'POST'))
|
||||
@auth_required()
|
||||
def organizer_delete(id):
|
||||
organizer = EventOrganizer.query.get_or_404(id)
|
||||
|
||||
@ -1597,6 +1864,7 @@ def update_event_place_with_form(place, form):
|
||||
from forms.event_place import UpdateEventPlaceForm, CreateEventPlaceForm
|
||||
|
||||
@app.route('/event_place/<int:id>/update', methods=('GET', 'POST'))
|
||||
@auth_required()
|
||||
def event_place_update(id):
|
||||
place = EventPlace.query.get_or_404(id)
|
||||
|
||||
@ -1621,6 +1889,7 @@ def event_place_update(id):
|
||||
place=place)
|
||||
|
||||
@app.route('/manage/organizer/<int:id>/places/create', methods=('GET', 'POST'))
|
||||
@auth_required()
|
||||
def manage_organizer_places_create(id):
|
||||
organizer = EventOrganizer.query.get_or_404(id)
|
||||
|
||||
|
||||
31
forms/admin_unit_member.py
Normal file
31
forms/admin_unit_member.py
Normal file
@ -0,0 +1,31 @@
|
||||
from flask_babelex import lazy_gettext
|
||||
from flask_wtf import FlaskForm
|
||||
from flask_wtf.file import FileField, FileAllowed
|
||||
from wtforms import StringField, SubmitField, DecimalField, TextAreaField, FormField, SelectField
|
||||
from wtforms.fields.html5 import EmailField, TelField
|
||||
from wtforms.validators import DataRequired, Optional, Regexp
|
||||
import decimal
|
||||
from models import Location
|
||||
from .widgets import MultiCheckboxField
|
||||
|
||||
class InviteAdminUnitMemberForm(FlaskForm):
|
||||
email = EmailField(lazy_gettext('Email'), validators=[DataRequired()])
|
||||
roles = MultiCheckboxField(lazy_gettext('Roles'))
|
||||
submit = SubmitField(lazy_gettext("Invite"))
|
||||
|
||||
class NegotiateAdminUnitMemberInvitationForm(FlaskForm):
|
||||
accept = SubmitField(lazy_gettext("Accept"))
|
||||
decline = SubmitField(lazy_gettext("Decline"))
|
||||
|
||||
class DeleteAdminUnitInvitationForm(FlaskForm):
|
||||
submit = SubmitField(lazy_gettext("Delete invitation"))
|
||||
email = EmailField(lazy_gettext('Email'), validators=[DataRequired()])
|
||||
|
||||
class DeleteAdminUnitMemberForm(FlaskForm):
|
||||
submit = SubmitField(lazy_gettext("Delete member"))
|
||||
email = EmailField(lazy_gettext('Email'), validators=[DataRequired()])
|
||||
|
||||
class UpdateAdminUnitMemberForm(FlaskForm):
|
||||
roles = MultiCheckboxField(lazy_gettext('Roles'))
|
||||
submit = SubmitField(lazy_gettext("Update member"))
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
from wtforms import DateTimeField
|
||||
from wtforms.widgets import html_params, HTMLString
|
||||
from wtforms import DateTimeField, SelectMultipleField
|
||||
from wtforms.widgets import html_params, HTMLString, ListWidget, CheckboxInput
|
||||
import pytz
|
||||
from datetime import datetime
|
||||
from flask_babelex import to_user_timezone
|
||||
|
||||
class MultiCheckboxField(SelectMultipleField):
|
||||
widget = ListWidget(prefix_label=False)
|
||||
option_widget = CheckboxInput()
|
||||
|
||||
def create_option_string(count, value):
|
||||
result = ""
|
||||
for i in range(count):
|
||||
|
||||
38
migrations/versions/8f4df40a36f3_.py
Normal file
38
migrations/versions/8f4df40a36f3_.py
Normal file
@ -0,0 +1,38 @@
|
||||
"""empty message
|
||||
|
||||
Revision ID: 8f4df40a36f3
|
||||
Revises: f71c86333bfb
|
||||
Create Date: 2020-09-24 18:53:02.861732
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import sqlalchemy_utils
|
||||
import db
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '8f4df40a36f3'
|
||||
down_revision = 'f71c86333bfb'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('adminunitmemberinvitation',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('admin_unit_id', sa.Integer(), nullable=False),
|
||||
sa.Column('email', sa.String(length=255), nullable=True),
|
||||
sa.Column('roles', sa.UnicodeText(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('email', 'admin_unit_id')
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table('adminunitmemberinvitation')
|
||||
# ### end Alembic commands ###
|
||||
32
migrations/versions/a8c662c46047_.py
Normal file
32
migrations/versions/a8c662c46047_.py
Normal file
@ -0,0 +1,32 @@
|
||||
"""empty message
|
||||
|
||||
Revision ID: a8c662c46047
|
||||
Revises: 8f4df40a36f3
|
||||
Create Date: 2020-09-25 11:26:03.139800
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import sqlalchemy_utils
|
||||
import db
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'a8c662c46047'
|
||||
down_revision = '8f4df40a36f3'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('adminunitmemberrole', sa.Column('title', sa.Unicode(length=255), nullable=True))
|
||||
op.add_column('role', sa.Column('title', sa.Unicode(length=255), nullable=True))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('role', 'title')
|
||||
op.drop_column('adminunitmemberrole', 'title')
|
||||
# ### end Alembic commands ###
|
||||
14
models.py
14
models.py
@ -45,6 +45,7 @@ class Role(db.Model, RoleMixin):
|
||||
__tablename__ = 'role'
|
||||
id = Column(Integer(), primary_key=True)
|
||||
name = Column(String(80), unique=True)
|
||||
title = Column(Unicode(255))
|
||||
description = Column(String(255))
|
||||
permissions = Column(UnicodeText())
|
||||
|
||||
@ -122,6 +123,7 @@ class AdminUnitMemberRole(db.Model, RoleMixin):
|
||||
__tablename__ = 'adminunitmemberrole'
|
||||
id = Column(Integer(), primary_key=True)
|
||||
name = Column(String(80), unique=True)
|
||||
title = Column(Unicode(255))
|
||||
description = Column(String(255))
|
||||
permissions = Column(UnicodeText())
|
||||
|
||||
@ -132,8 +134,19 @@ class AdminUnitMember(db.Model):
|
||||
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
||||
user = db.relationship('User', backref=db.backref('adminunitmembers', lazy=True))
|
||||
roles = relationship('AdminUnitMemberRole', secondary='adminunitmemberroles_members',
|
||||
order_by="AdminUnitMemberRole.id",
|
||||
backref=backref('members', lazy='dynamic'))
|
||||
|
||||
class AdminUnitMemberInvitation(db.Model):
|
||||
__tablename__ = 'adminunitmemberinvitation'
|
||||
__table_args__ = (
|
||||
UniqueConstraint('email', 'admin_unit_id'),
|
||||
)
|
||||
id = Column(Integer(), primary_key=True)
|
||||
admin_unit_id = db.Column(db.Integer, db.ForeignKey('adminunit.id'), nullable=False)
|
||||
email = Column(String(255))
|
||||
roles = Column(UnicodeText())
|
||||
|
||||
class AdminUnitOrgRoleOrganizations(db.Model):
|
||||
__tablename__ = 'adminunitorgroles_organizations'
|
||||
id = Column(Integer(), primary_key=True)
|
||||
@ -162,6 +175,7 @@ class AdminUnit(db.Model, TrackableMixin):
|
||||
name = Column(Unicode(255), unique=True)
|
||||
short_name = Column(Unicode(100), unique=True)
|
||||
members = relationship('AdminUnitMember', backref=backref('adminunit', lazy=True))
|
||||
invitations = relationship('AdminUnitMemberInvitation', backref=backref('adminunit', lazy=True))
|
||||
organizations = relationship('AdminUnitOrg', backref=backref('adminunit', lazy=True))
|
||||
event_organizers = relationship('EventOrganizer', backref=backref('adminunit', lazy=True))
|
||||
event_places = relationship('EventPlace', backref=backref('adminunit', lazy=True))
|
||||
|
||||
@ -9,7 +9,18 @@
|
||||
{% set field_class = field_class + ' is-invalid' %}
|
||||
{% endif %}
|
||||
|
||||
{{ field(class=field_class, **kwargs)|safe }}
|
||||
{% if 'ri' in kwargs and kwargs['ri'] == 'multicheckbox' %}
|
||||
<fieldset class="form-group">
|
||||
{% for choice in field %}
|
||||
<div class="form-check">
|
||||
{{ choice(class="form-check-input") }}
|
||||
{{ choice.label(class="form-check-label") }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
{% else %}
|
||||
{{ field(class=field_class, **kwargs)|safe }}
|
||||
{% endif %}
|
||||
|
||||
{% if 'ri' in kwargs %}
|
||||
{% if kwargs['ri'] == 'rrule' %}
|
||||
@ -475,6 +486,7 @@
|
||||
{{ render_tab('events', _('Events'), url_for('manage_admin_unit_events', id=admin_unit.id), active_id) }}
|
||||
{{ render_tab('organizers', _('Organizers'), url_for('manage_admin_unit_organizers', id=admin_unit.id), active_id) }}
|
||||
{{ render_tab('places', _('Places'), url_for('manage_admin_unit_event_places', id=admin_unit.id), active_id) }}
|
||||
{{ render_tab('members', _('Members'), url_for('manage_admin_unit_members', id=admin_unit.id), active_id) }}
|
||||
{{ render_tab('widgets', _('Widgets'), url_for('manage_admin_unit_widgets', id=admin_unit.id), active_id) }}
|
||||
</ul>
|
||||
{% endmacro %}
|
||||
@ -527,4 +539,10 @@ $( function() {
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_roles(roles) %}
|
||||
{% if roles %}
|
||||
{% for role in roles %}{{ _(role.title) }}{%if not loop.last %}, {% endif %}{% endfor %}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
24
templates/admin_unit/invite_member.html
Normal file
24
templates/admin_unit/invite_member.html
Normal file
@ -0,0 +1,24 @@
|
||||
{% extends "layout.html" %}
|
||||
{% from "_macros.html" import render_manage_menu, render_field_with_errors, render_field %}
|
||||
{% block content %}
|
||||
|
||||
<h1>{{ admin_unit.name }}</h1>
|
||||
|
||||
{{ render_manage_menu(admin_unit, 'members') }}
|
||||
|
||||
<h2>{{ _('Invite user') }}</h2>
|
||||
<form action="" method="POST">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
{{ render_field_with_errors(form.email) }}
|
||||
{{ render_field_with_errors(form.roles, ri="multicheckbox") }}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ render_field(form.submit) }}
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
@ -1,5 +1,5 @@
|
||||
{% extends "layout.html" %}
|
||||
{% from "_macros.html" import render_string_prop, render_logo, render_phone_prop, render_fax_prop, render_email_prop, render_events, render_location_prop, render_link_prop, render_image %}
|
||||
{% from "_macros.html" import render_roles, render_string_prop, render_logo, render_phone_prop, render_fax_prop, render_email_prop, render_events, render_location_prop, render_link_prop, render_image %}
|
||||
{% block title %}
|
||||
{{ admin_unit.name }}
|
||||
{% endblock %}
|
||||
@ -71,7 +71,7 @@
|
||||
{% for member in admin_unit.members %}
|
||||
<tr>
|
||||
<td>{{ member.user.email }}</td>
|
||||
<td>{% for role in member.roles %}{{ role.name }}{%if not loop.last %}, {% endif %}{% endfor %}</td>
|
||||
<td>{{ render_roles(member.roles)}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
@ -93,7 +93,7 @@
|
||||
{% for admin_unit_org in admin_unit.organizations %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('organization', organization_id=admin_unit_org.organization_id) }}">{{ admin_unit_org.organization.name }}</a></td>
|
||||
<td>{% for role in admin_unit_org.roles %}{{ role.name }}{%if not loop.last %}, {% endif %}{% endfor %}</td>
|
||||
<td>{{ render_roles(admin_unit_org.roles)}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
25
templates/admin_unit/update_member.html
Normal file
25
templates/admin_unit/update_member.html
Normal file
@ -0,0 +1,25 @@
|
||||
{% extends "layout.html" %}
|
||||
{% from "_macros.html" import render_manage_menu, render_field_with_errors, render_field %}
|
||||
{% block content %}
|
||||
|
||||
<h1>{{ admin_unit.name }}</h1>
|
||||
|
||||
{{ render_manage_menu(admin_unit, 'members') }}
|
||||
|
||||
<h2>{{ _('Update member') }}</h2>
|
||||
<form action="" method="POST">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
{{ member.user.email }}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{{ render_field_with_errors(form.roles, ri="multicheckbox") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ render_field(form.submit) }}
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
19
templates/email/invitation_notice.html
Normal file
19
templates/email/invitation_notice.html
Normal file
@ -0,0 +1,19 @@
|
||||
{% extends "email/layout.html" %}
|
||||
{% block content %}
|
||||
<p>{{ _('You have been invited to join %(admin_unit_name)s.', admin_unit_name=invitation.adminunit.name) }}</p>
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="btn btn-primary">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td> <a href="{{ url_for('admin_unit_member_invitation', id=invitation.id, _external=True) }}" target="_blank">{{ _('Click here to view the invitation') }}</a> </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
||||
3
templates/email/invitation_notice.txt
Normal file
3
templates/email/invitation_notice.txt
Normal file
@ -0,0 +1,3 @@
|
||||
{{ _('You have been invited to join %(admin_unit_name)s.', admin_unit_name=invitation.adminunit.name) }}
|
||||
{{ _('Click the link below to view the invitation') }}
|
||||
{{ url_for('admin_unit_member_invitation', id=invitation.id, _external=True) }}
|
||||
382
templates/email/layout.html
Normal file
382
templates/email/layout.html
Normal file
@ -0,0 +1,382 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>Email</title>
|
||||
<style>
|
||||
/* -------------------------------------
|
||||
GLOBAL RESETS
|
||||
------------------------------------- */
|
||||
|
||||
/*All the styling goes here*/
|
||||
|
||||
img {
|
||||
border: none;
|
||||
-ms-interpolation-mode: bicubic;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #f6f6f6;
|
||||
font-family: sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: separate;
|
||||
mso-table-lspace: 0pt;
|
||||
mso-table-rspace: 0pt;
|
||||
width: 100%; }
|
||||
table td {
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
BODY & CONTAINER
|
||||
------------------------------------- */
|
||||
|
||||
.body {
|
||||
background-color: #f6f6f6;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
|
||||
.container {
|
||||
display: block;
|
||||
margin: 0 auto !important;
|
||||
/* makes it centered */
|
||||
max-width: 580px;
|
||||
padding: 10px;
|
||||
width: 580px;
|
||||
}
|
||||
|
||||
/* This should also be a block element, so that it will fill 100% of the .container */
|
||||
.content {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-width: 580px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
HEADER, FOOTER, MAIN
|
||||
------------------------------------- */
|
||||
.main {
|
||||
background: #ffffff;
|
||||
border-radius: 3px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.content-block {
|
||||
padding-bottom: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
clear: both;
|
||||
margin-top: 10px;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
.footer td,
|
||||
.footer p,
|
||||
.footer span,
|
||||
.footer a {
|
||||
color: #999999;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
TYPOGRAPHY
|
||||
------------------------------------- */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
color: #000000;
|
||||
font-family: sans-serif;
|
||||
font-weight: 400;
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 35px;
|
||||
font-weight: 300;
|
||||
text-align: center;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
p,
|
||||
ul,
|
||||
ol {
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
p li,
|
||||
ul li,
|
||||
ol li {
|
||||
list-style-position: inside;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #3498db;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
BUTTONS
|
||||
------------------------------------- */
|
||||
.btn {
|
||||
box-sizing: border-box;
|
||||
width: 100%; }
|
||||
.btn > tbody > tr > td {
|
||||
padding-bottom: 15px; }
|
||||
.btn table {
|
||||
width: auto;
|
||||
}
|
||||
.btn table td {
|
||||
background-color: #ffffff;
|
||||
border-radius: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
.btn a {
|
||||
background-color: #ffffff;
|
||||
border: solid 1px #3498db;
|
||||
border-radius: 5px;
|
||||
box-sizing: border-box;
|
||||
color: #3498db;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 12px 25px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.btn-primary table td {
|
||||
background-color: #3498db;
|
||||
}
|
||||
|
||||
.btn-primary a {
|
||||
background-color: #3498db;
|
||||
border-color: #3498db;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
OTHER STYLES THAT MIGHT BE USEFUL
|
||||
------------------------------------- */
|
||||
.last {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.first {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.align-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.align-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.mt0 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.mb0 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.preheader {
|
||||
color: transparent;
|
||||
display: none;
|
||||
height: 0;
|
||||
max-height: 0;
|
||||
max-width: 0;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
mso-hide: all;
|
||||
visibility: hidden;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.powered-by a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
border-bottom: 1px solid #f6f6f6;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
RESPONSIVE AND MOBILE FRIENDLY STYLES
|
||||
------------------------------------- */
|
||||
@media only screen and (max-width: 620px) {
|
||||
table[class=body] h1 {
|
||||
font-size: 28px !important;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
table[class=body] p,
|
||||
table[class=body] ul,
|
||||
table[class=body] ol,
|
||||
table[class=body] td,
|
||||
table[class=body] span,
|
||||
table[class=body] a {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
table[class=body] .wrapper,
|
||||
table[class=body] .article {
|
||||
padding: 10px !important;
|
||||
}
|
||||
table[class=body] .content {
|
||||
padding: 0 !important;
|
||||
}
|
||||
table[class=body] .container {
|
||||
padding: 0 !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
table[class=body] .main {
|
||||
border-left-width: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
border-right-width: 0 !important;
|
||||
}
|
||||
table[class=body] .btn table {
|
||||
width: 100% !important;
|
||||
}
|
||||
table[class=body] .btn a {
|
||||
width: 100% !important;
|
||||
}
|
||||
table[class=body] .img-responsive {
|
||||
height: auto !important;
|
||||
max-width: 100% !important;
|
||||
width: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
PRESERVE THESE STYLES IN THE HEAD
|
||||
------------------------------------- */
|
||||
@media all {
|
||||
.ExternalClass {
|
||||
width: 100%;
|
||||
}
|
||||
.ExternalClass,
|
||||
.ExternalClass p,
|
||||
.ExternalClass span,
|
||||
.ExternalClass font,
|
||||
.ExternalClass td,
|
||||
.ExternalClass div {
|
||||
line-height: 100%;
|
||||
}
|
||||
.apple-link a {
|
||||
color: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-size: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
line-height: inherit !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
#MessageViewBody a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
font-size: inherit;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
.btn-primary table td:hover {
|
||||
background-color: #34495e !important;
|
||||
}
|
||||
.btn-primary a:hover {
|
||||
background-color: #34495e !important;
|
||||
border-color: #34495e !important;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body class="">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td class="container">
|
||||
<div class="content">
|
||||
|
||||
<!-- START CENTERED WHITE CONTAINER -->
|
||||
<table role="presentation" class="main">
|
||||
|
||||
<!-- START MAIN CONTENT AREA -->
|
||||
<tr>
|
||||
<td class="wrapper">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td>
|
||||
<p>{{ _('Hi there') }},</p>
|
||||
<p>{{ _('this is a message from Oveda - Die offene Veranstaltungsdatenbank.') }}</p>
|
||||
{% block content -%}
|
||||
{%- endblock content %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- END MAIN CONTENT AREA -->
|
||||
</table>
|
||||
<!-- END CENTERED WHITE CONTAINER -->
|
||||
|
||||
<!-- START FOOTER -->
|
||||
<div class="footer">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
<span class="apple-link">Oveda - Die offene Veranstaltungsdatenbank</span>.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<!-- END FOOTER -->
|
||||
|
||||
</div>
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@ -22,7 +22,7 @@ oveda - Offene Veranstaltungsdatenbank
|
||||
<form>
|
||||
<div class="form-row">
|
||||
<div class="col-12">
|
||||
<a class="btn btn-primary btn-lg" href="{{ url_for('security.register') }}" role="button">Kostenlos registrieren</a>
|
||||
<a class="btn btn-primary btn-lg" href="{{ url_for('security.register') }}" role="button">{{ _('Register for free') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -138,7 +138,7 @@ oveda - Offene Veranstaltungsdatenbank
|
||||
<form>
|
||||
<div class="form-row mb-4">
|
||||
<div class="col-12">
|
||||
<a class="btn btn-primary btn-lg" href="{{ url_for('security.register') }}" role="button">Kostenlos registrieren</a>
|
||||
<a class="btn btn-primary btn-lg" href="{{ url_for('security.register') }}" role="button">{{ _('Register for free') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
|
||||
27
templates/invitation/read.html
Normal file
27
templates/invitation/read.html
Normal file
@ -0,0 +1,27 @@
|
||||
{% extends "layout.html" %}
|
||||
{% from "_macros.html" import render_field %}
|
||||
{% block title %}
|
||||
{{ _('Invitation') }}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<h1>{{ _('Invitation') }}</h1>
|
||||
|
||||
<p>{{ _('Would you like to accept the invitation from %(name)s?', name=invitation.adminunit.name) }}</p>
|
||||
|
||||
<form action="" method="POST">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-auto">
|
||||
{{ render_field(form.accept, class='btn btn-success') }}
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
{{ render_field(form.decline, class='btn btn-secondary') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
@ -4,11 +4,21 @@
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
{% if invitations %}
|
||||
<h2>{{ _('Invitations') }}</h2>
|
||||
<div class="list-group">
|
||||
{% for invitation in invitations %}
|
||||
<a href="{{ url_for('admin_unit_member_invitation', id=invitation.id) }}" class="list-group-item list-group-item-action">{{ invitation.adminunit.name }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<h2>{{ _('Admin Units') }}</h2>
|
||||
<div class="my-4">
|
||||
<a class="btn btn-outline-secondary my-1" href="{{ url_for('admin_unit_create') }}" role="button"><i class="fa fa-plus"></i> {{ _('Create admin unit') }}</a>
|
||||
</div>
|
||||
|
||||
<div class="list-group list-group-flush">
|
||||
<div class="list-group">
|
||||
{% for admin_unit in admin_units %}
|
||||
<a href="{{ url_for('manage_admin_unit', id=admin_unit.id) }}" class="list-group-item list-group-item-action">{{ admin_unit.name }}</a>
|
||||
{% endfor %}
|
||||
|
||||
24
templates/manage/delete_invitation.html
Normal file
24
templates/manage/delete_invitation.html
Normal file
@ -0,0 +1,24 @@
|
||||
{% extends "layout.html" %}
|
||||
{% from "_macros.html" import render_field_with_errors, render_field %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h1>{{ _('Delete invitation') }} "{{ invitation.email }}"</h1>
|
||||
|
||||
<form action="" method="POST">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
{{ _('Invitation') }}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{{ render_field_with_errors(form.email) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ render_field(form.submit) }}
|
||||
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
24
templates/manage/delete_member.html
Normal file
24
templates/manage/delete_member.html
Normal file
@ -0,0 +1,24 @@
|
||||
{% extends "layout.html" %}
|
||||
{% from "_macros.html" import render_field_with_errors, render_field %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h1>{{ _('Delete member') }} "{{ member.user.email }}"</h1>
|
||||
|
||||
<form action="" method="POST">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
{{ _('Member') }}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{{ render_field_with_errors(form.email) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ render_field(form.submit) }}
|
||||
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
49
templates/manage/members.html
Normal file
49
templates/manage/members.html
Normal file
@ -0,0 +1,49 @@
|
||||
{% extends "layout.html" %}
|
||||
{% from "_macros.html" import render_roles, render_pagination, render_event_organizer, render_manage_menu %}
|
||||
{% block title %}
|
||||
{{ _('Members') }}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<h1>{{ admin_unit.name }}</h1>
|
||||
|
||||
{{ render_manage_menu(admin_unit, 'members') }}
|
||||
|
||||
<h2>{{ _('Invitations') }}</h2>
|
||||
<div class="my-4">
|
||||
{% if can_invite_users %}
|
||||
<a class="btn btn-outline-secondary my-1" href="{{ url_for('manage_admin_unit_member_invite', id=admin_unit.id) }}" role="button"><i class="fa fa-plus"></i> {{ _('Invite user') }}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
{% for invitation in invitations %}
|
||||
<li class="list-group-item">
|
||||
<div class="dropdown d-inline-block">
|
||||
<button class="btn btn-link dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{ invitation.email }}</button>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="{{ url_for('manage_admin_unit_invitation_delete', id=invitation.id) }}">{{ _('Delete') }}...</a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<h2>{{ _('Members') }}</h2>
|
||||
<ul class="list-group">
|
||||
{% for member in members %}
|
||||
<li class="list-group-item">
|
||||
<div class="dropdown d-inline-block">
|
||||
<button class="btn btn-link dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{ member.user.email }}</button>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="{{ url_for('manage_admin_unit_member_update', id=member.id) }}">{{ _('Edit') }}</a>
|
||||
<a class="dropdown-item" href="{{ url_for('manage_admin_unit_member_delete', id=member.id) }}">{{ _('Delete') }}...</a>
|
||||
</div>
|
||||
</div>
|
||||
<small>{{ render_roles(member.roles)}}</small>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<div class="my-4">{{ render_pagination(pagination) }}</div>
|
||||
|
||||
{% endblock %}
|
||||
@ -1,5 +1,5 @@
|
||||
{% extends "layout.html" %}
|
||||
{% from "_macros.html" import render_string_prop, render_logo, render_phone_prop, render_fax_prop, render_email_prop, render_events, render_location_prop, render_link_prop, render_image %}
|
||||
{% from "_macros.html" import render_rolesm render_string_prop, render_logo, render_phone_prop, render_fax_prop, render_email_prop, render_events, render_location_prop, render_link_prop, render_image %}
|
||||
{% block title %}
|
||||
{{ organization.name }}
|
||||
{% endblock %}
|
||||
@ -69,7 +69,7 @@
|
||||
{% for member in organization.members %}
|
||||
<tr>
|
||||
<td>{{ member.user.email }}</td>
|
||||
<td>{% for role in member.roles %}{{ role.name }}{%if not loop.last %}, {% endif %}{% endfor %}</td>
|
||||
<td>{{ render_roles(member.roles)}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
{% extends "layout.html" %}
|
||||
{% from "_macros.html" import render_roles %}
|
||||
{% block title %}
|
||||
{{ _('Profile') }}
|
||||
{% endblock %}
|
||||
@ -6,6 +7,26 @@
|
||||
|
||||
<h1>{{ current_user.email }}</h1>
|
||||
|
||||
{% if invitations %}
|
||||
<h2>{{ _('Invitations') }}</h2>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm table-bordered table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ _('Name') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for invitation in invitations %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('admin_unit_member_invitation', id=invitation.id) }}">{{ invitation.adminunit.name }}</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if admin_unit_members %}
|
||||
<h2>{{ _('Admin Units') }}</h2>
|
||||
<div class="table-responsive">
|
||||
@ -19,8 +40,8 @@
|
||||
<tbody>
|
||||
{% for member in admin_unit_members %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('admin_unit', admin_unit_id=member.adminunit.id) }}">{{ member.adminunit.name }}</a></td>
|
||||
<td>{% for role in member.roles %}{{ role.name }}{%if not loop.last %}, {% endif %}{% endfor %}</td>
|
||||
<td><a href="{{ url_for('manage_admin_unit', id=member.adminunit.id) }}">{{ member.adminunit.name }}</a></td>
|
||||
<td>{{ render_roles(member.roles)}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
@ -42,7 +63,7 @@
|
||||
{% for member in organization_members %}
|
||||
<tr>
|
||||
<td>{{ member.organization.name }}</td>
|
||||
<td>{% for role in member.roles %}{{ role.name }}{%if not loop.last %}, {% endif %}{% endfor %}</td>
|
||||
<td>{{ render_roles(member.roles)}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
@ -18,8 +18,16 @@
|
||||
{{ render_field(login_user_form.submit) }}
|
||||
</form>
|
||||
|
||||
<hr class="my-4">
|
||||
|
||||
{{ render_google_sign_in_button() }}
|
||||
<div class="card" class="my-4">
|
||||
<div class="card-body">
|
||||
<p class="card-text">{{ _('You do not have an account yet? Not a problem!') }}</p>
|
||||
<div class="my-2">
|
||||
<a href="{{ url_for_security('register') }}" class="btn btn-dark"><i class="fa fa-user-plus mr-2"></i> {{ _('Register for free') }}</a>
|
||||
</div>
|
||||
<div class="my-2">
|
||||
{{ render_google_sign_in_button() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
Binary file not shown.
@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2020-09-16 15:18+0200\n"
|
||||
"POT-Creation-Date: 2020-09-26 13:22+0200\n"
|
||||
"PO-Revision-Date: 2020-06-07 18:51+0200\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: de\n"
|
||||
@ -18,152 +18,196 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.8.0\n"
|
||||
|
||||
#: app.py:73
|
||||
#: app.py:88
|
||||
msgid "Event_"
|
||||
msgstr "Event_"
|
||||
|
||||
#: app.py:78
|
||||
#: app.py:93
|
||||
msgid "."
|
||||
msgstr "."
|
||||
|
||||
#: app.py:83
|
||||
#: app.py:98
|
||||
msgid "Event_Art"
|
||||
msgstr "Kunst"
|
||||
|
||||
#: app.py:84
|
||||
#: app.py:99
|
||||
msgid "Event_Book"
|
||||
msgstr "Literatur"
|
||||
|
||||
#: app.py:85
|
||||
#: app.py:100
|
||||
msgid "Event_Movie"
|
||||
msgstr "Film"
|
||||
|
||||
#: app.py:86
|
||||
#: app.py:101
|
||||
msgid "Event_Family"
|
||||
msgstr "Familie"
|
||||
|
||||
#: app.py:87
|
||||
#: app.py:102
|
||||
msgid "Event_Festival"
|
||||
msgstr "Festival"
|
||||
|
||||
#: app.py:88
|
||||
#: app.py:103
|
||||
msgid "Event_Religious"
|
||||
msgstr "Religion"
|
||||
|
||||
#: app.py:89
|
||||
#: app.py:104
|
||||
msgid "Event_Shopping"
|
||||
msgstr "Shopping"
|
||||
|
||||
#: app.py:90
|
||||
#: app.py:105
|
||||
msgid "Event_Comedy"
|
||||
msgstr "Comedy"
|
||||
|
||||
#: app.py:91
|
||||
#: app.py:106
|
||||
msgid "Event_Music"
|
||||
msgstr "Musik"
|
||||
|
||||
#: app.py:92
|
||||
#: app.py:107
|
||||
msgid "Event_Dance"
|
||||
msgstr "Tanz"
|
||||
|
||||
#: app.py:93
|
||||
#: app.py:108
|
||||
msgid "Event_Nightlife"
|
||||
msgstr "Party"
|
||||
|
||||
#: app.py:94
|
||||
#: app.py:109
|
||||
msgid "Event_Theater"
|
||||
msgstr "Theater"
|
||||
|
||||
#: app.py:95
|
||||
#: app.py:110
|
||||
msgid "Event_Dining"
|
||||
msgstr "Essen"
|
||||
|
||||
#: app.py:96
|
||||
#: app.py:111
|
||||
msgid "Event_Conference"
|
||||
msgstr "Konferenz"
|
||||
|
||||
#: app.py:97
|
||||
#: app.py:112
|
||||
msgid "Event_Meetup"
|
||||
msgstr "Networking"
|
||||
|
||||
#: app.py:98
|
||||
#: app.py:113
|
||||
msgid "Event_Fitness"
|
||||
msgstr "Fitness"
|
||||
|
||||
#: app.py:99
|
||||
#: app.py:114
|
||||
msgid "Event_Sports"
|
||||
msgstr "Sport"
|
||||
|
||||
#: app.py:100
|
||||
#: app.py:115
|
||||
msgid "Event_Other"
|
||||
msgstr "Sonstiges"
|
||||
|
||||
#: app.py:101
|
||||
#: app.py:116
|
||||
msgid "Typical Age range"
|
||||
msgstr "Typische Altersspanne"
|
||||
|
||||
#: app.py:727
|
||||
#: app.py:117
|
||||
msgid "Administrator"
|
||||
msgstr "Administrator:in"
|
||||
|
||||
#: app.py:118
|
||||
msgid "Event expert"
|
||||
msgstr "Veranstaltungsexpert:in"
|
||||
|
||||
#: app.py:806
|
||||
#, python-format
|
||||
msgid "Error in the %s field - %s"
|
||||
msgstr "Fehler im Feld %s: %s"
|
||||
|
||||
#: app.py:849
|
||||
#: app.py:874
|
||||
msgid "Invitation successfully accepted"
|
||||
msgstr "Einladung erfolgreich akzeptiert"
|
||||
|
||||
#: app.py:878
|
||||
msgid "Invitation successfully declined"
|
||||
msgstr "Einladung erfolgreich abgelehnt"
|
||||
|
||||
#: app.py:972
|
||||
msgid "Organization successfully created"
|
||||
msgstr "Organisation erfolgreich erstellt"
|
||||
|
||||
#: app.py:870
|
||||
#: app.py:993
|
||||
msgid "Organization successfully updated"
|
||||
msgstr "Organisation erfolgreich aktualisiert"
|
||||
|
||||
#: app.py:927
|
||||
#: app.py:1046
|
||||
msgid "Admin unit successfully created"
|
||||
msgstr "Verwaltungseinheit erfolgreich erstellt"
|
||||
|
||||
#: app.py:946
|
||||
#: app.py:1065
|
||||
msgid "AdminUnit successfully updated"
|
||||
msgstr "Verwaltungseinheit erfolgreich aktualisiert"
|
||||
|
||||
#: app.py:1006 app.py:1546
|
||||
#: app.py:1128 app.py:1881
|
||||
msgid "Place successfully updated"
|
||||
msgstr "Ort erfolgreich aktualisiert"
|
||||
|
||||
#: app.py:1030 app.py:1575
|
||||
#: app.py:1152 app.py:1911
|
||||
msgid "Place successfully created"
|
||||
msgstr "Ort erfolgreich erstellt"
|
||||
|
||||
#: app.py:1081 app.py:1251
|
||||
#: app.py:1203 app.py:1418
|
||||
msgid "Event successfully updated"
|
||||
msgstr "Veranstaltung erfolgreich aktualisiert"
|
||||
|
||||
#: app.py:1206
|
||||
#: app.py:1373
|
||||
msgid "Event successfully created"
|
||||
msgstr "Veranstaltung erfolgreich erstellt"
|
||||
|
||||
#: app.py:1209
|
||||
#: app.py:1376
|
||||
msgid "Thank you so much! The event is being verified."
|
||||
msgstr "Vielen Dank! Die Veranstaltung wird geprüft."
|
||||
|
||||
#: app.py:1274
|
||||
#: app.py:1441
|
||||
msgid "Entered name does not match event name"
|
||||
msgstr "Der eingegebene Name entspricht nicht dem Namen der Veranstaltung"
|
||||
|
||||
#: app.py:1279
|
||||
#: app.py:1446
|
||||
msgid "Event successfully deleted"
|
||||
msgstr "Veranstaltung erfolgreich gelöscht"
|
||||
|
||||
#: app.py:1462
|
||||
#: app.py:1559
|
||||
msgid "You have received an invitation"
|
||||
msgstr "Du hast eine Einladung erhalten"
|
||||
|
||||
#: app.py:1563
|
||||
msgid "Invitation successfully sent"
|
||||
msgstr "Einladung erfolgreich gesendet"
|
||||
|
||||
#: app.py:1592
|
||||
msgid "Member successfully updated"
|
||||
msgstr "Mitglied erfolgreich aktualisiert"
|
||||
|
||||
#: app.py:1618
|
||||
msgid "Entered email does not match member email"
|
||||
msgstr "Die eingegebene Email passt nicht zur Email des Mitglieds"
|
||||
|
||||
#: app.py:1623
|
||||
msgid "Member successfully deleted"
|
||||
msgstr "Mitglied erfolgreich gelöscht"
|
||||
|
||||
#: app.py:1650
|
||||
msgid "Entered email does not match invitation email"
|
||||
msgstr "Die eingegebene Email passt nicht zur Email der Einladung"
|
||||
|
||||
#: app.py:1655
|
||||
msgid "Invitation successfully deleted"
|
||||
msgstr "Einladung erfolgreich gelöscht"
|
||||
|
||||
#: app.py:1795
|
||||
msgid "Organizer successfully created"
|
||||
msgstr "Veranstalter erfolgreich erstellt"
|
||||
|
||||
#: app.py:1484
|
||||
#: app.py:1817
|
||||
msgid "Organizer successfully updated"
|
||||
msgstr "Veranstalter erfolgreich aktualisiert"
|
||||
|
||||
#: app.py:1506
|
||||
#: app.py:1840
|
||||
msgid "Entered name does not match organizer name"
|
||||
msgstr "Der eingegebene Name entspricht nicht dem Namen des Veranstalters"
|
||||
|
||||
#: app.py:1511
|
||||
#: app.py:1845
|
||||
msgid "Organizer successfully deleted"
|
||||
msgstr "Veranstalter erfolgreich gelöscht"
|
||||
|
||||
@ -204,12 +248,12 @@ msgstr "Längengrad"
|
||||
#: forms/admin_unit.py:19 forms/event.py:17 forms/event.py:35 forms/event.py:40
|
||||
#: forms/event.py:117 forms/event_place.py:20 forms/organization.py:19
|
||||
#: forms/organizer.py:19 forms/organizer.py:41 forms/place.py:19
|
||||
#: templates/_macros.html:104 templates/admin/admin_units.html:18
|
||||
#: templates/_macros.html:115 templates/admin/admin_units.html:18
|
||||
#: templates/admin_unit/list.html:13 templates/admin_unit/read.html:66
|
||||
#: templates/admin_unit/read.html:88 templates/event/list.html:17
|
||||
#: templates/event_place/list.html:19 templates/organization/list.html:19
|
||||
#: templates/organization/read.html:64 templates/place/list.html:19
|
||||
#: templates/profile.html:15 templates/profile.html:37
|
||||
#: templates/place/list.html:19 templates/profile.html:16
|
||||
#: templates/profile.html:36 templates/profile.html:58
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
@ -220,6 +264,8 @@ msgstr "Kurzname"
|
||||
#: forms/admin_unit.py:20
|
||||
msgid "The short name is used to create a unique identifier for your events"
|
||||
msgstr "Der Kurzname wird verwendet, um Ihre Veranstaltungen eindeutig identifizieren zu können"
|
||||
"Der Kurzname wird verwendet, um Ihre Veranstaltungen eindeutig "
|
||||
"identifizieren zu können"
|
||||
|
||||
#: forms/admin_unit.py:20 forms/organization.py:25
|
||||
msgid "Short name must contain only letters numbers or underscore"
|
||||
@ -231,18 +277,20 @@ msgstr "Der Kurzname darf nur Buchstaben, Nummern und Unterstriche enthalten"
|
||||
msgid "Link URL"
|
||||
msgstr "Link URL"
|
||||
|
||||
#: forms/admin_unit.py:22 forms/event.py:30 forms/event.py:36
|
||||
#: forms/organization.py:21 forms/organizer.py:21 templates/_macros.html:210
|
||||
#: forms/admin_unit.py:22 forms/admin_unit_member.py:12
|
||||
#: forms/admin_unit_member.py:22 forms/admin_unit_member.py:26
|
||||
#: forms/event.py:30 forms/event.py:36 forms/organization.py:21
|
||||
#: forms/organizer.py:21 templates/_macros.html:221
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
|
||||
#: forms/admin_unit.py:23 forms/event.py:31 forms/event.py:37
|
||||
#: forms/organization.py:22 forms/organizer.py:22 templates/_macros.html:231
|
||||
#: forms/organization.py:22 forms/organizer.py:22 templates/_macros.html:242
|
||||
msgid "Phone"
|
||||
msgstr "Telefon"
|
||||
|
||||
#: forms/admin_unit.py:24 forms/event.py:32 forms/organization.py:23
|
||||
#: forms/organizer.py:23 templates/_macros.html:239
|
||||
#: forms/organizer.py:23 templates/_macros.html:250
|
||||
msgid "Fax"
|
||||
msgstr "Fax"
|
||||
|
||||
@ -256,7 +304,7 @@ msgid "Images only!"
|
||||
msgstr "Nur Fotos!"
|
||||
|
||||
#: forms/admin_unit.py:35 templates/admin_unit/create.html:10
|
||||
#: templates/manage/admin_units.html:8
|
||||
#: templates/manage/admin_units.html:18
|
||||
msgid "Create admin unit"
|
||||
msgstr "Verwaltungseinheit erstellen"
|
||||
|
||||
@ -265,6 +313,36 @@ msgstr "Verwaltungseinheit erstellen"
|
||||
msgid "Update admin unit"
|
||||
msgstr "Verwaltungseinheit aktualisieren"
|
||||
|
||||
#: forms/admin_unit_member.py:13 forms/admin_unit_member.py:29
|
||||
#: templates/admin_unit/read.html:67 templates/admin_unit/read.html:89
|
||||
#: templates/profile.html:37 templates/profile.html:59
|
||||
msgid "Roles"
|
||||
msgstr "Rollen"
|
||||
|
||||
#: forms/admin_unit_member.py:14
|
||||
msgid "Invite"
|
||||
msgstr "Einladen"
|
||||
|
||||
#: forms/admin_unit_member.py:17
|
||||
msgid "Accept"
|
||||
msgstr "Akzeptieren"
|
||||
|
||||
#: forms/admin_unit_member.py:18
|
||||
msgid "Decline"
|
||||
msgstr "Ablehnen"
|
||||
|
||||
#: forms/admin_unit_member.py:21 templates/manage/delete_invitation.html:6
|
||||
msgid "Delete invitation"
|
||||
msgstr "Einladung löschen"
|
||||
|
||||
#: forms/admin_unit_member.py:25 templates/manage/delete_member.html:6
|
||||
msgid "Delete member"
|
||||
msgstr "Mitglied löschen"
|
||||
|
||||
#: forms/admin_unit_member.py:30 templates/admin_unit/update_member.html:9
|
||||
msgid "Update member"
|
||||
msgstr "Mitglied aktualisieren"
|
||||
|
||||
#: forms/event.py:19 forms/event_place.py:33 forms/event_place.py:37
|
||||
msgid "Other organizers can use this location"
|
||||
msgstr "Andere Veranstalter können diesen Ort verwenden"
|
||||
@ -293,27 +371,27 @@ msgstr "Beginn"
|
||||
msgid "End"
|
||||
msgstr "Ende"
|
||||
|
||||
#: forms/event.py:47 templates/_macros.html:293
|
||||
#: forms/event.py:47 templates/_macros.html:304
|
||||
msgid "Previous start date"
|
||||
msgstr "Vorheriges Startdatum"
|
||||
|
||||
#: forms/event.py:48 templates/_macros.html:192
|
||||
#: forms/event.py:48 templates/_macros.html:203
|
||||
msgid "Tags"
|
||||
msgstr "Stichworte"
|
||||
|
||||
#: forms/event.py:50 forms/event.py:138 forms/event_place.py:44
|
||||
#: templates/_macros.html:355 templates/event/create.html:59
|
||||
#: templates/_macros.html:366 templates/event/create.html:59
|
||||
#: templates/event/update.html:46 templates/manage/events.html:18
|
||||
#: templates/manage/places.html:18 templates/organizer/create.html:16
|
||||
#: templates/organizer/delete.html:13 templates/organizer/update.html:16
|
||||
msgid "Organizer"
|
||||
msgstr "Veranstalter"
|
||||
|
||||
#: forms/event.py:51 templates/_macros.html:311
|
||||
#: forms/event.py:51 templates/_macros.html:322
|
||||
msgid "Category"
|
||||
msgstr "Kategorie"
|
||||
|
||||
#: forms/event.py:52 forms/organization.py:37 templates/_macros.html:370
|
||||
#: forms/event.py:52 forms/organization.py:37 templates/_macros.html:381
|
||||
#: templates/admin_unit/create.html:16 templates/admin_unit/update.html:16
|
||||
#: templates/event/update.html:91 templates/organization/create.html:58
|
||||
msgid "Admin unit"
|
||||
@ -372,7 +450,7 @@ msgid "Photo"
|
||||
msgstr "Foto"
|
||||
|
||||
#: forms/event.py:72 forms/event.py:73 forms/event.py:104
|
||||
#: templates/_macros.html:325 templates/event/create.html:84
|
||||
#: templates/_macros.html:336 templates/event/create.html:84
|
||||
#: templates/event/update.html:55 templates/event_place/create.html:20
|
||||
#: templates/event_place/update.html:20 templates/place/create.html:20
|
||||
#: templates/place/update.html:20
|
||||
@ -389,6 +467,7 @@ msgstr "Neuen Ort eingeben"
|
||||
|
||||
#: forms/event.py:78 templates/event/create.html:31 templates/example.html:10
|
||||
#: templates/manage/events.html:36 templates/manage/organizers.html:22
|
||||
#: templates/manage/widgets.html:20 templates/manage/widgets.html:23
|
||||
msgid "Create event"
|
||||
msgstr "Veranstaltung erstellen"
|
||||
|
||||
@ -469,8 +548,8 @@ msgstr "Prüfung speichern"
|
||||
msgid "Find events"
|
||||
msgstr "Veranstaltungen finden"
|
||||
|
||||
#: forms/event.py:137 templates/manage/events.html:25
|
||||
#: templates/widget/event_date/list.html:31
|
||||
#: forms/event.py:137 templates/event_date/list.html:28
|
||||
#: templates/manage/events.html:25 templates/widget/event_date/list.html:31
|
||||
msgid "Keyword"
|
||||
msgstr "Stichwort"
|
||||
|
||||
@ -500,8 +579,7 @@ msgstr "Offizieller Name"
|
||||
msgid "Create organization"
|
||||
msgstr "Organisation hinzufügen"
|
||||
|
||||
#: forms/organization.py:40 templates/organization/read.html:12
|
||||
#: templates/organization/update.html:10
|
||||
#: forms/organization.py:40 templates/organization/update.html:10
|
||||
msgid "Update organization"
|
||||
msgstr "Organisation aktualisieren"
|
||||
|
||||
@ -519,16 +597,16 @@ msgstr "Veranstalter aktualisieren"
|
||||
msgid "Delete organizer"
|
||||
msgstr "Veranstalter löschen"
|
||||
|
||||
#: templates/_macros.html:103 templates/_macros.html:279
|
||||
#: templates/_macros.html:286 templates/event/list.html:16
|
||||
#: templates/_macros.html:114 templates/_macros.html:290
|
||||
#: templates/_macros.html:297 templates/event/list.html:16
|
||||
msgid "Date"
|
||||
msgstr "Datum"
|
||||
|
||||
#: templates/_macros.html:105 templates/event/list.html:18
|
||||
#: templates/_macros.html:116 templates/event/list.html:18
|
||||
msgid "Host"
|
||||
msgstr "Veranstalter"
|
||||
|
||||
#: templates/_macros.html:106 templates/_macros.html:246
|
||||
#: templates/_macros.html:117 templates/_macros.html:257
|
||||
#: templates/admin_unit/create.html:26 templates/admin_unit/update.html:26
|
||||
#: templates/event/list.html:19 templates/event_place/create.html:29
|
||||
#: templates/event_place/update.html:29 templates/organization/create.html:27
|
||||
@ -538,72 +616,80 @@ msgstr "Veranstalter"
|
||||
msgid "Location"
|
||||
msgstr "Standort"
|
||||
|
||||
#: templates/_macros.html:117 templates/_macros.html:296
|
||||
#: templates/_macros.html:128 templates/_macros.html:307
|
||||
#: templates/event/list.html:30
|
||||
msgid "Verified"
|
||||
msgstr "Verifiziert"
|
||||
|
||||
#: templates/_macros.html:130
|
||||
#: templates/_macros.html:141
|
||||
msgid "Show all events"
|
||||
msgstr "Alle Veranstaltungen anzeigen"
|
||||
|
||||
#: templates/_macros.html:146
|
||||
#: templates/_macros.html:157
|
||||
msgid "Show on Google Maps"
|
||||
msgstr "Auf Google Maps anzeigen"
|
||||
|
||||
#: templates/_macros.html:201
|
||||
#: templates/_macros.html:212
|
||||
msgid "Link"
|
||||
msgstr "Link"
|
||||
|
||||
#: templates/_macros.html:272 templates/event/create.html:38
|
||||
#: templates/_macros.html:283 templates/event/create.html:38
|
||||
#: templates/event/delete.html:13 templates/event/update.html:15
|
||||
msgid "Event"
|
||||
msgstr "Veranstaltung"
|
||||
|
||||
#: templates/_macros.html:282
|
||||
#: templates/_macros.html:293
|
||||
#, python-format
|
||||
msgid "%(count)d event dates"
|
||||
msgstr "%(count)d Termine"
|
||||
|
||||
#: templates/_macros.html:345
|
||||
#: templates/_macros.html:356
|
||||
msgid "Show directions"
|
||||
msgstr "Anreise planen"
|
||||
|
||||
#: templates/_macros.html:394
|
||||
#: templates/_macros.html:405
|
||||
msgid "Sign in with Google"
|
||||
msgstr "Mit Google anmelden"
|
||||
|
||||
#: templates/_macros.html:454
|
||||
#: templates/_macros.html:465
|
||||
msgid "Search location on Google"
|
||||
msgstr "Ort bei Google suchen"
|
||||
|
||||
#: templates/_macros.html:474
|
||||
#: templates/_macros.html:485 templates/manage/reviews.html:4
|
||||
msgid "Reviews"
|
||||
msgstr "Prüfungen"
|
||||
|
||||
#: templates/_macros.html:475 templates/admin_unit/read.html:30
|
||||
#: templates/_macros.html:486 templates/admin_unit/read.html:30
|
||||
#: templates/event/list.html:4 templates/event/list.html:8
|
||||
#: templates/event_place/read.html:22 templates/manage/events.html:4
|
||||
#: templates/manage/reviews.html:4 templates/organization/read.html:27
|
||||
#: templates/place/read.html:22
|
||||
#: templates/event_place/read.html:22 templates/layout.html:55
|
||||
#: templates/manage/events.html:4 templates/place/read.html:22
|
||||
msgid "Events"
|
||||
msgstr "Veranstaltungen"
|
||||
|
||||
#: templates/_macros.html:476 templates/manage/organizers.html:4
|
||||
#: templates/_macros.html:487 templates/manage/organizers.html:4
|
||||
msgid "Organizers"
|
||||
msgstr "Veranstalter"
|
||||
|
||||
#: templates/_macros.html:477 templates/event_place/list.html:3
|
||||
#: templates/_macros.html:488 templates/event_place/list.html:3
|
||||
#: templates/event_place/list.html:7 templates/manage/places.html:4
|
||||
#: templates/place/list.html:3 templates/place/list.html:7
|
||||
msgid "Places"
|
||||
msgstr "Orte"
|
||||
|
||||
#: templates/_macros.html:517 templates/_macros.html:519
|
||||
#: templates/_macros.html:489 templates/admin_unit/read.html:23
|
||||
#: templates/manage/members.html:4 templates/manage/members.html:31
|
||||
msgid "Members"
|
||||
msgstr "Mitglieder"
|
||||
|
||||
#: templates/_macros.html:490 templates/manage/widgets.html:4
|
||||
msgid "Widgets"
|
||||
msgstr "Widgets"
|
||||
|
||||
#: templates/_macros.html:530 templates/_macros.html:532
|
||||
msgid "Previous"
|
||||
msgstr "Zurück"
|
||||
|
||||
#: templates/_macros.html:522 templates/_macros.html:524
|
||||
#: templates/_macros.html:535 templates/_macros.html:537
|
||||
msgid "Next"
|
||||
msgstr "Weiter"
|
||||
|
||||
@ -611,47 +697,51 @@ msgstr "Weiter"
|
||||
msgid "Widget als iFrame einbetten"
|
||||
msgstr "Widget als iFrame einbetten"
|
||||
|
||||
#: templates/home.html:25 templates/home.html:141
|
||||
#: templates/security/login_user.html:25
|
||||
msgid "Register for free"
|
||||
msgstr "Kostenlos registrieren"
|
||||
|
||||
#: templates/layout.html:52
|
||||
msgid "Manage"
|
||||
msgstr "Verwaltung"
|
||||
|
||||
#: templates/layout.html:55
|
||||
#: templates/layout.html:56
|
||||
msgid "Example"
|
||||
msgstr "Beispiel"
|
||||
|
||||
#: templates/developer/read.html:4 templates/developer/read.html:10
|
||||
#: templates/layout.html:56
|
||||
#: templates/layout.html:57
|
||||
msgid "Developer"
|
||||
msgstr "Entwickler"
|
||||
|
||||
#: templates/layout.html:65 templates/profile.html:3
|
||||
#: templates/layout.html:66 templates/profile.html:4
|
||||
msgid "Profile"
|
||||
msgstr "Profil"
|
||||
|
||||
#: templates/admin/admin.html:3 templates/admin/admin.html:9
|
||||
#: templates/admin/admin_units.html:9 templates/layout.html:68
|
||||
#: templates/admin/admin_units.html:9 templates/layout.html:69
|
||||
msgid "Admin"
|
||||
msgstr "Administration"
|
||||
|
||||
#: templates/layout.html:72
|
||||
#: templates/layout.html:73
|
||||
msgid "Logout"
|
||||
msgstr "Ausloggen"
|
||||
|
||||
#: templates/manage/admin_units.html:8 templates/manage/members.html:12
|
||||
#: templates/profile.html:11
|
||||
msgid "Invitations"
|
||||
msgstr "Einladungen"
|
||||
|
||||
#: templates/admin/admin.html:15 templates/admin/admin_units.html:3
|
||||
#: templates/admin/admin_units.html:10 templates/admin_unit/list.html:3
|
||||
#: templates/admin_unit/list.html:7 templates/manage/admin_units.html:3
|
||||
#: templates/profile.html:10
|
||||
#: templates/manage/admin_units.html:16 templates/profile.html:31
|
||||
msgid "Admin Units"
|
||||
msgstr "Verwaltungseinheiten"
|
||||
|
||||
#: templates/admin_unit/read.html:67 templates/admin_unit/read.html:89
|
||||
#: templates/organization/read.html:65 templates/profile.html:16
|
||||
#: templates/profile.html:38
|
||||
msgid "Roles"
|
||||
msgstr "Rollen"
|
||||
|
||||
#: templates/admin_unit/read.html:27 templates/organization/list.html:3
|
||||
#: templates/organization/list.html:7 templates/profile.html:32
|
||||
#: templates/organization/list.html:7 templates/profile.html:53
|
||||
msgid "Organizations"
|
||||
msgstr "Organisationen"
|
||||
|
||||
@ -664,19 +754,36 @@ msgstr "Organisationen"
|
||||
msgid "Additional information"
|
||||
msgstr "Zusätzliche Informationen"
|
||||
|
||||
#: templates/admin_unit/invite_member.html:9 templates/manage/members.html:15
|
||||
msgid "Invite user"
|
||||
msgstr "Nutzer:in einladen"
|
||||
|
||||
#: templates/admin_unit/read.html:19 templates/event_place/read.html:19
|
||||
#: templates/organization/read.html:19 templates/place/read.html:19
|
||||
#: templates/place/read.html:19
|
||||
msgid "Info"
|
||||
msgstr "Info"
|
||||
|
||||
#: templates/admin_unit/read.html:23 templates/organization/read.html:23
|
||||
msgid "Members"
|
||||
msgstr "Mitglieder"
|
||||
|
||||
#: templates/admin_unit/read.html:56
|
||||
msgid "You are a member of this admin unit."
|
||||
msgstr "Du bist Mitglied dieser Verwaltungseinheit"
|
||||
|
||||
#: templates/email/invitation_notice.html:1
|
||||
#, python-format
|
||||
msgid "You have been invited to join %(admin_unit_name)s."
|
||||
msgstr "Du wurdest eingeladen, %(admin_unit_name)s beizutreten."
|
||||
|
||||
#: templates/email/invitation_notice.html:2
|
||||
msgid "Click here to view the invitation"
|
||||
msgstr "Klicke hier, um die Einladung anzunehmen."
|
||||
|
||||
#: templates/email/layout.html:351
|
||||
msgid "Hi there"
|
||||
msgstr "Moin"
|
||||
|
||||
#: templates/email/layout.html:352
|
||||
msgid "this is a message from Oveda - Die offene Veranstaltungsdatenbank."
|
||||
msgstr "das ist eine Nachricht von Oveda - Die offene Veranstaltungsdatenbank."
|
||||
|
||||
#: templates/event/create.html:48 templates/event/update.html:25
|
||||
msgid "Event date"
|
||||
msgstr "Termin"
|
||||
@ -711,16 +818,40 @@ msgstr "Sie können diese Seite erneut besuchen, um den Status zu prüfen."
|
||||
msgid "View"
|
||||
msgstr "Anzeigen"
|
||||
|
||||
#: templates/manage/events.html:30 templates/widget/event_date/list.html:36
|
||||
#: templates/event_date/list.html:14 templates/widget/event_date/list.html:17
|
||||
msgid "From"
|
||||
msgstr "Von"
|
||||
|
||||
#: templates/event_date/list.html:21 templates/widget/event_date/list.html:24
|
||||
msgid "to"
|
||||
msgstr "bis"
|
||||
|
||||
#: templates/event_date/list.html:33 templates/manage/events.html:30
|
||||
#: templates/widget/event_date/list.html:36
|
||||
msgid "Find"
|
||||
msgstr "Finden"
|
||||
|
||||
#: templates/manage/events.html:47 templates/manage/organizers.html:23
|
||||
#: templates/manage/places.html:35
|
||||
#: templates/invitation/read.html:4 templates/invitation/read.html:8
|
||||
#: templates/manage/delete_invitation.html:13
|
||||
msgid "Invitation"
|
||||
msgstr "Einladung"
|
||||
|
||||
#: templates/invitation/read.html:10
|
||||
#, python-format
|
||||
msgid "Would you like to accept the invitation from %(name)s?"
|
||||
msgstr "Möchtest du die Einladung von %(name)s akzeptieren?"
|
||||
|
||||
#: templates/manage/delete_member.html:13
|
||||
msgid "Member"
|
||||
msgstr "Mitglied"
|
||||
|
||||
#: templates/manage/events.html:47 templates/manage/members.html:38
|
||||
#: templates/manage/organizers.html:23 templates/manage/places.html:35
|
||||
msgid "Edit"
|
||||
msgstr "Bearbeiten"
|
||||
|
||||
#: templates/manage/events.html:48 templates/manage/organizers.html:24
|
||||
#: templates/manage/events.html:48 templates/manage/members.html:24
|
||||
#: templates/manage/members.html:39 templates/manage/organizers.html:24
|
||||
msgid "Delete"
|
||||
msgstr "Löschen"
|
||||
|
||||
@ -728,25 +859,29 @@ msgstr "Löschen"
|
||||
msgid "Assistents"
|
||||
msgstr "Assistenten"
|
||||
|
||||
#: templates/manage/widgets.html:12
|
||||
msgid "Veranstaltungen als iFrame einbetten"
|
||||
msgstr "Veranstaltungen als iFrame einbetten"
|
||||
|
||||
#: templates/manage/widgets.html:19
|
||||
msgid "Link, um Veranstaltungen vorzuschlagen"
|
||||
msgstr "Link, um Veranstaltungen vorzuschlagen"
|
||||
|
||||
#: templates/manage/widgets.html:26
|
||||
msgid "URL für Infoscreen"
|
||||
msgstr "URL für Infoscreen"
|
||||
|
||||
#: templates/organization/create.html:16 templates/organization/update.html:16
|
||||
msgid "Organization"
|
||||
msgstr "Organisation"
|
||||
|
||||
#: templates/organization/read.html:54
|
||||
msgid "You are a member of this organization."
|
||||
msgstr "Du bist Mitglied dieser Organisation"
|
||||
#: templates/security/login_user.html:23
|
||||
msgid "You do not have an account yet? Not a problem!"
|
||||
msgstr "Du hast noch keinen Account? Kein Problem!"
|
||||
|
||||
#: templates/widget/event_date/list.html:4
|
||||
msgid "Widget"
|
||||
msgstr "WIDGET"
|
||||
|
||||
#: templates/widget/event_date/list.html:17
|
||||
msgid "From"
|
||||
msgstr "Von"
|
||||
|
||||
#: templates/widget/event_date/list.html:24
|
||||
msgid "to"
|
||||
msgstr "bis"
|
||||
msgstr "Widget"
|
||||
|
||||
#~ msgid "You"
|
||||
#~ msgstr "Du"
|
||||
@ -811,3 +946,6 @@ msgstr "bis"
|
||||
#~ msgid "Admin unit successfully updated"
|
||||
#~ msgstr "Verwaltungseinheit erfolgreich aktualisiert"
|
||||
|
||||
#~ msgid "You are a member of this organization."
|
||||
#~ msgstr "Du bist Mitglied dieser Organisation"
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user