diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index b90f1a1..bb25209 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: - python-version: [3.8] + python-version: [3.13] steps: - uses: actions/checkout@v2 diff --git a/.pylintrc b/.pylintrc index cf55437..8000d96 100644 --- a/.pylintrc +++ b/.pylintrc @@ -1,7 +1,6 @@ [MASTER] ignore = ,input persistent = yes -load-plugins = pylint_quotes [MESSAGES CONTROL] disable = @@ -10,7 +9,6 @@ disable = duplicate-code, no-member, parse-error, - bad-continuation, too-few-public-methods, global-statement, cyclic-import, @@ -21,19 +19,13 @@ disable = [REPORTS] output-format = text -files-output = no reports = no [FORMAT] max-line-length = 120 -max-statement-lines = 75 single-line-if-stmt = no -no-space-check = trailing-comma,dict-separator max-module-lines = 1000 indent-string = ' ' -string-quote=single-avoid-escape -triple-quote=single -docstring-quote=double [MISCELLANEOUS] notes = FIXME,XXX,TODO @@ -79,9 +71,6 @@ good-names=logger,id,ID # Bad variable names which should always be refused, separated by a comma bad-names=foo,bar,baz,toto,tutu,tata -# List of builtins function names that should not be used, separated by a comma -bad-functions=apply,input - [DESIGN] max-args = 10 ignored-argument-names = _.* @@ -95,4 +84,4 @@ min-public-methods = 2 max-public-methods = 20 [EXCEPTIONS] -overgeneral-exceptions = Exception +overgeneral-exceptions = builtins.Exception diff --git a/Containerfile b/Containerfile index c82d05b..435c8b4 100644 --- a/Containerfile +++ b/Containerfile @@ -1,8 +1,8 @@ -FROM docker.io/python:3.9-bookworm +FROM docker.io/python:3.13-bookworm WORKDIR /src/ COPY ./ . RUN pip install -r requirements.txt RUN git config --system --add safe.directory /src -ENTRYPOINT [ "gunicorn", "selections:app", "--bind=0.0.0.0:8080"] \ No newline at end of file +ENTRYPOINT [ "gunicorn", "selections:app", "--bind=0.0.0.0:8080"] diff --git a/requirements.txt b/requirements.txt index ff4769b..3dc1633 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,50 +1,49 @@ -alabaster==0.7.12 -alembic==0.9.9 -astroid==2.4.1 -Beaker==1.11.0 -blinker==1.4 -certifi==2020.4.5.1 -cffi==1.14.0 -chardet==3.0.4 -click==7.1.2 -cryptography==3.3.2 -dnspython==1.16.0 -Flask==1.1.2 -Flask-Migrate==2.1.1 -Flask-pyoidc==1.2.0 -Flask-SQLAlchemy==2.3.2 -future==0.18.2 -gunicorn==19.7.1 -idna==2.9 -isort==4.3.21 -itsdangerous==1.1.0 -Jinja2==2.11.3 -lazy-object-proxy==1.4.3 -lxml==4.6.3 -Mako==1.1.2 -MarkupSafe==1.1.1 -mccabe==0.6.1 -oic==0.11.0.1 -Pillow==8.1.1 -pyasn1==0.4.8 -pyasn1-modules==0.2.8 -pycparser==2.20 -pycryptodomex==3.9.7 +alabaster==1.0.0 +alembic==1.16.5 +astroid==3.3.11 +Beaker==1.13.0 +blinker==1.9.0 +certifi==2025.8.3 +cffi==2.0.0 +chardet==5.2.0 +click==8.2.1 +cryptography==45.0.7 +dnspython==2.8.0 +Flask==3.1.2 +Flask-Migrate==4.1.0 +Flask-pyoidc==3.14.3 +Flask-SQLAlchemy==3.1.1 +future==1.0.0 +gunicorn==23.0.0 +idna==3.10 +isort==6.0.1 +itsdangerous==2.2.0 +Jinja2==3.1.6 +lazy-object-proxy==1.12.0 +lxml==6.0.1 +Mako==1.3.10 +MarkupSafe==3.0.2 +mccabe==0.7.0 +oic==1.6.1 +Pillow==11.3.0 +pyasn1==0.6.1 +pyasn1-modules==0.4.2 +pycparser==2.23 +pycryptodomex==3.23.0 pyjwkest==1.4.2 -pylint==2.5.2 -pylint-quotes==0.2.1 -PyMySQL==0.8.0 -pyOpenSSL==19.1.0 -python-dateutil==2.8.1 -python-docx==0.8.6 +pylint==3.3.8 +PyMySQL==1.1.2 +pyOpenSSL==25.2.0 +python-dateutil==2.9.0.post0 +python-docx==1.2.0 python-editor==1.0.4 -python-resize-image==1.1.11 -requests==2.23.0 -sentry-sdk==0.14.3 -six==1.14.0 -SQLAlchemy==1.3.17 -toml==0.10.1 -urllib3==1.25.9 -Werkzeug==1.0.1 -wrapt==1.12.1 -boto3==1.35.49 \ No newline at end of file +python-resize-image==1.1.20 +requests==2.32.5 +sentry-sdk==2.38.0 +six==1.17.0 +SQLAlchemy==2.0.43 +toml==0.10.2 +urllib3==2.5.0 +Werkzeug==3.1.3 +wrapt==1.17.3 +boto3==1.40.32 diff --git a/selections/__init__.py b/selections/__init__.py index cce8e2e..74baa99 100644 --- a/selections/__init__.py +++ b/selections/__init__.py @@ -5,6 +5,7 @@ from flask import Flask from flask_migrate import Migrate from flask_pyoidc.flask_pyoidc import OIDCAuthentication +from flask_pyoidc.provider_configuration import ProviderConfiguration, ClientMetadata from flask_sqlalchemy import SQLAlchemy import sentry_sdk from sentry_sdk.integrations.flask import FlaskIntegration @@ -20,8 +21,12 @@ else: app.config.from_pyfile(os.path.join(os.getcwd(), 'config.env.py')) -auth = OIDCAuthentication(app, issuer=app.config['OIDC_ISSUER'], - client_registration_info=app.config['OIDC_CLIENT_CONFIG']) + #auth = OIDCAuthentication(app, issuer=app.config['OIDC_ISSUER'], + # client_registration_info=app.config['OIDC_CLIENT_CONFIG']) + +client_metadata = ClientMetadata(app.config["OIDC_CLIENT_CONFIG"]) +provider_config = ProviderConfiguration(issuer=app.config["OIDC_ISSUER"], client_registration_info=client_metadata) +auth = OIDCAuthentication({'default': provider_config}, app) # Sentry sentry_sdk.init( @@ -45,7 +50,7 @@ try: s3.create_bucket(Bucket=app.config['S3_BUCKET_NAME']) except s3.exceptions.BucketAlreadyExists: - 1+1 + pass # Load Applications Blueprint from selections.blueprints.application import * @@ -55,7 +60,7 @@ @app.route('/') -@auth.oidc_auth +@auth.oidc_auth("default") @before_request def main(info=None): is_evals = '/eboard-evaluations' in info['group_list'] diff --git a/selections/blueprints/application.py b/selections/blueprints/application.py index b592f48..15c78b8 100644 --- a/selections/blueprints/application.py +++ b/selections/blueprints/application.py @@ -1,5 +1,4 @@ from collections import defaultdict -from zipfile import BadZipFile from flask import render_template, redirect, url_for, flash, request @@ -9,7 +8,7 @@ @app.route('/application/') -@auth.oidc_auth +@auth.oidc_auth("default") @before_request def get_application(app_id, info=None): applicant_info = Applicant.query.filter_by(id=app_id).first() @@ -33,7 +32,7 @@ def get_application(app_id, info=None): fields=fields) @app.route('/application/content/') -@auth.oidc_auth +@auth.oidc_auth("default") def get_application_pdf(app_id): applicant_info = Applicant.query.filter_by(id=app_id).first() resp = s3.get_object(Bucket=app.config['S3_BUCKET_NAME'], Key='/'+applicant_info.rit_id+'.pdf') @@ -42,7 +41,7 @@ def get_application_pdf(app_id): @app.route('/application', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth("default") def create_application(): applicant_rit_id = request.form.get('rit_id') applicant = Applicant( @@ -60,7 +59,7 @@ def create_application(): @app.route('/application/import', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth("default") #@before_request def import_application(): word_file = request.files['file'] @@ -97,7 +96,7 @@ def import_application(): if line[-1:] == ' ': app_text += line else: - app_text += '\n{}'.format(line) + app_text += f'\n{line}' applications[app_rit_id] = [app_gender, app_text] new_app = Applicant( @@ -115,7 +114,7 @@ def import_application(): @app.route('/application/delete/', methods=['GET']) -@auth.oidc_auth +@auth.oidc_auth("default") @before_request def delete_application(app_id, info=None): is_evals = '/eboard-evaluations' in info['group_list'] @@ -136,7 +135,7 @@ def delete_application(app_id, info=None): @app.route('/application/create') -@auth.oidc_auth +@auth.oidc_auth("default") @before_request def get_application_creation(info=None): is_evals = '/eboard-evaluations' in info['group_list'] @@ -149,7 +148,7 @@ def get_application_creation(info=None): @app.route('/application/', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth("default") @before_request def submit_application(app_id, info=None): member = Members.query.filter_by(username=info['uid']).first() @@ -188,17 +187,17 @@ def submit_application(app_id, info=None): db.session.add(member_score) db.session.flush() db.session.commit() - flash('Thanks for evaluating application #{}!'.format(app_id)) + flash(f'Thanks for evaluating application #{app_id}!') return redirect('/', 302) @app.route('/application/review/', methods=['GET']) -@auth.oidc_auth +@auth.oidc_auth("default") @before_request def review_application(app_id, info=None): applicant_info = Applicant.query.filter_by(id=app_id).first() evaluated = bool(Submission.query.filter_by(application=app_id, medium='Phone').all()) - scores = Submission.query.filter_by(application=app_id).all() + scores = Submission.query.filter_by(application=app_id).all() return render_template( 'review_app.html', info=info, @@ -209,11 +208,12 @@ def review_application(app_id, info=None): @app.route('/application/phone/', methods=['GET']) -@auth.oidc_auth +@auth.oidc_auth("default") @before_request def get_phone_application(app_id, info=None): applicant_info = Applicant.query.filter_by(id=app_id).first() - pdf_url = s3.generate_presigned_url('get_object', Params={'Bucket': app.config['S3_BUCKET_NAME'], 'Key': applicant_info.rit_id+'.pdf'}, ExpiresIn=30) + pdf_url = s3.generate_presigned_url('get_object', Params={'Bucket': app.config['S3_BUCKET_NAME'], + 'Key': applicant_info.rit_id+'.pdf'}, ExpiresIn=30) pdf_url = pdf_url.replace("s3.csh", "assets.csh") scores = [subs.score for subs in Submission.query.filter_by(application=app_id).all()] total = 0 @@ -232,7 +232,7 @@ def get_phone_application(app_id, info=None): @app.route('/application/phone/', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth("default") @before_request def promote_application(app_id, info=None): score = request.form.get('score') diff --git a/selections/blueprints/teams.py b/selections/blueprints/teams.py index 1569a0d..8190fc8 100644 --- a/selections/blueprints/teams.py +++ b/selections/blueprints/teams.py @@ -6,7 +6,7 @@ @app.route('/teams') -@auth.oidc_auth +@auth.oidc_auth("default") @before_request def get_teams(info=None): is_evals = '/eboard-evaluations' in info['group_list'] @@ -34,7 +34,7 @@ def get_teams(info=None): @app.route('/teams', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth("default") @before_request def create_team(info=None): is_evals = '/eboard-evaluations' in info['group_list'] @@ -69,7 +69,7 @@ def create_team(info=None): @app.route('/teams/', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth("default") @before_request def add_to_team(team_id, info=None): is_evals = '/eboard-evaluations' in info['group_list'] @@ -102,7 +102,7 @@ def add_to_team(team_id, info=None): @app.route('/teams/remove/', methods=['GET']) -@auth.oidc_auth +@auth.oidc_auth("default") @before_request def remove_from_team(username, info=None): is_evals = '/eboard-evaluations' in info['group_list'] diff --git a/selections/utils.py b/selections/utils.py index 33948a2..5a9c5c6 100644 --- a/selections/utils.py +++ b/selections/utils.py @@ -49,4 +49,4 @@ def assign_pending_applicants(): app_data.team = int(team) app_group += 1 db.session.flush() - db.session.commit() \ No newline at end of file + db.session.commit()