diff --git a/dashboard/auth.py b/dashboard/auth.py index 82e7fe4..bad89d6 100644 --- a/dashboard/auth.py +++ b/dashboard/auth.py @@ -11,9 +11,7 @@ def in_admin_session() -> bool: - if st.secrets.get("skip_auth", False): - return True - return is_user_logged() and st.session_state["user"] == os.environ["ADMIN"] + return st.session_state.get("is_admin", False) def is_user_logged() -> bool: @@ -30,7 +28,15 @@ def login(user): def _load_user_model(): email = st.session_state.user - st.session_state.user_model = Person.find_one(emails=email) + user = Person.find(email=email) + is_admin = email == os.environ["ADMIN"] + st.session_state.user_model = Person(name='ADMIN', emails=[email]) + if user: + st.session_state.user_model = user[0] + if is_admin: + st.session_state.is_admin = True + + assert user or is_admin, "If the user is not admin it must be registered" def current_user_model() -> Person: @@ -48,6 +54,8 @@ def current_user_model() -> Person: def logout(): del st.session_state["user"] + del st.session_state["user_model"] + del st.session_state["is_admin"] delete_token_in_cookies() @@ -58,6 +66,7 @@ def try_login_using_cookies(): return login(*credentials) return None + def authenticate(): if st.secrets.get("skip_auth", False): login(os.environ["ADMIN"]) diff --git a/dashboard/import_csv.py b/dashboard/import_csv.py index 3ec829d..5d5dea6 100644 --- a/dashboard/import_csv.py +++ b/dashboard/import_csv.py @@ -1,61 +1,68 @@ -import pandas as pd -from models import JournalPaper, Journal, Person, ConferencePresentation, Book, BookChapter import Levenshtein +import pandas as pd +from models import ( + Book, + BookChapter, + ConferencePresentation, + Journal, + JournalPaper, + Person, +) df = pd.read_csv("/src/data/profesores.csv") people = Person.all() matches = { - 'Jose Luis Castañeda Lorenzo' : 'José Luis Castañeda Lorenzo' , - 'Ernesto Alejandro Lopez Cadalso' : 'Ernesto Alejandro López Cadalso' , - 'Juan Pablo Consuegra Ayala' : 'Juan Pablo Consuegra Ayala' , - 'Suilan Estevez Velarde' : 'Suilan Estévez Velarde' , - 'Maria Elvira Fernandez Sa' : 'María Elvira Fernández Sa' , - 'Alejandro Piad Morffis' : 'Alejandro Piad Morffis' , - 'Carmen Teresa Fernandez Montoto' : 'Carmen Fernández' , - 'Lucina Garcia Hernandez' : 'Lucina García' , - 'Yudivian Almeida Cruz' : 'Yudivián Almeida Cruz' , - 'Luciano Garcia Garrido' : 'Luciano García' , - 'Alberto Fernandez Oliva' : 'Alberto Fernández ' , - 'Joanna Campbell Amos' : 'Joanna Campbell Amos' , - 'Juan Enrique Morales Calvo' : 'Juan Enrique Morales Calvo' , - 'Aracelys Garcia Armenteros' : 'Aracelys García Armenteros' , - 'Eduardo Quesada Orozco' : 'Eduardo Quesada Orozco' , - 'Gemayqzel Bouza Allende' : 'Gemayqzel Bouza Allende' , - 'Jose Alejandro Mesejo Chiong' : 'Jose A. Mesejo Chiong' , - 'Damian Valdes Santiago' : 'Damian Valdés Santiago' , - 'Fernando R. Rodriguez Flores' : 'Fernando Rodriguez Flores' , - 'Elianys Garcia - Pola Cordoves' : 'Elianys García-Pola Cordobes' , - 'Aymee De Los Angeles Marrero Severo' : 'Aymée Marrero Severo' , - 'Julian Sarria Gonzalez' : 'Julián Sarría González' , - 'Sofia Behar Jequin' : 'Sofía Behar Jequín' , - 'Yanet Garcia Serrano' : 'Yanet Garcia Serrano' , - 'Vivian Del R. Sistachs Vega' : 'Vivian del Rosario Sistachs Vega' , - 'Carlos Narciso Bouza Herrera' : 'Carlos Bouza Herrera' , - 'Sira Maria Allende Alonso' : 'Sira Allende Alonso' , - 'Miraida Ferras Ferras' : 'Miraida Ferras Ferras' , - 'Marta Lourdes Baguer Diaz Romanach' : 'Marta L. Baguer Diaz-Romanach' , - 'Angela Mireya Leon Mecias' : 'Ángela Mireya León Mecías' , - 'Frank Michel Enrique Hevia' : 'Frank Michel Enrique Hevia' , - 'Wilfredo Morales Lezca' : 'Wilfredo Morales Lezca' , - 'Marcel Ernesto Sanchez Aguilar' : 'Marcel Ernesto Sánchez Aguilar' , - 'Jorge Estrada Hernandez' : 'Jorge Estrada Hernández' , - 'Ernesto Luis Estevanell Valladares' : 'Ernesto Luis Estevanell Valladares' , - 'Daniel Alejandro Valdes Perez' : 'Daniel Valdés Pérez' , - 'Alejandro Roque Piedra' : 'Alejandro Roque Piedra' , - 'Jose Fidel Hernandez Advincula' : 'José Fidel Hernández Advíncula' , - 'Celia Tamara Gonzalez Gonzalez' : 'Celia T. González González' , - 'Juan Carlos Lopez Realpozo' : 'Juan Pablo Consuegra Ayala' , - 'Marleny Soler Martinez' : 'Marleny Soler Martínez' , - 'Roxana Cabrera Puig' : 'Roxana Cabrera Puig' , - 'Reynaldo Rodriguez Ramos' : 'Reinaldo Rodríguez Ramos' , - 'Mariano Rodriguez Ricard' : 'Mariano Rodríguez Ricard' , - 'Jose Enrique Valdes Castro' : 'Jose Enrique Valdes Castro' , - 'Joaquin Alberto Herrera Macias' : 'Joaquín Alberto Herrera Macías' , - 'Lisset Suarez Plasencia' : 'Lisset Suárez Plasencia' , - 'Yeneit Delgado Kios' : 'Yeneit Delgado Kios' , - 'Ernesto Alejandro Borrego Rodriguez' : 'Ernesto Borrego Rodríguez' , + "Jose Luis Castañeda Lorenzo": "José Luis Castañeda Lorenzo", + "Ernesto Alejandro Lopez Cadalso": "Ernesto Alejandro López Cadalso", + "Juan Pablo Consuegra Ayala": "Juan Pablo Consuegra Ayala", + "Suilan Estevez Velarde": "Suilan Estévez Velarde", + "Maria Elvira Fernandez Sa": "María Elvira Fernández Sa", + "Alejandro Piad Morffis": "Alejandro Piad Morffis", + "Carmen Teresa Fernandez Montoto": "Carmen Fernández", + "Lucina Garcia Hernandez": "Lucina García", + "Yudivian Almeida Cruz": "Yudivián Almeida Cruz", + "Luciano Garcia Garrido": "Luciano García", + "Alberto Fernandez Oliva": "Alberto Fernández ", + "Joanna Campbell Amos": "Joanna Campbell Amos", + "Juan Enrique Morales Calvo": "Juan Enrique Morales Calvo", + "Aracelys Garcia Armenteros": "Aracelys García Armenteros", + "Eduardo Quesada Orozco": "Eduardo Quesada Orozco", + "Gemayqzel Bouza Allende": "Gemayqzel Bouza Allende", + "Jose Alejandro Mesejo Chiong": "Jose A. Mesejo Chiong", + "Damian Valdes Santiago": "Damian Valdés Santiago", + "Fernando R. Rodriguez Flores": "Fernando Rodriguez Flores", + "Elianys Garcia - Pola Cordoves": "Elianys García-Pola Cordobes", + "Aymee De Los Angeles Marrero Severo": "Aymée Marrero Severo", + "Julian Sarria Gonzalez": "Julián Sarría González", + "Sofia Behar Jequin": "Sofía Behar Jequín", + "Yanet Garcia Serrano": "Yanet Garcia Serrano", + "Vivian Del R. Sistachs Vega": "Vivian del Rosario Sistachs Vega", + "Carlos Narciso Bouza Herrera": "Carlos Bouza Herrera", + "Sira Maria Allende Alonso": "Sira Allende Alonso", + "Miraida Ferras Ferras": "Miraida Ferras Ferras", + "Marta Lourdes Baguer Diaz Romanach": "Marta L. Baguer Diaz-Romanach", + "Angela Mireya Leon Mecias": "Ángela Mireya León Mecías", + "Frank Michel Enrique Hevia": "Frank Michel Enrique Hevia", + "Wilfredo Morales Lezca": "Wilfredo Morales Lezca", + "Marcel Ernesto Sanchez Aguilar": "Marcel Ernesto Sánchez Aguilar", + "Jorge Estrada Hernandez": "Jorge Estrada Hernández", + "Ernesto Luis Estevanell Valladares": "Ernesto Luis Estevanell Valladares", + "Daniel Alejandro Valdes Perez": "Daniel Valdés Pérez", + "Alejandro Roque Piedra": "Alejandro Roque Piedra", + "Jose Fidel Hernandez Advincula": "José Fidel Hernández Advíncula", + "Celia Tamara Gonzalez Gonzalez": "Celia T. González González", + "Juan Carlos Lopez Realpozo": "Juan Pablo Consuegra Ayala", + "Marleny Soler Martinez": "Marleny Soler Martínez", + "Roxana Cabrera Puig": "Roxana Cabrera Puig", + "Reynaldo Rodriguez Ramos": "Reinaldo Rodríguez Ramos", + "Mariano Rodriguez Ricard": "Mariano Rodríguez Ricard", + "Jose Enrique Valdes Castro": "Jose Enrique Valdes Castro", + "Joaquin Alberto Herrera Macias": "Joaquín Alberto Herrera Macías", + "Lisset Suarez Plasencia": "Lisset Suárez Plasencia", + "Yeneit Delgado Kios": "Yeneit Delgado Kios", + "Ernesto Alejandro Borrego Rodriguez": "Ernesto Borrego Rodríguez", } for i, row in df.iterrows(): @@ -68,7 +75,7 @@ else: person = Person(name=name) - person.institution="Universidad de La Habana" + person.institution = "Universidad de La Habana" person.faculty = "Matemática y Computación" person.department = department person.scientific_grade = academic_grade diff --git a/dashboard/models/__init__.py b/dashboard/models/__init__.py index 0a19d47..4d0b1c5 100644 --- a/dashboard/models/__init__.py +++ b/dashboard/models/__init__.py @@ -1,10 +1,9 @@ +from models.custom_model import CustomModel from models.data_models.award_model import Award from models.data_models.book_chapter_model import BookChapter from models.data_models.book_model import Book from models.data_models.classes_model import Classes -from models.data_models.conference_presentation_model import ( - ConferencePresentation, -) +from models.data_models.conference_presentation_model import ConferencePresentation from models.data_models.journal_model import Journal from models.data_models.journal_paper_model import JournalPaper from models.data_models.person_model import Person @@ -13,4 +12,3 @@ from models.data_models.research_group_model import ResearchGroup from models.data_models.subject_model import Subject from models.data_models.thesis_model import Thesis -from models.custom_model import CustomModel diff --git a/dashboard/models/custom_model.py b/dashboard/models/custom_model.py index d05eb6b..c83065f 100644 --- a/dashboard/models/custom_model.py +++ b/dashboard/models/custom_model.py @@ -47,7 +47,6 @@ def with_refs(model_class: ModelT) -> ModelT: fields = model_class.__fields__ for field_name, field in fields.items(): if isclass(field.type_) and issubclass(field.type_, Ref): - # Function that returns a validator for a Ref[T] field def _ref_val_wrapper(field): def ref_val(cls, value): @@ -62,7 +61,6 @@ def ref_val(cls, value): ) elif isclass(field.type_) and issubclass(field.type_, RefList): - # Function that returns a validator for a RefList[T] field def _reflist_val_wrapper(field): def ref_list_val(cls, value): diff --git a/dashboard/models/data_models/book_model.py b/dashboard/models/data_models/book_model.py index 3a7b625..522639a 100644 --- a/dashboard/models/data_models/book_model.py +++ b/dashboard/models/data_models/book_model.py @@ -1,7 +1,6 @@ -from pydantic import HttpUrl - from models.custom_model import collection_name, with_refs from models.data_models.publication_model import Publication +from pydantic import HttpUrl @with_refs diff --git a/dashboard/models/data_models/conference_presentation_model.py b/dashboard/models/data_models/conference_presentation_model.py index db5eeef..01a4279 100644 --- a/dashboard/models/data_models/conference_presentation_model.py +++ b/dashboard/models/data_models/conference_presentation_model.py @@ -1,7 +1,6 @@ -from pydantic import HttpUrl - from models.custom_model import collection_name, with_refs from models.data_models.publication_model import Publication +from pydantic import HttpUrl @with_refs diff --git a/dashboard/models/data_models/journal_model.py b/dashboard/models/data_models/journal_model.py index 37675ca..8d9c9b9 100644 --- a/dashboard/models/data_models/journal_model.py +++ b/dashboard/models/data_models/journal_model.py @@ -1,8 +1,7 @@ from typing import List -from pydantic import Field, HttpUrl - from models.custom_model import CustomModel, collection_name +from pydantic import Field, HttpUrl @collection_name("journals") diff --git a/dashboard/models/data_models/journal_paper_model.py b/dashboard/models/data_models/journal_paper_model.py index 881ea6e..256ea6e 100644 --- a/dashboard/models/data_models/journal_paper_model.py +++ b/dashboard/models/data_models/journal_paper_model.py @@ -1,9 +1,8 @@ -from pydantic import HttpUrl - from models.custom_model import Ref, collection_name, with_refs from models.data_models.journal_model import Journal from models.data_models.person_model import Person from models.data_models.publication_model import Publication +from pydantic import HttpUrl @with_refs diff --git a/dashboard/models/data_models/project_model.py b/dashboard/models/data_models/project_model.py index 492777a..28f09a3 100644 --- a/dashboard/models/data_models/project_model.py +++ b/dashboard/models/data_models/project_model.py @@ -2,7 +2,6 @@ from typing import List import streamlit as st - from models.custom_model import CustomModel, Ref, RefList, collection_name, with_refs from models.data_models.person_model import Person diff --git a/dashboard/models/permission.py b/dashboard/models/permission.py index 1fa1f88..565a5c9 100644 --- a/dashboard/models/permission.py +++ b/dashboard/models/permission.py @@ -9,11 +9,7 @@ WRITE = 2 ADMIN = 4 -PERMISSIONS = { - READ: "Lectura", - WRITE: "Escritura", - ADMIN: "Administrador" -} +PERMISSIONS = {READ: "Lectura", WRITE: "Escritura", ADMIN: "Administrador"} PERMISSIONS_BY_NAME = {v: k for k, v in PERMISSIONS.items()} ALL_PERMISSIONS = reduce(lambda p1, p2: p1 | p2, PERMISSIONS.keys()) diff --git a/dashboard/modules/graph.py b/dashboard/modules/graph.py index bab21de..14b3dae 100644 --- a/dashboard/modules/graph.py +++ b/dashboard/modules/graph.py @@ -1,128 +1,159 @@ -from streamlit_agraph import agraph, Node, Edge, Config -from modules.utils import darken_color, select_color -from modules.utils import count_theses_by_advisor, count_theses_between_two_advisors -from modules.utils import count_publications_by_person, count_publications_between_two_persons - from typing import List, Tuple -from models import Person from uuid import UUID +from models import Person +from modules.utils import ( + count_publications_between_two_persons, + count_publications_by_person, + count_theses_between_two_advisors, + count_theses_by_advisor, + darken_color, + select_color, +) +from streamlit_agraph import Config, Edge, Node, agraph + + class NodeGraph: - def __init__(self, info: Person, size = 25, color = '#ACDBC9') -> None: + def __init__(self, info: Person, size=25, color="#ACDBC9") -> None: self.info = info self.color = color self.size = size + class EdgeGraph: - def __init__(self, source:NodeGraph, target:NodeGraph, info, color='#ACDBC9') -> None: + def __init__( + self, source: NodeGraph, target: NodeGraph, info, color="#ACDBC9" + ) -> None: self.source = source self.target = target self.info = info self.color = color - -def build_advisors_graph( advisors, theses ) -> any: + +def build_advisors_graph(advisors, theses) -> any: nodes = [] edges = [] - count_theses = count_theses_by_advisor( theses ) + count_theses = count_theses_by_advisor(theses) max_theses = max(count_theses.values()) for advisor in advisors: - nodes.append(Node( - id=advisor, - label=advisor, - title=f"{advisor}\n{count_theses[ advisor ]} tesis", - color=darken_color('#ACDBC9', count_theses[advisor], 2*max_theses), - size=25 + count_theses[advisor] * 3, - )) + nodes.append( + Node( + id=advisor, + label=advisor, + title=f"{advisor}\n{count_theses[ advisor ]} tesis", + color=darken_color("#ACDBC9", count_theses[advisor], 2 * max_theses), + size=25 + count_theses[advisor] * 3, + ) + ) for thesis in theses: for advisor in thesis.advisors: for advisor_2 in thesis.advisors: if advisor == advisor_2: - continue - count_thesis = count_theses_between_two_advisors( theses, advisor, advisor_2 ) - edges.append( Edge( - source=advisor, - label=f"{count_thesis} tesis", - target=advisor_2, - color=darken_color('#52FFCC', count_thesis, max_theses ), - directed=False, - collapsible=False - )) - - config = Config( width=900, height=700 ) + continue + count_thesis = count_theses_between_two_advisors( + theses, advisor, advisor_2 + ) + edges.append( + Edge( + source=advisor, + label=f"{count_thesis} tesis", + target=advisor_2, + color=darken_color("#52FFCC", count_thesis, max_theses), + directed=False, + collapsible=False, + ) + ) + + config = Config(width=900, height=700) return agraph(nodes=nodes, edges=edges, config=config) - -def build_nodes_and_edges( publications: any, color: Tuple[str, str] ) -> Tuple[ List[NodeGraph], List[EdgeGraph] ]: + +def build_nodes_and_edges( + publications: any, color: Tuple[str, str] +) -> Tuple[List[NodeGraph], List[EdgeGraph]]: all_nodes: dict[UUID, Person] = {} nodes: List[NodeGraph] = [] edges: List[EdgeGraph] = [] - publications_by_person = count_publications_by_person( publications ) + publications_by_person = count_publications_by_person(publications) max_publications = max(publications_by_person.values()) - + for publication in publications: # save nodes for author in publication.authors: if author.uuid not in all_nodes: nn = NodeGraph( - author, - size=25 + 5*publications_by_person[author.uuid], + author, + size=25 + 5 * publications_by_person[author.uuid], color=darken_color( - color=select_color( author, color, '#ACDBC9' ), - number=publications_by_person[author.uuid], - range=2*max_publications - ) + color=select_color(author, color, "#ACDBC9"), + number=publications_by_person[author.uuid], + range=2 * max_publications, + ), ) - all_nodes[ author.uuid ] = nn - nodes.append( nn ) + all_nodes[author.uuid] = nn + nodes.append(nn) - # save edges - for i in range( len(publication.authors) ): + # save edges + for i in range(len(publication.authors)): author = publication.authors[i] for j in range(i + 1, len(publication.authors)): author_2 = publication.authors[j] - edges.append(EdgeGraph(all_nodes[author.uuid], all_nodes[author_2.uuid], publication)) + edges.append( + EdgeGraph( + all_nodes[author.uuid], all_nodes[author_2.uuid], publication + ) + ) del all_nodes return (nodes, edges) -def build_publications_graph( publications: List[any], color: Tuple[str, str], width = 900, height = 700 ) -> any: - nodesGraph, edgesGraph = build_nodes_and_edges( publications, color ) - publ_by_person = count_publications_by_person( publications ) + +def build_publications_graph( + publications: List[any], color: Tuple[str, str], width=900, height=700 +) -> any: + nodesGraph, edgesGraph = build_nodes_and_edges(publications, color) + publ_by_person = count_publications_by_person(publications) nodes: List[Node] = [] edges: List[Edge] = [] - + for node in nodesGraph: publ = f"{publ_by_person[ node.info.uuid ]} {'publicación' if publ_by_person[node.info.uuid] == 1 else 'publicaciones'}" - nodes.append(Node( - id=f"{node.info.uuid}", - title=f"{node.info.name}\n{publ}", - label=node.info.name, - color=node.color, - size=node.size - )) - + nodes.append( + Node( + id=f"{node.info.uuid}", + title=f"{node.info.name}\n{publ}", + label=node.info.name, + color=node.color, + size=node.size, + ) + ) + for edge in edgesGraph: - count_pub = count_publications_between_two_persons( publications, edge.source.info, edge.target.info ) - edges.append(Edge( - source=f"{edge.source.info.uuid}", - label=f"{count_pub} {'publicación' if count_pub == 1 else 'publicaciones'}", - target=f"{edge.target.info.uuid}", - color=edge.color, - directed=False, - collapsible=False - )) - edges.append(Edge( - source=f"{edge.target.info.uuid}", - target=f"{edge.source.info.uuid}", - label="", - color=edge.color, - directed=False, - collapsible=False - )) - - config = Config( width=width, height=height ) - return nodes, edges, agraph(nodes=nodes, edges=edges, config=config) + count_pub = count_publications_between_two_persons( + publications, edge.source.info, edge.target.info + ) + edges.append( + Edge( + source=f"{edge.source.info.uuid}", + label=f"{count_pub} {'publicación' if count_pub == 1 else 'publicaciones'}", + target=f"{edge.target.info.uuid}", + color=edge.color, + directed=False, + collapsible=False, + ) + ) + edges.append( + Edge( + source=f"{edge.target.info.uuid}", + target=f"{edge.source.info.uuid}", + label="", + color=edge.color, + directed=False, + collapsible=False, + ) + ) + config = Config(width=width, height=height) + return nodes, edges, agraph(nodes=nodes, edges=edges, config=config) diff --git a/dashboard/modules/utils.py b/dashboard/modules/utils.py index 8c0161d..44ec88a 100644 --- a/dashboard/modules/utils.py +++ b/dashboard/modules/utils.py @@ -1,14 +1,16 @@ -from random import randint import colorsys +from random import randint +from typing import Tuple +from uuid import UUID from models import Person -from uuid import UUID -from typing import Tuple + def generate_widget_key() -> str: return str(randint(0, 1000000)) -def count_theses_by_advisor( theses ) -> dict: + +def count_theses_by_advisor(theses) -> dict: advisors = {} for thesis in theses: @@ -19,40 +21,51 @@ def count_theses_by_advisor( theses ) -> dict: return advisors -def count_theses_between_two_advisors( theses, advisor_1, advisor_2 ) -> int: + +def count_theses_between_two_advisors(theses, advisor_1, advisor_2) -> int: count = 0 for thesis in theses: if advisor_1 in thesis.advisors and advisor_2 in thesis.advisors: count += 1 return count -def count_publications_by_person( publications ) -> dict: - count: dict[ UUID, int ] = {} - + +def count_publications_by_person(publications) -> dict: + count: dict[UUID, int] = {} + for publication in publications: for author in publication.authors: - if author.uuid not in count: - count[ author.uuid ] = 0 - count[ author.uuid ] += 1 + if author.uuid not in count: + count[author.uuid] = 0 + count[author.uuid] += 1 return count -def count_publications_between_two_persons( publications, person_1: Person, person_2: Person ) -> int: + +def count_publications_between_two_persons( + publications, person_1: Person, person_2: Person +) -> int: count = 0 for publication in publications: if person_1 in publication.authors and person_2 in publication.authors: count += 1 return count -def darken_color(color:str, number:int, range:int) -> str: - color = color.lstrip('#') - - h, l, s = colorsys.rgb_to_hls(*[int(color[i:i+2], 16)/255 for i in (0, 2, 4)]) + +def darken_color(color: str, number: int, range: int) -> str: + color = color.lstrip("#") + + h, l, s = colorsys.rgb_to_hls(*[int(color[i : i + 2], 16) / 255 for i in (0, 2, 4)]) l = max(0.1, l - (number / range)) - return '#%02x%02x%02x' % tuple(int(i*255) for i in colorsys.hls_to_rgb(h, l, s)) + return "#%02x%02x%02x" % tuple(int(i * 255) for i in colorsys.hls_to_rgb(h, l, s)) + -def select_color( person: Person, color: Tuple[str, str], default_color ) -> str: +def select_color(person: Person, color: Tuple[str, str], default_color) -> str: inst, cc = color - if person.institution == inst or person.department == inst or person.faculty == inst: + if ( + person.institution == inst + or person.department == inst + or person.faculty == inst + ): return cc - return default_color \ No newline at end of file + return default_color diff --git "a/dashboard/pages/01_\360\237\221\245_personal.py" "b/dashboard/pages/01_\360\237\221\245_personal.py" index 1a063d4..eeea43c 100644 --- "a/dashboard/pages/01_\360\237\221\245_personal.py" +++ "b/dashboard/pages/01_\360\237\221\245_personal.py" @@ -9,4 +9,4 @@ ), ) -router.start() \ No newline at end of file +router.start() diff --git "a/dashboard/pages/02_\360\237\223\235_docencia.py" "b/dashboard/pages/02_\360\237\223\235_docencia.py" index 6bc5cd4..bd75207 100644 --- "a/dashboard/pages/02_\360\237\223\235_docencia.py" +++ "b/dashboard/pages/02_\360\237\223\235_docencia.py" @@ -9,4 +9,4 @@ ), ) -router.start() \ No newline at end of file +router.start() diff --git "a/dashboard/pages/03_\360\237\221\245_grupos.py" "b/dashboard/pages/03_\360\237\221\245_grupos.py" index 2907a48..96c4ff8 100644 --- "a/dashboard/pages/03_\360\237\221\245_grupos.py" +++ "b/dashboard/pages/03_\360\237\221\245_grupos.py" @@ -9,4 +9,4 @@ ), ) -router.start() \ No newline at end of file +router.start() diff --git "a/dashboard/pages/04_\360\237\216\223_tesis.py" "b/dashboard/pages/04_\360\237\216\223_tesis.py" index 0af7573..da7ce59 100644 --- "a/dashboard/pages/04_\360\237\216\223_tesis.py" +++ "b/dashboard/pages/04_\360\237\216\223_tesis.py" @@ -9,4 +9,4 @@ ), ) -router.start() \ No newline at end of file +router.start() diff --git "a/dashboard/pages/05_\360\237\223\232_publicaciones.py" "b/dashboard/pages/05_\360\237\223\232_publicaciones.py" index a28b357..3e49821 100644 --- "a/dashboard/pages/05_\360\237\223\232_publicaciones.py" +++ "b/dashboard/pages/05_\360\237\223\232_publicaciones.py" @@ -10,28 +10,6 @@ from pages.publications_pages.papers import papers_page from pages.publications_pages.presentations import presentations_page - -class ControlledSectionModel: ... - - -class Page(abc.ABC): - def __init__(self, url: str, section_model: ControlledSectionModel): - self.url = url - self.section_model: Optional[ControlledSectionModel] = section_model - - # This is modified when the router is composed - self.full_url = url - - @property - def user_can_open(self): - if auth.in_admin_session or self.section_model is None: - return True - - @abc.abstractmethod - def build(self, router: PageRouter, **params): - pass - - # TODO: Only build router if it is not stored in session router = PageRouter( "publications", diff --git "a/dashboard/pages/06_\342\232\227\357\270\217_proyectos.py" "b/dashboard/pages/06_\342\232\227\357\270\217_proyectos.py" index 5f20413..ae800b6 100644 --- "a/dashboard/pages/06_\342\232\227\357\270\217_proyectos.py" +++ "b/dashboard/pages/06_\342\232\227\357\270\217_proyectos.py" @@ -9,4 +9,4 @@ ), ) -router.start() \ No newline at end of file +router.start() diff --git "a/dashboard/pages/07_\360\237\217\206_premios.py" "b/dashboard/pages/07_\360\237\217\206_premios.py" index 292043c..dd6f2e4 100644 --- "a/dashboard/pages/07_\360\237\217\206_premios.py" +++ "b/dashboard/pages/07_\360\237\217\206_premios.py" @@ -9,4 +9,4 @@ ), ) -router.start() \ No newline at end of file +router.start() diff --git "a/dashboard/pages/08_\360\237\252\221_expertos.py" "b/dashboard/pages/08_\360\237\252\221_expertos.py" index b6adcaa..1885969 100644 --- "a/dashboard/pages/08_\360\237\252\221_expertos.py" +++ "b/dashboard/pages/08_\360\237\252\221_expertos.py" @@ -9,4 +9,4 @@ ), ) -router.start() \ No newline at end of file +router.start() diff --git "a/dashboard/pages/09_\360\237\223\210_reportes.py" "b/dashboard/pages/09_\360\237\223\210_reportes.py" index b62cba1..c991d28 100644 --- "a/dashboard/pages/09_\360\237\223\210_reportes.py" +++ "b/dashboard/pages/09_\360\237\223\210_reportes.py" @@ -9,4 +9,4 @@ ), ) -router.start() \ No newline at end of file +router.start() diff --git "a/dashboard/pages/99_\360\237\233\240\357\270\217_admin.py" "b/dashboard/pages/99_\360\237\233\240\357\270\217_admin.py" index df4992c..edff0f8 100644 --- "a/dashboard/pages/99_\360\237\233\240\357\270\217_admin.py" +++ "b/dashboard/pages/99_\360\237\233\240\357\270\217_admin.py" @@ -9,4 +9,4 @@ ), ) -router.start() \ No newline at end of file +router.start() diff --git a/dashboard/pages/admin_pages/home.py b/dashboard/pages/admin_pages/home.py index 1747e1b..7cee3b1 100644 --- a/dashboard/pages/admin_pages/home.py +++ b/dashboard/pages/admin_pages/home.py @@ -22,7 +22,6 @@ def admin_page(router: PageRouter, **params): (database,) = st.tabs(["🗄️ Base de datos"]) - def format_bytes(n_bytes: int) -> str: if n_bytes > 1e6: return f"{round(n_bytes * 1e-6, 2)} MB" @@ -30,7 +29,6 @@ def format_bytes(n_bytes: int) -> str: return f"{round(n_bytes * 1e-3, 2)} kB" return f"{n_bytes} B" - with database: general_stats, tools_exp, tools_imp, tools_del = st.columns([2, 1, 1, 1]) stats = {model: model.stats() for model in collection_names.keys()} diff --git a/dashboard/pages/dashboard_pages/registration.py b/dashboard/pages/dashboard_pages/registration.py index 69ddbe5..c3978d0 100644 --- a/dashboard/pages/dashboard_pages/registration.py +++ b/dashboard/pages/dashboard_pages/registration.py @@ -13,7 +13,6 @@ def registration_page(router: PageRouter, token: str = None, **params): router.page_header("Registro") - # Verify token email = auth.verify_token(token) if email is None: diff --git a/dashboard/pages/docencia_pages/home.py b/dashboard/pages/docencia_pages/home.py index 18d6f72..6c3c4b4 100644 --- a/dashboard/pages/docencia_pages/home.py +++ b/dashboard/pages/docencia_pages/home.py @@ -7,8 +7,9 @@ def docencia_page(router: PageRouter, **params): - - st.set_page_config(page_title="MatCom Dashboard - Docencia", page_icon="📝", layout="wide") + st.set_page_config( + page_title="MatCom Dashboard - Docencia", page_icon="📝", layout="wide" + ) router.page_header("Docencia") @@ -17,7 +18,6 @@ def docencia_page(router: PageRouter, **params): with subjects_tab: if auth.is_user_logged(): with st.expander("⭐ Crear nueva asignatura"): - cols = st.columns([2, 2, 1, 1]) subject = cols[0].text_input("Nombre de la asignatura") career = cols[1].selectbox( @@ -41,12 +41,13 @@ def docencia_page(router: PageRouter, **params): subjects = [] - for subject in sorted(Subject.all(), key=lambda s: (s.year, s.semester, s.subject)): + for subject in sorted( + Subject.all(), key=lambda s: (s.year, s.semester, s.subject) + ): subjects.append(subject.encode()) st.dataframe(subjects) - with classes_tab: if auth.is_user_logged(): with st.expander("📝 Crear nueva entrada"): diff --git a/dashboard/pages/expertos_pages/home.py b/dashboard/pages/expertos_pages/home.py index 4422df6..fedb7cd 100644 --- a/dashboard/pages/expertos_pages/home.py +++ b/dashboard/pages/expertos_pages/home.py @@ -3,6 +3,7 @@ def expertos_page(router: PageRouter, **params): - st.set_page_config(page_title="MatCom Dashboard - Consejos Expertos", page_icon="🪑", layout="wide") + st.set_page_config( + page_title="MatCom Dashboard - Consejos Expertos", page_icon="🪑", layout="wide" + ) router.page_header("Expertos") - diff --git a/dashboard/pages/grupos_pages/home.py b/dashboard/pages/grupos_pages/home.py index 86ae448..3bfa805 100644 --- a/dashboard/pages/grupos_pages/home.py +++ b/dashboard/pages/grupos_pages/home.py @@ -5,18 +5,20 @@ def grupos_page(router: PageRouter, **params): - st.set_page_config(page_title="MatCom Dashboard - Grupos de Investigación",page_icon="👥",layout="wide",) + st.set_page_config( + page_title="MatCom Dashboard - Grupos de Investigación", + page_icon="👥", + layout="wide", + ) router.page_header("Grupos de Investigación") list_view, create_view = st.tabs(["👥 Listado de grupos", "📝 Crear o editar"]) - groups = ResearchGroup.all() people = Person.all() people.sort(key=lambda p: p.name) - with create_view: if auth.is_user_logged(): if ( @@ -34,7 +36,9 @@ def grupos_page(router: PageRouter, **params): format_func=lambda t: t.name, ) else: - group = ResearchGroup(name="", members=[], collaborators=[], keywords=[]) + group = ResearchGroup( + name="", members=[], collaborators=[], keywords=[] + ) if group: group.name = st.text_input("Nombre", key="group_name", value=group.name) @@ -68,7 +72,9 @@ def grupos_page(router: PageRouter, **params): group.save() st.success("Información guardad con éxito") else: - st.error("Acceso de solo lectura. Vaya a la página principal para loguearse.") + st.error( + "Acceso de solo lectura. Vaya a la página principal para loguearse." + ) with list_view: for group in groups: @@ -77,7 +83,9 @@ def grupos_page(router: PageRouter, **params): with left: st.write(f"#### {group.name}") - st.write("**Líneas de investigación:** " + "; ".join(group.keywords)) + st.write( + "**Líneas de investigación:** " + "; ".join(group.keywords) + ) st.write(f"**Coordinador**: {group.head.name}") with mid: @@ -95,6 +103,8 @@ def grupos_page(router: PageRouter, **params): "**Colaboradores:**\n" + "\n".join( f"- {p.name}" - for p in sorted(group.collaborators, key=lambda p: p.name) + for p in sorted( + group.collaborators, key=lambda p: p.name + ) ) ) diff --git a/dashboard/pages/personal_pages/home.py b/dashboard/pages/personal_pages/home.py index 622860f..ca9782a 100644 --- a/dashboard/pages/personal_pages/home.py +++ b/dashboard/pages/personal_pages/home.py @@ -6,10 +6,11 @@ def personal_page(router: PageRouter, **params): - st.set_page_config(page_title="MatCom Dashboard - Personal", page_icon="👤", layout="wide") + st.set_page_config( + page_title="MatCom Dashboard - Personal", page_icon="👤", layout="wide" + ) router.page_header("Personal") - people = Person.all() people.sort(key=lambda p: p.name) @@ -54,7 +55,12 @@ def personal_page(router: PageRouter, **params): person.department = st.text_input( "Departamento", key="person_department", value=person.department or "" ) - grades = ["Licenciado", "Ingeniero", "Máster en Ciencias", "Doctor en Ciencias"] + grades = [ + "Licenciado", + "Ingeniero", + "Máster en Ciencias", + "Doctor en Ciencias", + ] person.scientific_grade = st.selectbox( "Grado científico", grades, @@ -85,7 +91,6 @@ def personal_page(router: PageRouter, **params): person.save() st.success("Entrada salvada con éxito.") - people_comp = [] people_appl = [] people_math = [] diff --git a/dashboard/pages/premios_pages/home.py b/dashboard/pages/premios_pages/home.py index 008d73f..c5d2f0b 100644 --- a/dashboard/pages/premios_pages/home.py +++ b/dashboard/pages/premios_pages/home.py @@ -7,14 +7,15 @@ def premios_page(router: PageRouter, **params): - st.set_page_config(page_title="MatCom Dashboard - Premios", page_icon="🏆", layout="wide") + st.set_page_config( + page_title="MatCom Dashboard - Premios", page_icon="🏆", layout="wide" + ) router.page_header("Premios") list_view, create_view, edit_view = st.tabs( ["🏆 Listado de premios", "⭐ Crear nuevo premio", "📝 Editar premio"] ) - def save_award(award: Award, prefix): award.save() @@ -25,7 +26,6 @@ def save_award(award: Award, prefix): del st.session_state.current_award st.success("Premio guardado con éxito") - with create_view: if auth.is_user_logged(): if "current_award" in st.session_state: @@ -41,8 +41,9 @@ def save_award(award: Award, prefix): else: st.warning("⚠️ Complete la información obligatoria, marcada con 🔹") else: - st.error("Acceso de solo lectura. Vaya a la página principal para loguearse.") - + st.error( + "Acceso de solo lectura. Vaya a la página principal para loguearse." + ) with list_view: awards = Award.all() diff --git a/dashboard/pages/profile_pages/home.py b/dashboard/pages/profile_pages/home.py index 42ef928..3e3b1eb 100644 --- a/dashboard/pages/profile_pages/home.py +++ b/dashboard/pages/profile_pages/home.py @@ -18,7 +18,7 @@ def profile_page(router: PageRouter, **params): if not persons: st.error("Tu cuenta no está registrada") st.stop() - + person = persons[0] c1, c2 = st.columns([1, 5]) diff --git a/dashboard/pages/proyectos_pages/home.py b/dashboard/pages/proyectos_pages/home.py index 3c54462..411ea93 100644 --- a/dashboard/pages/proyectos_pages/home.py +++ b/dashboard/pages/proyectos_pages/home.py @@ -1,15 +1,17 @@ -import streamlit as st -import auth from uuid import uuid4 + +import auth +import streamlit as st from models import Project from page_router import PageRouter def proyectos_page(router: PageRouter, **params): - st.set_page_config(page_title="MatCom Dashboard - Proyectos", page_icon="⚗️", layout="wide") + st.set_page_config( + page_title="MatCom Dashboard - Proyectos", page_icon="⚗️", layout="wide" + ) router.page_header("Proyectos") - def save_project(project: Project, prefix): project.save() @@ -20,14 +22,12 @@ def save_project(project: Project, prefix): del st.session_state.current_project st.success("Proyecto guardado con éxito") - st.title("⚗️ Proyectos") list_view, create_view, edit_view = st.tabs( ["⚗️ Listado de proyectos", "⭐ Crear nuevo proyecto", "📝 Editar proyecto"] ) - with create_view: if auth.is_user_logged(): if "current_project" in st.session_state: @@ -43,20 +43,21 @@ def save_project(project: Project, prefix): else: st.warning("⚠️ Complete la información obligatoria, marcada con 🔹") else: - st.error("Acceso de solo lectura. Vaya a la página principal para loguearse.") - + st.error( + "Acceso de solo lectura. Vaya a la página principal para loguearse." + ) with edit_view: if auth.is_user_logged(): pass else: - st.error("Acceso de solo lectura. Vaya a la página principal para loguearse.") - + st.error( + "Acceso de solo lectura. Vaya a la página principal para loguearse." + ) projects = Project.all() projects.sort(key=lambda p: p.title) - with list_view: for project in projects: with st.expander( @@ -81,7 +82,9 @@ def save_project(project: Project, prefix): ) with right: - st.write(f"##### Entidad ejecutora principal:\n" + project.main_entity) + st.write( + f"##### Entidad ejecutora principal:\n" + project.main_entity + ) st.write("---") st.write( f"##### Entidades participantes adicionales:\n" diff --git a/dashboard/pages/publications_pages/books_and_chapters.py b/dashboard/pages/publications_pages/books_and_chapters.py index 25b5eb6..f6984a1 100644 --- a/dashboard/pages/publications_pages/books_and_chapters.py +++ b/dashboard/pages/publications_pages/books_and_chapters.py @@ -6,7 +6,9 @@ def books_and_chapters_page(router, **params): - st.set_page_config(page_title="MatCom Dashboard - Libros y Capítulos de Libros", layout="wide") + st.set_page_config( + page_title="MatCom Dashboard - Libros y Capítulos de Libros", layout="wide" + ) router.page_header("📕 Libros y Capítulos de Libros") year = st.sidebar.selectbox("Año", [2020, 2021, 2022], index=2) diff --git a/dashboard/pages/reportes_pages/home.py b/dashboard/pages/reportes_pages/home.py index 442485f..132c28c 100644 --- a/dashboard/pages/reportes_pages/home.py +++ b/dashboard/pages/reportes_pages/home.py @@ -2,16 +2,17 @@ import streamlit as st from models import Person, ResearchGroup -from reports import group_report, personal_report, research_balance -from streamlit.elements import select_slider from page_router import PageRouter +from pages.reportes_pages.reports import group_report, personal_report, research_balance +from streamlit.elements import select_slider def reportes_page(router: PageRouter, **params): - st.set_page_config(page_title="MatCom Dashboard - Reportes", page_icon="📈", layout="wide") + st.set_page_config( + page_title="MatCom Dashboard - Reportes", page_icon="📈", layout="wide" + ) router.page_header("Reportes") - balance, posgrado, personal, group = st.tabs( [ "⚗️ Balance de Investigación", @@ -27,7 +28,6 @@ def reportes_page(router: PageRouter, **params): groups = ResearchGroup.all() groups.sort(key=lambda g: g.name) - with balance: today = datetime.date.today() @@ -41,7 +41,6 @@ def reportes_page(router: PageRouter, **params): for line in research_balance(start_date, end_date): st.write(line) - with personal: person = st.selectbox("Seleccione la persona", people) diff --git a/dashboard/pages/reportes_pages/reports.py b/dashboard/pages/reportes_pages/reports.py new file mode 100644 index 0000000..a0e6cba --- /dev/null +++ b/dashboard/pages/reportes_pages/reports.py @@ -0,0 +1,513 @@ +import collections +from typing import Iterator, List + +import altair +import pandas as pd +import streamlit as st +from models import ( + Award, + Book, + BookChapter, + Classes, + ConferencePresentation, + JournalPaper, + Person, + Project, + ResearchGroup, + Thesis, +) + + +def _soft_bl(text: str) -> str: + return f"""{text} +""" + + +def _papers_by(persons: List[Person]) -> List[str]: + lines = [] + total = 0 + + articles = "" + article_count = 0 + for paper in JournalPaper.from_authors(persons): + articles += f"- {paper.format()}\n\n" + article_count += 1 + + total += article_count + + conferences = "" + conf_count = 0 + for paper in ConferencePresentation.from_authors(persons): + conferences += f"- {paper.format()}\n\n" + conf_count += 1 + + total += conf_count + + books = "" + book_counts = 0 + for paper in Book.from_authors(persons): + books += f"- {paper.format()}\n\n" + book_counts += 1 + + for paper in BookChapter.from_authors(persons): + books += f"- {paper.format()}\n\n" + book_counts += 1 + + total += book_counts + + lines.append(f"### 📚 Publicaciones ({total})") + + lines.append(f"#### 📃 Artículos ({article_count})") + if article_count > 0: + lines.append(articles) + + lines.append(f"#### 📢 Ponencias ({conf_count})") + if conf_count > 0: + lines.append(conferences) + + lines.append(f"#### 📕 Libros y Capítulos de Libro ({book_counts})") + if book_counts > 0: + lines.append(books) + + return lines + + +def group_report( + group: ResearchGroup, + show_general_info=False, + show_papers=False, + show_awards=False, +) -> Iterator[str]: + lines = [] + + # -------------------------------------------------------------------------- + if show_general_info: + lines.append("### 👤 Información general") + + general_info = "" + + if group.head is not None: + general_info += _soft_bl(f"- **Líder**: {group.head}") + + general_info += _soft_bl("- **Miembors:**") + for person in group.members: + general_info += _soft_bl(f" - {person.name}") + + if group.collaborators: + general_info += _soft_bl("- **Colaboradores:**") + for person in group.collaborators: + general_info += _soft_bl(f" - {person.name}") + + if group.keywords: + general_info += _soft_bl("- **Líneas de investigación:**") + for keyword in group.keywords: + general_info += _soft_bl(f" - {keyword}") + + lines.append(general_info) + + # -------------------------------------------------------------------------- + if show_papers: + # WARNING: This shows all the papers of the group members, some of them + # might be not related to the group research field. Maybe this can be + # fixed using tags/keywords for each models and only show the tags + # intersection. + lines.extend(_papers_by(group.members)) + + # -------------------------------------------------------------------------- + if show_awards: + awards = "" + entries = 0 + for award in Award.from_persons(group.members): + awards += _soft_bl("- " + award.title) + entries += 1 + + lines.append(f"### 🏆 Premios ({entries})") + if entries > 0: + lines.append(awards) + + # -------------------------------------------------------------------------- + + for line in lines: + yield line + + +def personal_report( + person: Person, + show_personal_info=False, + show_papers=False, + show_projects=False, + show_theses=False, + show_classes=False, + show_research_groups=False, + show_awards=False, +) -> Iterator[str]: + lines = [] + + # -------------------------------------------------------------------------- + if show_personal_info: + lines.append("### 👤 Información personal") + + personal_info = _soft_bl(f"- **Institución**: {person.institution}") + personal_info += _soft_bl(f"- **Facultad**: {person.faculty}") + personal_info += _soft_bl(f"- **Departamento**: {person.department}") + personal_info += _soft_bl(f"- **Grado científico:** {person.scientific_grade}") + personal_info += _soft_bl(f"- **Categoría docente:** {person.academic_grade}") + if person.orcid: + personal_info += _soft_bl( + f"- **Perfil ORCID:** [{person.orcid}](https://orcid.org/{person.orcid})" + ) + + lines.append(personal_info) + + # -------------------------------------------------------------------------- + if show_papers: + lines.extend(_papers_by([person])) + + # -------------------------------------------------------------------------- + if show_projects: + projects = "" + entries = 0 + for project in Project.from_members([person]): + projects += f"- {project.format()}\n\n" + entries += 1 + + lines.append(f"### ⚗️ Proyectos ({entries})") + if entries > 0: + lines.append(projects) + + # -------------------------------------------------------------------------- + if show_theses: + supervised_theses = "" + entries = 0 + for thesis in Thesis.from_advisors([person]): + supervised_theses += _soft_bl(f"- {thesis.title}") + entries += 1 + + lines.append(f"### 📑 Tesis tutoreadas ({entries})") + if entries > 0: + lines.append(supervised_theses) + + # -------------------------------------------------------------------------- + if show_classes: + classes = "" + entries = 0 + for _class in Classes.from_professors([person]): + classes += _soft_bl("- " + _class.subject.subject) + entries += 1 + + lines.append(f"### 🧑‍🏫 Clases ({entries})") + if entries > 0: + lines.append(classes) + + # -------------------------------------------------------------------------- + if show_research_groups: + table = _soft_bl("| Grupo | Colaborador | Miembro | Líder |") + table += _soft_bl("| -- | :--: | :--: | :--: |") + entries = 0 + + for group, status in ResearchGroup.from_person(person): + colaborator = "✅" if status.is_colaborator else "" + member = "✅" if status.is_member else "" + head = "✅" if status.is_head else "" + table += f"| {group.name} | {colaborator} | {member} | {head} |\n" + entries += 1 + + lines.append(f"### 🔬 Grupos de investigación ({entries})") + if entries > 0: + lines.append(table) + lines.append("") + + # -------------------------------------------------------------------------- + if show_awards: + awards = "" + entries = 0 + for award in Award.from_persons([person]): + awards += _soft_bl("- " + award.title) + entries += 1 + + lines.append(f"### 🏆 Premios ({entries})") + if entries > 0: + lines.append(awards) + + # -------------------------------------------------------------------------- + + for line in lines: + yield line + + +def research_balance(start_date, end_date): + lines = [] + + papers = [p for p in JournalPaper.all() if p.year == end_date.year] + papers.sort(key=lambda p: p.title) + + presentations = [ + p for p in ConferencePresentation.all() if p.year == end_date.year and p.paper + ] + presentations.sort(key=lambda p: p.title) + + books = [p for p in Book.all() if p.year == end_date.year] + books.sort(key=lambda b: b.title) + + chapters = [p for p in BookChapter.all() if p.year == end_date.year] + chapters.sort(key=lambda b: b.title) + + wos_scopus = [] + ricyt_scielo = [] + international = [] + national = [] + uh = [] + rest = [] + colab = [] + + for paper in papers: + if ( + "Web of Science" in paper.journal.indices + or "Scopus" in paper.journal.indices + ): + wos_scopus.append(paper) + elif "RICYT" in paper.journal.indices or "Scielo" in paper.journal.indices: + ricyt_scielo.append(paper) + elif "Otro (Internacional)" in paper.journal.indices: + international.append(paper) + elif "Otro (Nacional)" in paper.journal.indices: + national.append(paper) + elif paper.journal.publisher == "Universidad de La Habana": + uh.append(paper) + else: + rest.append(paper) + + for author in paper.authors: + if author.institution != "Universidad de La Habana": + colab.append(author) + break + + events = [p for p in ConferencePresentation.all() if p.year == end_date.year] + events.sort(key=lambda e: e.title) + + international_events = collections.defaultdict(list) + international_cuba = collections.defaultdict(list) + national_events = collections.defaultdict(list) + activities = collections.defaultdict(list) + + for e in events: + if e.event_type == "Internacional": + if "Cuba" in str(e.location): + international_cuba[(e.venue, e.location)].append(e) + else: + international_events[(e.venue, e.location)].append(e) + elif e.event_type == "Nacional": + national_events[(e.venue, e.location)].append(e) + else: + activities[(e.venue, e.location)].append(e) + + yield "### 📃 Publicaciones" + + data = pd.DataFrame( + [ + dict( + Tipo="Total", + Cantidad=len(papers) + len(presentations) + len(books) + len(chapters), + ), + dict(Tipo="Artículos", Cantidad=len(papers)), + dict(Tipo="WoS / Scopus", Cantidad=len(wos_scopus)), + dict(Tipo="RICYT / Scielo", Cantidad=len(ricyt_scielo)), + dict(Tipo="Internacional", Cantidad=len(international)), + dict(Tipo="Nacional", Cantidad=len(national)), + dict(Tipo="Editorial UH", Cantidad=len(uh)), + dict(Tipo="Sin índice", Cantidad=len(rest)), + dict(Tipo="Colaboraciones", Cantidad=len(colab)), + dict(Tipo="Presentaciones", Cantidad=len(presentations)), + dict(Tipo="Libros, etc", Cantidad=len(books) + len(chapters)), + ] + ) + + yield data + + yield altair.Chart(data).mark_bar().encode(y="Tipo", x="Cantidad") + + yield "#### 📃 Artículos" + + for paper in wos_scopus: + yield paper.format() + + for paper in ricyt_scielo: + yield paper.format() + + for paper in international: + yield paper.format() + + for paper in national: + yield paper.format() + + for paper in uh: + yield paper.format() + + for paper in rest: + yield paper.format() + + yield "#### 📢 Presentaciones (con publicación)" + + for presentation in presentations: + yield presentation.format() + + yield "#### 📕 Libros y Capítulos de Libro" + + for book in books: + yield book.format() + + for chapter in chapters: + yield chapter.format() + + yield "### 📢 Eventos" + + def total_events(d): + return sum(len(v) for v in d.values()) + + def total_events_first_author(d): + return sum(1 for v in d.values() for e in v if e.authors[0].faculty == "MatCom") + + def total_events_colab_uh(d): + return sum( + 1 + for v in d.values() + for e in v + if any( + a.institution == "Universidad de La Habana" + and not a.faculty == "MatCom" + for a in e.authors + ) + ) + + yield pd.DataFrame( + [ + dict( + Tipo="Eventos Internacionales", + Total=total_events(international_events), + Principal=total_events_first_author(international_events), + Colab=total_events_colab_uh(international_events), + ), + dict( + Tipo="Eventos Internacionales en Cuba", + Total=total_events(international_cuba), + Principal=total_events_first_author(international_cuba), + Colab=total_events_colab_uh(international_cuba), + ), + dict( + Tipo="Eventos Nacionales", + Total=total_events(national_events), + Principal=total_events_first_author(national_events), + Colab=total_events_colab_uh(national_events), + ), + dict( + Tipo="Actividades Cientítficas", + Total=total_events(activities), + Principal=total_events_first_author(activities), + Colab=total_events_colab_uh(activities), + ), + ] + ) + + if international_events: + yield "#### 💠 Internacionales" + + for (venue, location), events in international_events.items(): + yield f"_{venue}_, {location}: **{len(events)} ponencia(s)**" + + if international_cuba: + yield "#### 💠 Internacionales en Cuba" + + for (venue, location), events in international_cuba.items(): + yield f"_{venue}_, {location}: **{len(events)} ponencia(s)**" + + if national_events: + yield "#### 💠 Nacionales" + + for (venue, location), events in national_events.items(): + yield f"_{venue}_, {location}: **{len(events)} ponencia(s)**" + + if activities: + yield "#### 💠 Actividades Científicas" + + for (venue, location), events in activities.items(): + yield f"_{venue}_, {location}: **{len(events)} ponencia(s)**" + + yield "### ⚗️ Proyectos" + + projects = Project.all() + projects.sort(key=lambda p: (p.project_type, p.title)) + + df = ( + pd.DataFrame( + [ + dict(Proyecto=p.title, Estado=p.status, Tipo=p.project_type) + for p in projects + ] + ) + .groupby(["Tipo", "Estado"]) + .count() + .reset_index() + .set_index("Tipo") + ) + + yield df + + yield pd.DataFrame( + [ + dict( + Proyecto=p.title, + Fondos=p.funds_total, + Efectuado=p.funds_collected, + Financia="; ".join(p.funding), + Resto=p.funds_total - p.funds_collected, + ) + for p in projects + ] + ).set_index(["Proyecto", "Financia"]) + + for project in projects: + yield project.format() + + yield "### 👥 Personal" + + people = set(Person.own()) + + yield pd.DataFrame( + [dict(Persona=p.name, Grado=p.scientific_grade) for p in people] + ).groupby("Grado").count() + + people_with_papers = ( + set( + person + for paper in papers + presentations + books + chapters + events + for person in paper.authors + ) + & people + ) + + st.write( + f"**Personal con publicaciones:** {len(people_with_papers)} ({len(people_with_papers) * 100 / len(people):0.1f}%)" + ) + + people_in_projects = ( + set( + person + for project in projects + for person in [project.head] + project.members + ) + & people + ) + + st.write( + f"**Personal con proyectos:** {len(people_in_projects)} ({len(people_in_projects) * 100 / len(people):0.1f}%)" + ) + + st.write(f"**Personal en ambos:** {len(people_in_projects & people_with_papers)}") + + people_in_awards = ( + set(person for award in Award.all() for person in award.participants) & people + ) + + st.write( + f"**Personal con premios:** {len(people_in_awards)} ({len(people_in_awards) * 100 / len(people):0.1f}%)" + ) diff --git a/dashboard/pages/tesis_pages/home.py b/dashboard/pages/tesis_pages/home.py index b36b4ba..0e07d3d 100644 --- a/dashboard/pages/tesis_pages/home.py +++ b/dashboard/pages/tesis_pages/home.py @@ -14,11 +14,14 @@ def tesis_page(router: PageRouter, **params): - st.set_page_config(page_title="MatCom Dashboard - Tesis", page_icon="🎓", layout="wide") + st.set_page_config( + page_title="MatCom Dashboard - Tesis", page_icon="🎓", layout="wide" + ) router.page_header("Tesis") - - listing, create, details = st.tabs(["📃 Listado", "➕ Crear nueva Tesis", "📄 Detalles"]) + listing, create, details = st.tabs( + ["📃 Listado", "➕ Crear nueva Tesis", "📄 Detalles"] + ) theses: List[Thesis] = Thesis.all() @@ -112,7 +115,9 @@ def tesis_page(router: PageRouter, **params): if "file_uploader_key" not in st.session_state: st.session_state["file_uploader_key"] = generate_widget_key() pdf = st.file_uploader( - "📤 Subir Tesis", type="pdf", key=st.session_state["file_uploader_key"] + "📤 Subir Tesis", + type="pdf", + key=st.session_state["file_uploader_key"], ) with right: diff --git "a/dashboard/\342\255\220_dashboard.py" "b/dashboard/\342\255\220_dashboard.py" index 4e7dedc..4623f3b 100644 --- "a/dashboard/\342\255\220_dashboard.py" +++ "b/dashboard/\342\255\220_dashboard.py" @@ -14,17 +14,6 @@ def dashboard(router: PageRouter, **params): left, right = st.columns(2) with right: - # if not auth.is_user_logged(): - # st.info( - # """ - # Si usted es claustro de la facultad y desea modificar los datos, - # introduzca la contraseña correspondiente. De lo contrario, puede leer - # los datos pero no modificar. - - # Si usted cree que debería tener acceso, contacte con - # [@apiad](https://t.me/apiad) en Telegram.""" - # ) - auth.authenticate() if auth.is_user_logged(): @@ -46,11 +35,7 @@ def dashboard(router: PageRouter, **params): Route( url="signup", builder=registration_page, - redirect=lambda **_: ( - "home" - if auth.is_user_logged() - else None - ), + redirect=lambda **_: ("home" if auth.is_user_logged() else None), ) ], ),