Compare commits

..

6 Commits

Author SHA1 Message Date
sebastian.serfling 6d040c0040 many changes 2025-04-02 13:33:32 +00:00
sebastian.serfling 117bae03e0 add gitignore 2025-03-05 10:36:41 +00:00
sebastian.serfling bf95494ab3 Many Changes 2025-03-05 10:33:58 +00:00
sebastian.serfling 8d5e367d23 add docker compose 2024-09-02 07:58:39 +00:00
sebastian.serfling b138e0b985 Change Port 80 2024-09-02 07:47:59 +00:00
sebastian.serfling 41f730b402 change Port to 80 2024-09-02 07:46:27 +00:00
21 changed files with 473 additions and 127 deletions
+3
View File
@@ -0,0 +1,3 @@
apps/ticket_export/exports/RE2025.00012.1.docx
apps/ticket_export/exports/RE2025.00013.1.docx
apps/ticket_export/exports/RE2025.00014.1.docx
+3 -1
View File
@@ -5,5 +5,7 @@ backgroundColor="#2c3e50"
secondaryBackgroundColor="#34495e" secondaryBackgroundColor="#34495e"
textColor="#ffffff" textColor="#ffffff"
font="sans serif" font="sans serif"
layout="wide"
layout="wide" [browser]
serverAddress = "reporting.stines.de"
+166 -30
View File
@@ -1,52 +1,188 @@
import streamlit as st import streamlit as st
from streamlit_option_menu import option_menu
from sqlalchemy import create_engine
import sites.services_reporting as sr import sites.services_reporting as sr
import sites.userlist as us import sites.userlist as us
import sites.server as s import sites.server as s
import sites.tickets as ti import sites.tickets as ti
import sites.lastrun as lr import sites.lastrun as lr
from datetime import datetime
from dateutil.relativedelta import relativedelta
import mysql.connector
import pandas as pd
import os
# Page Settings # Page Settings
st.set_page_config(page_title="Reporting",layout="wide") st.set_page_config(page_title="Reporting", layout="wide")
start_date = datetime.today().replace(day=1) - relativedelta(months=1)
end_date = datetime.today().replace(day=1) - relativedelta(days=1)
start_date_lastmonth = datetime.today().replace(day=1) - relativedelta(months=2)
end_date_lastmonth = datetime.today().replace(day=1) - relativedelta(months=1) - relativedelta(days=1)
# Datumsformatierung
start_date_format = start_date.strftime("%Y-%m-%d")
end_date_format = end_date.strftime("%Y-%m-%d")
# Load custom CSS # Load custom CSS
def load_css(file_name): def load_css(file_name):
with open(file_name) as f: with open(file_name) as f:
st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True) st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True)
load_css('style.css') def get_customer_used_service(end_date):
# Define page functions mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"),
user=os.getenv("MYSQL_USER"),
password=os.getenv("MYSQL_PASSWORD"),
database=os.getenv("MYSQL_DATABASE")
)
mycursor = mydb.cursor()
mycursor.execute(f"""SELECT cs.companyname, cs.customer_ID, cs.services_ID,cs.name from Kunden.`daily.customer.services` cs WHERE add_date LIKE '%{end_date}%'""")
myresult = mycursor.fetchall()
mydb.close()
return myresult
def load_server_list(start_date, end_date):
db_url = (
f"mysql+mysqlconnector://{os.getenv('MYSQL_USER')}:"
f"{os.getenv('MYSQL_PASSWORD')}@{os.getenv('MYSQL_HOST')}/"
f"{os.getenv('MYSQL_DATABASE')}"
)
engine = create_engine(db_url)
query = f"""
SELECT server, cores, customer_id
FROM Kunden.`daily.spla.server` sr
WHERE sr.timestamp BETWEEN '{start_date}' AND '{end_date}'
"""
max_server_count = pd.read_sql_query(query, engine)
return max_server_count
def load_user_service_list(service_id, customer_id, start_date, end_date):
db_url = (
f"mysql+mysqlconnector://{os.getenv('MYSQL_USER')}:"
f"{os.getenv('MYSQL_PASSWORD')}@{os.getenv('MYSQL_HOST')}/"
f"{os.getenv('MYSQL_DATABASE')}"
)
engine = create_engine(db_url)
query = f"""
SELECT COUNT(*) AS max_count
FROM (
SELECT username
FROM Kunden.`daily.user.enabled` sr
WHERE sr.customer_ID = {customer_id}
AND sr.services_ID = {service_id}
AND sr.timestamp BETWEEN '{start_date_format}' AND '{end_date_format}'
) AS sub;
"""
max_user_count = pd.read_sql_query(query, engine)
return max_user_count.iloc[0]['max_count'] if not max_user_count.empty else 0
def load_user_disabled(start_date, end_date,customer_id):
db_url = (
f"mysql+mysqlconnector://{os.getenv('MYSQL_USER')}:"
f"{os.getenv('MYSQL_PASSWORD')}@{os.getenv('MYSQL_HOST')}/"
f"{os.getenv('MYSQL_DATABASE')}"
)
engine = create_engine(db_url)
query = f"""
SELECT disabledate, username, service_name, customer_name, ticketnumber, comment
FROM Kunden.`daily.user.disabled` sud
WHERE sud.disabledate BETWEEN '{start_date}' AND '{end_date}' AND customer_id = '{customer_id}' AND services_id IN (100,101,116,120) ORDER BY service_name
"""
all = pd.read_sql_query(query, engine)
return all
def home(): def home():
st.title("Home Page") st.title("Dashboard")
st.write("Welcome to the Home Page!") edit_start_date = start_date.strftime("%d.%m.%Y")
edit_end_date = end_date.strftime("%d.%m.%Y")
edit_start_date_lastmonth = start_date_lastmonth.strftime("%d.%m.%Y")
edit_end_date_lastmonth = end_date_lastmonth.strftime("%d.%m.%Y")
st.subheader(f"Übersicht {edit_start_date} - {edit_end_date}")
previous_value = None
columns = None
c = 0
print(end_date)
for i in get_customer_used_service(end_date.strftime("%Y-%m-%d")):
print(i)
if previous_value != i[1]:
st.subheader(f"{i[0]}")
columns = st.columns(4)
df = load_user_disabled(start_date_lastmonth, end_date_lastmonth, i[1])
if not df.empty:
st.text(f"Deaktivierte User {edit_start_date_lastmonth} - {edit_end_date_lastmonth}")
st.data_editor(df,use_container_width=True)
c = 0
active_users = load_user_service_list(i[2], i[1], start_date, end_date)
# Filter nach dem spezifischen Service und zähle die eindeutigen Benutzernamen
disabled_users_count = 0
if not df.empty and 'service_name' in df.columns and 'username' in df.columns:
# Annahme: i[3] enthält den Service-Namen, der mit der 'service_name'-Spalte übereinstimmt
service_filtered_df = df[df['service_name'] == i[3]]
disabled_users_count = service_filtered_df['username'].nunique()
if not active_users:
st.info(f"Kunde {i[0]} - Service {i[3]} - Not Data found!")
else:
columns[c].metric(
label=f"Aktive {i[3]} User",
value=active_users,
delta=f"-{disabled_users_count}" if disabled_users_count > 0 else None,
delta_color="inverse"
)
c += 1
previous_value = i[1]
col1, = st.columns(1)
df = load_server_list(start_date,end_date)
grouped = df.groupby('server')['cores'].count()*8/2
grouped_series = df.groupby('server')['cores'].max()
grouped_str = grouped_series.to_string(header=False)
df['cores'] = pd.to_numeric(df['cores'], errors='coerce')
server_cores = df.groupby('server')['cores'].max()
count_cores = server_cores.count()
with col1:
st.header("CPU Liste")
st.text(
f"Anzahl der Cores:\n{grouped_str}\n "
)
st.text(f"Gesamte Anzahl der Cores: {count_cores}")
st.text(f"Berechung der Core-Pakete = Anzahl der Cores ({count_cores}) * Core-Pakete aus SPLA (8) / 2")
st.header(f"Gesamt : {str(grouped.sum()).split('.')[0]} Pakete")
if 'page' not in st.session_state: # Ausgabe der Ergebnisse
st.session_state.page = 'Home'
# Navigation bar using streamlit-option-menu
with st.sidebar:
selected_page = option_menu(
menu_title="Navigation", # required
options=["Dashboard", "Services Reporting", "User Filter", "Server", "Tickets", "Last-Run"], # required
icons=["house", "bar-chart", "filter", "server", "ticket", "clock"], # optional
menu_icon="cast", # optional
default_index=0, # optional
orientation="vertikal", # horizontal navigation
)
# Sidebar navigation # Page display logic based on selected option
st.sidebar.title("Navigation") if selected_page == "Dashboard":
if st.sidebar.button('Home'):
st.session_state.page = 'Home'
if st.sidebar.button('Services Reporting'):
st.session_state.page = 'Services Reporting'
if st.sidebar.button('User Filter'):
st.session_state.page = 'User Filter'
if st.sidebar.button('Server'):
st.session_state.page = 'Server'
if st.sidebar.button('Tickets'):
st.session_state.page = 'Tickets'
if st.sidebar.button('Last-Run'):
st.session_state.page = 'Last-Run'
# Page display logic
if st.session_state.page == 'Home':
home() home()
elif st.session_state.page == 'Services Reporting': elif selected_page == "Services Reporting":
sr.services_reporting() sr.services_reporting()
elif st.session_state.page == 'User Filter': elif selected_page == "User Filter":
us.user_filter() us.user_filter()
elif st.session_state.page == 'Server': elif selected_page == "Server":
s.server_filter() s.server_filter()
elif st.session_state.page == 'Tickets': elif selected_page == "Tickets":
ti.ticket_filter() ti.ticket_filter()
elif st.session_state.page == 'Last-Run': elif selected_page == "Last-Run":
lr.user_filter() lr.user_filter()
Binary file not shown.
Binary file not shown.
+22 -11
View File
@@ -24,11 +24,12 @@ def fetch_tickets_from_database():
cursor = mydb.cursor() cursor = mydb.cursor()
# Tickets abrufen, inklusive customer_ID # Tickets abrufen, inklusive customer_ID
cursor.execute(""" cursor.execute(f"""
SELECT t.`number`, t.title, t.createdate, t.`type`, t.customer_ID, tct.firstdate, t.time, s.price, t.service_ID SELECT t.`number`, t.title, t.createdate, t.`type`, t.customer_ID, tct.firstdate, t.time, s.price, t.service_ID, t.tags
FROM Kunden.tickets t FROM Kunden.tickets t
JOIN Kunden.`tickets.customer.timerange` tct ON t.customer_ID = tct.customer_ID JOIN Kunden.`tickets.customer.timerange` tct ON t.customer_ID = tct.customer_ID
JOIN Kunden.services s ON s.service_ID = t.service_ID JOIN Kunden.services s ON s.service_ID = t.service_ID
WHERE closedate >= DATE_SUB(CURDATE(), INTERVAL 32 DAY)
ORDER by t.createdate ASC ORDER by t.createdate ASC
""") """)
tickets = cursor.fetchall() tickets = cursor.fetchall()
@@ -136,7 +137,7 @@ def set_cell_border(cell, **kwargs):
def fill_template(doc_path, output_path, data, tickets): def fill_template(doc_path, output_path, data, tickets):
doc = Document(doc_path) doc = Document(doc_path)
print("Korrekt")
# Platzhalter in normalem Text ersetzen # Platzhalter in normalem Text ersetzen
for paragraph in doc.paragraphs: for paragraph in doc.paragraphs:
for key, value in data.items(): for key, value in data.items():
@@ -161,8 +162,15 @@ def fill_template(doc_path, output_path, data, tickets):
second_table = doc.tables[1] second_table = doc.tables[1]
for ticket in tickets: for ticket in tickets:
row = second_table.add_row() row = second_table.add_row()
ticket_number, title, createdate, _, _, _, timerange, _, _, tags = ticket
print(ticket[9])
row.cells[0].text = ticket[0] # Ticketnummer row.cells[0].text = ticket[0] # Ticketnummer
row.cells[1].text = ticket[1] # Tickettitel if ticket[9]:
row.cells[1].text = f"{ticket[1]} - {ticket[9]}" # Tickettitel
else:
row.cells[1].text = ticket[1]
row.cells[2].text = ticket[2].strftime("%d.%m.%Y") # createdate als String formatieren row.cells[2].text = ticket[2].strftime("%d.%m.%Y") # createdate als String formatieren
row.cells[3].text = str(ticket[6]) # timerange (time_unit) row.cells[3].text = str(ticket[6]) # timerange (time_unit)
@@ -227,12 +235,16 @@ if __name__ == "__main__":
service_ID = next(iter(set(ticket[8] for ticket in tickets))) service_ID = next(iter(set(ticket[8] for ticket in tickets)))
price = next(iter(set(ticket[7] for ticket in tickets))) price = next(iter(set(ticket[7] for ticket in tickets)))
customer_ids = set(ticket[4] for ticket in tickets) customer_ids = set(ticket[4] for ticket in tickets)
print(tickets)
print(customer_ids)
for customer_id in customer_ids: for customer_id in customer_ids:
customer_data = fetch_customer_data(customer_id) customer_data = fetch_customer_data(customer_id)
customer_servicetime = fetch_customer_servicetime(customer_id) customer_servicetime = fetch_customer_servicetime(customer_id)
customer_price = fetch_customer_price(price, customer_id, service_ID) customer_price = fetch_customer_price(price, customer_id, service_ID)
customer_tickets = [ticket for ticket in tickets if ticket[4] == customer_id] customer_tickets = [ticket for ticket in tickets if ticket[4] == customer_id]
print(customer_data)
if not customer_data: if not customer_data:
print(f"Keine Kundendaten für Kunden-ID {customer_id} gefunden!") print(f"Keine Kundendaten für Kunden-ID {customer_id} gefunden!")
@@ -255,24 +267,23 @@ if __name__ == "__main__":
"housenumber": customer_data[2], "housenumber": customer_data[2],
"postcode": customer_data[3], "postcode": customer_data[3],
"city": customer_data[4], "city": customer_data[4],
"customernumber": customer_data[5], "cnumber": customer_data[5],
"year": datetime.now().year, "year": datetime.now().year,
"ordernumber": "0001", "onumber": "1",
"startdate": startdate.strftime("%d.%m.%Y"), "startdate": startdate.strftime("%d.%m.%Y"),
"enddate": enddate.strftime("%d.%m.%Y"), "enddate": enddate.strftime("%d.%m.%Y"),
"today": datetime.now().strftime("%d.%m.%Y"), "today": datetime.now().strftime("%d.%m.%Y"),
"price_per_minute": customer_price, "price_per_minute": customer_price,
"servicetime": customer_servicetime[0], "servicetime": customer_servicetime[0],
"gesamt_time_unit": 0, "gesamt_time_unit": 0,
"price_ex_mwst": 0, "price_ex_mwst": "0,00",
"sl_time_unit": 0, "sl_time_unit": 0,
"sl_minus_unit": 0, "sl_minus_unit": 0,
"zl_time_unit": 0, "zl_time_unit": 0,
"time_unit_sum": 0, "time_unit_sum": 0,
"mwst_set": 0, "mwst_set": "0,00",
"sum": 0, "sum": "0,00",
} }
output_path = f"apps/ticket_export/exports/RE2025.{customer_data[5]}.{data['onumber']}.docx"
output_path = f"apps/ticket_export/exports/RE2024.{customer_data[5]}.{data['ordernumber']}.docx"
fill_template('apps/ticket_export/template.docx', output_path, data, customer_tickets) fill_template('apps/ticket_export/template.docx', output_path, data, customer_tickets)
print("True") print("True")
Binary file not shown.
+13
View File
@@ -0,0 +1,13 @@
services:
streamlit:
build:
context: .
dockerfile: dockerfile
ports:
- 80:80
networks:
- frontend
networks:
frontend:
driver: bridge
+2 -2
View File
@@ -16,6 +16,6 @@ RUN pip3 install -r requirements.txt
EXPOSE 80 EXPOSE 80
HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health HEALTHCHECK CMD curl --fail http://localhost:80/_stcore/health
ENTRYPOINT ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"] ENTRYPOINT ["streamlit", "run", "app.py", "--server.port=80", "--server.address=0.0.0.0"]
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+3 -3
View File
@@ -16,14 +16,14 @@ def get_filtered_users(customer_id, service_id):
database=os.getenv("MYSQL_DATABASE") database=os.getenv("MYSQL_DATABASE")
) )
query = f"""SELECT * FROM Kunden.`services.reporting` where DATE(reportingdate) = CURDATE() """ query = f"""SELECT * FROM Kunden.`daily.user.online` where DATE(timestamp) = CURDATE() """
if customer_id: if customer_id:
query += f"AND customer_ID = {customer_id}" query += f"AND customer_ID = {customer_id}"
if service_id: if service_id:
query += f" AND service_ID = {service_id}" query += f" AND services_id = {service_id}"
query += " ORDER BY reportingdate DESC" query += " ORDER BY timestamp DESC"
users = pd.read_sql_query(query, mydb) users = pd.read_sql_query(query, mydb)
print(query) print(query)
mydb.close() mydb.close()
+43 -15
View File
@@ -8,7 +8,7 @@ from dotenv import load_dotenv
load_dotenv() load_dotenv()
def get_filtered_server(customer_id, service_id, service_status): def get_filtered_server(customer_ids, service_id, service_status, os_type, reporting):
mydb = mysql.connector.connect( mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"), host=os.getenv("MYSQL_HOST"),
user=os.getenv("MYSQL_USER"), user=os.getenv("MYSQL_USER"),
@@ -18,23 +18,30 @@ def get_filtered_server(customer_id, service_id, service_status):
# Prepare the base query # Prepare the base query
query = f""" query = f"""
select s.hostname,s.privat_ipaddress,s.public_ipaddress, s.ram, s.createdate, s.disabledate,s.customer_ID,s.server_ID,hc.name,hc.core select s.hostname, s.privat_ipaddress, s.public_ipaddress, s.ram, s.createdate, s.disabledate, s.os, s.customer_ID, s.server_ID, hc.name, hc.core
from Kunden.server s from Kunden.server s
join Kunden.`hardware.cpu` hc ON hc.cpu_ID = s.cpu_ID join Kunden.`hardware.cpu` hc ON hc.cpu_ID = s.cpu_ID
WHERE 1=1 WHERE 1=1
""" """
if customer_id:
query += f"AND s.customer_ID = {customer_id}" # If multiple customers are selected, use the IN clause
if customer_ids:
customer_ids_str = ', '.join([str(id) for id in customer_ids])
query += f" AND s.customer_ID IN ({customer_ids_str})"
if service_id: if service_id:
query += f" AND s.service_ID = {service_id}" query += f" AND s.service_ID = {service_id}"
if service_status: if service_status:
query += f" AND s.status = {service_status}" query += f" AND s.status = {service_status}"
if os_type:
query += f" AND s.os = '{os_type}'"
if reporting == "True":
query += f" AND licensekey IS NOT NULL"
users = pd.read_sql_query(query, mydb) users = pd.read_sql_query(query, mydb)
mydb.close() mydb.close()
return users return users
def get_initial_data(): def get_initial_data():
mydb = mysql.connector.connect( mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"), host=os.getenv("MYSQL_HOST"),
@@ -60,7 +67,6 @@ def get_initial_data():
mydb.close() mydb.close()
return service_ids, customers return service_ids, customers
def server_filter(): def server_filter():
st.title("Server Filter :mag_right:") st.title("Server Filter :mag_right:")
# Get initial data for widgets # Get initial data for widgets
@@ -68,15 +74,17 @@ def server_filter():
# Combine service_ID and name for display # Combine service_ID and name for display
service_options = initial_service_ids.apply(lambda row: f"{row['service_ID']} - {row['name']}", axis=1) service_options = initial_service_ids.apply(lambda row: f"{row['service_ID']} - {row['name']}", axis=1)
# Add selection widget for customer ID # Create a dictionary for customer selection
selected_customer = st.selectbox( customer_dict = {f"{row['companyname']} - {row['customer']}": row['customer_ID'] for _, row in customers.iterrows()}
'Select Customer',
["All"] + customers.apply(lambda row: f"{row['customer_ID']} - {row['companyname']} - {row['customer']}", # Use multiselect for multiple customer selection
axis=1).tolist() selected_customers = st.multiselect(
'Select Customer(s)',
list(customer_dict.keys()) # Display only companyname and customer
) )
# Extract customer_ID from selected option # Get the corresponding customer IDs
selected_customer_id = None if selected_customer == "All" else int(selected_customer.split(' - ')[0]) selected_customer_ids = [customer_dict[customer] for customer in selected_customers]
# Add selection widget for service ID # Add selection widget for service ID
selected_service = st.selectbox( selected_service = st.selectbox(
@@ -96,13 +104,33 @@ def server_filter():
# Extract status from selected option # Extract status from selected option
service_status = None if selected_status == "All" else int(selected_status.split(' - ')[0]) service_status = None if selected_status == "All" else int(selected_status.split(' - ')[0])
# Add SPLA server selection
reporting_box = st.selectbox(
'Select SPLA Server',
["Nein", "Ja"]
)
# Extract reporting status
reporting = None if reporting_box == "Nein" else "True"
# Add OS type selection
os_box = st.selectbox(
'Select OS Type',
["All", "Linux", "Windows"]
)
# Extract OS type
os_type = None if os_box == "All" else os_box
# Add a button to apply filters # Add a button to apply filters
if st.button('Apply Filters'): if st.button('Apply Filters'):
# Fetch filtered data from the database # Fetch filtered data from the database
filtered_data = get_filtered_server(selected_customer_id, selected_service_id, service_status) filtered_data = get_filtered_server(selected_customer_ids, selected_service_id, service_status, os_type, reporting)
# Display the filtered data # Display the filtered data
if not filtered_data.empty: if not filtered_data.empty:
st.dataframe(filtered_data) st.dataframe(filtered_data)
st.text(f"CPU SUMME = {sum(filtered_data['core'])}" )
st.text(f"Berechung der Core-Pakete: Anzahl der Cores({filtered_data['core'].count()}) * Core-Pakete aus SPLA (8) / 2")
st.text(f"Reporting Core-Pakete = {(filtered_data['core'].count())*8/2}".split('.')[0])
else: else:
st.write("No data available for the selected filters.") st.write("No data available for the selected filters.")
+199 -63
View File
@@ -1,55 +1,153 @@
import streamlit as st import streamlit as st
import pandas as pd import pandas as pd
import mysql.connector import mysql.connector
from datetime import datetime, date from datetime import datetime, date, timedelta
from sqlalchemy import create_engine
import os import os
from dotenv import load_dotenv from dotenv import load_dotenv
import altair as alt
load_dotenv() load_dotenv()
def get_filtered_data(customer_id, service_id, start_date, end_date): def get_filtered_data(customer_id, service_id, start_date, end_date):
mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"),
user=os.getenv("MYSQL_USER"),
password=os.getenv("MYSQL_PASSWORD"),
database=os.getenv("MYSQL_DATABASE")
)
# Prepare the query
query = f"""
SELECT DATE_FORMAT(sr.reportingdate, '%Y-%m') AS month,
COUNT(DISTINCT sr.username) as count
FROM Kunden.`services.reporting` sr
JOIN Kunden.services s ON sr.service_ID = s.service_ID
WHERE sr.customer_ID = {customer_id}
AND sr.service_ID = {service_id}
AND sr.username NOT LIKE '%admin%'
AND sr.username NOT LIKE '%test%'
AND sr.reportingdate BETWEEN '{start_date}' AND '{end_date}'
GROUP BY DATE_FORMAT(sr.reportingdate, '%Y-%m')
ORDER BY DATE_FORMAT(sr.reportingdate, '%Y-%m');
""" """
Fetches the user count data grouped by month within the specified date range.
"""
db_url = (
f"mysql+mysqlconnector://{os.getenv('MYSQL_USER')}:"
f"{os.getenv('MYSQL_PASSWORD')}@{os.getenv('MYSQL_HOST')}/"
f"{os.getenv('MYSQL_DATABASE')}"
)
engine = create_engine(db_url)
service_reporting = pd.read_sql_query(query, mydb) query = f"""
mydb.close() SELECT DATE_FORMAT(add_date, '%Y-%m') AS day,
count as count
FROM Kunden.`daily.users.count_by_services`
WHERE customer_ID = {customer_id}
AND services_ID = {service_id}
AND add_date BETWEEN '{start_date}' AND '{end_date}'
ORDER BY DATE_FORMAT(add_date, '%Y-%m');
"""
service_reporting = pd.read_sql_query(query, engine)
#engine.close()
return service_reporting return service_reporting
def get_initial_data(): def get_user_online(customer_id,service_id,start_date,end_date):
mydb = mysql.connector.connect( db_url = (
host=os.getenv("MYSQL_HOST"), f"mysql+mysqlconnector://{os.getenv('MYSQL_USER')}:"
user=os.getenv("MYSQL_USER"), f"{os.getenv('MYSQL_PASSWORD')}@{os.getenv('MYSQL_HOST')}/"
password=os.getenv("MYSQL_PASSWORD"), f"{os.getenv('MYSQL_DATABASE')}"
database=os.getenv("MYSQL_DATABASE")
) )
engine = create_engine(db_url)
if service_id == 100:
user_info = "sr.primarymail"
else:
user_info = "sr.username"
query = f"""
SELECT
{user_info} as username
FROM Kunden.`daily.user.online` sr
WHERE sr.customer_ID = {customer_id}
AND sr.services_ID = {service_id}
AND sr.timestamp BETWEEN '{start_date}' AND '{end_date}'
GROUP BY {user_info}
ORDER BY {user_info};
"""
user_online = pd.read_sql_query(query, engine)
user_online_count= user_online.shape[0]
#mydb.close()
return user_online, user_online_count
def get_max_user_count(customer_id, service_id, start_date, end_date):
"""
Fetches the maximum user count within the specified date range.
"""
db_url = (
f"mysql+mysqlconnector://{os.getenv('MYSQL_USER')}:"
f"{os.getenv('MYSQL_PASSWORD')}@{os.getenv('MYSQL_HOST')}/"
f"{os.getenv('MYSQL_DATABASE')}"
)
engine = create_engine(db_url)
user_info = "sr.username"
query = f"""
SELECT MAX(username) as max_count
FROM Kunden.`daily.user.enabled` WHERE customer_ID = {customer_id} AND services_ID = {service_id} AND timestamp BETWEEN '{start_date}' AND '{end_date}'
"""
max_user_count = pd.read_sql_query(query, engine)
#mydb.close()
return max_user_count.iloc[0]['max_count'] if not max_user_count.empty else 0
def get_active_users(customer_id, service_id, start_date, end_date):
"""
Fetch all active users for the given customer, service, and date range
based on the most recent activity and status.
"""
db_url = (
f"mysql+mysqlconnector://{os.getenv('MYSQL_USER')}:"
f"{os.getenv('MYSQL_PASSWORD')}@{os.getenv('MYSQL_HOST')}/"
f"{os.getenv('MYSQL_DATABASE')}"
)
engine = create_engine(db_url)
if service_id == 100:
user_info = "sr.primarymail"
else:
user_info = "sr.username"
query = f"""
SELECT
{user_info} as username
FROM Kunden.`daily.user.enabled` sr
WHERE sr.customer_ID = {customer_id}
AND sr.services_ID = {service_id}
AND sr.timestamp = '{start_date}'
ORDER BY {user_info};
"""
active_users = pd.read_sql_query(query, engine)
user_active_count = active_users.shape[0]
return active_users, user_active_count
def get_user_not_online(customer_id,service_id,start_date,end_date):
db_url = (
f"mysql+mysqlconnector://{os.getenv('MYSQL_USER')}:"
f"{os.getenv('MYSQL_PASSWORD')}@{os.getenv('MYSQL_HOST')}/"
f"{os.getenv('MYSQL_DATABASE')}"
)
engine = create_engine(db_url)
if service_id == 100:
user_info = "primarymail"
else:
user_info = "username"
query = f"""
SELECT
{user_info} as username
FROM Kunden.`daily.user.notonline` sr
WHERE sr.customer_ID = {customer_id}
AND sr.services_ID = {service_id}
AND sr.timestamp BETWEEN '{start_date}' AND '{end_date}'
GROUP BY {user_info}
ORDER BY {user_info};
"""
not_active_users = pd.read_sql_query(query, engine)
user_not_online_count = not_active_users.shape[0]
return not_active_users, user_not_online_count
def get_initial_data():
db_url = (
f"mysql+mysqlconnector://{os.getenv('MYSQL_USER')}:"
f"{os.getenv('MYSQL_PASSWORD')}@{os.getenv('MYSQL_HOST')}/"
f"{os.getenv('MYSQL_DATABASE')}"
)
engine = create_engine(db_url)
# Fetch unique service IDs and names # Fetch unique service IDs and names
service_id_query = """ service_id_query = """
SELECT DISTINCT s.service_ID, s.name SELECT DISTINCT s.service_ID, s.name
FROM Kunden.`services.reporting` sr FROM Kunden.`services.reporting` sr
JOIN Kunden.services s ON sr.service_ID = s.service_ID JOIN Kunden.services s ON sr.service_ID = s.service_ID
""" """
service_ids = pd.read_sql_query(service_id_query, mydb) service_ids = pd.read_sql_query(service_id_query, engine)
# Fetch customer information # Fetch customer information
customer_query = """ customer_query = """
@@ -59,73 +157,111 @@ def get_initial_data():
JOIN Kunden.`services.reporting`sr ON sr.customer_ID = co.customer_ID JOIN Kunden.`services.reporting`sr ON sr.customer_ID = co.customer_ID
GROUP BY c.customer_ID, c.customer, co.companyname; GROUP BY c.customer_ID, c.customer, co.companyname;
""" """
customers = pd.read_sql_query(customer_query, mydb) customers = pd.read_sql_query(customer_query, engine)
# Fetch date range # Fetch date range
date_query = """ date_query = """
SELECT MIN(reportingdate) AS min_date, MAX(reportingdate) AS max_date SELECT MIN(reportingdate) AS min_date, MAX(reportingdate) AS max_date
FROM Kunden.`services.reporting` FROM Kunden.`services.reporting`
""" """
date_range = pd.read_sql_query(date_query, mydb) date_range = pd.read_sql_query(date_query, engine)
mydb.close()
return service_ids, customers, date_range return service_ids, customers, date_range
def generate_month_range(min_date, max_date):
months = pd.date_range(start=min_date, end=max_date, freq='MS').strftime("%Y-%m").tolist()
return months
def services_reporting(): def services_reporting():
st.title("Reporting :mag_right:") st.title("Reporting :mag_right:")
# Get initial data for widgets # Get initial data for widgets
initial_service_ids, customers, initial_date_range = get_initial_data() initial_service_ids, customers, initial_date_range = get_initial_data()
# Combine service_ID and name for display
service_options = initial_service_ids.apply(lambda row: f"{row['service_ID']} - {row['name']}", axis=1) service_options = initial_service_ids.apply(lambda row: f"{row['service_ID']} - {row['name']}", axis=1)
# Add selection widget for customer ID # Selection widget for customer ID
customer_dict = {f"{row['companyname']} - {row['customer']}": row['customer_ID'] for _, row in customers.iterrows()}
# Selectbox with only the customer name and company displayed
selected_customer = st.selectbox( selected_customer = st.selectbox(
'Select Customer', 'Select Customer',
customers.apply(lambda row: f"{row['customer_ID']} - {row['companyname']} - {row['customer']}", axis=1).tolist() list(customer_dict.keys()) # Display only companyname and customer
) )
# Extract customer_ID from selected option # Get the corresponding customer ID
selected_customer_id = int(selected_customer.split(' - ')[0]) selected_customer_id = customer_dict[selected_customer]
# Add selection widget for service ID # Selection widget for service ID
selected_service = st.selectbox( selected_service = st.selectbox(
'Select Service', 'Select Service',
service_options.tolist() service_options.tolist()
) )
# Extract service_ID from selected option
selected_service_id = int(selected_service.split(' - ')[0]) selected_service_id = int(selected_service.split(' - ')[0])
# Convert date range to datetime objects # Convert date range to datetime objects
min_date = initial_date_range['min_date'][0] min_date = initial_date_range['min_date'][0]
max_date = initial_date_range['max_date'][0] max_date = initial_date_range['max_date'][0]
# Generate month options for dropdown min_date = (date.today().replace(day=1) - timedelta(days=1)).replace(day=1)
month_options = generate_month_range(min_date, max_date) start_date = st.date_input('Start Date', min_date)
end_date = st.date_input('End Date', initial_date_range['max_date'][0])
# Add dropdown for start and end months
start_month = st.selectbox('Start Month', month_options)
end_month = st.selectbox('End Month', month_options, index=len(month_options) - 1)
# Convert 'YYYY-MM' to 'YYYY-MM-DD' format for SQL query
start_date = datetime.strptime(start_month, '%Y-%m').date().replace(day=1)
end_date = datetime.strptime(end_month, '%Y-%m').date().replace(day=1)
end_date = (end_date.replace(day=28) + pd.DateOffset(days=4)).replace(day=1) - pd.DateOffset(days=1) # last day of the month
# Add a button to apply filters
if st.button('Apply Filters'): if st.button('Apply Filters'):
# Fetch filtered data from the database # Fetch filtered data from the database
filtered_data = get_filtered_data(selected_customer_id, selected_service_id, start_date, end_date) filtered_data = get_filtered_data(selected_customer_id, selected_service_id, start_date, end_date)
# Sort the data by month # Fetch max user count in the selected range
filtered_data = filtered_data.sort_values('month') max_count = get_active_users(selected_customer_id, selected_service_id, start_date, end_date)
# Sort the data by day
filtered_data = filtered_data.sort_values('day')
# Create a bar chart with the filtered data
if not filtered_data.empty: if not filtered_data.empty:
st.bar_chart(filtered_data.set_index('month')['count']) # Highlight the max value in the chart
filtered_data['color'] = filtered_data['count'].apply(lambda x: 'red' if x == max_count else 'steelblue')
# Create an Altair bar chart
bars = alt.Chart(filtered_data).mark_bar().encode(
x='day:O',
y='count:Q',
color=alt.Color('color:N', scale=None, legend=None)
)
# Add text labels to bars
text = bars.mark_text(
align='center',
baseline='middle',
dy=-10
).encode(
text='count:Q'
)
# Combine bars and text into a single chart
chart = (bars + text).properties(
title='User Enabled'
)
# Fetch the data for users not online, online, and active users
not_user_online, max_count_user_not_online = get_user_not_online(selected_customer_id, selected_service_id, start_date, end_date)
user_online, user_online_count = get_user_online(selected_customer_id, selected_service_id, start_date, end_date)
active_users_data, user_active_count = get_active_users(selected_customer_id, selected_service_id, min_date, end_date)
# Create three columns for each DataFrame
col1, col2, col3, col4, col5 = st.columns([2,2,2,2,2])
# Display each DataFrame in a separate column
# with col4:
# st.subheader(f"{selected_service.split(' - ')[1]} - User not Online")
# st.metric(label="1",label_visibility="hidden", value=max_count_user_not_online)
# st.data_editor(not_user_online['username'],key="2",use_container_width=True, hide_index=True)
with col2:
st.subheader(f"{selected_service.split(' - ')[1]} - Enabled Users")
st.metric(label="1",label_visibility="hidden", value=user_active_count)
st.data_editor(active_users_data, hide_index=True)
with col3:
st.subheader(f"{selected_service.split(' - ')[1]} - User Online")
st.metric(label="1",label_visibility="hidden", value=user_online_count)
st.data_editor(user_online,key=2,hide_index=True)
st.altair_chart(chart, use_container_width=True)
else: else:
st.write("No data available for the selected filters.") st.write("No data available for the selected filters.")
+2 -2
View File
@@ -20,7 +20,7 @@ def get_filtered_users(customer_id, start_date, end_date):
# Prepare the base query with date filter # Prepare the base query with date filter
query = f""" query = f"""
SELECT number, title, createdate, time FROM Kunden.tickets SELECT number, title, createdate, time FROM Kunden.tickets
WHERE createdate BETWEEN '{start_date}' AND '{end_date}' WHERE closedate BETWEEN '{start_date}' AND '{end_date}'
""" """
if customer_id: if customer_id:
query += f" AND customer_ID = {customer_id}" query += f" AND customer_ID = {customer_id}"
@@ -149,4 +149,4 @@ def ticket_filter():
st.write("No data available for the selected filters.") st.write("No data available for the selected filters.")
if __name__ == "__main__": if __name__ == "__main__":
ticket_filter() ticket_filter()
+1
View File
@@ -0,0 +1 @@
streamlit run app.py --server.port=80 --server.address=0.0.0.0
+16
View File
@@ -32,4 +32,20 @@
} }
.st-d7 , .st-d6 ,.st-d5 ,.st-d4 { .st-d7 , .st-d6 ,.st-d5 ,.st-d4 {
border-color: #fcbb2e; border-color: #fcbb2e;
}
.st-emotion-cache-1gwvy71{
padding: 0;
padding-left: 30px;
}
.e1f1d6gn4 > .stButton > button{
width: 100%;
justify-content: left;
border: 0;
}
[data-testid="baseButton-secondary"]:focus{
background-color: #f4f3f366 !important;
}
[data-testid="baseButton-secondary"]:active{
background-color: #f4f3f366!important;
} }