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

Sync upstream with conflict #186

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
9e9d09e
Tab title reflects proposal title in cfp wizard
rixx May 24, 2024
b82f926
Translations update: Czech and Chinese
pretalx-translations Jun 10, 2024
5095ea0
Fix data on event and organiser delete
rixx Jun 12, 2024
a8df732
Translations update: Portuguese, new: Vietnamese
pretalx-translations Jun 20, 2024
ce2836e
Don't merge resources into question section
rixx Jun 20, 2024
06cceed
Code style
rixx Jun 25, 2024
6d14929
Add is_featured filter to submissions API
rixx Jun 25, 2024
0ad0010
Fix code style
rixx Jul 5, 2024
59c4aa4
Fix locale preference message in wrong language
rixx Jul 5, 2024
c78a98f
Fix code style
rixx Jul 5, 2024
401ca8b
Use defusedxml
rixx Jul 25, 2024
3dab487
Remove unnecessary variables and context managers
rixx Jul 25, 2024
13c7a1f
Better use of direct assignments
rixx Jul 25, 2024
a901374
Fix code style
rixx Jul 25, 2024
b4fcefa
Use correct variable types
rixx Jul 26, 2024
e4749f4
Improve variable names
rixx Jul 26, 2024
1fe3408
Walrus and other if statement improvements
rixx Jul 26, 2024
7741a0a
Shuffle code to better places
rixx Jul 26, 2024
d994d19
Fix incorrect use of raw strings
rixx Jul 26, 2024
41afa69
Fix comments
rixx Jul 26, 2024
f5d1777
Make imports more consistent
rixx Jul 26, 2024
977ce54
Translations update: French
pretalx-translations Aug 2, 2024
a96af34
Remove console logs
rixx Aug 3, 2024
268f73c
Sanitize markdown preview
rixx Aug 3, 2024
7700b33
Show allowed image formats in help text
rixx Aug 5, 2024
92c1e81
Fix missing space in help text
rixx Aug 5, 2024
9996626
Remove reference to missing sourcemap
rixx Aug 5, 2024
6c5879f
django settings variable can't start with _ (#1810)
dest81 Aug 6, 2024
abb24a8
Remove release notes entry
rixx Aug 6, 2024
2cef658
Translations update: French, German
pretalx-translations Aug 6, 2024
5aadce3
Update translations
rixx Aug 6, 2024
44630f3
Translations update: German
pretalx-translations Aug 6, 2024
a4c464e
Release v2024.2.0
rixx Aug 6, 2024
1ef0dd8
Update translation percentages
rixx Aug 6, 2024
0f02bad
Update changelog
rixx Aug 6, 2024
9bc5a36
Bump version to development version
rixx Aug 6, 2024
69b4b7d
Update maintainer docs
rixx Aug 6, 2024
5670fbd
[ci] Don't show empty spellcheck summary
rixx Aug 9, 2024
c5bc376
[docs] Use better CSRF doc link
rixx Aug 9, 2024
ef9b344
Fix broken plugin list
rixx Aug 9, 2024
fe1f1c3
Release v2024.2.1
rixx Aug 9, 2024
a95e181
Bump version
rixx Aug 9, 2024
5b34f11
Fix missing QR codes
rixx Aug 12, 2024
236423b
Make iCal export private
rixx Aug 12, 2024
ca01acc
Fix breaking tests
rixx Aug 12, 2024
d1890e3
Fix breaking tests some more
rixx Aug 14, 2024
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
17 changes: 15 additions & 2 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,21 @@ jobs:
- name: Spellcheck docs
run: make spelling
working-directory: ./doc
- name:
run: '[ ! -s _build/spelling/output.txt ]'
- name: Put spelling errors into summary file
run: |
if [ -z "$(find _build -type f -name '*.spelling')" ]; then
echo "No spelling errors found."
exit 0
fi
echo "## Spellcheck results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
for file in $(find _build -type f -name "*.spelling"); do
sed 's/^/- /' < $file >> $GITHUB_STEP_SUMMARY
done
echo "" >> $GITHUB_STEP_SUMMARY
working-directory: ./doc
- name: Fail if there were spelling errors
run: '! find _build -type f -name "*.spelling" | grep -q .'
working-directory: ./doc

linkcheck:
Expand Down
2 changes: 1 addition & 1 deletion doc/api/fundamentals.rst
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,4 @@ If you see the ``o`` parameter on a resource, you can use it to sort the result
set by one of the allowed fields. Prepend a ``-`` to the field name to reverse
the sort order.

.. _CSRF policies: https://docs.djangoproject.com/en/1.11/ref/csrf/#ajax
.. _CSRF policies: https://docs.djangoproject.com/en/stable/howto/csrf/#using-csrf-protection-with-ajax
1 change: 1 addition & 0 deletions doc/api/resources/submissions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ Endpoints
:query submission_type: Filter submissions by submission type
:query state: Filter submission by state. Will filter by multiple states if you provide multiple state arguments.
:query questions: Pass a comma separated list of question IDs to load, or the string "all" to return all answers.
:query is_featured: Filter by the ``is_featured`` field (``true`` or ``false``).

.. http:get:: /api/events/(event)/submissions/{code}

Expand Down
1 change: 1 addition & 0 deletions doc/api/resources/talks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ Endpoints
:query submission_type: Filter submissions by submission type
:query state: Filter submission by state
:query questions: Pass a comma separated list of question IDs to load, or the string 'all' to return all answers.
:query is_featured: Filter by the ``is_featured`` field (``true`` or ``false``).

.. http:get:: /api/events/(event)/talks/{code}

Expand Down
20 changes: 19 additions & 1 deletion doc/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
.. _changelog:

Release Notes
- :feature:`orga:sidebar` Renamed CfP to Call for Speakers for clarity
=============

- :feature:`schedule,1794` The iCal schedule export has been made private (available only to organisers) as the utility of importing a conference's entire schedule is limited, and people were frustrated that the iCal export did not reflect any applied schedule filters.
- :bug:`schedule,1803` The QR code for schedule exporter links was not showing up when hovering on the QR code symbol.
- :release:`2024.2.1 <2024-08-07>`
- :bug:`orga` The plugin list was always shown as empty, even when there were plugins installed.
- :feature:`orga` Administrators can now also deactivate user accounts, which will log out that user and won't allow them to log in again.
- :release:`2024.2.0 <2024-08-06>`
- :bug:`orga` The markdown preview posed a security vulnerability by allowing speakers and organisers to include unsafe JavaScript. This JavaScript would only be executed when accessing the preview, i.e. when a speaker or organiser opened to proposal page (not attendees or the public). Thanks to Jorian Woltjer for reporting this issue.
- :feature:`api` The submission API now has a filter for the ``is_featured`` field.
- :feature:`cfp,1761` In the CfP submission multi-step form, the tab title now reflects the proposal title, to make it easier to work on multiple proposal submissions at the same time.
- :bug:`orga:speaker,1768` When filtering the speaker list by only accepted/confirmed speakers, the listed proposal count would be incorrect (inflated).
- :feature:`cfp,1574` pretalx now supports the ``~~`` strikethrough syntax in Markdown.
- :bug:`orga:schedule,1702` Sessions starting at exactly midnight of the first day of the event would not show up in the schedule editor (but could be scheduled there by dropping them on the day heading).
- :feature:`orga:schedule,1730` The schedule editor now allows you to schedule talks that are only "pending accepted" (i.e. the speaker has not yet received the acceptance email), so that organisers can try out how their schedule would look with a given number of tentatively accepted proposals.
- :feature:`orga` Administrators (i.e. instance owners) can now search a list of all users, which includes their teams and permissions, and links to trigger account deletion and password resets.
- :bug:`orga:review` Assigning reviewers could lead to incorrect assignments when browsers cached the form, but new reviewers were added to the team, shifting the overall order of input fields.
- :feature:`cfp` Choice and multiple choice questions now use a drop-down with typeahead (search for options) when they have a lot of options.
- :feature:`orga,1079` All images in forms in the organiser area now include a preview of the saved image, and open a lightbox instead of the image file when clicked.
- :announcement:`admin` We now recommend that you use a virtualenv instead of the ``pip --user`` installation method, and have updated our install and upgrade documentation accordingly.
- :bug:`orga` While organisers could reorder questions, and the order was saved and used in the frontend, the new order was not shown in the organiser backend.
- :feature:`orga` All tables in the organiser area now come with sticky headers, to accommodate the possible increased length of the tables.
Expand Down
6 changes: 3 additions & 3 deletions doc/maintainer/release.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ System checks
-------------

1. Deploy the release-ready commit to an instance. Check if the upgrade and the instance works.
2. Clone pretalx into a clean repo: ``git clone git@github.com:pretalx/pretalx pretalx-release && cd pretalx-release``
3. Set up your environment: ``mkvirtualenv pretalx-release && pip install -e . check-manifest twine``
2. Clean clone: ``git clone git@github.com:pretalx/pretalx pretalx-release && cd pretalx-release``
3. Set up your environment: ``mkvirtualenv pretalx-release && pip install -e . check-manifest twine wheel``
4. Run ``check-manifest`` **locally**.

Take-off and landing
Expand All @@ -37,7 +37,7 @@ Take-off and landing
3. Make a release commit: ``RELEASE=vx.y.z; git commit -am "Release $RELEASE" && git tag -m "Release $RELEASE" $RELEASE``
4. Build a new release: ``rm -rf dist/ build/ pretalx.egg-info && python -m build -n``
5. Upload the release: ``twine upload dist/pretalx-*``
6. Push the release: ``git push && git push --tags``
6. Push the release: ``git push``
7. Install/update the package somewhere.
8. Publish the blog post.
9. Add the release on `GitHub <https://github.com/pretalx/pretalx/releases>`_ (upload the archive you uploaded to PyPI, and add a link to the correct section of the :ref:`changelog`)
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ dependencies = [
"csscompressor~=0.9.0",
"cssutils~=2.9.0",
"defusedcsv~=2.0.0",
"Django~=4.2.0",
"defusedxml~=0.7.0",
"Django[argon2]~=4.2.0",
"django-bootstrap4~=3.0.0",
"django-compressor~=4.4.0",
"django-context-decorator",
Expand Down
2 changes: 1 addition & 1 deletion src/pretalx/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "2024.2.0.dev0"
__version__ = "2024.3.0.dev0"
3 changes: 1 addition & 2 deletions src/pretalx/agenda/context_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,4 @@ def is_html_export(request):
the form HTTP_ORIGINAL_NAME, so that 'is_html_export' cannot be
faked from the outside.
"""
context = {"is_html_export": request.META.get("is_html_export") is True}
return context
return {"is_html_export": request.META.get("is_html_export") is True}
50 changes: 24 additions & 26 deletions src/pretalx/agenda/management/commands/export_schedule_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import shutil
import urllib.parse
from pathlib import Path
from shutil import make_archive

from bs4 import BeautifulSoup
from django.conf import settings
Expand Down Expand Up @@ -32,8 +31,7 @@ def get(url):
except FileNotFoundError:
# … then fall back to asking the views.
response = client.get(url, is_html_export=True, HTTP_ACCEPT="text/html")
content = get_content(response)
return content
return get_content(response)

yield get

Expand All @@ -45,7 +43,7 @@ def find_assets(html):
for asset in soup.find_all(["script", "img"]):
yield asset.attrs["src"]
for asset in soup.find_all(["link"]):
if asset.attrs["rel"][0] in ["icon", "stylesheet"]:
if asset.attrs["rel"][0] in ("icon", "stylesheet"):
yield asset.attrs["href"]


Expand Down Expand Up @@ -116,12 +114,12 @@ def dump_content(destination, path, getter):
path = path + "index.html"

path = (Path(destination) / path.lstrip("/")).resolve()
if not Path(destination) in path.parents:
if Path(destination) not in path.parents:
raise CommandError("Path traversal detected, aborting.")
path.parent.mkdir(parents=True, exist_ok=True)

with open(path, "wb") as f:
f.write(content)
with open(path, "wb") as output_file:
output_file.write(content)
return content


Expand All @@ -141,37 +139,37 @@ def get_mediastatic_content(url):
):
raise FileNotFoundError()

with open(local_path, "rb") as f:
return f.read()
with open(local_path, "rb") as media_file:
return media_file.read()


def export_event(event, destination):
with (
override_settings(COMPRESS_ENABLED=True, COMPRESS_OFFLINE=True),
override_timezone(event.timezone),
fake_admin(event) as get,
):
with fake_admin(event) as get:
logging.info("Collecting URLs for export")
urls = [*event_urls(event)]
assets = set()
logging.info("Collecting URLs for export")
urls = list(event_urls(event))
assets = set()

logging.info(f"Exporting {len(urls)} pages")
for url in map(get_path, urls):
content = dump_content(destination, url, get)
assets |= set(map(get_path, find_assets(content)))
logging.info(f"Exporting {len(urls)} pages")
for url in map(get_path, urls):
content = dump_content(destination, url, get)
assets |= set(map(get_path, find_assets(content)))

css_assets = set()
css_assets = set()

logging.info(f"Exporting {len(assets)} static files from HTML links")
for url in assets:
content = dump_content(destination, url, get)
logging.info(f"Exporting {len(assets)} static files from HTML links")
for url in assets:
content = dump_content(destination, url, get)

if url.endswith(".css"):
css_assets |= set(find_urls(content))
if url.endswith(".css"):
css_assets |= set(find_urls(content))

logging.info(f"Exporting {len(css_assets)} files from CSS links")
for url_path in (get_path(urllib.parse.unquote(url)) for url in css_assets):
dump_content(destination, url_path, get)
logging.info(f"Exporting {len(css_assets)} files from CSS links")
for url_path in (get_path(urllib.parse.unquote(url)) for url in css_assets):
dump_content(destination, url_path, get)


def delete_directory(path):
Expand Down
1 change: 1 addition & 0 deletions src/pretalx/agenda/templates/agenda/feedback_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

{% block content %}
<script src="{% static "vendored/marked.min.js" %}" defer></script> {# do not compress #}
<script src="{% static "vendored/purify.min.js" %}" defer></script>
<script src="{% static "common/js/formTools.js" %}" defer></script>

<h3 class="talk-title">
Expand Down
24 changes: 13 additions & 11 deletions src/pretalx/agenda/views/schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
class ScheduleMixin:
@cached_property
def version(self):
if "version" in self.kwargs:
return unquote(self.kwargs["version"])
if version := self.kwargs.get("version"):
return unquote(version)
return None

def get_object(self):
Expand All @@ -50,8 +50,8 @@ def schedule(self):
return self.get_object()

def dispatch(self, request, *args, **kwargs):
if "version" in request.GET:
kwargs["version"] = request.GET["version"]
if version := request.GET.get("version"):
kwargs["version"] = version
return HttpResponsePermanentRedirect(
reverse(
f"agenda:versioned-{request.resolver_match.url_name}",
Expand Down Expand Up @@ -136,7 +136,7 @@ def get(self, request, *args, **kwargs):
if request.headers["If-None-Match"] == etag:
return HttpResponseNotModified()
headers = {"ETag": etag}
if file_type not in ["application/json", "text/xml"]:
if file_type not in ("application/json", "text/xml"):
headers["Content-Disposition"] = (
f'attachment; filename="{safe_filename(file_name)}"'
)
Expand Down Expand Up @@ -171,7 +171,7 @@ def get_text(self, request, **kwargs):
"""
)
output_format = request.GET.get("format", "table")
if output_format not in ["list", "table"]:
if output_format not in ("list", "table"):
output_format = "table"
result = draw_ascii_schedule(data, output_format=output_format)
return HttpResponse(
Expand Down Expand Up @@ -220,10 +220,10 @@ def get_object(self):

@context
def exporters(self):
return list(
return [
exporter(self.request.event)
for _, exporter in register_data_exporters.send(self.request.event)
)
]

@context
def my_exporters(self):
Expand All @@ -240,6 +240,10 @@ def show_talk_list(self):
)


def talk_sort_key(talk):
return (talk.start, talk.submission.title if talk.submission else "")


class ScheduleNoJsView(ScheduleView):
template_name = "agenda/schedule_nojs.html"

Expand All @@ -253,9 +257,7 @@ def get_schedule_data(self):
for date in data:
rooms = date.pop("rooms")
talks = [talk for room in rooms for talk in room.get("talks", [])]
talks.sort(
key=lambda x: (x.start, x.submission.title if x.submission else "")
)
talks.sort(key=talk_sort_key)
date["talks"] = talks
return {"data": list(data)}

Expand Down
4 changes: 2 additions & 2 deletions src/pretalx/agenda/views/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,8 @@ def widget_script(request, event):
widget_file = "agenda/js/pretalx-schedule.js"
else:
widget_file = "agenda/js/pretalx-schedule.min.js"
f = finders.find(widget_file)
with open(f, encoding="utf-8") as fp:
file_path = finders.find(widget_file)
with open(file_path, encoding="utf-8") as fp:
code = fp.read()
data = code.encode()
return HttpResponse(data, content_type="text/javascript")
35 changes: 18 additions & 17 deletions src/pretalx/api/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@


class ApiPermission(BasePermission):

def get_permission_object(self, view, obj, request, detail=False):
if func := getattr(view, "get_permission_object", None):
return func()
return obj or self.request.event

def has_permission(self, request, view):
return self._has_permission(view, getattr(request, "event", None), request)

def has_object_permission(self, request, view, obj):
return self._has_permission(view, obj, request)

def _has_permission(self, view, obj, request):
event = getattr(request, "event", None)
if not event: # Only true for root API view
Expand All @@ -20,24 +32,19 @@ def _has_permission(self, view, obj, request):
return request.user.has_perm(write_permission, permission_object)
return False

def get_permission_object(self, view, obj, request, detail=False):
if hasattr(view, "get_permission_object"):
return view.get_permission_object()
return obj or self.request.event

def has_permission(self, request, view):
return self._has_permission(view, getattr(request, "event", None), request)

def has_object_permission(self, request, view, obj):
return self._has_permission(view, obj, request)


class PluginPermission(ApiPermission):
"""Use this class to restrict access to views based on active plugins.

Set PluginPermission.plugin_required to the name of the plugin that is required to access the endpoint.
"""

def has_permission(self, request, view):
return self._has_permission(view, request)

def has_object_permission(self, request, view, obj):
return self._has_permission(view, request)

def _has_permission(self, view, request):
event = getattr(request, "event", None)
if not event:
Expand All @@ -47,9 +54,3 @@ def _has_permission(self, view, request):
if not plugin_name:
return True
return plugin_name in event.plugin_list

def has_permission(self, request, view):
return self._has_permission(view, request)

def has_object_permission(self, request, view, obj):
return self._has_permission(view, request)
Loading
Loading