Skip to content

Commit

Permalink
Merge branch 'main' into vimeo-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
djamg committed Dec 5, 2023
2 parents 4943b06 + 48ccb8d commit 8bf5efe
Show file tree
Hide file tree
Showing 109 changed files with 2,382 additions and 1,921 deletions.
14 changes: 8 additions & 6 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest] # TODO: Figure out macos-latest and Docker
python-version: ['3.11']
python-version: ['3.11', '3.12']

services:
redis:
Expand All @@ -61,10 +61,10 @@ jobs:
if: ${{ matrix.os == 'macos-latest' }}
- name: Checkout code
uses: actions/checkout@v3
- name: Install Firefox (for browser testing)
uses: browser-actions/setup-firefox@latest
- name: Install Geckodriver (for browser testing)
uses: browser-actions/setup-geckodriver@latest
- name: Install Chrome (for browser testing)
uses: browser-actions/setup-chrome@latest
- name: Install Chromedriver (for browser testing)
uses: nanasess/setup-chromedriver@v2
- name: Install Python
uses: actions/setup-python@v4
with:
Expand All @@ -78,10 +78,12 @@ jobs:
key: ${{ matrix.os }}-${{ env.pythonLocation }}-${{ hashFiles('requirements/base.txt') }}-${{ hashFiles('requirements.txt/test.txt') }}
- name: Install Python dependencies
run: make install-python-test
- name: Install Playwright browser
run: make install-playwright
- name: Install Node
uses: actions/setup-node@v3
with:
node-version: latest
node-version: 20
cache: npm
- name: Cache node modules
uses: actions/cache@v3
Expand Down
32 changes: 26 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ ci:
skip: [
'pip-audit',
'yesqa',
'creosote',
'no-commit-to-branch',
# 'hadolint-docker',
'docker-compose-check',
Expand Down Expand Up @@ -42,17 +43,15 @@ repos:
'PYSEC-2022-42969', # https://github.com/pytest-dev/pytest/issues/10392
'--ignore-vuln',
'PYSEC-2023-73', # https://github.com/RedisLabs/redisraft/issues/608
'--ignore-vuln',
'PYSEC-2023-101', # https://github.com/pytest-dev/pytest-selenium/issues/310
]
files: ^requirements/.*\.txt$
- repo: https://github.com/asottile/pyupgrade
rev: v3.15.0
hooks:
- id: pyupgrade
args: ['--keep-runtime-typing', '--py310-plus']
args: ['--keep-runtime-typing', '--py311-plus']
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.292
rev: v0.1.6
hooks:
- id: ruff
args: ['--fix', '--exit-non-zero-on-fix']
Expand Down Expand Up @@ -98,7 +97,7 @@ repos:
additional_dependencies:
- tomli
- repo: https://github.com/psf/black
rev: 23.9.1
rev: 23.11.0
hooks:
- id: black
# Mypy is temporarily disabled until the SQLAlchemy 2.0 migration is complete
Expand Down Expand Up @@ -146,6 +145,27 @@ repos:
args: ['-c', 'pyproject.toml']
additional_dependencies:
- 'bandit[toml]'
- repo: https://github.com/fredrikaverpil/creosote
rev: v3.0.0
hooks:
- id: creosote
args:
- --venv=.venv
- --path=funnel
- --path=tests
- --path=migrations/versions
- --deps-file=requirements/base.in
- --exclude-dep=argon2-cffi # Optional dep for passlib
- --exclude-dep=bcrypt # Optional dep for passlib
- --exclude-dep=greenlet # Optional dep for SQLAlchemy's asyncio support
- --exclude-dep=gunicorn # Not imported, used as server
- --exclude-dep=linkify-it-py # Optional dep for markdown-it-py
- --exclude-dep=psycopg # Optional dep for SQLAlchemy
- --exclude-dep=rq-dashboard # Creosote fails to recognise the import
- --exclude-dep=tzdata # Data-only dep, therefore no import statement
- --exclude-dep=urllib3 # Required to silence a pip-audit warning
- --exclude-dep=wtforms-sqlalchemy # Temp dep on an unreleased git branch

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
Expand Down Expand Up @@ -188,7 +208,7 @@ repos:
- id: forbid-tabs
- id: remove-tabs
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.0.3
rev: v3.1.0
hooks:
- id: prettier
args:
Expand Down
14 changes: 12 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ all:
@echo
@echo "For testing and CI:"
@echo " make install-test # Install everything needed for a test environment"
@echo " make install-playwright # Install browsers for Playwright-based tests"
@echo
@echo "For development:"
@echo " make install-dev # For first time setup and after dependency upgrades"
Expand Down Expand Up @@ -118,9 +119,18 @@ install-python-test: install-python-pip deps-editable
install-python: install-python-pip deps-editable
pip install --use-pep517 -r requirements/base.txt

install-dev: deps-editable install-python-dev install-npm assets
install-playwright:
@if command -v playwright > /dev/null; then\
echo "playwright install --with-deps";\
playwright install --with-deps;\
else\
echo "Install Playwright first: make install-python-test";\
exit 1;\
fi

install-test: deps-editable install-python-test install-npm assets
install-dev: deps-editable install-python-dev install-playwright install-npm assets

install-test: deps-editable install-python-test install-playwright install-npm assets

install: deps-editable install-python install-npm-ci assets

Expand Down
7 changes: 4 additions & 3 deletions funnel/assets/js/rsvp_form_modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import jsonForm from './utils/jsonform';
Vue.config.devtools = true;

const FormUI = {
init(jsonSchema) {
init(jsonSchema, useremail) {
/* eslint-disable no-new */
new Vue({
el: '#register-form',
data() {
return {
jsonSchema,
useremail,
};
},
components: {
Expand All @@ -27,7 +28,7 @@ const FormUI = {
};

$(() => {
window.Hasgeek.addRsvpForm = (jsonSchema) => {
FormUI.init(jsonSchema);
window.Hasgeek.addRsvpForm = (jsonSchema, useremail) => {
FormUI.init(jsonSchema, useremail);
};
});
5 changes: 2 additions & 3 deletions funnel/assets/js/schedule_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,9 +276,8 @@ const Schedule = {
this.config.slotInterval
);
if (this.config.schedule[session.eventDay]) {
this.config.schedule[session.eventDay].sessions[
session.startTime
].showLabel = true;
this.config.schedule[session.eventDay].sessions[session.startTime].showLabel =
true;
this.config.schedule[session.eventDay].sessions[session.startTime].rooms[
session.room_scoped_name
].talk = session;
Expand Down
2 changes: 1 addition & 1 deletion funnel/assets/js/utils/jsonform.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Form from './formhelper';

const jsonForm = Vue.component('jsonform', {
template: '#form-template',
props: ['jsonschema', 'title', 'formid'],
props: ['jsonschema', 'title', 'formid', 'useremail'],
methods: {
getFormData() {
const obj = {};
Expand Down
2 changes: 1 addition & 1 deletion funnel/assets/js/utils/ractive_util.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { USER_AVATAR_IMG_SIZE } from '../constants';
Ractive.DEBUG = false;

export const useravatar = Ractive.extend({
template: `{{#if user.profile_url && addprofilelink }}<a href="{{user.profile_url}}" class="nounderline">{{#if user.logo_url }}<img class="user__box__gravatar" src="{{ imgurl() }}" />{{else}}<div class="user__box__gravatar user__box__gravatar--initials" data-avatar-colour="{{ getAvatarColour(user.fullname) }}">{{ getInitials(user.fullname) }}</div>{{/if}}</a>{{else}}<span>{{#if user.logo_url }}<img class="user__box__gravatar" src="{{ imgurl() }}" />{{else}}<div class="user__box__gravatar user__box__gravatar--initials" data-avatar-colour="{{ getAvatarColour(user.fullname) }}">{{ getInitials(user.fullname) }}</div>{{/if}}</span>{{/if}}`,
template: `{{#if addprofilelink }}<a href="{{user.absolute_url}}" class="nounderline">{{#if user.logo_url }}<img class="user__box__gravatar" src="{{ imgurl() }}" />{{else}}<div class="user__box__gravatar user__box__gravatar--initials" data-avatar-colour="{{ getAvatarColour(user.fullname) }}">{{ getInitials(user.fullname) }}</div>{{/if}}</a>{{else}}<span>{{#if user.logo_url }}<img class="user__box__gravatar" src="{{ imgurl() }}" />{{else}}<div class="user__box__gravatar user__box__gravatar--initials" data-avatar-colour="{{ getAvatarColour(user.fullname) }}">{{ getInitials(user.fullname) }}</div>{{/if}}</span>{{/if}}`,
data: {
addprofilelink: true,
size: 'medium',
Expand Down
2 changes: 1 addition & 1 deletion funnel/assets/js/utils/vue_util.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { USER_AVATAR_IMG_SIZE } from '../constants';

export const userAvatarUI = Vue.component('useravatar', {
template:
'<a :href="user.profile_url" v-if="user.profile_url && addprofilelink" class="nounderline"><span class="user__box__wrapper" v-if="user.logo_url"><img class="user__box__gravatar" :src="imgurl"></span><div class="user__box__gravatar user__box__gravatar--initials" :data-avatar-colour="getAvatarColour(user.fullname)" v-else>{{ getInitials(user.fullname) }}</div></a v-if="user.profile_url && addprofilelink"></a><span v-else><img class="user__box__gravatar" :src="imgurl" v-if="user.logo_url"/><div class="user__box__gravatar user__box__gravatar--initials" :data-avatar-colour="getAvatarColour(user.fullname)" v-else>{{ getInitials(user.fullname) }}</span v-else>',
'<a :href="user.absolute_url" v-if="addprofilelink" class="nounderline"><span class="user__box__wrapper" v-if="user.logo_url"><img class="user__box__gravatar" :src="imgurl"></span><div class="user__box__gravatar user__box__gravatar--initials" :data-avatar-colour="getAvatarColour(user.fullname)" v-else>{{ getInitials(user.fullname) }}</div></a v-if="user.absolute_url && addprofilelink"></a><span v-else><img class="user__box__gravatar" :src="imgurl" v-if="user.logo_url"/><div class="user__box__gravatar user__box__gravatar--initials" :data-avatar-colour="getAvatarColour(user.fullname)" v-else>{{ getInitials(user.fullname) }}</span v-else>',
props: {
user: Object,
addprofilelink: {
Expand Down
6 changes: 2 additions & 4 deletions funnel/assets/sass/components/_ticket-modal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
}

.price-btn {
min-width: 200px;
min-width: 150px;
font-size: inherit;
padding: 0;
display: flex;
Expand All @@ -78,9 +78,7 @@
justify-content: center;
height: 42px;
line-height: 16px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
white-space: break-spaces;
}

.price-btn__txt {
Expand Down
11 changes: 6 additions & 5 deletions funnel/assets/sass/pages/project.scss
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,13 @@
border-color: inherit;
}
}
.register-block__content--half {
width: calc(50% - 8px);
.register-block__content {
width: calc(50% - $mui-grid-padding/2);
align-self: flex-end;
}
.register-block__content--half:first-child {
margin-right: 16px;
.register-block__content:only-child {
width: 100%;
align-self: flex-end;
}
}

Expand Down Expand Up @@ -141,7 +142,7 @@
border-color: inherit;
}
}
.register-block__content--half {
.register-block__content {
.register-block__content__rsvp-txt {
font-size: 9px;
}
Expand Down
3 changes: 1 addition & 2 deletions funnel/devtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
import weakref
from collections.abc import Callable, Iterable
from secrets import token_urlsafe
from typing import Any, NamedTuple
from typing_extensions import Protocol
from typing import Any, NamedTuple, Protocol

from flask import Flask

Expand Down
8 changes: 5 additions & 3 deletions funnel/forms/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ def validate_username(self, field: forms.Field) -> None:
raise_username_error(reason)


class EnableNotificationsDescriptionMixin:
class EnableNotificationsDescriptionProtoMixin:
"""Mixin to add a link in the description for enabling notifications."""

enable_notifications: forms.Field
Expand All @@ -513,7 +513,9 @@ def set_queries(self) -> None:


@Account.forms('email_add')
class NewEmailAddressForm(EnableNotificationsDescriptionMixin, forms.RecaptchaForm):
class NewEmailAddressForm(
EnableNotificationsDescriptionProtoMixin, forms.RecaptchaForm
):
"""Form to add a new email address to an account."""

__expects__ = ('edit_user',)
Expand Down Expand Up @@ -560,7 +562,7 @@ class EmailPrimaryForm(forms.Form):


@Account.forms('phone_add')
class NewPhoneForm(EnableNotificationsDescriptionMixin, forms.RecaptchaForm):
class NewPhoneForm(EnableNotificationsDescriptionProtoMixin, forms.RecaptchaForm):
"""Form to add a new mobile number (SMS-capable) to an account."""

__expects__ = ('edit_user',)
Expand Down
2 changes: 2 additions & 0 deletions funnel/forms/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,8 @@ def format_json(data: dict | str | None) -> str:

def validate_and_convert_json(form: forms.Form, field: forms.Field) -> None:
"""Confirm form data is valid JSON, and store it back as a parsed dict."""
if field.data is None:
return
try:
field.data = json.loads(field.data)
except ValueError:
Expand Down
4 changes: 3 additions & 1 deletion funnel/forms/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ class ProfileTransitionForm(forms.Form):

def set_queries(self) -> None:
"""Prepare form for use."""
self.transition.choices = list(self.edit_obj.state.transitions().items())
self.transition.choices = list(
self.edit_obj.profile_state.transitions().items()
)


@Account.forms('logo')
Expand Down
5 changes: 4 additions & 1 deletion funnel/forms/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import annotations

import re
from typing import cast

from baseframe import _, __, forms
from baseframe.forms.sqlalchemy import AvailableName
Expand Down Expand Up @@ -372,12 +373,14 @@ class ProjectRegisterForm(forms.Form):
)

def validate_form(self, field: forms.Field) -> None:
if not self.form.data:
return
if self.form.data and not self.schema:
raise forms.validators.StopValidation(
_("This registration is not expecting any form fields")
)
if self.schema:
form_keys = set(self.form.data.keys())
form_keys = set(cast(dict, self.form.data).keys())
schema_keys = {i['name'] for i in self.schema['fields']}
if not form_keys.issubset(schema_keys):
invalid_keys = form_keys.difference(schema_keys)
Expand Down
8 changes: 5 additions & 3 deletions funnel/forms/sync_ticket.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from baseframe import __, forms

from ..models import (
PROJECT_RSVP_STATE,
Account,
AccountEmail,
Project,
Expand Down Expand Up @@ -68,9 +69,10 @@ class ProjectBoxofficeForm(forms.Form):
validators=[forms.validators.AllowedIf('org')],
filters=[forms.filters.strip()],
)
allow_rsvp = forms.BooleanField(
__("Allow free registrations"),
default=False,
rsvp_state = forms.RadioField(
__("Registrations"),
choices=PROJECT_RSVP_STATE.items(),
default=PROJECT_RSVP_STATE.NONE,
)
is_subscription = forms.BooleanField(
__("Paid tickets are for a subscription"),
Expand Down
Loading

0 comments on commit 8bf5efe

Please sign in to comment.