diff --git a/forms.py b/forms.py index 68cfe3e..b7be90b 100644 --- a/forms.py +++ b/forms.py @@ -10,6 +10,7 @@ from wtforms.widgets import TextArea from models import Feast, Music +from utils import logger hymns = [('', 'None')] + [(h.ref, f'{h.ref} - {h.title}') for h in Music.neh_hymns()] @@ -17,6 +18,19 @@ translations = [('', 'None')] + [(h.translation, f'{h.translation}') for h in Music.neh_hymns()] +class FeastForm(FlaskForm): + # Required fields + name = StringField('Name', validators=[DataRequired()]) + month = StringField('Month', validators=[DataRequired()]) + day = StringField('Day', validators=[DataRequired()]) + collect = StringField('Collect', widget=TextArea(), validators=[DataRequired()]) + # Optional fields + introit = StringField('Introit', widget=TextArea()) + offertory = StringField('Offertory', widget=TextArea()) + tract = StringField('Tract', widget=TextArea()) + gradual = StringField('Gradual', widget=TextArea()) + alleluia = StringField('Alleluia', widget=TextArea()) + class AnthemForm(Form): title = StringField('Anthem') composer = StringField('Anthem composer') @@ -33,7 +47,7 @@ class PewSheetForm(FlaskForm): ) secondary_feasts = SelectMultipleField( 'Secondary Feasts', - choices=[('', '')] + feast_choices, + choices=[('', '')] + feast_choices, validate_choice=False ) date = DateField('Date', validators=[DataRequired()]) time = TimeField('Time', validators=[DataRequired()]) diff --git a/models.py b/models.py index 43a566b..6c7e98f 100644 --- a/models.py +++ b/models.py @@ -17,9 +17,9 @@ from models_base import get if typing.TYPE_CHECKING: - from forms import PewSheetForm, AnthemForm + from forms import PewSheetForm, AnthemForm, FeastForm -from utils import get_neh_df, advent, closest_sunday_to, NoPandasError, logger +from utils import get_neh_df, advent, closest_sunday_to, NoPandasError, logger, formatFeastName feasts_fields = ['name', 'month', 'day', 'coeaster', 'coadvent', 'introit', 'collect', 'epistle_ref', 'epistle', @@ -38,9 +38,48 @@ def _none2datemax(d: Optional[dt.date]) -> dt.date: @define class Feast: + optionalFields = ['introit', 'gat', 'gradual', 'alleluia', 'tract', 'offertory'] + + def infer_gat(gradual, alleluia): + gat = None + if gradual: + gat = 'Gradual' + if alleluia: + if gat is not None: + gat = gat + ' and Alleuia' + else: + gat = 'Alleuia' + if gat is not None: + gat = gat + ' Proper' + return gat + @classmethod def from_yaml(cls, slug): return _feast_from_yaml(slug) + + @classmethod + def to_yaml(cls, feastForm: 'FeastForm'): + name = formatFeastName(feastForm.name.data) + gat = cls.infer_gat(feastForm.gradual.data, feastForm.alleluia.data) + with open((DATA_DIR / name).with_suffix('.yaml'), "w") as f: + f.write('name: ' + feastForm.name.data + '\n') + #TODO: check validity of day and month, + # i.e. generate Date instance with Date(str) and check if it exists + f.write('month: ' + feastForm.month.data + '\n') + f.write('day: ' + feastForm.day.data + '\n') + f.write('collect: ' + feastForm.collect.data + '\n') + for field in cls.optionalFields: + if field != 'gat': + if feastForm[field].data: + f.write(field + ': ' + feastForm[field].data + '\n') + else: + if gat is not None: + f.write('gat: ' + gat + '\n') + + with open(DATA_DIR / '_list.txt', "a") as f: + f.write('\n' + name) + + @classmethod def all(cls): diff --git a/pypew.py b/pypew.py index a36cac8..2c221da 100644 --- a/pypew.py +++ b/pypew.py @@ -13,6 +13,8 @@ import views from utils import logger +from flask_wtf.csrf import CSRFProtect + load_dotenv() @@ -54,6 +56,7 @@ def create_app(pypew: Optional[PyPew] = None, **kwargs) -> Flask: app.add_url_rule('/feast/api/', 'feast_detail_api', views.feast_detail_api) app.add_url_rule('/feast/api//date', 'feast_date_api', views.feast_date_api) app.add_url_rule('/feast//docx', 'feast_docx_view', views.feast_docx_view) + app.add_url_rule('/pewSheet/feastCreation', 'create_feast', views.create_feast, methods=['GET']) app.add_url_rule('/pewSheet', 'pew_sheet_create_view', views.pew_sheet_create_view, methods=['GET']) app.add_url_rule('/pewSheet/docx', 'pew_sheet_docx_view', views.pew_sheet_docx_view, methods=['GET']) app.add_url_rule('/pewSheet/clearHistory', @@ -101,6 +104,7 @@ def main(argv: Optional[Sequence[str]] = None) -> None: pypew = PyPew() app = create_app(pypew) + csrf = CSRFProtect(app) if args.debug: # noinspection FlaskDebugMode diff --git a/templates/createFeast.html b/templates/createFeast.html new file mode 100644 index 0000000..74e23fc --- /dev/null +++ b/templates/createFeast.html @@ -0,0 +1,24 @@ +
+ {{ feastForm.csrf_token }} + {% for field in feastFormFields %} +
+
+ {{ feastForm[field].label(class='col-form-label') }} +
+
+ {{ feastForm[field](class='form-control', id='feast-' + field) }} + {% if feastForm[field].errors %} + {% for error in feastForm[field].errors %} + + {{ error }} + + {% endfor %} + {% endif %} +
+
+ {% endfor %} +
+ + +
+
diff --git a/templates/serviceForm.html b/templates/serviceForm.html index b4f2708..5f66c31 100644 --- a/templates/serviceForm.html +++ b/templates/serviceForm.html @@ -1,3 +1,6 @@ + + {% include "createFeast.html" %} +
@@ -32,7 +35,7 @@

{{ form.secondary_feasts.label(class='col-sm-2 col-form-label') }}
- {{ form.secondary_feasts(class='form-select') }} + {{ form.secondary_feasts(class='form-select', formnovalidate=True) }} {% if form.secondary_feasts.errors %} {% for error in form.secondary_feasts.errors %} @@ -41,9 +44,11 @@

{% endfor %} {% endif %}
+
+ +
-
{{ form.date.label(class='col-sm-1 col-form-label') }}
@@ -183,3 +188,136 @@

+ diff --git a/utils.py b/utils.py index a576dd4..7fd61ab 100644 --- a/utils.py +++ b/utils.py @@ -75,3 +75,7 @@ def advent(year: int) -> date: return christmas - timedelta(days=christmas_dow + 7*3) else: return christmas - timedelta(7 * 4) + +def formatFeastName(name: str) -> str: + nameComponents = name.split() + return ('-').join(nameComponents) \ No newline at end of file diff --git a/views/pew_sheet_views.py b/views/pew_sheet_views.py index c76e8d7..cafe595 100644 --- a/views/pew_sheet_views.py +++ b/views/pew_sheet_views.py @@ -7,17 +7,24 @@ send_file, session, url_for) from werkzeug.datastructures import ImmutableMultiDict -from forms import PewSheetForm +from forms import PewSheetForm, FeastForm from models import Feast, Service from utils import cache_dir, logger -__all__ = ['pew_sheet_create_view', 'pew_sheet_clear_history_endpoint', 'pew_sheet_docx_view'] +__all__ = ['pew_sheet_create_view', 'pew_sheet_clear_history_endpoint', 'pew_sheet_docx_view', 'create_feast'] dotenv.load_dotenv() COOKIE_NAME = os.environ.get('COOKIE_NAME', 'previousPewSheets') +def create_feast(): + feastForm = FeastForm(request.args) + print('Into feast creation...') + Feast.to_yaml(feastForm) + return make_response('', 204) def pew_sheet_create_view(): + feastFormFields = ["name", "month", "day", "collect", "introit", "offertory", "tract", "gradual", "alleluia"] + feastForm = FeastForm(request.args) form = PewSheetForm(request.args) if not form.primary_feast.data: form.primary_feast.data = Feast.next().slug @@ -49,10 +56,9 @@ def pew_sheet_create_view(): pass previous_services.sort(key=lambda args_service: args_service[1].date) - return render_template( 'pewSheet.html', form=form, service=service, - previous_services=previous_services + previous_services=previous_services, feastForm=feastForm, feastFormFields=feastFormFields )