Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added new and edit for organization #222

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ instance/testing.py
.webassets-cache
baseframe-packed.js
baseframe-packed.css
boxoffice/static/js/node_modules/
node_modules
boxoffice/static/gen
boxoffice/static/js/npm-debug.log
.vscode
yarn.lock
3 changes: 3 additions & 0 deletions boxoffice/assets/js/views/org.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ const orgTemplate = `
<a class="boxoffice-button boxoffice-button-action btn-right" href="/admin/o/{{orgName}}/ic/new" data-navigate>
New item collection
</a>
<a class="boxoffice-button boxoffice-button-action btn-right btn-margin-right" href="/admin/o/{{orgName}}/edit">
Edit organization
</a>
</div>
{{#itemCollections:ic}}
<div class="box col-sm-6 col-xs-12" id="item-collection-{{ @index }}">
Expand Down
1 change: 1 addition & 0 deletions boxoffice/forms/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-

from .org import *
from .item_collection import *
from .item import *
from .price import *
Expand Down
19 changes: 1 addition & 18 deletions boxoffice/forms/item.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,16 @@
# -*- coding: utf-8 -*-

import json
from flask import request
from html5print import HTMLBeautifier
from baseframe import __
import baseframe.forms as forms
from baseframe.forms.sqlalchemy import QuerySelectField
from ..models import db, Category, ItemCollection
from .utils import format_json, validate_json

__all__ = ['ItemForm']


def format_json(data):
if request.method == 'GET':
return json.dumps(data, indent=4, sort_keys=True)
# `json.loads` doesn't raise an exception for "null"
# so assign a default value of `{}`
if not data or data == 'null':
return json.dumps({})
return data


def format_description(data):
if request.method == 'GET' and data:
return HTMLBeautifier.beautify(data.text, 8)
Expand Down Expand Up @@ -49,13 +39,6 @@ def format_description(data):
}


def validate_json(form, field):
try:
json.loads(field.data)
except ValueError:
raise forms.validators.StopValidation(__("Invalid JSON"))


class ItemForm(forms.Form):
title = forms.StringField(__("Item title"),
validators=[forms.validators.DataRequired(__("Please specify a title")),
Expand Down
46 changes: 46 additions & 0 deletions boxoffice/forms/org.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-

from boxoffice.models import db, Organization
from baseframe.forms.sqlalchemy import QuerySelectField
import baseframe.forms as forms
from coaster.utils import buid
from baseframe import __
from .utils import validate_json, format_json

__all__ = ['OrgForm', 'NewOrgForm']


def get_default_details():
return {
u'access_token': buid(),
u'address': u'',
u'cin': u'',
u'logo': u'',
u'pan': u'',
u'refund_policy': u'',
u'support_email': u'',
u'ticket_faq': u'',
u'website': u''
}


class OrgForm(forms.Form):
contact_email = forms.EmailField(__("Contact email"),
validators=[
forms.validators.DataRequired(__("We need a valid email address")),
forms.validators.Length(min=5, max=80, message=__("%%(max)d characters maximum")),
forms.validators.ValidEmail(__("This does not appear to be a valid email address"))],
filters=[forms.filters.strip()])
details = forms.TextAreaField(__("Details"), filters=[format_json],
validators=[validate_json], default=get_default_details)
invoicer = QuerySelectField(__("Parent organization"), get_label='title',
validators=[forms.validators.DataRequired(__("Please select a parent organization"))])

def set_queries(self):
self.invoicer.query = Organization.query.filter(
Organization.invoicer == None).options(db.load_only('id', 'title'))


class NewOrgForm(OrgForm):
organization = forms.RadioField(u"Organization", validators=[forms.validators.DataRequired("Select an organization")],
description=u"Select the organization you’d like to setup Boxoffice for")
24 changes: 24 additions & 0 deletions boxoffice/forms/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-

import json
import six
import baseframe.forms as forms
from baseframe import __


def validate_json(form, field):
try:
json.loads(field.data)
except ValueError:
raise forms.validators.StopValidation(__("Invalid JSON"))


def format_json(data):
# `json.loads` doesn't raise an exception for "null"
# so assign a default value of `{}`
if not data or data == 'null':
data = {}
elif isinstance(data, six.string_types):
# This happens when putting JSON data from the form into the database
data = json.loads(data)
return json.dumps(data, indent=4, sort_keys=True)
25 changes: 25 additions & 0 deletions boxoffice/static/build/main_admin.14875c7f9092817d91d9.js

Large diffs are not rendered by default.

25 changes: 0 additions & 25 deletions boxoffice/static/build/main_admin.bfd69cdb099ad90caf9d.js

This file was deleted.

25 changes: 25 additions & 0 deletions boxoffice/static/build/main_invoice.14875c7f9092817d91d9.js

Large diffs are not rendered by default.

25 changes: 0 additions & 25 deletions boxoffice/static/build/main_invoice.bfd69cdb099ad90caf9d.js

This file was deleted.

25 changes: 25 additions & 0 deletions boxoffice/static/build/main_order.14875c7f9092817d91d9.js

Large diffs are not rendered by default.

25 changes: 0 additions & 25 deletions boxoffice/static/build/main_order.bfd69cdb099ad90caf9d.js

This file was deleted.

2 changes: 1 addition & 1 deletion boxoffice/static/build/manifest.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"assets":{"main_order":"main_order.bfd69cdb099ad90caf9d.js","main_invoice":"main_invoice.bfd69cdb099ad90caf9d.js","main_admin":"main_admin.bfd69cdb099ad90caf9d.js"}}
{"assets":{"main_order":"main_order.14875c7f9092817d91d9.js","main_invoice":"main_invoice.14875c7f9092817d91d9.js","main_admin":"main_admin.14875c7f9092817d91d9.js"}}
2 changes: 1 addition & 1 deletion boxoffice/views/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-

from . import admin, item_collection, order, participant, login, admin_item_collection, admin_order, admin_discount, admin_report, admin_item, admin_category
from . import admin, org, item_collection, order, participant, login, admin_item_collection, admin_order, admin_discount, admin_report, admin_item, admin_category
77 changes: 77 additions & 0 deletions boxoffice/views/org.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-

from flask import g, Markup, request, flash, url_for, redirect
from coaster.views import load_models
from baseframe import _
from baseframe.forms import render_message, render_redirect, render_form
from ..models import db, Organization
from ..forms import OrgForm, NewOrgForm
from .. import app, lastuser


@lastuser.requires_permission('siteadmin')
@lastuser.requires_login
@app.route('/admin/o/new', methods=['GET', 'POST'])
def new_org():
# Step 1: Get a list of organizations this user owns
existing = Organization.query.filter(Organization.userid.in_(g.user.organizations_owned_ids())).all()
existing_ids = [e.userid for e in existing]
# Step 2: Prune list to organizations without a profile
new_orgs = []
for user_org in g.user.organizations_owned():
if user_org['userid'] not in existing_ids:
new_orgs.append((user_org['userid'], user_org['title']))
if not new_orgs:
return render_message(
title=_(u"No organizations found"),
message=Markup(_(u"You do not have any organizations that are not setup on Boxoffice. "
u'Would you like to <a href="{link}">create a new organization</a>?').format(
link=lastuser.endpoint_url('/organizations/new'))))
eligible_orgs = []
for orgid, title in new_orgs:
eligible_orgs.append((orgid, title))
if not eligible_orgs:
return render_message(
title=_(u"No organizations available"),
message=_(u"To setup Boxoffice for an organization, you must be the owner of the organization."))

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the logic used in Funnel's /new handler. This code looks fragile.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Damn, then that needs to be tossed as well. We can live with this for now, knowing that both places will need to be changed after hasgeek/lastuser#232.

# Step 3: Ask user to select organization
form = NewOrgForm()
form.organization.choices = eligible_orgs
if request.method == 'GET':
form.organization.data = new_orgs[0][0]
if form.validate_on_submit():
# Step 4: Make a profile
user_org = [user_org for user_org in g.user.organizations_owned() if user_org['userid'] == form.organization.data][0]
organization = Organization(name=user_org['name'], title=user_org['title'], userid=user_org['userid'])
form.populate_obj(organization)
db.session.add(organization)
db.session.commit()
flash(_(u"Created an organization for {org}").format(org=organization.title), "success")
return redirect(url_for('org', org=organization.name), code=303)
return render_form(
form=form,
title=_(u"Setup Boxoffice for your organization..."),
submit="Next",
formid="org_new",
cancel_url=url_for('index'),
ajax=False)


@app.route('/admin/o/<name>/edit', methods=['GET', 'POST'])
@load_models(
(Organization, {'name': 'name'}, 'org'),
permission='org_admin')
def edit_org(org):
form = OrgForm(obj=org)
if form.validate_on_submit():
form.populate_obj(org)
db.session.commit()
flash(_("Your changes have been saved"), 'info')
return redirect(url_for('org', org=org.name), code=303)
return render_form(
form=form,
title=_("Edit organization settings"),
submit=_("Save changes"),
cancel_url='/admin/o/{{org}}'.format(org=org.name),
ajax=False)