Skip to content

Commit

Permalink
Merge branch 'main' into whatsapp-integration
Browse files Browse the repository at this point in the history
  • Loading branch information
jace committed Dec 13, 2023
2 parents 0400176 + 1a1b2e8 commit c30a9c8
Show file tree
Hide file tree
Showing 61 changed files with 814 additions and 884 deletions.
11 changes: 5 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ repos:
- id: pyupgrade
args: ['--keep-runtime-typing', '--py311-plus']
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.5
rev: v0.1.7
hooks:
- id: ruff
args: ['--fix', '--exit-non-zero-on-fix']
Expand Down Expand Up @@ -91,7 +91,7 @@ repos:
- toml
- tomli
- repo: https://github.com/PyCQA/isort
rev: 5.12.0
rev: 5.13.0
hooks:
- id: isort
additional_dependencies:
Expand Down Expand Up @@ -138,7 +138,7 @@ repos:
additional_dependencies:
- tomli
- repo: https://github.com/PyCQA/bandit
rev: 1.7.5
rev: 1.7.6
hooks:
- id: bandit
language_version: python3
Expand Down Expand Up @@ -208,11 +208,10 @@ repos:
- id: forbid-tabs
- id: remove-tabs
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.1.0
rev: v4.0.0-alpha.4
hooks:
- id: prettier
args:
['--single-quote', '--trailing-comma', 'es5', '--end-of-line', 'lf']
args: ['--single-quote', '--trailing-comma', 'es5', '--end-of-line', 'lf']
exclude: funnel/templates/js/
- repo: https://github.com/ducminh-phan/reformat-gherkin
rev: v3.0.1
Expand Down
1 change: 1 addition & 0 deletions .prettierrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ module.exports = {
endOfLine: 'lf',
singleQuote: true,
trailingComma: 'es5',
printWidth: 88,
};
4 changes: 1 addition & 3 deletions funnel/assets/sass/components/_ticket-modal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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
15 changes: 8 additions & 7 deletions funnel/forms/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
PASSWORD_MIN_LENGTH,
Account,
Anchor,
User,
check_password_strength,
getuser,
)
Expand Down Expand Up @@ -158,7 +159,7 @@ class PasswordForm(forms.Form):
"""Form to validate a user's password, for password-gated sudo actions."""

__expects__ = ('edit_user',)
edit_user: Account
edit_user: User

password = forms.PasswordField(
__("Password"),
Expand All @@ -181,7 +182,7 @@ class PasswordPolicyForm(forms.Form):

__expects__ = ('edit_user',)
__returns__ = ('password_strength', 'is_weak', 'warning', 'suggestions')
edit_user: Account
edit_user: User
password_strength: int | None = None
is_weak: bool | None = None
warning: str | None = None
Expand Down Expand Up @@ -252,7 +253,7 @@ class PasswordCreateForm(forms.Form):

__returns__ = ('password_strength',)
__expects__ = ('edit_user',)
edit_user: Account
edit_user: User
password_strength: int | None = None

password = forms.PasswordField(
Expand Down Expand Up @@ -334,7 +335,7 @@ class PasswordChangeForm(forms.Form):

__returns__ = ('password_strength',)
__expects__ = ('edit_user',)
edit_user: Account
edit_user: User
password_strength: int | None = None

old_password = forms.PasswordField(
Expand Down Expand Up @@ -473,7 +474,7 @@ class UsernameAvailableForm(forms.Form):
"""Form to check for whether a username is available to use."""

__expects__ = ('edit_user',)
edit_user: Account
edit_user: User

username = forms.StringField(
__("Username"),
Expand Down Expand Up @@ -519,7 +520,7 @@ class NewEmailAddressForm(
"""Form to add a new email address to an account."""

__expects__ = ('edit_user',)
edit_user: Account
edit_user: User

email = forms.EmailField(
__("Email address"),
Expand Down Expand Up @@ -566,7 +567,7 @@ class NewPhoneForm(EnableNotificationsDescriptionProtoMixin, forms.RecaptchaForm
"""Form to add a new mobile number (SMS-capable) to an account."""

__expects__ = ('edit_user',)
edit_user: Account
edit_user: User

phone = forms.TelField(
__("Phone number"),
Expand Down
6 changes: 4 additions & 2 deletions funnel/forms/auth_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
AuthClient,
AuthClientCredential,
AuthClientPermissions,
User,
valid_name,
)
from .helpers import strip_filters
Expand All @@ -29,7 +30,8 @@ class AuthClientForm(forms.Form):
"""Register a new OAuth client application."""

__returns__ = ('account',)
account: Account | None = None
edit_user: User
account: Account

title = forms.StringField(
__("Application title"),
Expand Down Expand Up @@ -127,7 +129,7 @@ def _urls_match(self, url1: str, url2: str) -> bool:
def validate_redirect_uri(self, field: forms.Field) -> None:
"""Validate redirect URI points to the website for confidential clients."""
if self.confidential.data and not self._urls_match(
self.website.data, field.data
self.website.data or '', field.data
):
raise forms.validators.ValidationError(
_("The scheme, domain and port must match that of the website URL")
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: 2 additions & 2 deletions funnel/forms/organization.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from baseframe import _, __, forms

from ..models import Account, Team
from ..models import Account, Team, User

__all__ = ['OrganizationForm', 'TeamForm']

Expand All @@ -19,7 +19,7 @@ class OrganizationForm(forms.Form):
"""Form for an organization's name and title."""

__expects__: Iterable[str] = ('edit_user',)
edit_user: Account
edit_user: User
edit_obj: Account | None

title = forms.StringField(
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 @@ -371,12 +372,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
4 changes: 2 additions & 2 deletions funnel/models/auth_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ class AuthClient(ScopeMixin, UuidMixin, BaseMixin, Model):
__scope_null_allowed__ = True
#: Account that owns this client
account_id: Mapped[int] = sa.orm.mapped_column(
sa.ForeignKey('account.id'), nullable=True
sa.ForeignKey('account.id'), nullable=False
)
account: Mapped[Account | None] = with_roles(
account: Mapped[Account] = with_roles(
relationship(
Account,
foreign_keys=[account_id],
Expand Down
3 changes: 1 addition & 2 deletions funnel/models/email_address.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
from pyisemail import is_email
from pyisemail.diagnosis import BaseDiagnosis
from sqlalchemy import event, inspect
from sqlalchemy.orm import Mapper
from sqlalchemy.orm.attributes import NO_VALUE
from sqlalchemy.orm import NO_VALUE, Mapper
from werkzeug.utils import cached_property

from coaster.sqlalchemy import StateManager, auto_init_default, immutable, with_roles
Expand Down
12 changes: 10 additions & 2 deletions funnel/models/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,11 @@ def decorator(attr: T) -> T:
# None or '' not allowed
raise ValueError(f"Could not determine name for {attr!r}")
if use_name in cls.__dict__:
raise AttributeError(f"{cls.__name__} already has attribute {use_name}")
raise AttributeError(
f"{cls.__name__} already has attribute {use_name}",
name=use_name,
obj=cls,
)
setattr(cls, use_name, attr)
return attr

Expand Down Expand Up @@ -291,7 +295,11 @@ def decorator(temp_cls: TempType) -> ReopenedType:
):
# Refuse to overwrite existing attributes
if hasattr(cls, attr):
raise AttributeError(f"{cls.__name__} already has attribute {attr}")
raise AttributeError(
f"{cls.__name__} already has attribute {attr}",
name=attr,
obj=cls,
)
# All good? Copy the attribute over...
setattr(cls, attr, value)
# ...And remove it from the temporary class
Expand Down
4 changes: 2 additions & 2 deletions funnel/models/label.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ def __getattr__(self, name: str) -> bool | str | None:
Label.name == name, Label.project == self._obj.project
).one_or_none()
if label is None:
raise AttributeError
raise AttributeError(f"No label {name} in {self._obj.project}")

if not label.has_options:
return label in self._obj.labels
Expand All @@ -357,7 +357,7 @@ def __setattr__(self, name: str, value: bool) -> None:
Label._archived.is_(False),
).one_or_none()
if label is None:
raise AttributeError
raise AttributeError(f"No label {name} in {self._obj.project}")

if not label.has_options:
if value is True:
Expand Down
4 changes: 4 additions & 0 deletions funnel/models/login_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
class LoginSessionError(Exception):
"""Base exception for user session errors."""

def __init__(self, login_session: LoginSession, *args) -> None:
self.login_session = login_session
super().__init__(login_session, *args)


class LoginSessionExpiredError(LoginSessionError):
"""This user session has expired and cannot be marked as currently active."""
Expand Down
Loading

0 comments on commit c30a9c8

Please sign in to comment.