4ALXHBHZXTYWDOOGJDQV372JOYHA6LLYML72PVLFBSSML2S6226AC KHY2ARKUYXO75YYVSPSBTL6PKWSMLSZINJ5UI4WRNXZUA7K3BS5AC 34IHEUGYMZX2SRKNIPWU773ZRYOI37SJHVWHIIEJXU7LETQMP5KAC MD3YZL7UZVMXUQM2ZLAQ2IQGYL4BY7ZBAQHZJJ6KXMH4HKG2EQAQC VKL4K7RIU44ELZLG3LGWMKODNVJMVZ5GGDITMPE4Z2TTQGXCVJBAC RNHBTG23XBZEWM6W6ZBQGLDUMGH74NKUORUEATD2Y4AQY4QXXCVAC KWAFRWDXIDNGRJRDC6WIT2QUGAYOBCPEM5UTTZBY7ES5HBA6EKYAC WA74Q2QVFYL5CA4ZZKAKQVSHCCM6IGFPH77WGJ2E67W37QM76SWQC 4GHSW2JXIZSWPV2TP76W347AUA5MLIRKESVQEWVKWAGKFEFA52PAC TQPQVWNKJLT43UDQN2I4AXWXUMGSAS7XE52SFONZO2PPYII3TFTQC CSVKQAZKZCZM5X6WT23IYD62XNLH5LF6DD3FO47QLJR7JI775KNAC TR5I4JERWQG64Z2IEB4Q2BXLDNUEG6FFZVBQM4VU46OXKE75TBBQC BDHZ3KKWECPDK4K2AIJK24OCMBTNRMHI2HZEZ7QCVD4PCRFKYIZQC U2P5JVQUPDUSY2CJYAV6TRUT2MXOEMVZOTHRN2VF4PHHQYR7WKEQC NQQINJY7GYQBCMVMSVVNOHHDZRSXDB4H7QYK2RHC7SD66L7RODWQC RD7LCMKKGBJSAN6SCXO53NFOQU5FDD4NIZYPFZC4RCULGANUJGVAC 5HWKQX4YXODU2TSA6MU34B7RXHTWI5EJFVTWZ43XCZ3YYYICN3XAC GYPIIYFUROH3LPEJG6OMJWOSP57LKK3L4W3H4TSAXI32IO7UCO2AC PVDK3SJ75IKLO5M4WH6Y5EOKP4I5PSQBUKJWA5K25HRO7HI536EQC W3HTM6XGFE34AW5PWARJQGV3AJWDPAUCOLCNBT3GLAI3D3LKGIBQC EQIWOLEXQ4O3HFP6EO2QB4P742HIT4WNE3RVJQ5QQEI2IV4GLCPQC EQCMGJEKUGG7YS3SLE6FZTHSNK56UKAAZPN6IXILYCV7DPA3JIRQC 6E5ZZNS5HEZY3INKALW5PFER26K7H7HNVALBCNPE34KQPWRDOLZQC OICRTIO2PV674BF7JURYTYK3H4NQVCCNUQT5LSVFWEEISQ5BBB4AC MOKNJOQUECVWSOWUUHEGKQQQYF37DHG7GCLWSUGVTLTTUOJVISCQC 6LWK5RUG2KZTPZ2EJGRHEJC3FMHNJIRDFG323W2ZO7EKFQQFINQAC LY233NXOGRAT5I6L5XG6JGM6SJQWYXIIAFMTHJRQFFB7XF6AH66QC E34UETQNFDAZHATHEMF4HBUYJ4673XUUPQ3FU2HD2WUYFWO5WOUAC UEMLM7XK4TAKNYTPVOIVUIVHAGM3WQ43UZS5RXXX737HMC56OVSQC HUJVDCG2M44OTZECFKRC4BKZJLJM6R6GU3EYTU2PWNH7HDTSWP6AC QUBL4AG3IUUZG4SRXYXA25FW75TPLCU2YUK7YT2PUD5HVRSOYSSAC NB466DF6BIGPDGOIRKCIX42O3OIEQPNPO4S2P3BJU5RMEMQNPMHAC XZJAOJPGTOZ4MB4SWMFJ7TYDZK2W3NIMG2EIEKJQOCGJ6XCMNX2AC 5VSG7G63HWGMPIZOWXKA5XIQOZ7J3UW52RHEKRNEXUH24B6SJXSAC AIBL5IE7MJXIB5LWNZXD6WNDJIFSAVWD2HWQZEGQC4FEMUTMAVMAC OWXXPSZW3TRTD3EPQSATDXZQRSILYGHFEA32S3XKXOIJPZCAMQ2QC SVZFNBSJ2QJH2ONX3RXOUZCQ3KI2JFEF4JC33EXAQ3BLD2WS4VKAC LOCMOE3QUIQX5EOEDEDQDUQTQBSXXW4HFF32S6F5ZAF5472EQYWAC LVPJOZYR54LG23EJXU4TSTUMK3IYYEYYD5AYHEUJMQXUKIZ6KHFAC M7GEEQZA7MEVVBT2G4WFKZ7THPVM3ML3MVWHBK5DZ5JBVJCL4CSAC MHPV54KKZKPXM66QN2OS4WI25EAHHNRWK55EDRLMILCF3MV7XRXQC QHP6Q5AHX4IB67KPRSSAMCLGQR2ACXYJZGTT5RC27DXZBWABG5GAC XWXPGIBXLORUWSDDEODRPOFNMZIRUBZSNRQZFOS2OPPIEPWNDJMAC RHMSH2FVQJW47BRJG4WJOIOQIZG7PAHCGCRJ6ZXT67Y65HXUN6SQC 5C2EAUHZCRZ2G64VJHE7YTWM46UQEA737JEUWPCUAR3CZO457KAAC GR7IV5CXNF27F6VJR2QMES6YVPZBOBY7DM5YLVZOUR4WBJJFQOOQC P2BD4T32HSFGKLD2B3RYZSE7A4BFZZ2R4ZCAMJV3KJ4PE2VNHFXAC PY5U7GCBFAZ6H244URZW35TTLDMTLPS6HCH74L5L3H6B5T6NZ7NAC QCDC4VNJGOGRQWS6ARTAYZHC2NG5S6W57DRLCEL27AGH4FT6CN7QC YUVERMAI2KMVBH22HXBU64C6U36WN2KMVZKQ6C5O3IEB4JFB3X2AC HVOGLDAD5AL6LNIVN7M4TUG5AHMZ7KQH263JOQBQZJRKZNWRNKMQC ADIPROSPCJXQWZJNWKP7XGNXYQPGSNYHKOB4XFHHTN5FJNRXTPQQC TGG2WOHYGD7T4CBVTJXQYCHNAEKRZ3QY43344N5BLH3Y3P5PC2GQC import osimport sysimport dashimport dash_core_components as dccimport dash_html_components as htmlimport plotly.graph_objects as gosys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']app = dash.Dash(__name__, external_stylesheets=external_stylesheets)from dash_app.knowledge_base.last_activity import last_recorded_activityfrom dash_app.knowledge_base.backmarket_work_analysis import get_bm_start_times_graph_datalast_activity = last_recorded_activity()bm_start_time_graph = get_bm_start_times_graph_data()colors = {'background': '#111111','text': '#7FDBFF'}app.layout = html.Div(style={'backgroundColor': colors['background']}, children=[html.H1(children='Hello Dash',style={'textAlign': 'center','color': colors['text']}),html.Div(children='Dash: A web application framework for Python.', style={'textAlign': 'center','color': colors['text']}),html.Div(f"""Currently working on {last_activity["project"]}""", style={'textAlign': 'center', 'color': colors['text']}),html.Div(f"""It started on {last_activity["start_time"]}""", style={'textAlign': 'center', 'color': colors['text']}),html.Div(f"""end_date is {last_activity["end_time"]}""", style={'textAlign': 'center', 'color': colors['text']}),dcc.Graph(id='backmarket-analysis-1',figure={'data': [{'x': bm_start_time_graph[0], 'y': bm_start_time_graph[1]}]})])if __name__ == '__main__':app.run_server(debug=True)
import osfrom pymongo import MongoClientclass DBManager:def __init__(self):self.connection = MongoClient(os.getenv("MONGODB_URI"))if os.getenv("MONGODB_URI"):# This covers the case where DB name is provided in the URIself.db = self.connection.get_database()else:self.db = self.connection.ptcself.projects_collection = self.db['projects']def projects(self):return self.projects_collection.find()@staticmethoddef serialize_log(log):start = log["start"]hour, minute, second = start.split(":")if len(hour) == 1:hour = "0" + hourif len(minute) == 1:minute = "0" + minuteif len(second) == 1:second = "0" + secondlog["start"] = f"{hour}:{minute}:{second}"from datetime import datetime, timedeltastart_time = datetime.fromisoformat("{}T{}".format(log["date"], log.pop("start")))log["start_time"] = start_timeif log["end"] == "Not yet.":log["end_time"] = Nonereturnhour, minute, second = log["end"].split(":")if len(hour) == 1:hour = "0" + hourif len(minute) == 1:minute = "0" + minuteif len(second) == 1:second = "0" + secondlog["end"] = f"{hour}:{minute}:{second}"end_time = datetime.fromisoformat("{}T{}".format(log["date"], log.pop("end")))if end_time < start_time:end_time += timedelta(days=1)log["end_time"] = end_timedef logs(self):logs = []for project in self.projects():for log in project["logs"]:log["project"] = project["name"]logs.extend(project["logs"])for log in logs:self.serialize_log(log)return logsdb_manager = DBManager()
"""This file provides the following functionality- Data analysis for day vs backmarket work start time"""from dash_app.engine import db_managerfrom datetime import datedef get_bm_start_times_graph_data():logs = db_manager.logs()logs = [log for log in logs if log["project"] == "backmarket"] # Only backmarket projectsfor log in logs:log.update({"day": date.fromisoformat(log["date"]), "start_time": log["start_time"].time().hour})# logs = [log for log in logs if log["day"].month == 10]logs = [log for log in logs if 6 <= log["start_time"] <= 15]logs_as_dict = {}for log in logs:if log["day"] not in logs_as_dict:logs_as_dict[log["day"]] = log["start_time"]continueif log["start_time"] < logs_as_dict[log["day"]]:logs_as_dict[log["day"]] = log["start_time"]return list(logs_as_dict.keys()), list(logs_as_dict.values())
from datetime import datetimefrom ..engine import db_managerdef last_recorded_activity():logs = db_manager.logs()logs = sorted(logs, key=lambda log: log["start_time"])return logs[-1]
import osfrom pymongo import MongoClientfrom app.fms import FileManagerclass ProjectsMongoSynchronizer:def __init__(self):self.connection = MongoClient(os.getenv("MONGODB_URI"))if os.getenv("MONGODB_URI"):# This covers the case where DB name is provided in the URIself.db = self.connection.get_database()else:self.db = self.connection.ptc# self.users_collection = self.db['User']self.projects_collection = self.db['projects']def synchronize(self):projects = FileManager.read('projects')projects = [project for project in projects if not projects[project].get('archived')]for project in projects:self.sync_project_data(project)def sync_project_data(self, project_name):updated_logs = FileManager.read('logs/{}'.format(project_name))if not self.projects_collection.count_documents({"name": project_name}):print(f"Adding new project.. {project_name}")return self.projects_collection.insert({"name": project_name,"logs": updated_logs})print(f"Updating existing project.. {project_name}")return self.projects_collection.update({"name": project_name}, {"logs": updated_logs})
Name: File Management System.Details:import jsonp_file.seek(0)p_file.truncate()p_file.write(simplejson.dumps(objects, indent=4))@staticmethoddef update(file_name, objects, mode='r+'):with open('data/' + file_name + '.json', mode) as p_file:objects = json.load(p_file)return objects@staticmethoddef read(file_name: str):with open(BASE_DIR + '/data/' + file_name + '.json', 'r') as p_file:class FileManager(object):"""File manager to read or write to files with Json objects."""import simplejsonfrom .settings import BASE_DIRthis file should implement A manager class for reading, writing to/from files.Author:Zee93""""""
class Log(object):def __init__(self, start, end=None):self.start = Time()self.start.set_string(start)self.end = Time()self.set_string(end)def stop(self):self.end.set_current_time()self.date = "00/00/00"from .p_time import Time
# handles timeimport timeclass Time(object):def set_string(self, string):if string is None:t = list(map(int, string.split(":")))self.seconds = t[2]self.minutes = t[1]self.hours = t[0]def __str__(self):return "{}:{}:{}".format(self.hours, self.minutes, self.seconds)def set_seconds(self, seconds):self.seconds = seconds % 60def get_seconds(self):def log_time(log):if log is None:print("No logs for this day")return 0start = Time(str_time=log['start'])end = Time(str_time=log['end'])end.minues(start)return enddef greater_than(self, time):return self.get_seconds() > time.get_seconds()@staticmethod# 'yyyy-mm-dd'return str(datetime.now().date())@staticmethoddef date():def minues(self, before):if self.greater_than(before): # before midnightseconds = abs(self.get_seconds() - before.get_seconds())return self.set_seconds(seconds)else: # after midnightbefore_midnight = Time('24:00:00').minues(before)return self.add_time(before_midnight)def add_time(self, t):return self.set_seconds(self.get_seconds() + t.get_seconds())return self.hours * 3600 + self.minutes * 60 + self.secondsreturn selfself.hours = int(seconds / 3600)self.minutes = int(seconds / 60) - self.hours * 60return 0if string.startswith('Not'):string = time.ctime().split()[-2]# print("WARNING: you have an unclosed time log.")# print("This is you total time so far.")has 3 distinct attributes Hour, Minute, Second.Every new method or modification on old methods must work on them asdef __init__(self, str_time=None, sec_time=None):if str_time:self.set_string(str_time)elif sec_time or sec_time == 0:self.set_seconds(sec_time)else:self.set_string(time.ctime().split()[-2])the main properties that define the object.""""""from datetime import datetime
Name: Project Management System.Details:## this file should implement A manager class for reading, writing and deleting to/from projects file.## Also it should convert the extracted information to the proper type.## the operations that should be implemented are CRUD "Create - Read - Update - Delete"Author: Zee93import jsonimport simplejsonfrom .settings import BASE_DIRreturn projects@staticmethoddef update(projects, file_name='projects'):with open(BASE_DIR + '/data/' + file_name + '.json', 'r+') as projects_file:projects_file.seek(0)projects_file.truncate()projects_file.write(simplejson.dumps(projects, indent=4))@staticmethoddef read(file_name='projects'):with open(BASE_DIR + '/data/' + file_name + '.json', 'r+') as projects_file:projects = json.load(projects_file)class ProjectsManager:""""""
import jsonimport gspread as gsfrom oauth2client.client import SignedJwtAssertionCredentialsfrom calendar import month_namedef upload_to_spread_sheet(p_name, spreadsheet, month, cells_time): # cells_time= {cells_row: time}print("Syncing: \n" + str(cells_time) + "...")json_key = json.load(open('cred-ptc.json'))credentials = SignedJwtAssertionCredentials(json_key['client_email'],bytes(json_key['private_key'], 'utf-8'),json_key['scope'])print('Authenticating....')gc = gs.authorize(credentials)print('opening your sheet...')sheet = gc.open(spreadsheet)month_sheet = sheet.worksheet(month_name[month])rows_left = len(cells_time)for (row, value) in cells_time.items():print("Writing value in row number: " + row)print(str(rows_left) + " items left.")rows_left -= 1# update startmonth_sheet.update_acell('B' + row, '00:00:00')# update endmonth_sheet.update_acell('c' + row, value)print('finished writing')
#!/usr/bin/env python3import sysif __name__ == "__main__":execute_from_command_line(sys.argv[1:])from execute import execute_from_command_line# Projects Time Control
print("Creating project...")print("Happy coding...")start_timer_on_project(*args)print("your projects are: " + str(list_projects()))return get_time_for_certain_day(*args)print(Time.date())try:try:except:except:return sync()return get_status()elif action == "sync_mongodb":return sync_to_mongo_db()elif action == "status":elif action == "sync":return get_total_monthly_time_on_project(args[0])return get_total_monthly_time_on_project(args[0], month)year = int(args[2])return get_total_monthly_time_on_project(args[0], month, year)month = int(args[1])elif action == "month_time_for":else:print("Wrong Command")elif action == "date":elif action == "yesterday_time_for":date = datetime.date.today() - datetime.timedelta(days=1)return get_time_for_certain_day(args[0], date=str(date))elif action == "total_time_for":print(get_total_time_for_project(args[0]))elif action == "draw":total_time_for_all_projects()elif action == "today_time_for":elif action == "list":elif action == "stop":print("Stopping timer...")stop_timer_on_project(*args)elif action == "start":create_project(*args)def list_projects():def get_time_for_certain_day(p_name, date=Time.date()):print(total_time)if action == "createp":def execute_from_command_line(args):action = args.pop(0)def sync_to_mongo_db():from app.sync_to_mongo import ProjectsMongoSynchronizerengine = ProjectsMongoSynchronizer()engine.synchronize()return str(total_time)all_logs = FileManager.read('logs/{}'.format(p_name))int(log.get('date').split('-')[1]) == 6])cells_time = {}for day_date in month_days:cell_row = str(int(day_date.split('-')[2]) + 1) # we start from 2 not 1cells_time.update({cell_row: get_time_for_certain_day(p_name, date=day_date)})# return upload_to_spread_sheet(p_name=p_name, spreadsheet=spreadsheet, month=month, cells_time=cells_time)return 0month_days = set([log['date'] for log in all_logs if log.get('date', None) anddef sync(p_name='cube', spreadsheet='WorkSheet', month=datetime.date.month):all_logs = FileManager.read('logs/{}'.format(p_name))day_logs = [log for log in all_logs if log.get('date', None) == date]total_time = Time(sec_time=sum([Time.log_time(log).get_seconds() for log in day_logs]))print(total_time)return str(total_time)all_logs = FileManager.read('logs/{}'.format(p_name))total_time = Time(sec_time=sum([Time.log_time(log).get_seconds() for log in month_logs]))month_logs = [log for log in all_logs if log.get('date', None) andint(log.get('date').split('-')[1]) == month] # filtered by monthmonth_logs = [log for log in month_logs if log.get('date', None) and int(log.get('date').split('-')[0]) == year]def get_total_time_for_project(project_name):all_logs = FileManager.read('logs/{}'.format(project_name))total_time = Time(sec_time=sum([Time.log_time(log).get_seconds() for log in all_logs]))average_per_log = str(total_time.hours / (len(all_logs) or 1))[:4]return "{} - with average per log: {} - number of logs: {}".format(total_time, average_per_log, len(all_logs))def total_time_for_all_projects():print("Project: Total time")for project in list_projects():print("{}: {}".format(project, get_total_time_for_project(project)))total_time = Nonefor project in list_projects():project_time = Time(sec_time=sum([Time.log_time(log).get_seconds() for log in FileManager.read('logs/{}'.format(project))]))if not total_time:total_time = project_timeelse:total_time.add_time(project_time)print("total user recorded time: {}".format(total_time))def get_total_monthly_time_on_project(p_name, month=datetime.date.today().month, year=datetime.date.today().year):projects = FileManager.read('projects')return [project for project in projects if not projects[project].get('archived')]# GET PROJECT NAME.# UPDATE THE LOG.# CHANGE PROJECT STATE TO OFF.projects = FileManager.read('projects')# ADD THE ELAPSED TIME.total_time.add_time(elapsed_time)print("Elapsed time: " + str(elapsed_time))FileManager.update('projects', projects)current_project["total_spent_time"] = str(total_time)projects[p_name] = current_projecttotal_time = Time(str_time=current_project["total_spent_time"])current_project = projects.get(p_name)current_project["state"] = "OFF"logs = FileManager.read('logs/{}'.format(p_name))if logs[-1]["end"] != "Not yet.":logs[-1]["end"] = str(now)FileManager.update('logs/{}'.format(p_name), logs)start = Time()start.set_string(logs[-1]["start"])now.minues(start)elapsed_time = nowprint("Error. Either you don't have a running log or the program is writing on the wrong log instance.")returnsettings = FileManager.read('settings')p_name = settings["working on"]def stop_timer_on_project(time=None):print("stopping Time: " + str(now))now = Time(str_time=time) if time else Time()# START LOG TIME# put the project in workon in the settings file.settings["working on"] = p_nameFileManager.update('settings', settings)settings = FileManager.read('settings')logs = FileManager.read('logs/{}'.format(p_name))FileManager.update('logs/{}'.format(p_name), logs)logs.append({'start': str(now), 'end': 'Not yet.', 'date': Time.date()})# CHANGE PROJECT STATE TO ONprojects = FileManager.read('projects')print("We don't have a project with this name dear.")projects.get(p_name)["state"] = "ON"FileManager.update('projects', projects)returnif not projects.get(p_name):def get_status():settings = FileManager.read('settings')project_name = settings['working on']projects = FileManager.read('projects')status = projects.get(project_name)["state"]print('last project: {} and its status: {}'.format(project_name, status))def start_timer_on_project(p_name, time=None):if time:now = Time(str_time=time)else:now = Time()print("Time now: {}".format(now))def create_project(p_name, details='', p_estimatedtime="Unknown"):project = {'estimated time': p_estimatedtime,'details': details,}print('project created.')projects = FileManager.read('projects')projects.update({p_name: project})FileManager.update('logs/{}'.format(p_name), [], mode='w')FileManager.update('projects', projects)'state': 'OFF','total_spent_time': "0:0:0"import osimport sys# from spread import upload_to_spread_sheetimport datetimefrom app.fms import FileManagerfrom app.p_time import Timesys.path.append(os.path.dirname(os.path.abspath(__file__)))