Skip to content
Snippets Groups Projects
Commit a27f7d3a authored by Michel Jouvin's avatar Michel Jouvin
Browse files

Initial import of OSITAH application from IJCLab version

parent dc59b6ab
No related branches found
No related tags found
No related merge requests found
Showing
with 5882 additions and 0 deletions
# gunicorn configuration examples
The files in this directory provide 3 files to manage OSITAH application with gunicorn:
- gunicorn@.service: the systemd script to manage gunicorn with systemd. It is a multi-instance service and OSITAH is typically managed with the unit `gunicorn@ositah`.
- gunicorn.ositah: a file typically placed in `/etc/sysconfig` and defining the paramters specifich to OSITAH gunicorn instance
- app.conf.py: the gunicorn parameters used to start the OSITAH instance
All these files must be considered as templates. In particular, the various paths must be customized according to your site configuration.
GUNICORN_OPTIONS='--config /pdisk/ositah/conf/ositah.conf.py'
GUNICORN_APP_DIR=/pdisk/ositah/conf
GUNICORN_APP="'ositah.main:make_app()'"
[Install]
WantedBy=multi-user.target
[Service]
EnvironmentFile=/etc/sysconfig/gunicorn.%i
ExecStart=/bin/sh -cv '/pdisk/anaconda/envs/ositah/bin/gunicorn --chdir ${GUNICORN_APP_DIR} --pid /var/run/gunicorn.%i.pid ${GUNICORN_OPTIONS} ${GUNICORN_APP}'
PIDFile=/var/run/gunicorn.%i.pid
Restart=always
SyslogIdentifier=gunicorn
[Unit]
Description=gunicorn service %I
# Configuration file for running OSITAH with gunicorn as a systemd service
workers = 1
threads = 4
bind = "0.0.0.0:7777"
daemon = False # don't run as a daemon with systemd
capture_output = True
# loglevel = 'debug'
# Adjust to site specific configuration
accesslog = "/pdisk/ositah/logs/ositah.accesslog"
errorlog = "/pdisk/ositah/logs/ositah.errorlog"
# Dash app initialization
import os
import dash_bootstrap_components as dbc
from dash import Dash
from flask import Flask
APP_NAME = __name__
FLASK_TEMPLATES_DIR = f"{os.path.dirname(__file__)}/templates"
app = Dash(
APP_NAME,
server=Flask(APP_NAME, template_folder=FLASK_TEMPLATES_DIR),
external_stylesheets=[dbc.themes.BOOTSTRAP, dbc.icons.BOOTSTRAP],
suppress_callback_exceptions=True,
)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<!-- From Bootstrap icon arrow-down-up -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down-up" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M11.5 15a.5.5 0 0 0 .5-.5V2.707l3.146 3.147a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 1 0 .708.708L11 2.707V14.5a.5.5 0 0 0 .5.5zm-7-14a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L4 13.293V1.5a.5.5 0 0 1 .5-.5z"/>
</svg>
\ No newline at end of file
/* CSS for the validation part of OSITAH */
div.login_page {
margin-left: 50px;
}
div.login_form_field {
font-weight: bold;
margin-top: 20px;
}
input.login_button {
margin-top: 30px;
margin-left: 45px;
}
ul.flash-message {
display: inline-block;
list-style-type: none;
padding-left: 0;
}
/* CSS for Dash components */
.team_list_dropdown {
margin-top: 15px;
}
.validated_hito_missing {
background-color: tomato;
}
table.sortable th::after, th.sorttable_sorted::after, th.sorttable_sorted_reverse::after {
content: " ";
display: inline-block;
width: 24px;
height: 24px;
}
table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sorttable_nosort):after {
content: url("arrow_down_up.svg");
}
th.sorttable_sorted::after {
background: url("sort_ascending.svg");
background-size: contain;
}
th.sorttable_sorted_reverse::after {
background: url("sort_descending.svg");
background-size: cover;
}
#sorttable_sortfwdind, #sorttable_sortrevind { display: none; }
\ No newline at end of file
<!-- From Bootstrap icon sort-alpha-down -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-sort-alpha-down" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M10.082 5.629 9.664 7H8.598l1.789-5.332h1.234L13.402 7h-1.12l-.419-1.371h-1.781zm1.57-.785L11 2.687h-.047l-.652 2.157h1.351z"/>
<path d="M12.96 14H9.028v-.691l2.579-3.72v-.054H9.098v-.867h3.785v.691l-2.567 3.72v.054h2.645V14zM4.5 2.5a.5.5 0 0 0-1 0v9.793l-1.146-1.147a.5.5 0 0 0-.708.708l2 1.999.007.007a.497.497 0 0 0 .7-.006l2-2a.5.5 0 0 0-.707-.708L4.5 12.293V2.5z"/>
</svg>
\ No newline at end of file
<!-- From Bootstrap icon sort-alpha-down-alt -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-sort-alpha-down-alt" viewBox="0 0 16 16">
<path d="M12.96 7H9.028v-.691l2.579-3.72v-.054H9.098v-.867h3.785v.691l-2.567 3.72v.054h2.645V7z"/>
<path fill-rule="evenodd" d="M10.082 12.629 9.664 14H8.598l1.789-5.332h1.234L13.402 14h-1.12l-.419-1.371h-1.781zm1.57-.785L11 9.688h-.047l-.652 2.156h1.351z"/>
<path d="M4.5 2.5a.5.5 0 0 0-1 0v9.793l-1.146-1.147a.5.5 0 0 0-.708.708l2 1.999.007.007a.497.497 0 0 0 .7-.006l2-2a.5.5 0 0 0-.707-.708L4.5 12.293V2.5z"/>
</svg>
\ No newline at end of file
This diff is collapsed.
# Configuration file for OSITAH application
# Where to read the data
hito:
db:
# type muste be sqlite or mysql
#type: sqlite
type: mysql
# location must be a filename for sqlite or server/database for mysql
#location: 'c:\temp\hito-dev.sqlite'
location: 'localhost/hito'
user: hitousery
password: *verysecret*
# After this time (in seconds), DB connection is recycled
inactivity_timeout: 900
# For some unidentified reason, in SQLite, "stagiaire" carriere type is not found with an exact match...
agent_query: |
SELECT
DISTINCT(agent.id)
, agent.nom
, agent.prenom
, agent.team_id as team_id
, team.nom as team
, agent.statut as statut
, agent.email as email
, agent.corps_exercice_metier as cem
, CASE
WHEN agent.email_auth IS NULL THEN agent.email
ELSE agent.email_auth
END AS email_auth
FROM
agent
LEFT JOIN team on team.id = agent.team_id
JOIN carriere on carriere.agent_id = agent.id
WHERE
agent.archive = 0
AND
carriere.date_debut = (
SELECT MAX(c.date_debut)
FROM carriere AS c
WHERE
agent.id = c.agent_id
AND
(c.type IN ("apprenti", "cdd", "emeritat", "stagiaire", "visiteur") OR c.type LIKE "arrivee%" OR c.type LIKE "stagiaire%")
)
AND
carriere.date_debut <= $$TODAY$$
# Patterns to identify the different activity categories from the activity name
categories:
consultance: 'Consultances & Expertises'
enseignement: 'Enseignement Supérieur'
local_project: 'Local projects'
service: 'Services & Support'
# Time unit (default is hours for categories not listed). Supported values h(our), w(eek)
time_unit:
local_project: w
nsip_project: w
service: w
# Column titles to use when displying the information about categories and agents
titles:
consultance: 'Consultance'
declarations_number: 'Déclarations effectuées'
enseignement: 'Enseignement'
fullname: 'Agent'
local_project: 'projets locaux'
missings_number: 'Déclarations obligatoires manquantes'
nsip_project: 'projets NSIP'
percent_global: 'Temps déclarés (%)'
service: 'Service'
statut: 'Statut'
team: 'Equipe'
# Web server information
server:
port: 9999
authentication:
ldap:
# uri can be space-separated list
uri: 'ldaps://ijclabad1.ijclab.in2p3.fr ldaps://ijclabad2.ijclab.in2p3.fr ldaps://ccijclabad01.ijclab.in2p3.fr'
base_dn: 'ou=ijclab,dc=ijclab,dc=in2p3,dc=fr'
bind_dn: 'CN=Non-Interactive Queries,OU=SI,OU=Services techniques,OU=Laboratoire,DC=lal,DC=in2p3,DC=fr'
password: 'ldap_bind_password'
# Options related to declarations
declaration:
# Default date must be a date included into the selected validation period. It is a default, if no other explicitly select
default_date: 2021-07-01
# max_hours specifies the upper valid value for activities declared in hours
max_hours: 400
# Agent statut whose declaration is not mandatory
optional_statutes:
- benevole
- emerite
- stagiaire
- visiteur
# Team who are not required to declare: values must match the beginning of the team name
optional_teams:
- Administration
- Support
# Thresholds used to mark declarations as low, suspect or good
# The value is the upper bound for the corresonding class
thresholds:
low: 50
suspect: 80
good: 100
# Information related to validation
validation:
override_period:
- ROLE_SUPER_ADMIN
- ROLE_PROJECT_MANAGER
# Users with specific rights
roles:
# List users (with their connection email) who are given a read-only access to OSITAH (no validation right)
read-only:
- user@my.dom.ain
# NSIP related parameters
nsip:
# The following sections configures information about NSIP service
# For each part of the API, there must be a base URL and some operation sub-urls
agent_api:
base_url: /api_labo/agent
declaration_add: /declaration/create
declaration_delete: /declaration/delete
declaration_update: /declaration/update
institute_api:
base_url: /api_institut
declaration_period_list: /declaration_period/list
lab_api:
base_url: /api_labo
agent_list: /agent/list
declaration_list: /declaration/list
project_list: /project/list
reference_list: /reference/list
server_url: https://nsip.in2p3.fr
token: nsip_lab_token
# teaching dictionary allows to define a ratio to apply to teaching activities.
# It also allows to define (optionally) a list of CEM that this ratio must
# be applied to (instead of all agents).
# master allows to define the masterproject identifying teaching activities
# (default: Enseignement Supérieur)
teaching:
masterproject: Enseignement Supérieur
ratio: 4.4
cem:
- cem_enseignant_chercheur
# Match against NSIP reference types to define the OSITAH masterproject.
# A reference with no value will cause the entry to be ignored by OSITAH.
# Reference types can be regex.
reference_masterprojects:
consultancyexpertise: Consultances & Expertises
highereducation: Enseignement Supérieur
servicesupport: Services & Support
# project_teams allow to define a list of teams for a project
# The project name is matched against the list of defined projects and must be a regex matching
# the beginning of the project name. A team can be specified as a regex.
# Example below is for IJCLab: update according to your needs.
project_teams:
Consultances & Expertises:
- .*
Enseignement Supérieur:
- Accélérateurs.*
- A2C.*
- Direction
- Energie.*
- Ingénierie.*
- Nucléaire.*
- PHE.*
- Plateforme.*
- Santé.*
- Théorie.*
Services & Support / Assurance-Qualité:
- Support - Projets
Services & Support / Budget-Finances:
- Administration - Division financière
Services & Support / Communication-Documentation:
- Support - Communication
#Services & Support / Environnement:
Services & Support / Formation:
- Support - Enseignement
#Services & Support / Hygiène-Sécurité:
Services & Support / Management:
- .*
Services & Support / Partenariat:
- Support - STIRI
Services & Support / Patrimoine:
- Support - Infrastructure
Services & Support / Radioprotection:
- Support - Service SPR
Services & Support / Ressources Humaines:
- Administration.* - RH.*
Services & Support / Secrétariat:
- Direction - Assistantes
#Services & Support / Services Généraux:
Services & Support / Support-Biologie:
- Santé.*
Services & Support / Support-Electronique:
- Ingénierie - Electronique.*
Services & Support / Support-Informatique:
- Ingénierie - Informatique
Services & Support / Support-Instrumentation:
- Ingénierie - Détecteurs.*
Services & Support / Support-Mécanique:
- Ingénierie - Mécanique
#Services & Support / Sûreté:
Services & Support / Valorisation:
- Support - STIRI
This diff is collapsed.
/* CSS for the validation part of OSITAH */
div.login_page {
margin-left: 50px;
}
div.login_form_field {
font-weight: bold;
margin-top: 20px;
}
input.login_button {
margin-top: 30px;
margin-left: 45px;
}
ul.flash-message {
display: inline-block;
list-style-type: none;
padding-left: 0;
}
/* CSS for Dash components */
.team_list_dropdown {
margin-top: 15px;
}
.validated_hito_missing {
background-color: tomato;
}
table.sortable th::after, th.sorttable_sorted::after, th.sorttable_sorted_reverse::after {
content: " ";
display: inline-block;
width: 24px;
height: 24px;
}
table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sorttable_nosort):after {
content: url("arrow_down_up.svg");
}
th.sorttable_sorted::after {
background: url("sort_ascending.svg");
background-size: contain;
}
th.sorttable_sorted_reverse::after {
background: url("sort_descending.svg");
background-size: cover;
}
#sorttable_sortfwdind, #sorttable_sortrevind { display: none; }
\ No newline at end of file
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>OSITAH Login page</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
{% with messages = get_flashed_messages(with_categories=True) %}
{% if messages %}
<ul class="bg-warning flash-message">
{%- for category, message in messages %}
<li>{{ category }}: {{ message }}</li>
{% endfor -%}
</ul>
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</body>
</html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="/docs/4.0/assets/img/favicons/favicon.ico">
<title>Signin Template for Bootstrap</title>
<link rel="canonical" href="https://getbootstrap.com/docs/4.0/examples/sign-in/">
<!-- Bootstrap core CSS -->
<link href="../../dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="signin.css" rel="stylesheet">
</head>
<body class="text-center">
<form class="form-signin">
<img class="mb-4" src="https://getbootstrap.com/docs/4.0/assets/brand/bootstrap-solid.svg" alt="" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
<label for="inputEmail" class="sr-only">Email address</label>
<input type="email" id="inputEmail" class="form-control" placeholder="Email address" required autofocus>
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" id="inputPassword" class="form-control" placeholder="Password" required>
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me"> Remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
<p class="mt-5 mb-3 text-muted">&copy; 2017-2018</p>
</form>
</body>
</html>
<div class="login_page">
{% extends 'base.html' %}
{% block content %}
<p>Log in using <strong>{{ provider.title }}</strong></p>
<form method=post>
<div class="login_form">
{% for field in form %}
{% if field.widget.__class__.__name__ == 'HiddenInput' %}
{{ field() }}
{% else %}
<div class="login_form_field">
{{ field.label() }}
</div>
<div>
{{ field() }}
{% if field.errors %}
Errors: {{ field.errors|join(' / ') }}
{% endif %}
</div>
{% endif %}
{% endfor %}
<input type="submit" value="Login" class="btn btn-secondary login_button">
</div>
</form>
{% endblock %}
</div>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment