forked from AFPy/PonyConf
Maintenance update
* Upgrade to django 3.1 * Upgrade dependencies * Remove django-bower * Add favicon * Fix bugs from unit tests
This commit is contained in:
parent
c827c2f4d9
commit
ef07664dee
6
.gitmodules
vendored
6
.gitmodules
vendored
|
@ -1,3 +1,3 @@
|
||||||
[submodule "components"]
|
[submodule "node_modules"]
|
||||||
path = components
|
path = node_modules
|
||||||
url = git://github.com/toulibre/ponyconf-components
|
url = ./node_modules
|
||||||
|
|
|
@ -7,6 +7,6 @@ from . import views
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('profile/', views.profile, name='profile'),
|
path('profile/', views.profile, name='profile'),
|
||||||
path('accounts/login/', views.EmailLoginView.as_view(), {'extra_context': {'buttons': [views.RESET_PASSWORD_BUTTON]}}, name='login'),
|
path('accounts/login/', views.EmailLoginView.as_view(), {'extra_context': {'buttons': [views.RESET_PASSWORD_BUTTON]}}, name='login'),
|
||||||
path('logout/', auth_views.logout, {'next_page': settings.LOGOUT_REDIRECT_URL}, name='logout'),
|
path('logout/', auth_views.LogoutView.as_view(), {'next_page': settings.LOGOUT_REDIRECT_URL}, name='logout'),
|
||||||
path('', include('django.contrib.auth.urls')),
|
path('', include('django.contrib.auth.urls')),
|
||||||
]
|
]
|
||||||
|
|
|
@ -12,7 +12,7 @@ from cfp.models import Participant, Volunteer
|
||||||
|
|
||||||
def speaker_required(view_func):
|
def speaker_required(view_func):
|
||||||
def wrapped_view(request, **kwargs):
|
def wrapped_view(request, **kwargs):
|
||||||
speaker_token = kwargs.pop('speaker_token')
|
speaker_token = kwargs.pop('speaker_token', None)
|
||||||
if speaker_token:
|
if speaker_token:
|
||||||
try:
|
try:
|
||||||
speaker_token = UUID(speaker_token)
|
speaker_token = UUID(speaker_token)
|
||||||
|
@ -30,7 +30,7 @@ def speaker_required(view_func):
|
||||||
|
|
||||||
def volunteer_required(view_func):
|
def volunteer_required(view_func):
|
||||||
def wrapped_view(request, **kwargs):
|
def wrapped_view(request, **kwargs):
|
||||||
volunteer_token = kwargs.pop('volunteer_token')
|
volunteer_token = kwargs.pop('volunteer_token', None)
|
||||||
if volunteer_token:
|
if volunteer_token:
|
||||||
try:
|
try:
|
||||||
volunteer_token = UUID(volunteer_token)
|
volunteer_token = UUID(volunteer_token)
|
||||||
|
|
28
cfp/migrations/0027_auto_20200809_1530.py
Normal file
28
cfp/migrations/0027_auto_20200809_1530.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# Generated by Django 3.1 on 2020-08-09 13:30
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cfp', '0026_conference_end_date'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='talk',
|
||||||
|
name='accepted',
|
||||||
|
field=models.BooleanField(default=None, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='talk',
|
||||||
|
name='confirmed',
|
||||||
|
field=models.BooleanField(default=None, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='talk',
|
||||||
|
name='video_licence',
|
||||||
|
field=models.CharField(choices=[('CC-Zero CC-BY', 'CC-Zero CC-BY'), ('CC-BY-SA', 'CC-BY-SA'), ('CC-BY-ND', 'CC-BY-ND'), ('CC-BY-NC', 'CC-BY-NC'), ('CC-BY-NC-SA', 'CC-BY-NC-SA'), ('CC-BY-NC-ND', 'CC-BY-NC-ND')], default='CC-BY-SA', max_length=32, verbose_name='Video licence'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -167,8 +167,6 @@ class Track(PonyConfModel):
|
||||||
slug = AutoSlugField(populate_from='name')
|
slug = AutoSlugField(populate_from='name')
|
||||||
description = models.TextField(blank=True, verbose_name=_('Description'))
|
description = models.TextField(blank=True, verbose_name=_('Description'))
|
||||||
|
|
||||||
#managers = models.ManyToManyField(User, blank=True, verbose_name=_('Managers'))
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ('site', 'name')
|
unique_together = ('site', 'name')
|
||||||
ordering = ['name']
|
ordering = ['name']
|
||||||
|
@ -347,10 +345,10 @@ class Talk(PonyConfModel):
|
||||||
category = models.ForeignKey(TalkCategory, verbose_name=_('Talk Category'), on_delete=models.PROTECT)
|
category = models.ForeignKey(TalkCategory, verbose_name=_('Talk Category'), on_delete=models.PROTECT)
|
||||||
videotaped = models.BooleanField(_("I'm ok to be recorded on video"), default=True)
|
videotaped = models.BooleanField(_("I'm ok to be recorded on video"), default=True)
|
||||||
video_licence = models.CharField(choices=LICENCES, default='CC-BY-SA',
|
video_licence = models.CharField(choices=LICENCES, default='CC-BY-SA',
|
||||||
max_length=10, verbose_name=_("Video licence"))
|
max_length=32, verbose_name=_("Video licence"))
|
||||||
sound = models.BooleanField(_("I need sound"), default=False)
|
sound = models.BooleanField(_("I need sound"), default=False)
|
||||||
accepted = models.NullBooleanField(default=None)
|
accepted = models.BooleanField(null=True, default=None)
|
||||||
confirmed = models.NullBooleanField(default=None)
|
confirmed = models.BooleanField(null=True, default=None)
|
||||||
start_date = models.DateTimeField(null=True, blank=True, default=None, verbose_name=_('Beginning date and time'))
|
start_date = models.DateTimeField(null=True, blank=True, default=None, verbose_name=_('Beginning date and time'))
|
||||||
duration = models.PositiveIntegerField(default=0, verbose_name=_('Duration (min)'))
|
duration = models.PositiveIntegerField(default=0, verbose_name=_('Duration (min)'))
|
||||||
room = models.ForeignKey(Room, blank=True, null=True, default=None, on_delete=models.SET_NULL)
|
room = models.ForeignKey(Room, blank=True, null=True, default=None, on_delete=models.SET_NULL)
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
var markdown_preview_url = "{% url 'markdown-preview' %}";
|
var markdown_preview_url = "{% url 'markdown-preview' %}";
|
||||||
</script>
|
</script>
|
||||||
<script src="{% static 'jquery.cookie/jquery.cookie.js' %}"></script>
|
<script src="{% static 'jquery.cookie/jquery.cookie.js' %}"></script>
|
||||||
<script src="{% static 'js/markdown-preview.js' %}"></script>
|
<script src="{% static 'ponyconf/markdown-preview.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from django.urls import path, re_path, register_converter
|
from django.urls import path, re_path, register_converter, include
|
||||||
|
|
||||||
from . import views, converters
|
from . import views, converters
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ urlpatterns = [
|
||||||
path('staff/volunteers/email/preview/', views.volunteer_email_preview, name='volunteer-email-preview'),
|
path('staff/volunteers/email/preview/', views.volunteer_email_preview, name='volunteer-email-preview'),
|
||||||
path('staff/add-user/', views.create_user, name='create-user'),
|
path('staff/add-user/', views.create_user, name='create-user'),
|
||||||
re_path(r'^staff/schedule/((?P<program_format>[\w]+)/)?$', views.staff_schedule, name='staff-schedule'),
|
re_path(r'^staff/schedule/((?P<program_format>[\w]+)/)?$', views.staff_schedule, name='staff-schedule'),
|
||||||
path('staff/select2/', views.Select2View.as_view(), name='django_select2-json'),
|
path('staff/select2/', include('django_select2.urls')),
|
||||||
path('admin/', views.admin, name='admin'),
|
path('admin/', views.admin, name='admin'),
|
||||||
path('admin/conference/', views.conference_edit, name='conference-edit'),
|
path('admin/conference/', views.conference_edit, name='conference-edit'),
|
||||||
path('admin/homepage/', views.homepage_edit, name='homepage-edit'),
|
path('admin/homepage/', views.homepage_edit, name='homepage-edit'),
|
||||||
|
|
|
@ -1299,7 +1299,7 @@ def schedule(request, program_format, pending, template, staff, cache=None):
|
||||||
raise Http404(_("Format '%s' not available" % program_format))
|
raise Http404(_("Format '%s' not available" % program_format))
|
||||||
|
|
||||||
|
|
||||||
def public_schedule(request, program_format):
|
def public_schedule(request, program_format=None):
|
||||||
if not request.conference.schedule_available and not is_staff(request, request.user):
|
if not request.conference.schedule_available and not is_staff(request, request.user):
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
if request.conference.schedule_redirection_url and program_format is None:
|
if request.conference.schedule_redirection_url and program_format is None:
|
||||||
|
@ -1309,7 +1309,7 @@ def public_schedule(request, program_format):
|
||||||
|
|
||||||
|
|
||||||
@staff_required
|
@staff_required
|
||||||
def staff_schedule(request, program_format):
|
def staff_schedule(request, program_format=None):
|
||||||
return schedule(request, program_format=program_format, pending=True, template='cfp/staff/schedule.html', staff=True, cache=False)
|
return schedule(request, program_format=program_format, pending=True, template='cfp/staff/schedule.html', staff=True, cache=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit fe849d749c0b9d382f3134d8344ee72637432a7c
|
|
1
node_modules
Submodule
1
node_modules
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 9634617237843dfd0eae718b74c42666d28a38c0
|
26
package.json
Normal file
26
package.json
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"name": "ponyconf",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Organise your conferences",
|
||||||
|
"main": "index.js",
|
||||||
|
"directories": {
|
||||||
|
"doc": "doc"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"jquery": "^3.5.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {},
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/PonyConf/PonyConf.git"
|
||||||
|
},
|
||||||
|
"author": "Élie Bouttier and contributors",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/PonyConf/PonyConf/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/PonyConf/PonyConf#readme"
|
||||||
|
}
|
|
@ -1,8 +0,0 @@
|
||||||
from django.contrib.sites.shortcuts import get_current_site
|
|
||||||
|
|
||||||
|
|
||||||
def site(request):
|
|
||||||
|
|
||||||
return {
|
|
||||||
'site': get_current_site(request),
|
|
||||||
}
|
|
|
@ -1,13 +1,5 @@
|
||||||
"""
|
"""
|
||||||
Django settings for ponyconf project.
|
Django settings for ponyconf project.
|
||||||
|
|
||||||
Generated by 'django-admin startproject' using Django 1.9.6.
|
|
||||||
|
|
||||||
For more information on this file, see
|
|
||||||
https://docs.djangoproject.com/en/1.9/topics/settings/
|
|
||||||
|
|
||||||
For the full list of settings and their values, see
|
|
||||||
https://docs.djangoproject.com/en/1.9/ref/settings/
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
@ -17,10 +9,6 @@ import os
|
||||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
|
||||||
# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/
|
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
SECRET_KEY = 'm2d03t^m)!nsborq5a1#e!#m)wjl&-%tu4ew@fxf1_b_t*@36r'
|
SECRET_KEY = 'm2d03t^m)!nsborq5a1#e!#m)wjl&-%tu4ew@fxf1_b_t*@36r'
|
||||||
|
|
||||||
|
@ -33,7 +21,7 @@ ALLOWED_HOSTS = []
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
# the post_migrate creating the first site should be call at first
|
# the post_migrate creating the first site should be called at first
|
||||||
'django.contrib.sites',
|
'django.contrib.sites',
|
||||||
|
|
||||||
# our apps
|
# our apps
|
||||||
|
@ -41,11 +29,8 @@ INSTALLED_APPS = [
|
||||||
'accounts',
|
'accounts',
|
||||||
'cfp',
|
'cfp',
|
||||||
'mailing',
|
'mailing',
|
||||||
#'planning',
|
|
||||||
#'volunteers',
|
|
||||||
|
|
||||||
# external apps
|
# third-party apps
|
||||||
'djangobower',
|
|
||||||
'bootstrap3',
|
'bootstrap3',
|
||||||
'django_select2',
|
'django_select2',
|
||||||
'crispy_forms',
|
'crispy_forms',
|
||||||
|
@ -152,71 +137,22 @@ LOCALE_PATHS = [
|
||||||
MEDIA_URL = '/media/'
|
MEDIA_URL = '/media/'
|
||||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||||
|
|
||||||
# Static files (CSS, JavaScript, Images)
|
|
||||||
# https://docs.djangoproject.com/en/1.9/howto/static-files/
|
|
||||||
|
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
STATICFILES_FINDERS = [
|
STATICFILES_DIRS = [
|
||||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
('jquery', os.path.join(BASE_DIR, 'node_modules/jquery/dist/')),
|
||||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
|
||||||
'djangobower.finders.BowerFinder',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
BOWER_COMPONENTS_ROOT = os.path.join(BASE_DIR, 'components')
|
|
||||||
BOWER_INSTALLED_APPS = (
|
|
||||||
'bootstrap',
|
|
||||||
'jquery#2',
|
|
||||||
'jquery-ui',
|
|
||||||
'jquery-cookie',
|
|
||||||
'select2',
|
|
||||||
'eonasdan-bootstrap-datetimepicker',
|
|
||||||
'moment',
|
|
||||||
)
|
|
||||||
|
|
||||||
LOGIN_REDIRECT_URL = 'home'
|
LOGIN_REDIRECT_URL = 'home'
|
||||||
|
|
||||||
SITE_ID = 1
|
SITE_ID = 1
|
||||||
|
|
||||||
BOOTSTRAP3 = {
|
|
||||||
|
|
||||||
# The URL to the jQuery JavaScript file
|
|
||||||
# If not set, "build-in" CDN is used (maxcdn)
|
|
||||||
# 'jquery_url': '//code.jquery.com/jquery.min.js',
|
|
||||||
'jquery_url': STATIC_URL + 'jquery/dist/jquery.js',
|
|
||||||
|
|
||||||
# The Bootstrap base URL
|
|
||||||
# If not set, "build-in" CDN is used (maxcdn)
|
|
||||||
# 'base_url': '//netdna.bootstrapcdn.com/bootstrap/3.2.0/',
|
|
||||||
'base_url': STATIC_URL + 'bootstrap/dist/',
|
|
||||||
|
|
||||||
# The complete URL to the Bootstrap CSS file
|
|
||||||
# (None means derive it from base_url)
|
|
||||||
'css_url': None,
|
|
||||||
|
|
||||||
# The complete URL to the Bootstrap CSS file
|
|
||||||
# (None means no theme)
|
|
||||||
'theme_url': None,
|
|
||||||
|
|
||||||
# The complete URL to the Bootstrap JavaScript file
|
|
||||||
# (None means derive it from base_url)
|
|
||||||
'javascript_url': None,
|
|
||||||
}
|
|
||||||
|
|
||||||
SELECT2_JS = 'select2/dist/js/select2.min.js'
|
|
||||||
SELECT2_CSS = 'select2/dist/css/select2.min.css'
|
|
||||||
SELECT2_I18N_PATH = 'select2/dist/js/i18n'
|
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = [
|
AUTHENTICATION_BACKENDS = [
|
||||||
'django.contrib.auth.backends.ModelBackend',
|
'django.contrib.auth.backends.ModelBackend',
|
||||||
'ponyconf.backends.EmailBackend',
|
'ponyconf.backends.EmailBackend',
|
||||||
]
|
]
|
||||||
LOGOUT_REDIRECT_URL = 'home'
|
LOGOUT_REDIRECT_URL = 'home'
|
||||||
|
|
||||||
CRISPY_TEMPLATE_PACK='bootstrap3'
|
CRISPY_TEMPLATE_PACK = 'bootstrap3'
|
||||||
|
|
||||||
# django-registration
|
|
||||||
ACCOUNT_ACTIVATION_DAYS = 7
|
|
||||||
INCLUDE_REGISTER_URL = True
|
|
||||||
|
|
||||||
CACHES = {
|
CACHES = {
|
||||||
'default': {
|
'default': {
|
||||||
|
|
BIN
ponyconf/static/ponyconf/ponyconf.png
Normal file
BIN
ponyconf/static/ponyconf/ponyconf.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
|
@ -6,12 +6,12 @@
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
{% comment %}<link rel="icon" href="{% static 'favicon.ico' %}">{% endcomment %}
|
<link rel="icon" href="{% static 'ponyconf/ponyconf.png' %}">
|
||||||
|
|
||||||
<title>{% block title %}{{ conference.name }}{% endblock %}</title>
|
<title>{% block title %}{{ conference.name }}{% endblock %}</title>
|
||||||
|
|
||||||
{% bootstrap_css %}
|
{% bootstrap_css %}
|
||||||
<link href="{% static 'css/ponyconf.css' %}" rel="stylesheet">
|
<link href="{% static 'ponyconf/ponyconf.css' %}" rel="stylesheet">
|
||||||
{% block css %}{% endblock %}
|
{% block css %}{% endblock %}
|
||||||
|
|
||||||
{% block js %}{% endblock %}
|
{% block js %}{% endblock %}
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
|
|
||||||
<script src="{% bootstrap_jquery_url %}"></script>
|
<script src="{% bootstrap_jquery_url %}"></script>
|
||||||
{% bootstrap_javascript %}
|
{% bootstrap_javascript %}
|
||||||
<script src="{% static 'js/ponyconf.js' %}"></script>
|
<script src="{% static 'ponyconf/ponyconf.js' %}"></script>
|
||||||
{% block js_end %}{% endblock %}
|
{% block js_end %}{% endblock %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
django<3
|
django
|
||||||
|
|
||||||
django-bootstrap3
|
django-bootstrap3
|
||||||
django-bower
|
|
||||||
django-crispy-forms
|
django-crispy-forms
|
||||||
django-select2<6
|
django-select2
|
||||||
django-colorful
|
django-colorful
|
||||||
django-autoslug
|
django-autoslug
|
||||||
|
|
||||||
|
|
|
@ -4,25 +4,26 @@
|
||||||
#
|
#
|
||||||
# pip-compile
|
# pip-compile
|
||||||
#
|
#
|
||||||
bleach==3.1.0
|
asgiref==3.2.10 # via django
|
||||||
chardet==3.0.4
|
bleach==3.1.5 # via -r requirements.in
|
||||||
django-appconf==1.0.3 # via django-select2
|
chardet==3.0.4 # via -r requirements.in
|
||||||
django-autoslug==1.9.6
|
django-appconf==1.0.4 # via django-select2
|
||||||
django-bootstrap3==11.1.0
|
django-autoslug==1.9.8 # via -r requirements.in
|
||||||
django-bower==5.2.0
|
django-bootstrap3==14.1.0 # via -r requirements.in
|
||||||
django-colorful==1.3
|
django-colorful==1.3 # via -r requirements.in
|
||||||
django-crispy-forms==1.8.0
|
django-crispy-forms==1.9.2 # via -r requirements.in
|
||||||
django-select2==5.11.1
|
django-select2==7.4.2 # via -r requirements.in
|
||||||
django==2.2.8
|
django==3.1 # via -r requirements.in, django-appconf, django-bootstrap3, django-colorful, django-select2
|
||||||
icalendar==4.0.3
|
icalendar==4.0.6 # via -r requirements.in
|
||||||
jinja2==2.10.3
|
importlib-metadata==1.7.0 # via django-bootstrap3, markdown
|
||||||
markdown==3.1.1
|
jinja2==2.11.2 # via -r requirements.in
|
||||||
|
markdown==3.2.2 # via -r requirements.in
|
||||||
markupsafe==1.1.1 # via jinja2
|
markupsafe==1.1.1 # via jinja2
|
||||||
|
packaging==20.4 # via bleach
|
||||||
|
pyparsing==2.4.7 # via packaging
|
||||||
python-dateutil==2.8.1 # via icalendar
|
python-dateutil==2.8.1 # via icalendar
|
||||||
pytz==2019.3 # via django, icalendar
|
pytz==2020.1 # via django, icalendar
|
||||||
six==1.13.0 # via bleach, django-appconf, django-bower, python-dateutil
|
six==1.15.0 # via bleach, packaging, python-dateutil
|
||||||
sqlparse==0.3.0 # via django
|
sqlparse==0.3.1 # via django
|
||||||
webencodings==0.5.1 # via bleach
|
webencodings==0.5.1 # via bleach
|
||||||
|
zipp==3.1.0 # via importlib-metadata
|
||||||
# The following packages are considered to be unsafe in a requirements file:
|
|
||||||
# setuptools
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user