Advertisement
mrnosuch

member-career

May 9th, 2024
706
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 11.63 KB | Gaming | 0 0
  1. # -*- coding: utf-8 -*-
  2.  
  3. # Python 3
  4.  
  5. import os
  6. import sys
  7. import sqlite3
  8. import bbot.discord
  9.  
  10.  
  11. SCRIPT_PATH : str      = os.path.dirname(os.path.realpath(sys.argv[0]))
  12. local_db_path :str     = "/home/pi/Scripts/blastardbot/bot.db"  ## Production
  13. # local_db_path :str     = "/home/pi/Scripts/blastardbot/bot-dev.db"  ## Development
  14.  
  15.  
  16. # Define queries
  17.  
  18. MEMBER_SELECT = '''
  19. SELECT
  20.     rosterID
  21.     clan_id,
  22.     name,
  23.     psn_id,
  24.     status,
  25.     join_date,
  26.     exit_date,
  27.     return_date,
  28.     rec_id  
  29. FROM
  30.     member
  31. WHERE
  32.     status IN ('Member','Alumni')
  33. ORDER BY
  34.     name;
  35. '''
  36.  
  37. MEMBER_CAREER_SELECT = '''
  38. SELECT
  39.     name,
  40.     psn_id,
  41.     start_date,
  42.     event,
  43.     end_date,
  44.     status,
  45.     rosterID
  46. FROM
  47.     member_career
  48. WHERE
  49.     rosterID = :rosterID;
  50. '''
  51.  
  52. CAREER_INSERT = '''
  53. INSERT INTO
  54.     career (
  55.         rosterID,
  56.         start_date,
  57.         end_date,
  58.         event,
  59.         status
  60.     )
  61. VALUES (
  62.    :rosterID,
  63.    :start_date,
  64.    :end_date,
  65.    :event,
  66.    :status
  67. )
  68. '''
  69.  
  70. CAREER_UPDATE_EXIT = '''
  71. UPDATE
  72.    career
  73. SET
  74.    end_date = :end_date,
  75.    status   = :status
  76. WHERE
  77.    rosterID = :rosterID
  78. AND
  79.    start_date = :start_date
  80. '''
  81.  
  82. CAREER_UPDATE_START = '''
  83. UPDATE
  84.    career
  85. SET
  86.    start_date = :new_start_date
  87. WHERE
  88.    rosterID = :rosterID
  89. AND
  90.    start_date = :old_start_date
  91. '''
  92.  
  93. CAREER_DELETE_RETURN = '''
  94. DELETE FROM
  95.    career
  96. WHERE
  97.    rosterID = :rosterID
  98. AND
  99.    start_date = :return_date
  100. AND
  101.    event = "Return"
  102. '''
  103.  
  104. CAREER_UPDATE_RETURN = '''
  105. UPDATE
  106.    career
  107. SET
  108.    start_date = :return_date,
  109.    status     = "Active",
  110.    event      = "Return"
  111. WHERE
  112.    rosterID = :rosterID
  113. AND
  114.    start_date = :event_date
  115. '''
  116.  
  117. CAREER_CREATE_RETURN = '''
  118. INSERT INTO
  119.    career (start_date, event, rosterID, status)
  120. VALUES (
  121.    :return_date,
  122.    'Return',
  123.    :rosterID,
  124.    'Active'
  125. )
  126. '''
  127.  
  128. # define classes
  129.  
  130. class CareerSummary():
  131.  
  132.     rosterID        = None
  133.     name            = None
  134.     missing         = True
  135.     prev_start      = None
  136.     join_date       = None
  137.     exit_date       = None
  138.     return_date     = None
  139.     status          = None
  140.     last_event      = None
  141.     event_count     = 0
  142.     last_event_date = None
  143.     career_data     = None
  144.     db              = None
  145.  
  146.     def __init__(self, db, rosterID, name):
  147.  
  148.         self.rosterID    = rosterID
  149.         self.name        = name
  150.         self.db          = db
  151.  
  152.         self.career_load()
  153.        
  154.  
  155.     def career_load(self):
  156.  
  157.         self.missing         = True
  158.         self.prev_start      = None
  159.         self.join_date       = None
  160.         self.exit_date       = None
  161.         self.return_date     = None
  162.         self.status          = None
  163.         self.last_event      = None
  164.         self.event_count     = 0
  165.         self.last_event_date = None
  166.  
  167.         self.career_data =  db_select(self.db, MEMBER_CAREER_SELECT, {'rosterID' : self.rosterID})
  168.  
  169.         if len(self.career_data) > 0:
  170.  
  171.             self.missing = False
  172.             self.event_count = len(self.career_data)
  173.             self.last_event = self.career_data[self.event_count-1]['event']
  174.             self.last_event_date = self.career_data[self.event_count-1]['start_date']
  175.             self.join_date = self.career_data[0]['start_date']
  176.             self.exit_date = self.career_data[0]['end_date']
  177.             self.status = self.career_data[self.event_count-1]['status']
  178.  
  179.             if self.event_count > 1:
  180.                 self.prev_start = self.career_data[self.event_count-2]['start_date']
  181.             else:
  182.                 self.prev_start = self.career_data[0]['start_date']
  183.  
  184.         else:
  185.             print("No career events found.")
  186.  
  187.         for career_event in self.career_data:
  188.  
  189.             if not self.exit_date:
  190.                 self.exit_date = career_event['end_date']
  191.             else:
  192.                 if career_event['end_date'] and self.exit_date < career_event['end_date']:
  193.                     self.exit_date = career_event['end_date']
  194.  
  195.             if career_event['start_date']>self.join_date and career_event['start_date']>noneToEmpty(self.return_date):
  196.                 self.return_date = career_event['start_date']
  197.  
  198.         print(self)
  199.  
  200.     def career_create(self, join_date):
  201.  
  202.         options = {
  203.             'rosterID' : self.rosterID,
  204.             'start_date' : join_date,
  205.             'end_date' : None,
  206.             'event' : 'Join',
  207.             'status' : 'Active'
  208.         }
  209.  
  210.         db_execute(self.db, CAREER_INSERT, options)
  211.         print(f"Join event on {join_date} created for {self.name} ({self.rosterID}).")
  212.  
  213.         self.career_load()
  214.  
  215.  
  216.     def join_update(self, join_date):
  217.  
  218.         options = {
  219.             'rosterID' : self.rosterID,
  220.             'old_start_date' : self.join_date,
  221.             'new_start_date' : join_date
  222.         }
  223.         db_execute(self.db, CAREER_UPDATE_START, options)
  224.         print(f"Join event update from {self.join_date} to {join_date} for {self.name} ({self.rosterID})")
  225.  
  226.         self.career_load()
  227.  
  228.  
  229.     def exit_update(self, exit_date, return_date):
  230.        
  231.         print(f"Current exit date is: {self.exit_date}")
  232.         print(f"    New exit will be: {exit_date}, return date: {return_date}")
  233.         event_date = self.last_event_date
  234.         event_status = "Alumni"
  235.  
  236.         # It's NOT possible to have a return date and NO exit date
  237.         if return_date and not exit_date:
  238.             print("Error! Return without exit!")
  239.             return
  240.  
  241.         # Possible that exit date was reverted to None
  242.         if not exit_date:
  243.             event_status = "Active"
  244.             print("Updating exit with ACTIVE status.")
  245.  
  246.        
  247.         if return_date and return_date > exit_date:
  248.             # If the return date is AFTER the exit date, the end date should be on last career event
  249.             event_date = self.prev_start
  250.    
  251.         options = {
  252.             'rosterID'   : self.rosterID,
  253.             'start_date' : event_date,
  254.             'end_date'   : exit_date,
  255.             'status'     : event_status
  256.         }
  257.  
  258.         db_execute(self.db, CAREER_UPDATE_EXIT, options)
  259.         print(f"Updating exit date to {exit_date} and status {event_status} for event starting on {event_date} for {self.name} ({self.rosterID}).")
  260.  
  261.         self.career_load()
  262.  
  263.  
  264.     def return_update(self, return_date, exit_date):
  265.  
  266.         if not return_date:
  267.  
  268.             # This will be a deletion of the last event in the career
  269.             options = {
  270.                 'rosterID' : self.rosterID,
  271.                 'return_date' : self.return_date
  272.             }            
  273.  
  274.             print(f"Removing return event from {self.name} ({self.rosterID})")
  275.             db_execute(self.db, CAREER_DELETE_RETURN, options)
  276.  
  277.         else:
  278.  
  279.             # We need to figure out if we are UPDATING a return date
  280.             # or creating a new returning event
  281.  
  282.             # If the return_date is BEFORE the exit_date, it's an update
  283.  
  284.             if (return_date < exit_date):
  285.  
  286.                 # We are updating
  287.                 options = {
  288.                     'rosterID' : self.rosterID,
  289.                     'return_date' : self.return_date,
  290.                     'event_date'  : self.last_event_date
  291.                 }  
  292.                 db_execute(self.db, CAREER_UPDATE_RETURN, options)
  293.                 print(f"Updating return date {self.return_date} for {self.name} ({self.rosterID}).")
  294.  
  295.             else:
  296.  
  297.                 # If the return date is AFTER the exit date, it's a new return event
  298.  
  299.                 # Just check status to be safe. Only an alumni can return
  300.  
  301.                 if self.status == "Alumni":
  302.                     # We are creating a new event
  303.                     options = {
  304.                         'rosterID' : self.rosterID,
  305.                         'return_date' : return_date
  306.                     }
  307.                     db_execute(self.db, CAREER_CREATE_RETURN, options)
  308.                     print(f"Creating return event on {return_date} for {self.name} ({self.rosterID}).")
  309.                 else:
  310.                     print(f"Can't add an exit event as {self.name} (self.rosterID) isn't alumni.")
  311.        
  312.         self.career_load()
  313.  
  314.     def event_sync(self, join_date, exit_date, return_date):
  315.  
  316.         if self.missing:
  317.  
  318.             # Create career if missing
  319.  
  320.             print("* No career data found. Creating...")
  321.             self.career_create(join_date)
  322.  
  323.         else:
  324.  
  325.             # Otherwise update join date if there's a difference
  326.                        
  327.             if join_date != self.join_date:
  328.                 print("* Join date mismatch. Updating join date...")
  329.                 self.join_update(join_date)
  330.  
  331.         if exit_date != self.exit_date:
  332.             print("* Exit data mismatch. Updating exit date...")
  333.             self.exit_update(exit_date, return_date)
  334.  
  335.         if return_date != self.return_date:
  336.             print("* Return date mismatch. Updating return date...")
  337.             self.return_update(return_date, exit_date)
  338.  
  339.  
  340.     def __str__(self):
  341.         return f"Career for {self.name} ({self.rosterID}) status {self.status} - join: {self.join_date}, exit: {self.exit_date}, return: {self.return_date}, events: {self.event_count}"
  342.  
  343.  
  344. # Define functions
  345.  
  346. def noneOrNull(v):
  347.  
  348.     if v is None:
  349.         return True
  350.     if len(v) is 0:
  351.         return True
  352.     return False
  353.  
  354. def noneToEmpty(v):
  355.     if v is None:
  356.         return ""
  357.     else:
  358.         return v
  359.  
  360. def emptyToNone(v):
  361.  
  362.     if v == "":
  363.         return None
  364.     return v
  365.  
  366.  
  367. def db_open():
  368.  
  369.     print("Opening database: ",local_db_path)    
  370.  
  371.     db = sqlite3.connect(local_db_path)
  372.     db.row_factory = sqlite3.Row
  373.  
  374.     return db
  375.  
  376.  
  377. def db_close(db):
  378.  
  379.     print("Closing data base.")
  380.     db.commit()
  381.     db.close()
  382.  
  383.  
  384. def db_select(db, query, options = None):
  385.  
  386.     cur = db.cursor()
  387.  
  388.     if options is not None:
  389.         rows = cur.execute(query, options).fetchall()
  390.     else:
  391.         rows = cur.execute(query).fetchall()
  392.  
  393.     data=[{k: item[k] for k in item.keys()} for item in rows]
  394.  
  395.     return data    
  396.  
  397.  
  398. def db_execute(db, query, options):
  399.  
  400.     cur = db.cursor()
  401.  
  402.     cur.execute(query, options)
  403.  
  404.     db.commit()
  405.  
  406.  
  407. def members_fetch(db):
  408.  
  409.     print("Loading all current and previous members.")
  410.  
  411.     members=db_select(db, MEMBER_SELECT)
  412.  
  413.     return members
  414.  
  415. def member_check(db, members):
  416.  
  417.     member_count = 0
  418.  
  419.     for m in members:
  420.  
  421.         member_count = member_count + 1
  422.  
  423.         # Career rows are
  424.         #   rosterID
  425.         #   start_date
  426.         #   event (Join, Return)
  427.         #   end_date
  428.         #   status (Active, Alumni)
  429.  
  430.         # Rules for career updates
  431.         #   Info in members must have:
  432.                 # join_date must be the earliest date
  433.                 # When return_date is defined:
  434.                 #   If return date is > exit_date, member is active
  435.                 #   If return date is < exit_date, member is alumni
  436.                 # exit_date must come after join_date (if it exists)
  437.         #   If the member row doesn't follow this,
  438.         #   it won't be processed as it is considered invalid.
  439.  
  440.         member_name = m['name']
  441.         rosterID    = m['clan_id']
  442.         join_date   = emptyToNone(m['join_date'])
  443.         exit_date   = emptyToNone(m['exit_date'])
  444.         return_date = emptyToNone(m['return_date'])
  445.  
  446.         print(f"===== Roster data for #{member_count}, {member_name} ({rosterID}) join: {join_date} exit: {exit_date} return: {return_date} =====")
  447.  
  448.         summary = CareerSummary(db, rosterID, member_name)
  449.         summary.event_sync(join_date, exit_date, return_date)
  450.        
  451.  
  452. #
  453. # MAIN PROCEDURE
  454. #
  455.  
  456. db = db_open()
  457.  
  458. members = members_fetch(db)
  459.  
  460. member_check(db, members)
  461.  
  462. print("\n----\n")
  463. db_close(db)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement