diff --git a/Dockerfile b/Dockerfile index 35937b47..46d17eb0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -42,6 +42,7 @@ RUN apt-get update && \ COPY deploy/nginx.conf /beacon/nginx.conf COPY deploy/supervisord.conf /beacon/supervisord.conf COPY deploy/entrypoint.sh /usr/local/bin/entrypoint.sh +COPY deploy/permissions.sh /usr/local/bin/permissions.sh COPY beacon /beacon/beacon COPY ui /beacon/ui diff --git a/beacon/request/handlers.py b/beacon/request/handlers.py index a5c622e6..1ab5d54c 100644 --- a/beacon/request/handlers.py +++ b/beacon/request/handlers.py @@ -59,131 +59,113 @@ async def wrapper(request: Request): LOG.debug(access_token) if access_token is not None: - with open("/beacon/beacon/request/public_datasets.yml", 'r') as stream: - public_datasets = yaml.safe_load(stream) - list_of_public_datasets= public_datasets['public_datasets'] - try: - specific_datasets = qparams.query.request_parameters['datasets'] - except Exception: - specific_datasets = [] - access_token = access_token[7:] # cut out 7 characters: len('Bearer ') - + print('we have access token') + else: + access_token = 'Bearer public' + try: + specific_datasets = qparams.query.request_parameters['datasets'] + except Exception: + specific_datasets = [] + access_token = access_token[7:] # cut out 7 characters: len('Bearer ') + LOG.debug(access_token) + + + authorized_datasets, authenticated = await resolve_token(access_token, search_datasets) + LOG.debug(authorized_datasets) + #LOG.debug('all datasets: %s', all_datasets) + LOG.info('resolved datasets: %s', authorized_datasets) + LOG.debug(authenticated) + LOG.debug(specific_datasets) + + + specific_datasets_unauthorized = [] + specific_datasets_unauthorized_and_found = [] + bio_list = [] + search_and_authorized_datasets = [] + specific_search_datasets = [] + # Get response + if specific_datasets != []: + for element in authorized_datasets: + if element in specific_datasets: + search_and_authorized_datasets.append(element) + for elemento in specific_datasets: + if elemento not in search_and_authorized_datasets: + specific_datasets_unauthorized.append(elemento) + qparams.query.request_parameters = {} + qparams.query.request_parameters['datasets'] = '*******' + _, _, datasets = get_datasets(None, qparams) + beacon_datasets = [ r for r in datasets ] + all_datasets = [r['id'] for r in beacon_datasets] - - authorized_datasets, authenticated = await resolve_token(access_token, search_datasets) - LOG.debug(authorized_datasets) - #LOG.debug('all datasets: %s', all_datasets) - LOG.info('resolved datasets: %s', authorized_datasets) - LOG.debug(authenticated) - LOG.debug(specific_datasets) + response_datasets = [ r['id'] for r in beacon_datasets if r['id'] in search_and_authorized_datasets] + LOG.debug(specific_search_datasets) + LOG.debug(response_datasets) + list_of_dataset_dicts=[] - specific_datasets_unauthorized = [] - specific_datasets_unauthorized_and_found = [] - bio_list = [] - search_and_authorized_datasets = [] - specific_search_datasets = [] - for public_dataset in list_of_public_datasets: - authorized_datasets.append(public_dataset) - # Get response - if specific_datasets != []: - for element in authorized_datasets: - if element in specific_datasets: - search_and_authorized_datasets.append(element) - for elemento in specific_datasets: - if elemento not in search_and_authorized_datasets: - specific_datasets_unauthorized.append(elemento) - qparams.query.request_parameters = {} - qparams.query.request_parameters['datasets'] = '*******' - _, _, datasets = get_datasets(None, qparams) - beacon_datasets = [ r for r in datasets ] - all_datasets = [r['id'] for r in beacon_datasets] - - response_datasets = [ r['id'] for r in beacon_datasets if r['id'] in search_and_authorized_datasets] - LOG.debug(specific_search_datasets) - LOG.debug(response_datasets) - - list_of_dataset_dicts=[] - - for data_r in response_datasets: - dict_dataset = {} - dict_dataset['dataset']=data_r - dict_dataset['ids']=[ r['ids'] for r in beacon_datasets if r['id'] == data_r ] - list_of_dataset_dicts.append(dict_dataset) + for data_r in response_datasets: + dict_dataset = {} + dict_dataset['dataset']=data_r + dict_dataset['ids']=[ r['ids'] for r in beacon_datasets if r['id'] == data_r ] + list_of_dataset_dicts.append(dict_dataset) - for dataset_searched in specific_datasets_unauthorized: - if dataset_searched not in all_datasets: - dict_dataset = {} - dict_dataset['dataset']=dataset_searched - dict_dataset['ids'] = ['Dataset not found'] - LOG.debug(dict_dataset['dataset']) - LOG.debug(dict_dataset['ids']) - list_of_dataset_dicts.append(dict_dataset) - - for data_s in specific_datasets_unauthorized_and_found: + for dataset_searched in specific_datasets_unauthorized: + if dataset_searched not in all_datasets: dict_dataset = {} - dict_dataset['dataset']=data_s - dict_dataset['ids'] = ['Unauthorized dataset'] + dict_dataset['dataset']=dataset_searched + dict_dataset['ids'] = ['Dataset not found'] + LOG.debug(dict_dataset['dataset']) + LOG.debug(dict_dataset['ids']) list_of_dataset_dicts.append(dict_dataset) + + for data_s in specific_datasets_unauthorized_and_found: + dict_dataset = {} + dict_dataset['dataset']=data_s + dict_dataset['ids'] = ['Unauthorized dataset'] + list_of_dataset_dicts.append(dict_dataset) - LOG.debug(specific_datasets_unauthorized_and_found) - LOG.debug(specific_datasets_unauthorized) - LOG.debug(list_of_dataset_dicts) + LOG.debug(specific_datasets_unauthorized_and_found) + LOG.debug(specific_datasets_unauthorized) + LOG.debug(list_of_dataset_dicts) - else: - qparams.query.request_parameters = {} - qparams.query.request_parameters['datasets'] = '*******' - _, _, datasets = get_datasets(None, qparams) - beacon_datasets = [ r for r in datasets ] - LOG.debug(authorized_datasets) - specific_datasets = [ r['id'] for r in beacon_datasets if r['id'] not in authorized_datasets] - response_datasets = [ r['id'] for r in beacon_datasets if r['id'] in authorized_datasets] - LOG.debug(specific_datasets) - LOG.debug(response_datasets) - specific_datasets_unauthorized.append(specific_datasets) - for unauth in specific_datasets_unauthorized: - for unauth_spec in unauth: - biosample_ids = [ r['ids'] for r in beacon_datasets if r['id'] == unauth_spec ] - bio_list.append(biosample_ids) - - list_of_dataset_dicts=[] - - for data_r in response_datasets: - dict_dataset = {} - dict_dataset['dataset']=data_r - dict_dataset['ids']=[ r['ids'] for r in beacon_datasets if r['id'] == data_r ] - list_of_dataset_dicts.append(dict_dataset) - - for data_s in specific_datasets: - dict_dataset = {} - dict_dataset['dataset']=data_s - dict_dataset['ids'] = ['Unauthorized dataset'] - list_of_dataset_dicts.append(dict_dataset) - #LOG.debug(list_of_dataset_dicts) else: - #write here code for public datasets - list_of_dataset_dicts=[] qparams.query.request_parameters = {} qparams.query.request_parameters['datasets'] = '*******' _, _, datasets = get_datasets(None, qparams) beacon_datasets = [ r for r in datasets ] - with open("/beacon/beacon/request/public_datasets.yml", 'r') as stream: - public_datasets = yaml.safe_load(stream) - list_of_public_datasets= public_datasets['public_datasets'] - LOG.debug(list_of_public_datasets) - for data_r in list_of_public_datasets: + LOG.debug(authorized_datasets) + specific_datasets = [ r['id'] for r in beacon_datasets if r['id'] not in authorized_datasets] + response_datasets = [ r['id'] for r in beacon_datasets if r['id'] in authorized_datasets] + LOG.debug(specific_datasets) + LOG.debug(response_datasets) + specific_datasets_unauthorized.append(specific_datasets) + for unauth in specific_datasets_unauthorized: + for unauth_spec in unauth: + biosample_ids = [ r['ids'] for r in beacon_datasets if r['id'] == unauth_spec ] + bio_list.append(biosample_ids) + + list_of_dataset_dicts=[] + + for data_r in response_datasets: dict_dataset = {} dict_dataset['dataset']=data_r dict_dataset['ids']=[ r['ids'] for r in beacon_datasets if r['id'] == data_r ] list_of_dataset_dicts.append(dict_dataset) + + for data_s in specific_datasets: + dict_dataset = {} + dict_dataset['dataset']=data_s + dict_dataset['ids'] = ['Unauthorized dataset'] + list_of_dataset_dicts.append(dict_dataset) #LOG.debug(list_of_dataset_dicts) + qparams = RequestParams(**json_body).from_request(request) - if access_token is not None: + if access_token != 'public': decoded = jwt.decode(access_token, options={"verify_signature": False}) LOG.debug(decoded) token_username = decoded['preferred_username'] diff --git a/beacon/utils/auth.py b/beacon/utils/auth.py index b569748f..85e00389 100644 --- a/beacon/utils/auth.py +++ b/beacon/utils/auth.py @@ -32,11 +32,13 @@ async def resolve_token(token, requested_datasets_ids): 'Accept': 'application/json'}, json={'datasets': requested_datasets_ids}, # will set the Content-Type to application/json ) as resp: + ''' if resp.status > 200: LOG.error('Permissions server error %d', resp.status) error = await resp.text() LOG.error('Error: %s', error) raise web.HTTPUnauthorized(body=error) + ''' content = await resp.content.read() authorized_datasets = content.decode('utf-8') authorized_datasets_list = authorized_datasets.split('"') diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index 9daf4d7a..79c32eae 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -103,6 +103,7 @@ services: - ./logger.yml:/beacon/logger.yml ports: - "5051:5051" + - 8010:8000 networks: - beacon-priv - pub @@ -178,3 +179,5 @@ services: volumes: - ../frontend:/usr/src/app + + diff --git a/deploy/permissions.sh b/deploy/permissions.sh new file mode 100644 index 00000000..f722f263 --- /dev/null +++ b/deploy/permissions.sh @@ -0,0 +1,3 @@ +#!/bin/bash +bash permissions/permissions-ui/start.sh +python -m permissions \ No newline at end of file diff --git a/permissions/auth.py b/permissions/auth.py index ae60a1a3..ee386ac8 100644 --- a/permissions/auth.py +++ b/permissions/auth.py @@ -61,7 +61,8 @@ async def get_user_info(access_token): else: LOG.error('Content: %s', content) LOG.error('Invalid token') - raise web.HTTPUnauthorized() + user = 'public' + return user user = None async with ClientSession(trust_env=True) as session: @@ -75,7 +76,8 @@ async def get_user_info(access_token): else: content = await resp.text() LOG.error('Content: %s', content) - raise web.HTTPUnauthorized() + user = 'public' + return user @@ -96,7 +98,10 @@ async def decorated(request): LOG.info('The user is: %r', user) if user is None: raise web.HTTPUnauthorized() - username = user.get('preferred_username') + elif user == 'public': + username = 'public' + else: + username = user.get('preferred_username') LOG.debug('username: %s', username) return await func(request, username) diff --git a/permissions/controlled_datasets.yml b/permissions/controlled_datasets.yml index e6d055a1..ff46c590 100644 --- a/permissions/controlled_datasets.yml +++ b/permissions/controlled_datasets.yml @@ -1,2 +1,3 @@ controlled_datasets: -- CINECA_synthetic_cohort_EUROPE_UK1 \ No newline at end of file +- nothing +- vamos diff --git a/permissions/permissions-ui/.dockerignore b/permissions/permissions-ui/.dockerignore new file mode 100644 index 00000000..a2ce891c --- /dev/null +++ b/permissions/permissions-ui/.dockerignore @@ -0,0 +1,4 @@ +.dockerignore +*.pyc +__pycache__ +env \ No newline at end of file diff --git a/permissions/permissions-ui/bash/__init__.py b/permissions/permissions-ui/bash/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/permissions/permissions-ui/bash/admin.py b/permissions/permissions-ui/bash/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/permissions/permissions-ui/bash/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/permissions/permissions-ui/bash/apps.py b/permissions/permissions-ui/bash/apps.py new file mode 100644 index 00000000..72b9b510 --- /dev/null +++ b/permissions/permissions-ui/bash/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class BashConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'bash' diff --git a/permissions/permissions-ui/bash/models.py b/permissions/permissions-ui/bash/models.py new file mode 100644 index 00000000..71a83623 --- /dev/null +++ b/permissions/permissions-ui/bash/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/permissions/permissions-ui/bash/tests.py b/permissions/permissions-ui/bash/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/permissions/permissions-ui/bash/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/permissions/permissions-ui/bash/urls.py b/permissions/permissions-ui/bash/urls.py new file mode 100644 index 00000000..b50e254d --- /dev/null +++ b/permissions/permissions-ui/bash/urls.py @@ -0,0 +1,11 @@ +from django.urls import path +#from .views import HomePageView +from . import views +app_name = 'bash' + +urlpatterns = [ + path('', views.bash_view, name='index'), + path('public', views.public_view, name='public'), + path('controlled', views.controlled_view, name='controlled'), + path('registered', views.registered_view, name='registered') +] \ No newline at end of file diff --git a/permissions/permissions-ui/bash/views.py b/permissions/permissions-ui/bash/views.py new file mode 100644 index 00000000..11e5f905 --- /dev/null +++ b/permissions/permissions-ui/bash/views.py @@ -0,0 +1,141 @@ +from django.shortcuts import render, redirect +from django.views.generic import TemplateView +import subprocess +from web.forms import BamForm +import time +from django.http import HttpResponseRedirect, HttpResponseBadRequest +import logging + +import json +import yaml + +LOG = logging.getLogger(__name__) + + +def add_public_datasets(list_datasets): + with open("../beacon/permissions/public_datasets.yml", 'r') as pfile: + public_datasets = yaml.safe_load(pfile) + pfile.close + public_datasets['public_datasets']=list_datasets + with open("../beacon/permissions/public_datasets.yml", 'w') as pfile: + yaml.dump(public_datasets, pfile) + pfile.close + +def add_controlled_datasets(list_datasets): + with open("../beacon/permissions/controlled_datasets.yml", 'r') as pfile: + controlled_datasets = yaml.safe_load(pfile) + pfile.close + controlled_datasets['controlled_datasets']=list_datasets + with open("../beacon/permissions/controlled_datasets.yml", 'w') as pfile: + yaml.dump(controlled_datasets, pfile) + pfile.close + +def add_registered_datasets(list_users, list_datasets): + with open("../beacon/permissions/registered_datasets.yml", 'r') as pfile: + registered_datasets = yaml.safe_load(pfile) + pfile.close + for user in list_users: + registered_datasets[user]=[] + for dataset in list_datasets: + if dataset not in registered_datasets[user]: + registered_datasets[user].append(dataset) + with open("../beacon/permissions/registered_datasets.yml", 'w') as pfile: + yaml.dump(registered_datasets, pfile) + pfile.close + +def load_public_datasets(): + with open("../beacon/permissions/public_datasets.yml", 'r') as pfile: + public_datasets = yaml.safe_load(pfile) + pfile.close() + + list_of_public_datasets = public_datasets['public_datasets'] + + return list_of_public_datasets + +def load_controlled_datasets(): + with open("../beacon/permissions/controlled_datasets.yml", 'r') as pfile: + controlled_datasets = yaml.safe_load(pfile) + pfile.close() + + list_of_controlled_datasets = controlled_datasets['controlled_datasets'] + + return list_of_controlled_datasets + +def load_users(): + with open("../beacon/permissions/registered_datasets.yml", 'r') as pfile: + registered_datasets = yaml.safe_load(pfile) + pfile.close() + + list_users=[] + + for k, v in registered_datasets.items(): + list_users.append(k) + + return list_users + +def load_registered_datasets(): + with open("../beacon/permissions/public_datasets.yml", 'r') as pfile: + registered_datasets = yaml.safe_load(pfile) + pfile.close() + + return registered_datasets + + +def bash_view(request): + template = "home.html" + form =BamForm() + context = {'form': form} + if request.method == 'POST': + form = BamForm(request.POST) + if form.is_valid(): + reference = form.cleaned_data['Datasets'] + if reference == 'PUBLIC': + return redirect("bash:public") + elif reference == 'CONTROLLED': + return redirect("bash:controlled") + elif reference == 'REGISTERED': + return redirect("bash:registered") + return render(request, template, context) + +def public_view(request): + template = "public.html" + bash_out=load_public_datasets() + context={'bash_out': bash_out} + if request.method == 'POST': + answer = request.POST.getlist('list', False) + print(answer) + add_public_datasets(answer) + context = { + 'answer': answer, + } + return redirect("bash:index") + return render(request, template, context) + +def controlled_view(request): + template = "controlled.html" + bash_out=load_controlled_datasets() + context={'bash_out': bash_out} + if request.method == 'POST': + answer = request.POST.getlist('list', False) + print(answer) + add_controlled_datasets(answer) + context = { + 'answer': answer, + } + return redirect("bash:index") + return render(request, template, context) + +def registered_view(request): + template = "registered.html" + bash_out=load_users() + registered_datasets=load_registered_datasets() + context={'bash_out': bash_out, 'registered_datasets': registered_datasets['public_datasets']} + if request.method == 'POST': + answer = request.POST.getlist('list', False) + datasets_list = request.POST.getlist('list_datasets', False) + add_registered_datasets(answer, datasets_list) + context = { + 'answer': answer, 'datasets_list': datasets_list + } + return redirect("bash:index") + return render(request, template, context) \ No newline at end of file diff --git a/permissions/permissions-ui/manage.py b/permissions/permissions-ui/manage.py new file mode 100755 index 00000000..19be6dd3 --- /dev/null +++ b/permissions/permissions-ui/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'web.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/permissions/permissions-ui/media/Ebi_official_logo.png b/permissions/permissions-ui/media/Ebi_official_logo.png new file mode 100644 index 00000000..8811f905 Binary files /dev/null and b/permissions/permissions-ui/media/Ebi_official_logo.png differ diff --git a/permissions/permissions-ui/media/app.js b/permissions/permissions-ui/media/app.js new file mode 100644 index 00000000..bd497e44 --- /dev/null +++ b/permissions/permissions-ui/media/app.js @@ -0,0 +1,44 @@ +const btnAdd = document.querySelector('#btnAdd'); +const btnRemove = document.querySelector('#btnRemove'); +const listbox = document.querySelector('#list'); +const framework = document.querySelector('#framework'); + +btnAdd.onclick = (e) => { + e.preventDefault(); + + // validate the option + if (framework.value == '') { + alert('Please enter the name.'); + return; + } + // create a new option + console.log(framework.value) + const option = new Option(framework.value, framework.value); + option.setAttribute('selected', 'selected'); + // add it to the list + listbox.add(option, undefined); + + // reset the value of the input + framework.value = ''; + framework.focus(); +}; + +// remove selected option +btnRemove.onclick = (e) => { + e.preventDefault(); + + // save the selected options + let selected = []; + + for (let i = 0; i < listbox.options.length; i++) { + selected[i] = listbox.options[i].selected; + } + + // remove all selected option + let index = listbox.options.length; + while (index--) { + if (selected[index]) { + listbox.remove(index); + } + } +}; \ No newline at end of file diff --git a/permissions/permissions-ui/media/app2.js b/permissions/permissions-ui/media/app2.js new file mode 100644 index 00000000..b976b4db --- /dev/null +++ b/permissions/permissions-ui/media/app2.js @@ -0,0 +1,65 @@ +const btnAdd2 = document.querySelector('#btnAdd2'); +const btnRemove = document.querySelector('#btnRemove'); +const datasets = document.querySelector('#list_datasets'); +const framework = document.querySelector('#framework'); +btnAdd2.onclick = (e) => { + e.preventDefault(); + + // validate the option + let selected = []; + + for (let i = 0; i < datasets.options.length; i++) { + selected[i] = datasets.options[i].selected; + if (datasets.options[i].selected == true){ + selected[i] = datasets.options[i].value + } + } + + + for (let i = 0; i < selected.length; i++) { + console.log(selected[i]) + const option = new Option(selected[i], selected[i]); + option.setAttribute('selected', 'selected'); + // add it to the list + listbox.add(option, undefined); + } + // create a new option + + if (framework.value == '') { + alert('Please enter the name.'); + return; + } + + // create a new option + const option = new Option(framework.value, framework.value); + option.setAttribute('selected', 'selected'); + // add it to the list + listbox.add(option, undefined); + + // reset the value of the input + framework.value = ''; + framework.focus(); + + + + }; + +// remove selected option +btnRemove.onclick = (e) => { + e.preventDefault(); + + // save the selected options + let selected = []; + + for (let i = 0; i < listbox.options.length; i++) { + selected[i] = listbox.options[i].selected; + } + + // remove all selected option + let index = listbox.options.length; + while (index--) { + if (selected[index]) { + listbox.remove(index); + } + } +}; \ No newline at end of file diff --git a/permissions/permissions-ui/media/append.js b/permissions/permissions-ui/media/append.js new file mode 100644 index 00000000..6329f246 --- /dev/null +++ b/permissions/permissions-ui/media/append.js @@ -0,0 +1,8 @@ +$('#datasets').on('change', function() { + + var val = $(this).val(), + text = $(this).find("option:selected").text(); + + $('#list').append(new Option(text, val)); + + }); \ No newline at end of file diff --git a/permissions/permissions-ui/media/arrows.js b/permissions/permissions-ui/media/arrows.js new file mode 100644 index 00000000..87eef24b --- /dev/null +++ b/permissions/permissions-ui/media/arrows.js @@ -0,0 +1,3 @@ +function classToggle() { + document.getElementById("header").classList.toggle("bi-caret-up-fill"); + } diff --git a/permissions/permissions-ui/media/logo.png b/permissions/permissions-ui/media/logo.png new file mode 100644 index 00000000..5699da04 Binary files /dev/null and b/permissions/permissions-ui/media/logo.png differ diff --git a/permissions/permissions-ui/media/logo_1.png b/permissions/permissions-ui/media/logo_1.png new file mode 100644 index 00000000..5435a857 Binary files /dev/null and b/permissions/permissions-ui/media/logo_1.png differ diff --git a/permissions/permissions-ui/media/mystyle.css b/permissions/permissions-ui/media/mystyle.css new file mode 100644 index 00000000..25f08370 --- /dev/null +++ b/permissions/permissions-ui/media/mystyle.css @@ -0,0 +1,267 @@ +* { margin: 0; padding: 0; } +.terminal { + border-radius: 5px 5px 5px 5px; + position: relative; +} +.terminal .top { + background: #E8E6E8; + color: black; + padding: 5px; + margin-left: 5px; + border-radius: 5px 5px 0 0; +} +.terminal .btns { + position: absolute; + top: 7px; + margin-left: 15px; +} +.terminal .circle { + width: 12px; + height: 12px; + display: inline-block; + border-radius: 15px; + margin-left: 2px; + border-width: 1px; + border-style: solid; +} +.title{ + text-align: center; +} +.red { background: #EC6A5F; border-color: #D04E42; } +.green { background: #64CC57; border-color: #4EA73B; } +.yellow{ background: #F5C04F; border-color: #D6A13D; } +.clear{clear: both;} +.terminal .body { + background: black; + color: #7AFB4C; + padding: 100px; + margin-left: 5px; + overflow: auto; + text-align: left; + height: 300px; +} +.space { + margin: 25px; +} + + +.hovertext { + position: relative; + border-bottom: 1px dotted black; + } + +.hovertext:before { + content: attr(data-hover); + visibility: hidden; + opacity: 0; + width: 140px; + background-color: black; + color: #fff; + text-align: center; + border-radius: 5px; + padding: 5px 0; + transition: opacity 1s ease-in-out; + position: absolute; + z-index: 1; + left: 70px; + top: -10px; + } + +.hovertext:hover:before { + opacity: 1; + visibility: visible; + } +.prova{ + color: blue; + } + +.typewriter h3{ + color: #185177; + display: inline-block; + overflow: hidden; /* Ensures the content is not revealed until the animation */ + border-right: .15em solid orange; /* The typwriter cursor */ + white-space: nowrap; /* Keeps the content on a single line */ + margin: 0 auto; /* Gives that scrolling effect as the typing happens */ + letter-spacing: .15em; /* Adjust as needed */ + animation: + typing 3.5s steps(40, end), + blink-caret .75s step-end infinite; + } + + /* The typing effect */ +@keyframes typing { + from { max-width: 0 } + to { max-width: 100% } + } + + /* The typewriter cursor effect */ +@keyframes blink-caret { + from, to { border-color: transparent } + 50% { border-color: orange; } + } + +#myDIV { + display: none; +} + +#example { + display: none; +} + +.result{ + margin-left: -100px; + margin-top: -120px; +} + +.links{ + display: inline-block; +} + +.results{ + position: relative; + display: inline; +} + +td, +th { + border: 1px solid rgb(190, 190, 190); + padding-left: 10px; + padding-right: 10px; +} + +td { + text-align: left; +} + +tr:nth-child(even) { + background-color: #eee; +} + +th[scope='col'] { + background-color: #696969; + color: #fff; +} + +th[scope='row'] { + background-color: #d7d9f2; +} + +caption { + padding: 10px; + caption-side: bottom; +} + +table { + border-collapse: collapse; + letter-spacing: 1px; + font-family: sans-serif; + font-size: 0.8rem; + display: block; + height: 500px; + overflow-y: scroll; +} + +.false { + padding: 1rem; + box-shadow: 0 15px 30px 0 rgba(0,0,0,0.11), + 0 5px 15px 0 rgba(0,0,0,0.08); + background-color: #ffffff; + border-radius: 0.5rem; + + border-left: 1px solid red; + transition: border-left 300ms ease-in-out, padding-left 300ms ease-in-out; +} + +.false:hover { + padding-left: 0.5rem; + border-left: 0.5rem solid #EC6A5F; +} + +.false > :first-child { + margin-top: 0; +} + +.false > :last-child { + margin-bottom: 0; +} + +.true { + padding: 1rem; + box-shadow: 0 15px 30px 0 rgba(0,0,0,0.11), + 0 5px 15px 0 rgba(0,0,0,0.08); + background-color: #ffffff; + border-radius: 0.5rem; + + border-left: 1px solid green; + transition: border-left 300ms ease-in-out, padding-left 300ms ease-in-out; +} + +.true:hover { + padding-left: 0.5rem; + border-left: 0.5rem solid #00ff99; +} + +.true > :first-child { + margin-top: 0; +} + +.true > :last-child { + margin-bottom: 0; +} + +.none { + padding: 1rem; + box-shadow: 0 15px 30px 0 rgba(0,0,0,0.11), + 0 5px 15px 0 rgba(0,0,0,0.08); + background-color: #ffffff; + border-radius: 0.5rem; + + border-left: 1px solid grey; + transition: border-left 300ms ease-in-out, padding-left 300ms ease-in-out; +} + +.none:hover { + padding-left: 0.5rem; + border-left: 0.5rem solid grey; +} + +.none > :first-child { + margin-top: 0; +} + +.none > :last-child { + margin-bottom: 0; +} + +.kcbutton { + cursor: pointer; + border: 0; + border-radius: 4px; + font-weight: 600; + margin: 0 10px; + width: 200px; + padding: 10px 0; + box-shadow: 0 0 20px rgba(104, 85, 224, 0.2); + transition: 0.4s; + color: #239B56; + background-color: rgba(255, 255, 255, 1); + border: 1px solid #239B56; +} + +.kcbutton:hover { + color: white; + box-shadow: 0 0 20px rgba(2, 45, 2, 0.6); + background-color: #239B56; +} +.welcome{ + margin-top: 15px; +} + +.valid { + color: green; +} + +.notvalid{ + color: red; +} + diff --git a/permissions/permissions-ui/media/tablesorter.js b/permissions/permissions-ui/media/tablesorter.js new file mode 100644 index 00000000..bac8ec88 --- /dev/null +++ b/permissions/permissions-ui/media/tablesorter.js @@ -0,0 +1,54 @@ +function sortTable(n) { + var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0; + table = document.getElementById("EGAtable"); + switching = true; + //Set the sorting direction to ascending: + dir = "asc"; + /*Make a loop that will continue until + no switching has been done:*/ + while (switching) { + //start by saying: no switching is done: + switching = false; + rows = table.rows; + /*Loop through all table rows (except the + first, which contains table headers):*/ + for (i = 1; i < (rows.length - 1); i++) { + //start by saying there should be no switching: + shouldSwitch = false; + /*Get the two elements you want to compare, + one from current row and one from the next:*/ + x = rows[i].getElementsByTagName("TD")[n]; + y = rows[i + 1].getElementsByTagName("TD")[n]; + /*check if the two rows should switch place, + based on the direction, asc or desc:*/ + if (dir == "asc") { + if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) { + //if so, mark as a switch and break the loop: + shouldSwitch= true; + break; + } + } else if (dir == "desc") { + if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) { + //if so, mark as a switch and break the loop: + shouldSwitch = true; + break; + } + } + } + if (shouldSwitch) { + /*If a switch has been marked, make the switch + and mark that a switch has been done:*/ + rows[i].parentNode.insertBefore(rows[i + 1], rows[i]); + switching = true; + //Each time a switch is done, increase this count by 1: + switchcount ++; + } else { + /*If no switching has been done AND the direction is "asc", + set the direction to "desc" and run the while loop again.*/ + if (switchcount == 0 && dir == "asc") { + dir = "desc"; + switching = true; + } + } + } + } \ No newline at end of file diff --git a/permissions/permissions-ui/media/white-orange-logo.png b/permissions/permissions-ui/media/white-orange-logo.png new file mode 100644 index 00000000..4ab5f844 Binary files /dev/null and b/permissions/permissions-ui/media/white-orange-logo.png differ diff --git a/permissions/permissions-ui/my_auth/__init__.py b/permissions/permissions-ui/my_auth/__init__.py new file mode 100644 index 00000000..7bf22f8b --- /dev/null +++ b/permissions/permissions-ui/my_auth/__init__.py @@ -0,0 +1,8 @@ +from django.conf import settings +from django.utils.http import urlencode + + +def provider_logout(request): + logout_url = settings.OIDC_OP_LOGOUT_ENDPOINT + return_to_url = request.build_absolute_uri(settings.LOGOUT_REDIRECT_URL) + return logout_url + '?' + urlencode({'redirect_uri': return_to_url, 'client_id': settings.OIDC_RP_CLIENT_ID}) \ No newline at end of file diff --git a/permissions/permissions-ui/requirements.txt b/permissions/permissions-ui/requirements.txt new file mode 100644 index 00000000..2809464d --- /dev/null +++ b/permissions/permissions-ui/requirements.txt @@ -0,0 +1,4 @@ +Django==4.1.3 +django-crispy-forms==1.14.0 +django-environ==0.8.1 +mozilla-django-oidc==3.0.0 \ No newline at end of file diff --git a/permissions/permissions-ui/start.sh b/permissions/permissions-ui/start.sh new file mode 100755 index 00000000..42287f0f --- /dev/null +++ b/permissions/permissions-ui/start.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +python3 permissions/permissions-ui/manage.py migrate +python3 permissions/permissions-ui/manage.py runserver 0.0.0.0:8000 \ No newline at end of file diff --git a/permissions/permissions-ui/templates/base.html b/permissions/permissions-ui/templates/base.html new file mode 100644 index 00000000..61fb9a01 --- /dev/null +++ b/permissions/permissions-ui/templates/base.html @@ -0,0 +1,125 @@ +{% load crispy_forms_tags %} + + + +
+ + + +