mirror of
https://github.com/godotengine/godot-showreel-voting.git
synced 2026-09-03 18:15:13 +03:00
156 lines
4.7 KiB
Python
156 lines
4.7 KiB
Python
from functools import wraps
|
|
from typing import Dict
|
|
from flask import Flask, current_app, render_template, request, url_for, session
|
|
from flask import redirect
|
|
from authlib.integrations.flask_client import OAuth
|
|
|
|
from gdshowreelvote.database import User, DB
|
|
|
|
ADMIN_ROLE = 'showreel-admin'
|
|
STAFF_ROLE = 'showreel-staff'
|
|
|
|
oauth = OAuth()
|
|
|
|
MOCK_USERS = {
|
|
'moderator': {'mod': True, 'staff': True, 'fund_member': True},
|
|
'staff': {'mod': False, 'staff': True, 'fund_member': False},
|
|
'diamond-member': {'mod': False, 'staff': False, 'fund_member': True},
|
|
'user': {'mod': False, 'staff': False, 'fund_member': False},
|
|
}
|
|
|
|
|
|
def login_required(f):
|
|
@wraps(f)
|
|
def decorated_func(*args, **kwargs):
|
|
if session.get('user'):
|
|
return f(*args, **kwargs)
|
|
else:
|
|
return redirect(url_for('oidc.login'))
|
|
return decorated_func
|
|
|
|
|
|
def admin_required(f):
|
|
@wraps(f)
|
|
def decorated_func(*args, **kwargs):
|
|
if session.get('user') and ADMIN_ROLE in session['user'].get('roles', []):
|
|
return f(*args, **kwargs)
|
|
else:
|
|
return redirect(url_for('oidc.login'))
|
|
return decorated_func
|
|
|
|
|
|
def _can_vote(user: Dict) -> bool:
|
|
if ADMIN_ROLE in user.get('roles', []) or STAFF_ROLE in user.get('roles', []) or _fund_member_can_vote(user):
|
|
return True
|
|
return False
|
|
|
|
|
|
def vote_role_required(f):
|
|
@wraps(f)
|
|
def decorated_func(*args, **kwargs):
|
|
if session.get('user') and _can_vote(session['user']):
|
|
return f(*args, **kwargs)
|
|
else:
|
|
return redirect(url_for('oidc.login'))
|
|
return decorated_func
|
|
|
|
|
|
def get_issuer():
|
|
if current_app.config.get('OIDC_MOCK', False):
|
|
return 'https://example.org/keycloak/realms/test'
|
|
else:
|
|
return oauth.oidc.load_server_metadata()['issuer']
|
|
|
|
|
|
# Mock implementation
|
|
|
|
def mock_login():
|
|
content = render_template('mock-login.html', users=MOCK_USERS)
|
|
return render_template('default.html', content=content, title='Login')
|
|
|
|
|
|
def mock_auth():
|
|
username = request.form.get('username', '').lower()
|
|
if not username in MOCK_USERS:
|
|
return redirect(url_for('oidc.login'))
|
|
roles = []
|
|
roles.append(ADMIN_ROLE) if MOCK_USERS[username]['mod'] else None
|
|
roles.append(STAFF_ROLE) if MOCK_USERS[username]['staff'] else None
|
|
fund_roles = []
|
|
fund_roles.append('member') if MOCK_USERS[username]['fund_member'] else None
|
|
oidc_info = {
|
|
'sub': f'MOCK_USER:{username}',
|
|
'email_verified': True,
|
|
'name': username.capitalize(),
|
|
'preferred_username': username,
|
|
'given_name': username.capitalize(),
|
|
'family_name': username.capitalize(),
|
|
'email': f'{username}@example.com',
|
|
'roles': roles,
|
|
'fund': {'roles': fund_roles}
|
|
}
|
|
update_or_create_user(oidc_info)
|
|
|
|
session['user'] = oidc_info
|
|
return redirect('/')
|
|
|
|
|
|
def mock_logout():
|
|
session.pop('user', None)
|
|
return redirect('/')
|
|
|
|
|
|
# OIDC implementation
|
|
|
|
def oidc_login():
|
|
redirect_uri = url_for('oidc.auth', _external=True)
|
|
return oauth.oidc.authorize_redirect(redirect_uri)
|
|
|
|
|
|
def _fund_member_can_vote(user: Dict):
|
|
fund_roles = user.get('fund', {}).get('roles', [])
|
|
return any([role in fund_roles for role in current_app.config.get('FUND_ROLES_WITH_VOTE_RIGHTS', [])])
|
|
|
|
|
|
def oidc_auth():
|
|
token = oauth.oidc.authorize_access_token()
|
|
session['user'] = token['userinfo']
|
|
update_or_create_user(token['userinfo'])
|
|
return redirect('/')
|
|
|
|
|
|
def update_or_create_user(oidc_info: Dict):
|
|
if user := DB.session.get(User, oidc_info['sub']):
|
|
user.is_staff = STAFF_ROLE in oidc_info.get('roles', [])
|
|
user.is_superuser = ADMIN_ROLE in oidc_info.get('roles', [])
|
|
user.is_fund_member = _fund_member_can_vote(oidc_info)
|
|
else:
|
|
user = User(
|
|
id=oidc_info['sub'],
|
|
username=oidc_info.get('name', oidc_info.get('preferred_username', '')),
|
|
email=oidc_info['email'],
|
|
is_staff = STAFF_ROLE in oidc_info.get('roles', []),
|
|
is_superuser = ADMIN_ROLE in oidc_info.get('roles', []),
|
|
is_fund_member = _fund_member_can_vote(oidc_info)
|
|
)
|
|
DB.session.add(user)
|
|
DB.session.commit()
|
|
|
|
|
|
def oidc_logout():
|
|
session.pop('user', None)
|
|
return redirect('/')
|
|
|
|
|
|
def init_app(app: Flask):
|
|
if app.config.get('OIDC_MOCK', False):
|
|
app.add_url_rule('/login', 'oidc.login', mock_login)
|
|
app.add_url_rule('/auth', 'oidc.auth', mock_auth, methods=['POST'])
|
|
app.add_url_rule('/logout', 'oidc.logout', mock_logout)
|
|
else:
|
|
oauth.init_app(app)
|
|
oauth.register(name='oidc')
|
|
app.add_url_rule('/login', 'oidc.login', oidc_login)
|
|
app.add_url_rule('/auth', 'oidc.auth', oidc_auth)
|
|
app.add_url_rule('/logout', 'oidc.logout', oidc_logout)
|