diff --git a/alembic/versions/0ba9060b0434_add_schedule_description_and_separate_.py b/alembic/versions/0ba9060b0434_add_schedule_description_and_separate_.py new file mode 100644 index 000000000..1ed0ca05e --- /dev/null +++ b/alembic/versions/0ba9060b0434_add_schedule_description_and_separate_.py @@ -0,0 +1,63 @@ +"""Add schedule description and separate recording preference option for panels + +Revision ID: 0ba9060b0434 +Revises: 983af01225fc +Create Date: 2024-08-08 03:37:03.691021 + +""" + + +# revision identifiers, used by Alembic. +revision = '0ba9060b0434' +down_revision = '983af01225fc' +branch_labels = None +depends_on = None + +from alembic import op +import sqlalchemy as sa + + + +try: + is_sqlite = op.get_context().dialect.name == 'sqlite' +except Exception: + is_sqlite = False + +if is_sqlite: + op.get_context().connection.execute('PRAGMA foreign_keys=ON;') + utcnow_server_default = "(datetime('now', 'utc'))" +else: + utcnow_server_default = "timezone('utc', current_timestamp)" + +def sqlite_column_reflect_listener(inspector, table, column_info): + """Adds parenthesis around SQLite datetime defaults for utcnow.""" + if column_info['default'] == "datetime('now', 'utc')": + column_info['default'] = utcnow_server_default + +sqlite_reflect_kwargs = { + 'listeners': [('column_reflect', sqlite_column_reflect_listener)] +} + +# =========================================================================== +# HOWTO: Handle alter statements in SQLite +# +# def upgrade(): +# if is_sqlite: +# with op.batch_alter_table('table_name', reflect_kwargs=sqlite_reflect_kwargs) as batch_op: +# batch_op.alter_column('column_name', type_=sa.Unicode(), server_default='', nullable=False) +# else: +# op.alter_column('table_name', 'column_name', type_=sa.Unicode(), server_default='', nullable=False) +# +# =========================================================================== + + +def upgrade(): + op.add_column('event', sa.Column('public_description', sa.Unicode(), server_default='', nullable=False)) + op.add_column('panel_application', sa.Column('public_description', sa.Unicode(), server_default='', nullable=False)) + op.add_column('panel_application', sa.Column('record', sa.Integer(), server_default='227291107', nullable=False)) + + +def downgrade(): + op.drop_column('panel_application', 'record') + op.drop_column('panel_application', 'public_description') + op.drop_column('event', 'public_description') diff --git a/uber/api.py b/uber/api.py index 0a7d925ac..fe224b6a0 100644 --- a/uber/api.py +++ b/uber/api.py @@ -1447,7 +1447,7 @@ def schedule(self): 'start_unix': int(mktime(event.start_time.utctimetuple())), 'end_unix': int(mktime(event.end_time.utctimetuple())), 'duration': event.minutes, - 'description': event.description, + 'description': event.public_description or event.description, 'panelists': [panelist.attendee.full_name for panelist in event.assigned_panelists] } for event in sorted(session.query(Event).all(), key=lambda e: [e.start_time, e.location_label]) diff --git a/uber/configspec.ini b/uber/configspec.ini index f07003e70..3bc29ff36 100644 --- a/uber/configspec.ini +++ b/uber/configspec.ini @@ -1724,8 +1724,6 @@ other = string(default="Other") [[livestream]] opt_in = string(default="It's fine to record or livestream this panel") -record_only = string(default="Recording for the public is okay, but not livestreaming") -private_record = string(default="Recording is okay, but please don't post it publicly") opt_out = string(default="Please don't record or livestream this panel") [[panel_app_status]] diff --git a/uber/model_checks.py b/uber/model_checks.py index 8d5d47adb..620e0306c 100644 --- a/uber/model_checks.py +++ b/uber/model_checks.py @@ -638,6 +638,19 @@ def specify_nonstandard_time(app): return 'Please explain why your panel needs to be longer than sixty minutes.' +@validation.PanelApplication +def select_livestream_opt(app): + if not app.livestream: + return 'Please select your preference for recording/livestreaming.' \ + if len(c.LIVESTREAM_OPTS) > 2 else 'Please tell us if we can livestream your panel.' + + +@validation.PanelApplication +def select_record_opt(app): + if not app.record and len(c.LIVESTREAM_OPTS) <= 2: + return 'Please tell us if we can record your panel.' + + @validation.PanelApplication def specify_table_needs(app): if app.need_tables and not app.tables_desc: diff --git a/uber/models/panels.py b/uber/models/panels.py index 2511df46f..450375089 100644 --- a/uber/models/panels.py +++ b/uber/models/panels.py @@ -23,6 +23,7 @@ class Event(MagModel): duration = Column(Integer) # half-hour increments name = Column(UnicodeText, nullable=False) description = Column(UnicodeText) + public_description = Column(UnicodeText) assigned_panelists = relationship('AssignedPanelist', backref='event') applications = relationship('PanelApplication', backref=backref('event', cascade="save-update,merge"), @@ -73,7 +74,8 @@ def guidebook_desc(self): panelists_creds = '

' + '

'.join( a.other_credentials for a in self.applications[0].applicants if a.other_credentials ) if self.applications else '' - return self.description + panelists_creds + description = self.public_description or self.description + return description + panelists_creds @property def guidebook_location(self): @@ -104,6 +106,7 @@ class PanelApplication(MagModel): length_text = Column(UnicodeText) length_reason = Column(UnicodeText) description = Column(UnicodeText) + public_description = Column(UnicodeText) unavailable = Column(UnicodeText) available = Column(UnicodeText) affiliations = Column(UnicodeText) @@ -123,6 +126,7 @@ class PanelApplication(MagModel): tabletop = Column(Boolean, default=False) cost_desc = Column(UnicodeText) livestream = Column(Choice(c.LIVESTREAM_OPTS), default=c.OPT_IN) + record = Column(Choice(c.LIVESTREAM_OPTS), default=c.OPT_IN) panelist_bringing = Column(UnicodeText) extra_info = Column(UnicodeText) applied = Column(UTCDateTime, server_default=utcnow(), default=lambda: datetime.now(UTC)) @@ -141,12 +145,18 @@ def update_event_info(self): if self.event: self.event.name = self.name self.event.description = self.description + self.event.public_description = self.public_description @presave_adjustment def set_default_dept(self): if len(c.PANEL_DEPT_OPTS) <= 1 and not self.department: self.department = c.PANELS + @presave_adjustment + def set_record(self): + if len(c.LIVESTREAM_OPTS) > 2 and not self.record: + self.record = c.OPT_OUT + @property def email(self): return self.submitter and self.submitter.email diff --git a/uber/site_sections/schedule.py b/uber/site_sections/schedule.py index e4a49212b..33051b047 100644 --- a/uber/site_sections/schedule.py +++ b/uber/site_sections/schedule.py @@ -100,7 +100,7 @@ def schedule_tsv(self, session): 'date': event.start_time_local.strftime('%m/%d/%Y'), 'start_time': event.start_time_local.strftime('%I:%M:%S %p'), 'end_time': (event.start_time_local + timedelta(minutes=event.minutes)).strftime('%I:%M:%S %p'), - 'description': normalize_newlines(event.description).replace('\n', ' ') + 'description': normalize_newlines(event.public_description or event.description).replace('\n', ' '), })) return render('schedule/schedule.tsv', { @@ -132,7 +132,7 @@ def ical(self, session, **params): name=event.name, begin=event.start_time, end=(event.start_time + timedelta(minutes=event.minutes)), - description=normalize_newlines(event.description), + description=normalize_newlines(event.public_description or event.description), created=event.created_info.when, location=event.location_label)) @@ -160,7 +160,7 @@ def csv(self, out, session): (event.start_time_local + timedelta(minutes=event.minutes)).strftime('%I:%M:%S %p'), event.location_label, event.guidebook_track, - normalize_newlines(event.description).replace('\n', ' '), + normalize_newlines(event.public_description or event.description).replace('\n', ' '), '', '', '', '' ]) for r in sorted(rows, key=lambda tup: tup[4]): @@ -179,7 +179,7 @@ def panels(self, out, session): event.start_time_local.strftime('%I%p %a').lstrip('0'), '{} minutes'.format(event.minutes), event.location_label, - event.description, + event.public_description or event.description, panelist_names]) @schedule_view @@ -194,7 +194,7 @@ def panels_json(self, session): 'start_unix': int(mktime(event.start_time.utctimetuple())), 'end_unix': int(mktime(event.end_time.utctimetuple())), 'duration': event.minutes, - 'description': event.description, + 'description': event.public_description or event.description, 'panelists': [panelist.attendee.full_name for panelist in event.assigned_panelists] } for event in sorted(session.query(Event).all(), key=lambda e: [e.start_time, e.location_label]) @@ -243,6 +243,7 @@ def form(self, session, message='', panelists=(), **params): if event.is_new: event.name = add_panel.name event.description = add_panel.description + event.public_description = add_panel.public_description for pa in add_panel.applicants: if pa.attendee_id: assigned_panelist = AssignedPanelist(attendee_id=pa.attendee.id, event_id=event.id) diff --git a/uber/templates/emails/panels/application.html b/uber/templates/emails/panels/application.html index e318b68fc..adbf3016d 100644 --- a/uber/templates/emails/panels/application.html +++ b/uber/templates/emails/panels/application.html @@ -33,6 +33,7 @@
  • Department: {{ app.department_label }}
  • Type: {{ app.presentation_label }}{% if app.presentation == c.OTHER %} ({{ app.other_presentation }}){% endif %}
  • Description: {{ app.description }}
  • + {% if app.public_description %}
  • Schedule Description: {{ app.public_description }}
  • {% endif %} {% if c.PANEL_RATING_OPTS|length > 1 %}
  • Rating: {{ app.rating_label }}
  • {% endif %} {% if c.PANEL_CONTENT_OPTS|length > 1 %}
  • Mature Content: {{ app.granular_rating_labels|join(', ') }}
  • @@ -42,7 +43,12 @@
  • Expected Length: {{ app.length_label if app.length != c.OTHER and not app.length_text else app.length_text }}
  • {% if app.length_reason %}
  • Reason for Length: {{ app.length_reason }}
  • {% endif %}
  • Noise Level: {{ app.noise_level_label }}
  • + {% if c.LIVE_STREAM_OPTS|length > 2 %}
  • Recording or Livestreaming: {{ app.livestream_label }}
  • + {% else %} +
  • Recording: {{ app.record_label }}
  • +
  • Livestreaming: {{ app.livestream_label }}
  • + {% endif %} {% if app.tables_desc %}
  • Special Table Set-up: {{ app.tables_desc }}
  • {% endif %} {% if app.cost_desc %}
  • Upfront Cost and Materials: {{ app.cost_desc }}
  • {% endif %} {% if app.available %}
  • Availability: {{ app.available|linebreaksbr }}
  • {% endif %} diff --git a/uber/templates/mivs/show_info.html b/uber/templates/mivs/show_info.html index d2c8e3d8d..fb9670e9e 100644 --- a/uber/templates/mivs/show_info.html +++ b/uber/templates/mivs/show_info.html @@ -50,6 +50,8 @@

    Gameplay Images

    Upload a Screenshot + {# TODO: Add Guidebook image upload!! #} +
    {{ csrf_token() }} diff --git a/uber/templates/panel_app_form.html b/uber/templates/panel_app_form.html index 1bb1a7828..9f91b1f18 100644 --- a/uber/templates/panel_app_form.html +++ b/uber/templates/panel_app_form.html @@ -62,7 +62,7 @@
    - {{ options(c.PANEL_DEPT_OPTS, app.department) }} @@ -81,7 +81,7 @@
    - {{ options(c.PANEL_RATING_OPTS, app.rating) }}
    @@ -119,7 +119,17 @@

    - Will appear as a subheading on the schedule. 200 words max. 18+ panels will not be accepted. + This is to explain your pitch to us - this can be different from what you want to show the public. 18+ panels will not be accepted. +

    +
    +
    + +
    + +
    +
    +

    + To be shown on the public facing schedule. 200 words max. Leave blank if this is the same as the Panel Description.

    {% if c.PANEL_CONTENT_OPTS|length > 1 %} @@ -138,7 +148,7 @@
    Do you want your content to be highlighted by the MAGScouts program? - {{ options(c.PANEL_MAGSCOUTS_OPTS, app.magscouts_opt_in) }}
    @@ -169,7 +179,7 @@
    - {{ options(c.PANEL_LENGTH_OPTS, app.length) }}
    @@ -195,17 +205,18 @@
    - {{ options(c.NOISE_LEVEL_OPTS, app.noise_level) }}
    +{% if c.LIVE_STREAM_OPTS|length > 2 %}
    - {{ options(c.LIVESTREAM_OPTS, app.livestream) }}
    @@ -214,6 +225,34 @@ While we don't record/live stream every panel, we attempt to record and post most panels to our YouTube channel after the event.

    +{% else %} +
    + +
    + +
    +
    +

    + While we don't record every panel, we attempt to record and post most panels to our YouTube channel after the event. +

    +
    +
    + +
    + +
    +
    +

    + If you answered Yes to being livestreamed, please ensure that you're not presenting anything that could be considered copyright infringement. +

    +
    +{% endif %}
    diff --git a/uber/templates/panel_app_form_new.html b/uber/templates/panel_app_form_new.html index c4462f084..9489ed93f 100644 --- a/uber/templates/panel_app_form_new.html +++ b/uber/templates/panel_app_form_new.html @@ -119,7 +119,17 @@

    - Will appear as a subheading on the schedule. 200 words max. 18+ panels will not be accepted. + This is to explain your pitch to us - this can be different from what you want to show the public. 18+ panels will not be accepted. +

    +
    +
    + +
    + +
    +
    +

    + To be shown on the public facing schedule. 200 words max. Leave blank if this is the same as the Panel Description.

    {% if c.PANEL_CONTENT_OPTS|length > 1 %} @@ -202,10 +212,12 @@
    +{% if c.LIVE_STREAM_OPTS|length > 2 %}
    @@ -214,6 +226,34 @@ While we don't record/live stream every panel, we attempt to record and post most panels to our YouTube channel after the event.

    +{% else %} +
    + +
    + +
    +
    +

    + While we don't record every panel, we attempt to record and post most panels to our YouTube channel after the event. +

    +
    +
    + +
    + +
    +
    +

    + If you answered Yes to being livestreamed, please ensure that you're not presenting anything that could be considered copyright infringement. +

    +
    +{% endif %}
    diff --git a/uber/templates/panels/guest.html b/uber/templates/panels/guest.html index 36dcdfc51..05e28b1d1 100644 --- a/uber/templates/panels/guest.html +++ b/uber/templates/panels/guest.html @@ -37,7 +37,7 @@

    Additional Information

    Please let us know of any schedule conflicts due to prior obligations, travel times, or other needs. (e.g. you made a deal with a fairy godmother to get here and have to be back in your room by midnight.) - Panels run form 12 PM to 3 AM Thursday, 10 AM to 3 AM Friday, 10 AM to 3 AM Saturday, and 10 AM to 3 PM Sunday. + Panels run from 12 PM to 3 AM Thursday, 10 AM to 3 AM Friday, 10 AM to 3 AM Saturday, and 10 AM to 3 PM Sunday.

    diff --git a/uber/templates/panels/index.html b/uber/templates/panels/index.html index 84a85b5da..eb6e6e9f2 100644 --- a/uber/templates/panels/index.html +++ b/uber/templates/panels/index.html @@ -106,7 +106,7 @@

    Additional Information

    Please list all times during the event when you will NOT be available to hold your panel. This is used for scheduling purposes. Rescheduling based on information not given here will be very difficult. -

    Panels run form 12 PM to 3 AM Thursday, 10 AM to 3 AM Friday, 10 AM to 3 AM Saturday, and 10 AM to 3 PM Sunday. +

    Panels run from 12 PM to 3 AM Thursday, 10 AM to 3 AM Friday, 10 AM to 3 AM Saturday, and 10 AM to 3 PM Sunday.

    @@ -131,8 +131,8 @@

    Additional Information

    diff --git a/uber/templates/panels_admin/app.html b/uber/templates/panels_admin/app.html index dea52f051..7e8350c75 100644 --- a/uber/templates/panels_admin/app.html +++ b/uber/templates/panels_admin/app.html @@ -153,6 +153,15 @@

    Panel Application View all panel applications + {% if app.public_description %} +
    + +
    + {{ app.public_description|linebreaksbr }} +
    +
    + {% endif %} + {% if c.PANEL_RATING_OPTS|length > 1 %}
    @@ -203,9 +212,18 @@

    Panel Application View all panel applications + {% if c.LIVE_STREAM_OPTS|length > 2 %}
    {{ app.livestream_label }}
    + {% else %} +
    + Recording: {{ app.record_label }} +
    +
    + Livestreaming: {{ app.livestream_label }} +
    + {% endif %}

    {% if app.tables_desc %} diff --git a/uber/templates/panels_admin/form.html b/uber/templates/panels_admin/form.html index f768e55bf..c0c610fcc 100644 --- a/uber/templates/panels_admin/form.html +++ b/uber/templates/panels_admin/form.html @@ -13,11 +13,6 @@

    Edit Panel

    -
    -

    - Please list all times during the event when you will NOT be available to hold your panel. - This is used for scheduling purposes. Rescheduling based on information not given here will be very difficult. -

    diff --git a/uber/templates/schedule/form.html b/uber/templates/schedule/form.html index b1b388892..4de3a44f4 100644 --- a/uber/templates/schedule/form.html +++ b/uber/templates/schedule/form.html @@ -101,6 +101,10 @@ Description: + + Public/Schedule Description: + +
    diff --git a/uber/templates/schedule/schedule.tsv b/uber/templates/schedule/schedule.tsv index 93195a998..3ed1e975e 100644 --- a/uber/templates/schedule/schedule.tsv +++ b/uber/templates/schedule/schedule.tsv @@ -1,3 +1,3 @@ {% autoescape off %}Session Title Date Time Start Time End Room/Location Schedule Track (Optional) Description (Optional) -{% for place, events in schedule %}{% for event in events %}{{ event.name }} {{event.date}} {{ event.start_time }} {{ event.end_time }} {{ place }} {{ event.description|default("NO DESCRIPTION") }} +{% for place, events in schedule %}{% for event in events %}{{ event.name }} {{event.date}} {{ event.start_time }} {{ event.end_time }} {{ place }} {{ event.public_description|default(event.description|default("NO DESCRIPTION")) }} {% endfor %}{% endfor %}{% endautoescape %} diff --git a/uber/templates/schedule/schedule.xml b/uber/templates/schedule/schedule.xml index 822577c58..7484aae17 100644 --- a/uber/templates/schedule/schedule.xml +++ b/uber/templates/schedule/schedule.xml @@ -2,7 +2,7 @@ {% for place, events in schedule %} {% for event in events %} - {{ event.description|default("NO DESCRIPTION") }} + {{ event.public_description|default(event.description|default("NO DESCRIPTION")) }} {% endfor %} {% endfor %}