Ejemplo n.º 1
0
def calculette_rh(db: SQLAlchemy, structure_repo: StructureRepository):
    demande = DemandeRH()

    json = request.json

    model = json["model"]
    form = json["form"]

    user = get_current_profile()

    model = cleanup_model(model, form)

    demande = DemandeRH(data=model)
    demande.form_state = form

    porteur_dto = model.get("porteur")
    if porteur_dto:
        porteur_id = porteur_dto["value"]
        demande.porteur = db.session.query(Profile).get(porteur_id)

    if user != demande.porteur:
        demande.gestionnaire = user

    structure_dto = model.get("laboratoire")
    if structure_dto:
        structure_id = structure_dto["value"]
        demande.structure = structure_repo.get_by_id(structure_id)

    blob = devis_rh(demande)
    response = make_response(blob)
    response.headers["content-type"] = "application/pdf"
    return response
Ejemplo n.º 2
0
def check_user_can_edit():
    profile = get_current_profile()
    if profile.has_role(Role.ADMIN_CENTRAL) or profile.has_role(
            Role.FAQ_EDITOR):
        return

    raise Forbidden
Ejemplo n.º 3
0
def update_demande(id, model, form):
    user = get_current_profile()
    model = cleanup_model(model, form)

    demande = db.session.query(Demande).get(id)
    check_read_access(demande)
    check_write_access(demande)

    demande.form_state = form

    messages = []
    if not demande.has_same_data(model):
        demande.update_data(model)
        porteur = get_porteur(model)
        if porteur != demande.porteur:
            demande.porteur = porteur
            demande.gestionnaire = user
        demande.structure = get_structure(model)
        db.session.commit()

        messages.append([
            "Votre demande a été modifiée. La version précédente de la demande a été archivée.",
            "success",
        ])
    else:
        messages.append(
            ["Vous n'avez pas effectué de modification.", "success"])

    if not demande.is_valid():
        messages.append(
            ["Attention, votre demande est encore incomplète.", "warning"])

    whoosh.index_object(demande)

    return messages
Ejemplo n.º 4
0
def get_bi_context():
    check_permission()

    user = get_current_profile()
    ctx = get_stats2(user)
    ctx["selectors"] = get_selectors()
    return ctx
Ejemplo n.º 5
0
def get_nb_demandes_a_valider():
    user = get_current_profile()

    ctx = {
        "total_demandes": 0,
        "nb_pi_a_valider": 0,
        "nb_recrutements_a_valider": 0,
        "nb_conventions_a_valider": 0,
        "nb_autres_a_valider": 0,
    }

    if user.has_role(Role.RESPONSABLE, "*"):
        demandes = mes_taches(user)
        demandes = [d for d in demandes if d.wf_state == EN_VALIDATION.id]

        conventions = [
            d for d in demandes
            if isinstance(d, (DemandeConvention, DemandeAvenantConvention))
        ]
        recrutements = [d for d in demandes if isinstance(d, DemandeRH)]
        pi = [d for d in demandes if isinstance(d, DemandePiMixin)]
        autres = [d for d in demandes if isinstance(d, DemandeAutre)]

        ctx["total_demandes"] = len(demandes)
        ctx["nb_conventions_a_valider"] = len(conventions)
        ctx["nb_recrutements_a_valider"] = len(recrutements)
        ctx["nb_pi_a_valider"] = len(pi)
        ctx["nb_autres_a_valider"] = len(autres)

    return ctx
Ejemplo n.º 6
0
def get_demandes(scope="all", archives=False, tag="") -> JSONList:
    archives = bool(archives)
    profile = get_current_profile()

    view = get_table_view(scope, profile, archives)
    if not view:
        return []

    demandes: list[Demande] = view.get_demandes_for(profile)

    def make_pred(tag):
        def pred(demande):
            if tag == "rh":
                return isinstance(demande, DemandeRH)
            elif tag == "conventions":
                return isinstance(
                    demande, (DemandeConvention, DemandeAvenantConvention))
            elif tag == "pi":
                return isinstance(demande, DemandePiMixin)
            elif tag == "autres":
                return isinstance(demande, DemandeAutre)
            else:
                raise RuntimeError()

        return pred

    if tag:
        demandes = r.filter(make_pred(tag), demandes)

    demandes.sort(key=lambda d: d.created_at, reverse=True)
    return demandes_to_json(demandes, profile)
Ejemplo n.º 7
0
def sg_get_possible_child_types(id: str) -> list[dict[str, str]]:
    user = get_current_profile()

    structure = structure_repo.get_by_id(id)
    if not structure:
        raise NotFound()

    if not has_permission(structure, "P3"):
        return []

    result = []
    for candidate_type in ALL_TYPES:
        if candidate_type.reel:
            continue
        if structure.type.can_have_child_of_type(candidate_type):
            if user.has_role(Role.ADMIN_CENTRAL):
                result.append({
                    "value": candidate_type.id,
                    "text": candidate_type.name
                })
            elif candidate_type in [DE, EQ]:
                result.append({
                    "value": candidate_type.id,
                    "text": candidate_type.name
                })

    return result
Ejemplo n.º 8
0
def update_global_roles(data: dict[str, JSON]):
    user = get_current_profile()

    if not user.has_role(Role.ADMIN_CENTRAL):
        raise Forbidden

    for role_name in data:
        role = getattr(Role, role_name)

        users = role_service.get_users_with_role(role)
        for user in users:
            role_service.ungrant_role(user, role)

        values = data[role_name]
        if isinstance(values, dict):
            values = [values]
        if not values:
            continue

        for user_id in glom(values, ["id"]):
            user = profile_repo.get_by_id(ProfileId(user_id))
            role_service.grant_role(user, role)

    db.session.commit()

    cache.evict("users")
Ejemplo n.º 9
0
    def get_workflow(self, demande: Demande) -> JSON:
        current_user = get_current_profile()
        workflow = demande.get_workflow(current_user)

        owners = list(workflow.current_owners())

        owners.sort(key=owner_sorter)
        owners_dto = [{
            "full_name": owner.full_name,
            "id": owner.id
        } for owner in owners]

        transitions_dto = [{
            "id": t.id,
            "label": t.label,
            "category": t.category,
            "form": t.get_form(workflow),
        } for t in workflow.possible_transitions()]

        result = {
            "state": {
                "label": workflow.state.label,
                "next_action": workflow.state.next_action,
            },
            "owners": owners_dto,
            "history": [],  # TODO
            "transitions": transitions_dto,
        }
        return result
Ejemplo n.º 10
0
def search(q, **search_args):
    """Interface to search indexes.

    :param q: unparsed search string.
    :param search_args: any valid parameter for
        :meth:`whoosh.searching.Search.search`. This includes `limit`,
        `groupedby` and `sortedby`
    """
    index = whoosh.index

    fields = {"name": 1.5, "text": 1.0}
    parser = DisMaxParser(fields, index.schema)
    query = parser.parse(q)

    # security access filter
    user = get_current_profile()

    if not is_membre_dri(user):
        pass
        # TODO
        # roles = {f"user:{user.id}", "all"}
        # for role in user.get_roles():
        #     if role.type in [RoleType.DIRECTION.value, RoleType.GDL.value]:
        #         structure = role.context
        #         structures = [structure] + structure.descendants()
        #         roles |= {f"org:{s.id}" for s in structures}
        #
        # terms = [wq.Term("allowed_roles_and_users", role) for role in roles]
        # query &= wq.Or(terms)

    with index.searcher(closereader=False) as searcher:
        # 'closereader' is needed, else results cannot by used outside 'with'
        # statement
        return searcher.search(query, **search_args)
Ejemplo n.º 11
0
def wf_transition(demande_id, action, data=None):
    data = data or {}
    user = get_current_profile()
    db = injector.get(SQLAlchemy)

    demande = db.session.query(Demande).get(demande_id)
    workflow = demande.get_workflow(user)

    try:
        transition = workflow.get_transition_by_id(action)
    except IndexError:
        msg = (
            "Action impossible. Quelqu'un a probablement effectué une action "
            "sur la demande en parallèle avec vous.",
            "danger",
        )
        return msg

    workflow.execute_transition(transition, data=data)
    db.session.commit()
    msg = (
        f"Votre action '{transition.label}' sur la demande '{demande.nom}' a bien été prise en compte.",
        "success",
    )
    return msg
Ejemplo n.º 12
0
def has_read_access(demande: Demande) -> bool:
    user = get_current_profile()

    if user in (demande.porteur, demande.gestionnaire, demande.contact_labco):
        return True

    if user.has_role(Role.ADMIN_CENTRAL):
        return True

    wf_states = {
        state["new_state"]
        for state in demande.wf_history if "new_state" in state
    }

    # DRI & DRV
    if wf_states != {EN_EDITION.id}:
        if is_membre_dri(user):
            return True
        if demande.structure and is_membre_drv(user, demande.structure):
            return True

    if is_responsable_ou_gestionnaire(user, demande):
        return True

    if is_responsable_structure_concernee(user, demande):
        return True

    if is_contributeur(user, demande):
        return True

    return False
Ejemplo n.º 13
0
def acces_restreint(demande: Demande) -> bool:
    """Retourne True si l'utilisateur courant n'a pas le droit de voir les info
    confidentielles d'un formulaire RH."""

    if not isinstance(demande, DemandeRH):
        return False

    user = get_current_profile()

    if user in {demande.porteur, demande.gestionnaire, demande.contact_labco}:
        return False

    if user.has_role(Role.ADMIN_CENTRAL):
        return False

    # Les responsables "ascendants" ne voient pas le détail
    # sauf pour les structures "concernées".
    # NB: le labo est toujours "concerné"
    if demande.structure:
        if user.has_role(Role.RESPONSABLE, demande.structure):
            return False

    dri = structure_repo.get_by_dn(DRI_DN)
    if user.has_role(Role.RESPONSABLE, dri):
        return False

    structures = demande.get_structure_concernees()
    for structure in structures:
        if user.has_role(Role.RESPONSABLE, structure):
            return False

    # Responsable facultaire et admin facultaire
    if demande.structure:
        structures.add(demande.structure)

    for structure in structures:
        ancestors = structure.ancestors
        for ancestor in ancestors:
            if ancestor.type != FA:
                continue
            if user.has_role(Role.RESPONSABLE, ancestor):
                return False

            # Admin facultaire
            for sous_structure in ancestor.children:
                if sous_structure.sigle.startswith("DRV "):
                    if user.has_role(Role.ADMIN_LOCAL, sous_structure):
                        return False

    contact_service = injector.get(ContactService)
    mapping = contact_service.get_mapping()
    for d in mapping.values():
        if d.get(ContactType.CONTACT_RH) == user:
            return False

    return True
Ejemplo n.º 14
0
def timeline() -> JSONDict:
    user = get_current_profile()

    notifications = Notification.query.get_for_user(user)
    notifications_dto = NotificationSchema().dump(notifications,
                                                  many=True).data

    user.date_derniere_notification_vue = datetime.utcnow()
    db.session.commit()

    ctx = {"notifications": notifications_dto}
    return ctx
Ejemplo n.º 15
0
def has_write_access(demande: Demande) -> bool:
    if not demande.editable:
        return False

    user = get_current_profile()

    if user in {demande.porteur, demande.gestionnaire}:
        return True

    if is_contributeur(user, demande):
        return True

    return False
Ejemplo n.º 16
0
def get_permissions_for_structure(structure: Structure) -> set[str]:
    if current_app.config.get("TESTING"):
        return set()

    user = get_current_profile()
    permissions = set()

    # cas admin central
    if user.has_role(Role.ADMIN_CENTRAL):
        return {"P1", "P2", "P3", "P4", "P5", "P6"}

    # P1: Infos clés - Edition
    # Admin local: Pour S seulement (et ses départements et équipes si S est un Labo)
    # Admin facultaire: De F et de toute structure descendante

    # P2: Hiérarchie des structures – Edition de structures existantes
    # Admin local: Non, à l’exception des départements et équipes si S est un Labo
    # Admin facultaire: De F et de toute structure descendante

    # P3: Hiérarchie des structures – Création / suppression de structures virtuelles (ex : Carnot)
    # Admin local: Non, à l’exception des départements et équipes si S est un Labo
    # Admin facultaire: Non, à l’exception des départements et équipes des laboratoires
    # descendant de F

    # P4: Membre – Edition pour rattachement d’un utilisateur
    # Admin local: Pour S seulement
    # Admin facultaire: Pour F et toute structure descendante

    # P5: Rôles - Edition
    # Admin local: Pour S seulement (et ses départements et équipes si S est un Labo)
    # Admin facultaire: Pour F et toute structure descendante

    # P6: Contacts Lab & Co - Edition
    # Admin local: Non
    # Admin facultaire: Pour F et toute structure descendante

    # Cas admin facultaire
    for ancestor in [structure] + structure.ancestors:
        if user.has_role(Role.ADMIN_LOCAL, ancestor) and ancestor.type == FA:
            permissions.update(["P1", "P2", "P3", "P4", "P5", "P6"])
            return permissions

    # Cas admin local "normal"
    if user.has_role(Role.ADMIN_LOCAL, structure):
        permissions.update(["P3", "P4", "P5"])

    for ancestor in structure.ancestors:
        if user.has_role(Role.ADMIN_LOCAL, ancestor) and ancestor.type == LA:
            permissions.update(["P1", "P2", "P3", "P4", "P5"])

    return permissions
Ejemplo n.º 17
0
def preferences():
    user = get_current_profile()

    if user.preferences_notifications is None:
        user.preferences_notifications = 0

    if user.preferences_nb_jours_notifications is None:
        user.preferences_nb_jours_notifications = 0

    return {
        "choices": CHOICES,
        "preferences_notifications": user.preferences_notifications,
        "nb_jours_notification": user.preferences_nb_jours_notifications,
    }
Ejemplo n.º 18
0
def get_contacts_for_user() -> JSONDict:
    user = get_current_profile()

    roles: dict[Role, set[Structure]] = role_service.get_roles_for_user(user)
    structures = list(roles[Role.MEMBRE])
    structures.sort(key=lambda x: x.nom)

    result1 = []
    for structure in structures:
        for contact_type in ContactType:
            contact = contact_service.get_contact(structure, contact_type)
            if contact:
                structure_dto = {
                    "name": structure.nom,
                    "id": structure.id,
                    "type": structure.type_name,
                    "sigle": structure.sigle,
                }
                result1.append(
                    {
                        "structure": structure_dto,
                        "contacts": make_contacts_dto(structure),
                    }
                )
                break

    result2 = []
    mapping: dict[Structure, dict[ContactType, Profile]] = contact_service.get_mapping()
    for structure, d in mapping.items():
        if user in d.values():
            for contact_type, user1 in d.items():
                if user1 == user:
                    structure_dto = {
                        "name": structure.nom,
                        "id": structure.id,
                        "type": structure.type_name,
                        "sigle": structure.sigle,
                    }
                    result2.append(
                        {
                            "structure": structure_dto,
                            "bureau": contact_type.value,
                        }
                    )

    return {
        "structures": result1,
        "mes_contacts": result2,
    }
Ejemplo n.º 19
0
def can_add_pj(demande: Demande) -> bool:
    user = get_current_profile()
    if user in (demande.porteur, demande.gestionnaire, demande.contact_labco):
        return True

    if is_gestionnaire(user, demande):
        return True

    if is_contributeur(user, demande):
        return True

    if user in demande.valideurs():
        return True

    return False
Ejemplo n.º 20
0
def get_stats(**args):
    check_permission()

    args2 = {}
    for arg_name, arg_value in args.items():
        if not arg_value:
            continue
        if isinstance(arg_value, List):
            value = r.map(lambda x: x["value"], arg_value)
        elif isinstance(arg_value, Dict):
            value = arg_value["value"]
        else:
            value = arg_value
        args2[arg_name] = value

    user = get_current_profile()
    return get_stats2(user, **args2)
Ejemplo n.º 21
0
def get_boxes(archives=False) -> JSON:
    archives = bool(archives)
    user = get_current_profile()

    if role_service.has_role(user, Role.RESPONSABLE, "*"):
        scopes = SCOPES_RESPONSABLE
    else:
        scopes = SCOPES
    result = []
    for scope in scopes:
        table_view = get_table_view(scope, user, archives)
        if table_view:
            result.append({
                "title": table_view.title,
                "scope": scope,
                "archives": archives
            })

    return result
Ejemplo n.º 22
0
def post_process_form_and_model(form, model=None):
    user = get_current_profile()
    roles = role_service.get_roles_for_user(user)
    structures_d_affectation = roles[Role.MEMBRE_AFFECTE]

    structures_comme_gestionnaire = roles[Role.GESTIONNAIRE]
    structures_comme_porteur = roles[Role.PORTEUR]

    structures = []
    if structures_comme_gestionnaire:
        structures += structures_comme_gestionnaire
    if structures_comme_porteur:
        structures += structures_comme_porteur

    field = form.get_field("laboratoire")
    field.choices = [{"value": s.id, "label": s.nom} for s in structures]

    porteurs = {user}
    for structure in structures_comme_gestionnaire:
        membres = role_service.get_users_with_given_role(
            Role.PORTEUR, structure)
        porteurs.update(membres)

    field = form.get_field("porteur")
    choices = [{
        "value": user.id,
        "label": f"{user.nom}, {user.prenom}"
    } for user in sorted(porteurs, key=lambda x: (x.nom, x.prenom))]
    field.choices = choices

    if not model:
        return

    porteur = user
    model["porteur"] = {
        "value": porteur.id,
        "label": f"{user.nom}, {user.prenom}"
    }

    structure = first(structures_d_affectation)
    model["laboratoire"] = {"value": structure.id, "label": structure.nom}
Ejemplo n.º 23
0
def feuille_cout_editable(demande: Demande) -> bool:
    """
    Feuille de coût : celle-ci devient modifiable par le Contact Lab&Co lorsqu'il a la main.
    Chaque enregistrement, par le Porteur, un Contributeur, un Gestionnaire ou un Contact...

    https://trello.com/c/O702eRzQ/
    """
    if not isinstance(demande, DemandeConvention):
        return False

    user = get_current_profile()
    if user in (demande.porteur, demande.gestionnaire, demande.contact_labco):
        return True

    if is_gestionnaire(user, demande):
        return True

    if is_contributeur(user, demande):
        return True

    return False
Ejemplo n.º 24
0
def create_demande(model, form):
    user = get_current_profile()
    # TODO: check permissions

    model = cleanup_model(model, form)

    form_type = form["name"]

    demande = demande_factory(type=form_type, demandeur=user, data=model)

    demande.porteur = get_porteur(model)
    demande.structure = get_structure(model)

    if user != demande.porteur:
        demande.gestionnaire = user
    else:
        demande.gestionnaire = None

    demande.form_state = form

    new_id = db.session.query(func.max(Demande.id)).one()[0] + 1
    demande.id = new_id

    db.session.add(demande)
    db.session.commit()

    messages = [
        ["Votre demande a été créée.", "success"],
    ]
    if not demande.is_valid():
        messages.append(
            ["Attention, votre demande est encore incomplète.", "warning"])

    whoosh.index_object(demande)

    return {
        "id": demande.id,
        "messages": messages,
    }
Ejemplo n.º 25
0
    def is_active(self) -> bool:
        profile = get_current_profile()
        required_roles = self.get("requires_role")
        precondition = self.get("precondition")

        if precondition:
            return precondition()

        if not required_roles:
            return True

        for role in required_roles:
            if role == "alc" and profile.has_role(Role.ADMIN_CENTRAL):
                return True

            if role == "directeur" and profile.has_role(Role.RESPONSABLE, "*"):
                return True

            if isinstance(role, Role) and profile.has_role(role):
                return True

        return False
Ejemplo n.º 26
0
def preferences_post():
    user = get_current_profile()

    payload = request.json

    pref = payload["preferences_notifications"]
    nb_jours_notification = payload["nb_jours_notification"]

    modified = False
    if pref != user.preferences_notifications:
        user.preferences_notifications = pref
        modified = True

    if nb_jours_notification != user.preferences_nb_jours_notifications:
        user.preferences_nb_jours_notifications = nb_jours_notification
        modified = True

    if modified:
        db.session.commit()
        flash("Vos préférences ont été mises à jours")

    return "", 204
Ejemplo n.º 27
0
def get_structure_choices():
    l2_ids = (db.session.query(
        StatsLine.l2).filter(StatsLine.l2 != None).distinct().all())
    l3_ids = (db.session.query(
        StatsLine.l3).filter(StatsLine.l3 != None).distinct().all())
    l4_ids = (db.session.query(
        StatsLine.l4).filter(StatsLine.l4 != None).distinct().all())
    l5_ids = (db.session.query(
        StatsLine.l5).filter(StatsLine.l5 != None).distinct().all())
    l6_ids = (db.session.query(
        StatsLine.l6).filter(StatsLine.l6 != None).distinct().all())

    user = get_current_profile()
    if user.has_role(Role.RESPONSABLE, "*"):
        structures = mes_structures(user)

    else:
        ids = l2_ids + l3_ids + l4_ids + l5_ids + l6_ids
        structure_ids = [x[0] for x in ids]
        query = db.session.query(Structure)
        structures = [query.get(id) for id in structure_ids]

    to_sort = [(structure.path + [structure.nom], structure)
               for structure in structures]
    to_sort.sort(key=lambda x: x[0])
    structures = [t[1] for t in to_sort]

    def make_label(structure):
        prefix = "+-" * structure.depth
        return f"{prefix}{structure.nom} ({structure.type})"

    return [{
        "value": "",
        "text": "-"
    }] + [{
        "value": str(s.id),
        "text": make_label(s)
    } for s in structures]
Ejemplo n.º 28
0
def upload(request: Request, db: SQLAlchemy):
    user = get_current_profile()
    form = request.form
    demande_id = form["demande_id"]
    demande = db.session.query(Demande).get(demande_id)
    check_can_add_pj(demande)

    files = request.files
    for file in files.values():
        file_name = file.filename

        data = file.read()
        blob = Blob(data)
        db.session.add(blob)
        db.session.flush()

        demande.attachments[file_name] = {
            "date": datetime.now().isoformat(),
            "id": blob.id,
            "creator": user.login,
        }

    db.session.commit()
    return "OK"
Ejemplo n.º 29
0
def get_user_context() -> JSONDict:
    user = get_current_profile()
    return get_context(user)
Ejemplo n.º 30
0
 def get_possible_transitions(self, obj: Demande) -> JSON:
     user = get_current_profile()
     return obj.get_workflow(user).possible_transitions()