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
|
import {
AGGIETIME_URI,
AGGIETIME_DOMAIN,
USER_PATH,
USER_CACHE_EXP_SEC,
CLOCKIN_PATH,
CLOCKOUT_PATH,
OPEN_SHIFT_PATH,
OPEN_SHIFT_EXP_SEC,
} from "./constants.js";
import { with_exponential_retry } from "./exponential_retry.js";
import { client } from "./axios_client.js";
import expireCache from "expire-cache";
const aggietime = client.create({
baseURL: AGGIETIME_URI,
});
const replace_path_args = (path, map) =>
path.replaceAll(/:([a-zA-Z0-9_]+)/g, (_, key) => map[key]);
const get_user_position_or_specified = async (position_id) => {
const { positions } = await get_user_info();
if (position_id === undefined && positions.length != 1) {
throw "Must specify a position when there's not only one to choose from";
} else if (position_id === undefined) {
return positions[0];
}
return position_id;
};
export const get_user_info = async () => {
if (!expireCache.get("user")) {
const user = await with_exponential_retry(() =>
aggietime.get(USER_PATH).then(({ data, config }) => {
const csrf_token = config.jar
.toJSON()
.cookies.find(
({ domain, key }) =>
domain === AGGIETIME_DOMAIN && key === "XSRF-TOKEN"
).value;
expireCache.set("aggietime-csrf", csrf_token);
return data;
})
);
expireCache.set("user", user, USER_CACHE_EXP_SEC);
}
return expireCache.get("user");
};
const do_clock_mutation = async (path, { position_id } = {}) => {
position_id = await get_user_position_or_specified(position_id);
return await aggietime
.post(
replace_path_args(path, { position_id }),
{
comment: "",
},
{
headers: {
"X-XSRF-TOKEN": expireCache.get("aggietime-csrf"),
},
}
)
.then(({ data }) => {
expireCache.remove("status_line");
return data;
});
};
// Actions
export const clock_in = async (rest) => do_clock_mutation(CLOCKIN_PATH, rest);
export const clock_out = async (rest) => do_clock_mutation(CLOCKOUT_PATH, rest);
export const current_shift = async () => {
const req_path = replace_path_args(OPEN_SHIFT_PATH, await get_user_info());
const {
request: {
res: { responseUrl: response_url },
},
data,
} = await aggietime.get(req_path);
if (`${AGGIETIME_URI}/${req_path}` != response_url) {
// IMO a very weird decision - when there is no open shift the api redirects
// home instead of sending back a 404 or something actually *reasonable* :3
return null;
}
return data;
};
export const get_status_line = async () => {
if (!expireCache.get("status_line")) {
const { anumber } = await get_user_info();
const shift = await current_shift();
let status_line = "No Shift";
if (shift && shift?.start) {
const start = new Date(shift?.start);
status_line =
((new Date().getTime() - start.getTime()) / (1000 * 60 * 60)).toFixed(
2
) + " hours";
}
expireCache.set(
"status_line",
`${anumber} - ${status_line}`,
OPEN_SHIFT_EXP_SEC
);
}
return { status: expireCache.get("status_line") };
};
|