-
Notifications
You must be signed in to change notification settings - Fork 0
/
admin_tiles_per_member.py
173 lines (154 loc) · 6.41 KB
/
admin_tiles_per_member.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
import sys
import logging
from datetime import datetime
from operator import itemgetter
from math import ceil, inf
from exiles_api import db_date, session, TilesManager, MembersManager, OwnersCache
from google_api.sheets import Spreadsheet
from logger import get_logger
from config import (
ADMIN_SPREADSHEET_ID, ADMIN_TPM_SHEET_ID, BUILDING_TILE_MULT, PLACEBALE_TILE_MULT,
INACTIVITY, RUINS_CLAN_ID, ALLOWANCE_INCLUDES_INACTIVES, LOG_LEVEL_STDOUT, LOG_LEVEL_FILE
)
# catch unhandled exceptions
logger = get_logger('admin_tiles_per_member.log', log_level_stdout=LOG_LEVEL_STDOUT, log_level_file=LOG_LEVEL_FILE)
def handle_exception(exc_type, exc_value, exc_traceback):
if issubclass(exc_type, KeyboardInterrupt):
sys.__excepthook__(exc_type, exc_value, exc_traceback)
return
logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
sys.excepthook = handle_exception
# save current time
now = datetime.utcnow()
if LOG_LEVEL_STDOUT > logging.INFO:
print("Updating tiles per member sheet...")
logger.info("Updating tiles per member sheet...")
# estimate db age by reading the last_login date of the first character in the characters table
if dbAge := db_date():
dbAgeStr = "Database Date: " + dbAge.strftime("%d-%b-%Y %H:%M UTC")
else:
execTime = datetime.utcnow() - now
execTimeStr = str(execTime.seconds) + "." + str(execTime.microseconds)
logger.info(f"Found no characters in db!\nRequired time: {execTimeStr} sec.")
sys.exit(0)
# instanciate the Spreadsheet object
sheets = Spreadsheet(ADMIN_SPREADSHEET_ID, activeSheetId=ADMIN_TPM_SHEET_ID)
# Create a new list of values to add to the sheet
date_str = now.strftime("%d-%b-%Y %H:%M UTC")
values = []
logger.debug("Gather tiles statistics.")
tiles = TilesManager.get_tiles_consolidated(BUILDING_TILE_MULT, PLACEBALE_TILE_MULT)
logger.debug("Gather member statistics.")
members = MembersManager.get_members(INACTIVITY)
logger.debug("Compile tiles per member data.")
for object_id, ctd in tiles.items():
# owner_id 0 is a game reserved id and can be ignored
if ctd['owner_id'] == 0:
continue
# ensure that owner_id is in members
if ctd['owner_id'] in members:
name = members[ctd['owner_id']]['name']
if name == 'Ruins' and ctd['owner_id'] != RUINS_CLAN_ID:
owner = session.query(OwnersCache).get(ctd['owner_id'])
if owner:
name = owner.name + " (Ruins)"
else:
logger.error("Object without owner! Should be moved to dedicated Ruins clan by ruins script.")
logger.error(f"object_id: {object_id} / contents: {ctd}")
logger.error("Skipping object")
continue
if ALLOWANCE_INCLUDES_INACTIVES:
num_members = num_members_str = members[ctd['owner_id']]['numMembers']
else:
num_members = members[ctd['owner_id']]['numActiveMembers']
num_members_str = f"({num_members} / {members[ctd['owner_id']]['numMembers']})"
if num_members > 0:
tpm = round(ctd['sum_tiles'] / num_members)
else:
tpm = inf
location = f"TeleportPlayer {ceil(ctd['x'])} {ceil(ctd['y'])} {ceil(ctd['z'])}"
values.append([
object_id,
name,
ctd['owner_id'],
ctd['building_pieces'],
ctd['placeables'],
num_members_str,
tpm,
ctd['class'],
location]
)
# sort the values by tiles in descending order
logger.debug("Sort values for upload.")
values.sort(key=itemgetter(4), reverse=True)
values.sort(key=itemgetter(3), reverse=True)
values.sort(key=itemgetter(2))
values.sort(key=itemgetter(6), reverse=True)
# generate the headlines and add them to the values list
columnTwoHeader = "Members" if ALLOWANCE_INCLUDES_INACTIVES else "Members (active / total)"
values = [
['Last Upload: ' + date_str, '', dbAgeStr],
[
'Object ID',
'Owner Names',
'Owner ID',
'Building pieces',
'Placeables',
columnTwoHeader,
'Tiles per member',
'Item Class',
'Location'
]
] + values
logger.debug("Format and upload data to tiles per member sheet.")
# set the gridsize so it fits in all the values including the two headlines
lastRow = len(values)
sheets.set_grid_size(cols=9, rows=lastRow, frozen=2)
# ungroup everything
sheets.delete_dimension_group()
sheets.set_visibility(hidden=False)
# replace inf for first row
if values[2][6] == inf:
values[2][6] = '∞'
# initialize some loop vars
prev_id = values[2][2]
prev_row = 2
multiline = False
# re-group by owner_ids
for row in range(3, lastRow):
# compare owner_id with that of last row(s)
if values[row][2] == prev_id:
multiline = True
else:
if multiline:
sheets.set_dimension_group(startIndex=prev_row + 1, endIndex=row, hidden=True)
multiline = False
prev_id = values[row][2]
prev_row = row
# replace all occurrences of math.inf with ∞
if values[row][6] == inf:
values[row][6] = '∞'
# ensure that last row is being grouped too if applicable
if multiline:
sheets.set_dimension_group(startIndex=prev_row + 1, hidden=True)
# set a basic filter starting from the second headline going up to the last row
sheets.set_filter(startRowIndex=2)
# merge the cells of the first headline
sheets.merge_cells(endRowIndex=1, endColumnIndex=2)
sheets.merge_cells(startColumnIndex=3, endColumnIndex=5, endRowIndex=1)
# format the datalines
sheets.set_alignment(startRowIndex=3, endColumnIndex=3, horizontalAlignment='LEFT')
sheets.set_alignment(startRowIndex=3, startColumnIndex=4, endColumnIndex=5, horizontalAlignment='RIGHT')
sheets.set_alignment(startRowIndex=3, startColumnIndex=6, endColumnIndex=6, horizontalAlignment='CENTER')
sheets.set_alignment(startRowIndex=3, startColumnIndex=7, endColumnIndex=7, horizontalAlignment='RIGHT')
sheets.set_alignment(startRowIndex=3, startColumnIndex=8, endColumnIndex=9, horizontalAlignment='LEFT')
sheets.set_format(startColumnIndex=4, endColumnIndex=5, startRowIndex=3, type='NUMBER', pattern='#,##0.00')
sheets.set_format(startColumnIndex=7, endColumnIndex=7, startRowIndex=3, type='NUMBER', pattern='#,##0')
# update the cells with the values
sheets.commit()
sheets.update('Tiles per member!A1:I' + str(lastRow), values)
execTime = datetime.utcnow() - now
execTimeStr = str(execTime.seconds) + "." + str(execTime.microseconds)
if LOG_LEVEL_STDOUT > logging.INFO:
print(f"Done! Required time: {execTimeStr} sec.")
logger.info(f"Done! Required time: {execTimeStr} sec.")