Compare commits
1156 Commits
master
...
release/20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cfbe6f458f | ||
|
|
a97e80baab | ||
|
|
b37108e5dd | ||
|
|
4ef591771e | ||
|
|
3311ba8dd6 | ||
|
|
007fd2ec8f | ||
|
|
5af3f44a53 | ||
|
|
e299fdc178 | ||
|
|
0811738b98 | ||
|
|
d6134e799e | ||
|
|
48e0a31cf5 | ||
|
|
f7a17b2f99 | ||
|
|
a754525a59 | ||
|
|
f2420b958d | ||
|
|
061c153061 | ||
|
|
2e4fbfc8ab | ||
|
|
60345dd21e | ||
|
|
1837b442cf | ||
|
|
df0ce7f910 | ||
|
|
1e6b9d1c18 | ||
|
|
48d9e38c39 | ||
|
|
988775b9dd | ||
|
|
329ea51487 | ||
|
|
e8322b4b1a | ||
|
|
bdd1bd2ba2 | ||
|
|
6ca79e9a02 | ||
|
|
89bf87cb62 | ||
|
|
b2ee1f2760 | ||
|
|
45ca81a3e3 | ||
|
|
c795f42290 | ||
|
|
43ac62b561 | ||
|
|
d4e46a4a97 | ||
|
|
e16fbaa34b | ||
|
|
dc7732ab5f | ||
|
|
8a22ac324c | ||
|
|
817bb80f87 | ||
|
|
ab8afb72d2 | ||
|
|
579772977b | ||
|
|
ede4cfabf0 | ||
|
|
eeb19647f5 | ||
|
|
19e64135ca | ||
|
|
a269e2a716 | ||
|
|
4d439e63a9 | ||
|
|
7db937f8af | ||
|
|
2dbf47d874 | ||
|
|
cad0d2e867 | ||
|
|
d8b0c3b0a4 | ||
|
|
9e0f94964e | ||
|
|
1bbe5cc31f | ||
|
|
b2384f2869 | ||
|
|
31fd384704 | ||
|
|
db5cf2502a | ||
|
|
68862e4545 | ||
|
|
28d5843d52 | ||
|
|
acd770962b | ||
|
|
eccd71f450 | ||
|
|
5ece1d34e3 | ||
|
|
3f276a42e1 | ||
|
|
16c79aca39 | ||
|
|
2227432970 | ||
|
|
d321b94395 | ||
|
|
f0711f27b4 | ||
|
|
34a752d455 | ||
|
|
722409de0b | ||
|
|
19a9890dd9 | ||
|
|
f9a51e243f | ||
|
|
6346d4ccd6 | ||
|
|
ed3dda6cf5 | ||
|
|
8927f07bcf | ||
|
|
5ce193d474 | ||
|
|
4b86432381 | ||
|
|
3885cc6aba | ||
|
|
812181acb5 | ||
|
|
8459b57e1b | ||
|
|
2ff211f2c2 | ||
|
|
8dc37f274f | ||
|
|
4c83e02c4a | ||
|
|
1c0922ace2 | ||
|
|
29b4d5ae4b | ||
|
|
d32304c50a | ||
|
|
46a3998fe0 | ||
|
|
765949fdfd | ||
|
|
1bcc6dae3f | ||
|
|
9ee2ed444b | ||
|
|
802c75bad9 | ||
|
|
59d5b81da0 | ||
|
|
90c6b914fa | ||
|
|
d4805ebb09 | ||
|
|
734576817c | ||
|
|
d61dd0f00e | ||
|
|
6937f9dca4 | ||
|
|
caf2868d02 | ||
|
|
cf96d93246 | ||
|
|
6d13b952c4 | ||
|
|
270712f905 | ||
|
|
7fb2f00846 | ||
|
|
c47ae47a2f | ||
|
|
75b771f87c | ||
|
|
ec4656eca9 | ||
|
|
13620a63d0 | ||
|
|
836ed97d07 | ||
|
|
6470af0a01 | ||
|
|
c33ae332e9 | ||
|
|
a6ec6d1b2b | ||
|
|
55033d0749 | ||
|
|
868a0060dc | ||
|
|
56fe7ed953 | ||
|
|
a6a5162385 | ||
|
|
b5e874bd99 | ||
|
|
d584457997 | ||
|
|
459bd89198 | ||
|
|
45f6303219 | ||
|
|
a42f32acf4 | ||
|
|
9c06b07665 | ||
|
|
552ca31603 | ||
|
|
b8a417a5d7 | ||
|
|
314a031dd1 | ||
|
|
3790983b5e | ||
|
|
872279de0b | ||
|
|
f5ab2118ad | ||
|
|
f865b1cfb7 | ||
|
|
53d252b23d | ||
|
|
09ec231303 | ||
|
|
5a4c82e4cb | ||
|
|
81af707091 | ||
|
|
bf16f988c5 | ||
|
|
8c0be931c0 | ||
|
|
9b8052149a | ||
|
|
bd2739eb13 | ||
|
|
2f24a5588b | ||
|
|
7b9ec69e7b | ||
|
|
95f58e3b4d | ||
|
|
c1353fc971 | ||
|
|
4a62eecf83 | ||
|
|
6d60af23c3 | ||
|
|
80bb4b296f | ||
|
|
3ec509ec2e | ||
|
|
4598256c7c | ||
|
|
98b980cf2b | ||
|
|
d0654e9f37 | ||
|
|
8f3a38cb0d | ||
|
|
b1d05c7e66 | ||
|
|
0e41205472 | ||
|
|
3394ebcdad | ||
|
|
36ae9c5035 | ||
|
|
c5d25b5717 | ||
|
|
9ea7d3ef27 | ||
|
|
e40b01d276 | ||
|
|
38455d4549 | ||
|
|
5535b1af34 | ||
|
|
412277b3a7 | ||
|
|
ac41aec71c | ||
|
|
1a315483eb | ||
|
|
8891a51c2e | ||
|
|
602113242d | ||
|
|
17a64a719b | ||
|
|
ef9042fe20 | ||
|
|
ce2dc1c2dc | ||
|
|
6d04a8ac19 | ||
|
|
882c740880 | ||
|
|
f124018125 | ||
|
|
b489b72ff5 | ||
|
|
99a200907a | ||
|
|
5f0d9d728b | ||
|
|
f817773338 | ||
|
|
edcde83323 | ||
|
|
8bd5fd2106 | ||
|
|
573f054ee2 | ||
|
|
8569a5de3c | ||
|
|
b3ce129bce | ||
|
|
c4b9396f52 | ||
|
|
579ae9bd96 | ||
|
|
0871985f08 | ||
|
|
78e866492f | ||
|
|
1f2046c6ad | ||
|
|
1a3102a19a | ||
|
|
8678e33ec2 | ||
|
|
42175b89c0 | ||
|
|
a96a6ebf5d | ||
|
|
78ce11a30d | ||
|
|
c78afbbc5c | ||
|
|
94a5a7386b | ||
|
|
9aec3455f6 | ||
|
|
b4a058f0ca | ||
|
|
dcad4b70e9 | ||
|
|
e5d27a536c | ||
|
|
db08388ce7 | ||
|
|
5499070a4f | ||
|
|
792fb153e3 | ||
|
|
c1ff6737f4 | ||
|
|
f42c1e11eb | ||
|
|
53b395bd98 | ||
|
|
1c91c92d67 | ||
|
|
3bf54fcb47 | ||
|
|
30c39d58dd | ||
|
|
50955aff3a | ||
|
|
c798b4659f | ||
|
|
e6e7275de0 | ||
|
|
39a1c05df1 | ||
|
|
cd0d3fe9d5 | ||
|
|
e13ce42cac | ||
|
|
aade8504fa | ||
|
|
58e331f85c | ||
|
|
2cddc9bcd7 | ||
|
|
40c2c34678 | ||
|
|
7a8648cd99 | ||
|
|
93c5a188f0 | ||
|
|
0e110d69f2 | ||
|
|
2ef883984d | ||
|
|
de35856749 | ||
|
|
18293764fd | ||
|
|
3d48220b8f | ||
|
|
97f0a59fcf | ||
|
|
34dfea1379 | ||
|
|
394c2d1d94 | ||
|
|
30f3aaea27 | ||
|
|
d6b9b0b950 | ||
|
|
b78d93a056 | ||
|
|
5d599b28fe | ||
|
|
aec9271e07 | ||
|
|
d063675736 | ||
|
|
4b7f924f7d | ||
|
|
e475ec6686 | ||
|
|
4145f81850 | ||
|
|
8d7f18c734 | ||
|
|
0d1afdc900 | ||
|
|
92c4646ca9 | ||
|
|
a1be67d8d3 | ||
|
|
9a01c1c2b0 | ||
|
|
f392e5020a | ||
|
|
d181cd1552 | ||
|
|
aa3033e1f4 | ||
|
|
c08cffecd4 | ||
|
|
eb1ef32754 | ||
|
|
175c84b1a6 | ||
|
|
4d3c75dbcf | ||
|
|
cfe9dee433 | ||
|
|
b91f9f1f04 | ||
|
|
8ed0ab8413 | ||
|
|
7b0af5e7c5 | ||
|
|
7b92f7760d | ||
|
|
d7ca2c428a | ||
|
|
e45981d499 | ||
|
|
35f07a7993 | ||
|
|
afe127d9fe | ||
|
|
19082a7a10 | ||
|
|
6691f2a701 | ||
|
|
52be61570a | ||
|
|
ea81d619be | ||
|
|
9140455795 | ||
|
|
a1579e62c5 | ||
|
|
fc86d826e9 | ||
|
|
0762ffcef8 | ||
|
|
6c5b120526 | ||
|
|
a8aa6bf950 | ||
|
|
3d13dc1829 | ||
|
|
8c0f308694 | ||
|
|
de822fb1ba | ||
|
|
da86206a24 | ||
|
|
5a107031e6 | ||
|
|
25a7c3ef20 | ||
|
|
1a3e375523 | ||
|
|
d3f5f51458 | ||
|
|
e38b3cfe7a | ||
|
|
faecd974b9 | ||
|
|
f4eda34035 | ||
|
|
b37f14d25c | ||
|
|
d3f26f1696 | ||
|
|
0745ac2fd4 | ||
|
|
a41f4f0a33 | ||
|
|
c73725170e | ||
|
|
9c45bea785 | ||
|
|
d82c1750fd | ||
|
|
4c87e4a5fc | ||
|
|
dd527378bb | ||
|
|
f42ce95f60 | ||
| 86b2938a53 | |||
| 7d955ff90f | |||
| f0401d8fda | |||
| 00471df086 | |||
|
|
2514106476 | ||
|
|
aee0b7dbbf | ||
|
|
8c3786947e | ||
|
|
257edec1a7 | ||
|
|
76d5d4c94d | ||
|
|
0af9c4a76e | ||
|
|
80b218c816 | ||
|
|
83aa943410 | ||
|
|
0dd3bbea73 | ||
|
|
3d3162e4a0 | ||
|
|
14c6cb8bc0 | ||
|
|
eff1da6644 | ||
|
|
f97c147ddd | ||
|
|
3eff873d3a | ||
|
|
45d14cc7b2 | ||
|
|
852df91c7a | ||
|
|
9d4184e3ad | ||
|
|
16f3c65b7f | ||
|
|
e48ba7e938 | ||
|
|
ed83742cf8 | ||
|
|
12af90bacc | ||
|
|
31a45c1b5c | ||
|
|
99d24524d1 | ||
|
|
f5ef362242 | ||
|
|
929a2749f7 | ||
|
|
5cafd35bda | ||
|
|
3efc55676e | ||
|
|
4a05a30848 | ||
|
|
8c774733ef | ||
|
|
9d35418251 | ||
|
|
b54e3bdf10 | ||
|
|
fbf9c97247 | ||
|
|
d6787f9855 | ||
|
|
dca4175659 | ||
|
|
ababdc7a46 | ||
|
|
9c92818ff9 | ||
|
|
cd252b9de3 | ||
|
|
2e666e89e9 | ||
|
|
21bc458743 | ||
|
|
a0f850cbad | ||
|
|
59ba573947 | ||
|
|
645fb16cb1 | ||
|
|
00e9625c34 | ||
|
|
55d953b445 | ||
|
|
be6d361bf7 | ||
|
|
69ec843bf0 | ||
|
|
d590485f50 | ||
|
|
f5178cf625 | ||
|
|
4b6c048eaf | ||
|
|
6d1cc6c1ff | ||
|
|
ce4be9f5e2 | ||
|
|
ba284ca60d | ||
|
|
bb962f1708 | ||
|
|
51991df213 | ||
|
|
5f35de8b92 | ||
|
|
02372a6684 | ||
|
|
070c75a8c6 | ||
|
|
7423e66fec | ||
|
|
6268d04d16 | ||
|
|
243c07101e | ||
|
|
1cfd2421bd | ||
|
|
be6fc9ffb5 | ||
|
|
da1e959be2 | ||
|
|
74fdea2941 | ||
| 27fc6beec4 | |||
|
|
9308c5d0de | ||
|
|
6bc0eb86d5 | ||
|
|
9faf63fcea | ||
|
|
fae8aa8de9 | ||
|
|
aa5d3a53c0 | ||
|
|
fc5c5a2470 | ||
|
|
3c10886991 | ||
|
|
bb26eac2a7 | ||
|
|
766c0f99d5 | ||
|
|
0ac9510546 | ||
|
|
fa39529f3f | ||
|
|
f3571fe7f4 | ||
|
|
2550c58d99 | ||
|
|
116cdd4a45 | ||
|
|
5f7225e3ab | ||
|
|
03d5586548 | ||
|
|
d59956942d | ||
|
|
79ea4a9856 | ||
|
|
bea4975e7e | ||
|
|
925760b13d | ||
|
|
48ec743dfa | ||
|
|
a963949bbb | ||
|
|
a377878781 | ||
|
|
fe71a7be33 | ||
|
|
cb45b9774f | ||
|
|
faff6f60d5 | ||
|
|
7d51376cb5 | ||
|
|
9f99ca23ba | ||
|
|
236ef204eb | ||
|
|
4f7ce57111 | ||
|
|
60853bc281 | ||
|
|
dba44aa4fb | ||
|
|
6ebdd80030 | ||
|
|
8ed55b1ed9 | ||
|
|
ed0e20fa6a | ||
|
|
815e9a45b4 | ||
|
|
dc974135bf | ||
|
|
2bbc219df3 | ||
|
|
e91e639112 | ||
|
|
5b4af4bb34 | ||
|
|
702357910a | ||
|
|
77ea2d1500 | ||
|
|
8036e5e328 | ||
|
|
a4bfcdad16 | ||
|
|
554010ee84 | ||
|
|
5ce6856b75 | ||
|
|
6fdcc2470a | ||
|
|
ef31a733e2 | ||
|
|
e84297ab05 | ||
|
|
a46c432a3f | ||
|
|
e79401af7b | ||
|
|
884f737d81 | ||
|
|
7e46628b25 | ||
|
|
39d0070e1a | ||
|
|
01615aaa07 | ||
|
|
70fb8c0b91 | ||
|
|
ad54d92b86 | ||
|
|
92a8edd435 | ||
|
|
31d82cc5d8 | ||
|
|
4dae6953a2 | ||
|
|
f83b902857 | ||
|
|
b2683e71c5 | ||
|
|
fdefe0e48f | ||
|
|
5281bcf79d | ||
|
|
9c75e13aec | ||
|
|
ffed474c34 | ||
|
|
3b8d1c8175 | ||
|
|
3c3a848144 | ||
|
|
d7e7fe1d6f | ||
|
|
36af83ff5c | ||
|
|
f8af9ffc85 | ||
|
|
0f5c51c6c2 | ||
|
|
224cde2b45 | ||
|
|
f0d7d0426e | ||
|
|
ee5ec65a4d | ||
|
|
b52c07015d | ||
|
|
b3285f9581 | ||
|
|
438731d0f4 | ||
|
|
8a7d30b276 | ||
|
|
756913a9cd | ||
|
|
7f59f07a7d | ||
|
|
eb5017665e | ||
|
|
4e1378b796 | ||
|
|
8b529d6732 | ||
|
|
826cda8e08 | ||
|
|
555d33e0fa | ||
|
|
fd81588369 | ||
|
|
bb004e4293 | ||
|
|
ff6ef0a28b | ||
|
|
cec7ecc88f | ||
|
|
0375bd8c05 | ||
| b9b45969f3 | |||
|
|
b7d83178f7 | ||
| e4ef026c47 | |||
| 33d3be8fdd | |||
| 4d9932ee67 | |||
| c2c59374b3 | |||
|
|
916cca1d73 | ||
|
|
2698f06c57 | ||
|
|
4b0cec7d36 | ||
|
|
d75e9fd8c8 | ||
|
|
7889eb273b | ||
|
|
c9cc587c61 | ||
|
|
e7a26268ce | ||
|
|
c1f68522aa | ||
|
|
c687ade3fa | ||
| 10b8e8ca7a | |||
| 0ad9a0f56f | |||
| 90ab23b356 | |||
| 0317201406 | |||
|
|
43a9fe7fe5 | ||
|
|
5672f9f60a | ||
|
|
c4fad68192 | ||
|
|
f24382fb10 | ||
|
|
350a2cc4b8 | ||
|
|
48c3ab4c2c | ||
|
|
4c18d50c3b | ||
|
|
d7e1ad6010 | ||
|
|
d784de4e4a | ||
|
|
0cc5c6142d | ||
|
|
73cf8bfd91 | ||
|
|
f2309a28a9 | ||
|
|
890a5d8ad1 | ||
|
|
4f36a511e9 | ||
|
|
bfd344a9f7 | ||
|
|
6e4424f722 | ||
|
|
9f8157d338 | ||
|
|
6172626254 | ||
|
|
c9fa280c57 | ||
|
|
eadaf7d69f | ||
|
|
b1d70323f3 | ||
|
|
0eb775826f | ||
|
|
b369d00b3e | ||
|
|
cff165d9d9 | ||
|
|
224aaed969 | ||
|
|
430a155b75 | ||
|
|
df26128ce4 | ||
|
|
02fa7225ac | ||
|
|
a07c0121df | ||
|
|
9dca404fb0 | ||
|
|
adbb21abc2 | ||
|
|
2fa27cafbb | ||
|
|
b9be0a70af | ||
|
|
ecbcdc9dae | ||
|
|
461d547c09 | ||
|
|
ab8e1b8899 | ||
|
|
3ec8e8ca2c | ||
|
|
d3c7ddbd55 | ||
|
|
41470c277f | ||
|
|
d4507e25c2 | ||
|
|
8e550617ea | ||
|
|
b66a7f4707 | ||
|
|
d1c373f7fb | ||
|
|
cbb5bea8c6 | ||
|
|
e43d7e061e | ||
|
|
1604d68817 | ||
|
|
b715b245e7 | ||
|
|
20586471ab | ||
|
|
0e482a3ccd | ||
|
|
242fc146e9 | ||
|
|
a176248104 | ||
|
|
a9f0e2bf3d | ||
|
|
b510a44adf | ||
|
|
bbf23e9f0b | ||
|
|
4c3bab739a | ||
|
|
40d8f14197 | ||
|
|
01ba5d8d72 | ||
|
|
cdab2de5a6 | ||
|
|
db58d9267c | ||
|
|
536c4c4732 | ||
|
|
f3a84a9609 | ||
|
|
a7915cbb5f | ||
|
|
866e89eefa | ||
|
|
93f3b4f184 | ||
|
|
0eaaaa4d7e | ||
|
|
2c3c4861c4 | ||
|
|
2a76f9acc1 | ||
|
|
6e51cd0305 | ||
|
|
1b18bdbfb6 | ||
|
|
8ebe30746d | ||
|
|
e4ca27a84d | ||
|
|
3de7d580dc | ||
|
|
188947ecad | ||
|
|
856e2a2891 | ||
|
|
5ebb725532 | ||
|
|
1d40f41651 | ||
|
|
70f9d24b73 | ||
|
|
705cedbf3c | ||
|
|
49aabfe6f4 | ||
|
|
785d0ea377 | ||
|
|
4853b1e464 | ||
|
|
367a95b5c5 | ||
|
|
b0d74fcfd0 | ||
|
|
4f20c5fd5f | ||
|
|
1f856822e2 | ||
|
|
a1f5a996ae | ||
|
|
6cfd76c788 | ||
|
|
e36a95fd76 | ||
|
|
2c0e563fa6 | ||
|
|
b70dff8031 | ||
|
|
ba36093b0e | ||
|
|
64c0ab734b | ||
|
|
1e064a774f | ||
|
|
2b590b0754 | ||
|
|
38b32ef5b1 | ||
|
|
b7d48c67bf | ||
|
|
a18388e841 | ||
|
|
cb50ae8089 | ||
|
|
a56a4b9647 | ||
|
|
d2d6136bc4 | ||
|
|
97bd91f006 | ||
|
|
f691137a78 | ||
|
|
aa981b0913 | ||
|
|
ed7e06b5b2 | ||
|
|
7fe007a098 | ||
|
|
b85397a9b5 | ||
|
|
b135001c10 | ||
|
|
28e6a70e90 | ||
|
|
1c84383352 | ||
|
|
84b33bb21f | ||
|
|
ee297d9ea7 | ||
|
|
ee64c58fe6 | ||
|
|
1f28f76006 | ||
|
|
e1a584de0c | ||
|
|
f3f53e73b4 | ||
|
|
4048bd3a51 | ||
|
|
4495b98a6e | ||
|
|
c8c2c7af95 | ||
|
|
42a9bd9f32 | ||
|
|
f067aefdca | ||
|
|
8bcd67d935 | ||
|
|
95becf7643 | ||
|
|
8d502a9fd0 | ||
|
|
09e3f29501 | ||
|
|
fac9ccad75 | ||
|
|
0dd80fd829 | ||
|
|
02e38a9c2c | ||
|
|
dd1b3c0b1b | ||
|
|
c87531aff7 | ||
|
|
6244359847 | ||
|
|
fc2e3f4df6 | ||
|
|
0067f0c52b | ||
|
|
ea46b3337b | ||
|
|
3b79802d32 | ||
|
|
ef7531c980 | ||
|
|
ff5acd2702 | ||
|
|
4db2c8cbcb | ||
|
|
fccfefe24b | ||
|
|
252cfc7bad | ||
|
|
7b6baa14c4 | ||
|
|
af3ad559a1 | ||
|
|
41f389fb05 | ||
|
|
b93109a5ca | ||
|
|
ed6ae8c93e | ||
|
|
8fa438336f | ||
|
|
a483b8e24e | ||
|
|
47407e7aa2 | ||
|
|
5a390a2c2b | ||
|
|
ead68b24a3 | ||
|
|
8598a39b1e | ||
|
|
cb2f8b05f0 | ||
|
|
462acd3c7f | ||
|
|
0a41699f5b | ||
|
|
511f420555 | ||
|
|
5066cd099d | ||
|
|
8a77f0c892 | ||
|
|
f91b50a9e8 | ||
|
|
c43e958859 | ||
|
|
493f4a7365 | ||
|
|
efcbe17b6b | ||
|
|
9376388f90 | ||
|
|
728fcc05cc | ||
|
|
7f437ed685 | ||
|
|
1e6d9a7f55 | ||
| 23153e492a | |||
|
|
7731b18fad | ||
|
|
dc585fb9bd | ||
|
|
fdcfe75325 | ||
|
|
083da3fe7f | ||
|
|
14b03ff340 | ||
| 803c2118b6 | |||
|
|
192c85fa30 | ||
|
|
36deb7defe | ||
|
|
4e930d23a6 | ||
|
|
a83da83b84 | ||
|
|
674b15afab | ||
| ad1dc19919 | |||
| 12aa283b0a | |||
| c0d72c383c | |||
| 37fbc35f2c | |||
| 8ef4bc3970 | |||
| bf3ce47c9a | |||
| 15c1ee9e9c | |||
| f9d2eddeb5 | |||
| 5ad1d23981 | |||
| f2e31cf6ad | |||
| 2debf80598 | |||
| bad0327762 | |||
| 40a735a451 | |||
| 8fbde8c069 | |||
|
|
beea92f5d7 | ||
|
|
f369c2a228 | ||
|
|
dbe86b8ed8 | ||
|
|
2c4a58ff59 | ||
|
|
a0343f50e0 | ||
|
|
e7ab95fcb7 | ||
|
|
74e62f5f4c | ||
|
|
3ddc0e2860 | ||
|
|
aa8e6f8b00 | ||
| 427a1dee07 | |||
| a789cf2705 | |||
| 229f06cefa | |||
| d2e81bb488 | |||
| 4a0151e922 | |||
| d99d0fa39e | |||
| c924337761 | |||
| 53201d335c | |||
| efff92c549 | |||
| 6f77fcee26 | |||
|
|
29ae140d65 | ||
|
|
8051360bfc | ||
|
|
2fb5acd485 | ||
|
|
1f66eb0abc | ||
|
|
70523d5bbf | ||
|
|
a2e5f804d6 | ||
|
|
789d7372d9 | ||
|
|
bf4e3827e0 | ||
|
|
16fca4b2f0 | ||
|
|
f15179fb02 | ||
|
|
f64efa3494 | ||
|
|
8433f07e57 | ||
|
|
554ea353e0 | ||
|
|
877a4e1758 | ||
|
|
6f9cea9ca6 | ||
|
|
81f2f79bf2 | ||
|
|
14caad33e4 | ||
|
|
db475ddef1 | ||
|
|
994811770b | ||
|
|
41a6da9409 | ||
|
|
24ed8da007 | ||
|
|
a3164dd27b | ||
|
|
6852772808 | ||
|
|
b284049782 | ||
|
|
c625cda845 | ||
|
|
7c7bd3c530 | ||
|
|
e1eeb8990c | ||
|
|
88e5daebfa | ||
|
|
0fa04710ff | ||
|
|
44898fbfd3 | ||
|
|
7ea932a321 | ||
|
|
44e7a0e743 | ||
|
|
810569202a | ||
|
|
8d5b4c7fc0 | ||
|
|
490a1362c3 | ||
|
|
e254f8f181 | ||
|
|
eb80a4c220 | ||
|
|
bcec34670d | ||
|
|
212d69cbe3 | ||
|
|
6a969e0991 | ||
|
|
bb4dd6e125 | ||
|
|
efb0a950d5 | ||
|
|
655ba409b4 | ||
|
|
c380516855 | ||
|
|
34c6c9e6bd | ||
|
|
4752c81e7f | ||
|
|
243561e3b7 | ||
|
|
e79cd16d3f | ||
|
|
84fa00fa16 | ||
|
|
96419787be | ||
|
|
4607ef5c0f | ||
|
|
90d7619966 | ||
|
|
57e3298dc6 | ||
|
|
fd23018647 | ||
|
|
78d08f3b0e | ||
|
|
bca7defb4c | ||
|
|
f073dd337f | ||
|
|
0947032a94 | ||
|
|
398ef69ff7 | ||
|
|
bfd7451c0f | ||
|
|
ef22cf169e | ||
|
|
3ea72e584c | ||
|
|
16ca8cd99e | ||
|
|
47297a2579 | ||
|
|
3492ec65fc | ||
|
|
07cdb6be77 | ||
|
|
d4da7535f9 | ||
|
|
0ff464dde2 | ||
|
|
f044a235ae | ||
|
|
536c667b59 | ||
|
|
18d8b73eb3 | ||
|
|
5a84119c77 | ||
|
|
783ff6e9b3 | ||
|
|
aa09333383 | ||
|
|
1978718129 | ||
|
|
67f769329e | ||
|
|
f57f3ba9b8 | ||
|
|
2e525fa01b | ||
|
|
2ddb549a75 | ||
|
|
df6e860620 | ||
|
|
003ffb4adf | ||
|
|
b3cbfcfb9d | ||
|
|
a2f755b914 | ||
|
|
85e2195297 | ||
|
|
cfa58f2c32 | ||
|
|
57b3b358ad | ||
|
|
13fe6adbb2 | ||
|
|
6fc7905b04 | ||
|
|
709952bf60 | ||
|
|
08591c5de6 | ||
|
|
74727c2d77 | ||
|
|
02a8948ee4 | ||
|
|
7ee782fb6a | ||
|
|
8d7063c116 | ||
|
|
7ca26ed325 | ||
|
|
d8065efec5 | ||
|
|
2f4152ff8b | ||
|
|
217530fb93 | ||
|
|
fe3cea131a | ||
|
|
4abf02aa15 | ||
|
|
779bbb2f82 | ||
|
|
1d39a01ded | ||
|
|
6d135f9cd7 | ||
|
|
59b263e5b8 | ||
|
|
86b06226cb | ||
|
|
b0537723a7 | ||
|
|
4a8c77d4e0 | ||
|
|
ab0b900721 | ||
|
|
afe44bac89 | ||
|
|
c0fdc4d2dc | ||
|
|
d1d3b30ece | ||
|
|
9dbbc26d06 | ||
|
|
3d2c7282dd | ||
|
|
d6caa819b0 | ||
|
|
24807db81c | ||
|
|
49d8a7f0dc | ||
|
|
6ccc0eb6c9 | ||
|
|
6d391f730f | ||
|
|
037626cb76 | ||
|
|
fab61f4e17 | ||
|
|
b2a1c8f85a | ||
|
|
15c1d6b463 | ||
|
|
6b21a33625 | ||
|
|
9efaa2bf61 | ||
|
|
539fe803af | ||
|
|
771778669e | ||
|
|
55063d0f94 | ||
|
|
6e764b21e1 | ||
|
|
163e57ef76 | ||
|
|
8953fc32d8 | ||
|
|
253ed6c19b | ||
|
|
0112c9d015 | ||
|
|
e6e6f19418 | ||
|
|
f2be7767cb | ||
|
|
5489b80ff0 | ||
|
|
29c6770581 | ||
|
|
597c765673 | ||
|
|
c01e668d9e | ||
|
|
567f6a6302 | ||
|
|
c127e0822c | ||
|
|
a2de9572ba | ||
|
|
6691098ddf | ||
|
|
b32900a44f | ||
|
|
8373f52f22 | ||
|
|
104bc8d08a | ||
|
|
e5d80908ce | ||
|
|
0cad38ecad | ||
|
|
280237b46c | ||
|
|
a70f931688 | ||
|
|
9a51e75892 | ||
|
|
3cfc8a69dc | ||
|
|
bf58944fda | ||
|
|
ee3ae12735 | ||
|
|
0cad4e68eb | ||
|
|
2859eebcc5 | ||
|
|
7fe0c4ae27 | ||
|
|
2b809e0f81 | ||
|
|
0866fbbed6 | ||
|
|
e99be8070e | ||
|
|
615d5dab17 | ||
|
|
398897efe1 | ||
|
|
7066715495 | ||
|
|
0863303740 | ||
|
|
39db1999fb | ||
|
|
92a44b9f41 | ||
|
|
133cfab42f | ||
|
|
2ef53d7a51 | ||
|
|
59e96d7d3c | ||
|
|
b22a84f054 | ||
|
|
08335c8b11 | ||
|
|
7aa2ecc4af | ||
|
|
39eb3baebd | ||
|
|
630739aae6 | ||
|
|
2c0af0a321 | ||
|
|
6883bebd16 | ||
|
|
96a159c007 | ||
|
|
1cb0372009 | ||
|
|
6d19f687b2 | ||
|
|
54a084d2cb | ||
|
|
523a7378c6 | ||
|
|
24c7411109 | ||
|
|
4fa32f63fd | ||
|
|
b6a8e172a4 | ||
|
|
841e53628f | ||
|
|
195b5097a4 | ||
|
|
e805e69dc7 | ||
|
|
f1580dbfe7 | ||
|
|
dbc99e0d8d | ||
|
|
f71bd74aa0 | ||
|
|
dee958aa2b | ||
|
|
30693cd629 | ||
|
|
0b3b066b9b | ||
|
|
413b44b4d2 | ||
|
|
03aceae130 | ||
|
|
093cc3913b | ||
|
|
567223ed66 | ||
|
|
e97e8e56e8 | ||
|
|
30983ec507 | ||
|
|
94f5f40570 | ||
|
|
82a6cb4525 | ||
| f31626f51c | |||
| e8a15e0ae7 | |||
| 7fd06adc2d | |||
|
|
decef795c2 | ||
|
|
70981e0c3f | ||
|
|
661e9ca417 | ||
|
|
bde6ec1a2b | ||
|
|
53c6c6b51c | ||
|
|
f5f09f0516 | ||
|
|
95e2a2c3f0 | ||
|
|
95ed1bae84 | ||
|
|
9b99199be6 | ||
|
|
17a2722012 | ||
|
|
ceb16dad93 | ||
|
|
50762f8214 | ||
|
|
43eaaf9de7 | ||
|
|
dab011fbee | ||
|
|
c96459a128 | ||
|
|
ec401056b2 | ||
|
|
4f6d065990 | ||
|
|
455cc36a69 | ||
|
|
7c919b513c | ||
|
|
d6892c168c | ||
|
|
b816d3dbb1 | ||
|
|
b1a4386de4 | ||
|
|
e95f5dd1b2 | ||
|
|
6028c5d48d | ||
|
|
6f3ee10860 | ||
|
|
6bf0831566 | ||
|
|
7e9a8a493d | ||
|
|
9facc58e3a | ||
|
|
7e5cdc3b7e | ||
|
|
f98c57157b | ||
|
|
c77e066f9e | ||
|
|
be788fc5e6 | ||
|
|
b2c70c0c87 | ||
|
|
e231090168 | ||
|
|
fb7efa9930 | ||
|
|
e0b9c975b0 | ||
|
|
35e9178472 | ||
|
|
831ff8d4a0 | ||
|
|
7ceb125026 | ||
|
|
0778d472f8 | ||
|
|
ae16f30c42 | ||
|
|
0f87f69077 | ||
|
|
200ee82b9d | ||
|
|
8a3101d562 | ||
|
|
adb90fd214 | ||
|
|
23c63ff09d | ||
|
|
6536257042 | ||
|
|
15fd32b252 | ||
|
|
72820f08ae | ||
|
|
b2129d6e05 | ||
|
|
29d3ed38cb | ||
|
|
54a43cc124 | ||
|
|
d0d8392817 | ||
|
|
84aecddc7c | ||
|
|
edd7beb4d7 | ||
|
|
a625d33995 | ||
|
|
af0da563f1 | ||
|
|
64b77ec238 | ||
|
|
4a839b91d7 | ||
|
|
112f6d4da4 | ||
|
|
acf6842017 | ||
|
|
6508461ae6 | ||
|
|
b6df6a218d | ||
|
|
3c13b62502 | ||
|
|
107366d4f8 | ||
|
|
a508307df3 | ||
|
|
c93792634a | ||
|
|
8ff404e534 | ||
|
|
1369874dc2 | ||
|
|
7859d1d2b2 | ||
|
|
25ebdb6e76 | ||
|
|
13c2375727 | ||
|
|
bbf5d3e2bc | ||
|
|
8a92ffb6ba | ||
|
|
683597e2bf | ||
|
|
5606cdb12f | ||
|
|
e281b1d385 | ||
|
|
824bdd29a2 | ||
|
|
67b8435e08 | ||
|
|
5bed9aadb4 | ||
|
|
09891b5d83 | ||
|
|
c813821922 | ||
|
|
1ef1cc2530 | ||
|
|
57c1c61ce1 | ||
|
|
4eaeb152fe | ||
|
|
02f719d206 | ||
|
|
d1c7a88c64 | ||
|
|
ad9417911a | ||
|
|
2f037290d9 | ||
|
|
8fd8b89ff4 | ||
|
|
1bb3867463 | ||
|
|
0ff9f1832e | ||
|
|
616011edfe | ||
|
|
cfd85435f2 | ||
|
|
a1b9d3c518 | ||
|
|
d933395a9f | ||
|
|
73466456ee | ||
|
|
1dba813d4b | ||
|
|
4ea30cef62 | ||
|
|
3310d9fc8b | ||
|
|
65b5e6ade6 | ||
|
|
5e02b424a8 | ||
|
|
562a3ffa36 | ||
|
|
106a186ea6 | ||
|
|
9915c7d9ed | ||
|
|
17cb6786f8 | ||
|
|
5746d8d34b | ||
|
|
4b2599ae71 | ||
|
|
d685792061 | ||
|
|
56218b5dd8 | ||
|
|
0e24c21db2 | ||
|
|
59ce3acd8f | ||
|
|
42242a6b35 | ||
|
|
057806e3d9 | ||
|
|
ac21a67c8a | ||
|
|
c639c2b0a0 | ||
|
|
1a493b85f8 | ||
|
|
475239f6e9 | ||
|
|
eb9e1b7167 | ||
|
|
194642e927 | ||
|
|
5e73c588a4 | ||
|
|
e43cf35ec4 | ||
|
|
5f66780522 | ||
|
|
ae1cd473ed | ||
|
|
e61089ce2c | ||
|
|
18cc4953ad | ||
|
|
8f0024fa26 | ||
|
|
6b2e0b67e0 | ||
|
|
b9483b5bdd | ||
|
|
7ad98c2946 | ||
|
|
e6451f29f8 | ||
|
|
f9db444764 | ||
|
|
50a8ce271d | ||
|
|
6216c3786c | ||
|
|
0bd7f44dd8 | ||
|
|
790dc2961b | ||
|
|
6bb2d7f761 | ||
|
|
6f8e18750c | ||
|
|
e4d60309a0 | ||
|
|
9d1b520718 | ||
|
|
49805f48c9 | ||
|
|
2b8d00551c | ||
|
|
6bbd129634 | ||
|
|
a494a9ca68 | ||
|
|
a56804cee6 | ||
|
|
3631f2f122 | ||
|
|
59c151f639 | ||
|
|
830b9ee608 | ||
|
|
2d988fc405 | ||
|
|
0e15d8e3c0 | ||
|
|
b3093139b2 | ||
|
|
275072160e | ||
|
|
a0514b5179 | ||
|
|
f55d9c2c62 | ||
|
|
ca43cc4dce | ||
|
|
d85ab35812 | ||
|
|
f5f60a403c | ||
|
|
48837ffa6f | ||
|
|
ea254c584f | ||
|
|
6f21a567a7 | ||
|
|
e11639bf24 | ||
|
|
6e0ceefa48 | ||
|
|
6189ea154d | ||
|
|
c1d23d15f4 | ||
|
|
b6ca0eb3f2 | ||
|
|
728682a07f | ||
|
|
ce44e93b4d | ||
|
|
938aabb2a8 | ||
|
|
bb2f14b67c | ||
|
|
6d4463e57e | ||
|
|
47ce2380be | ||
|
|
c17724cea1 | ||
|
|
e9399e107f | ||
|
|
0dc50e4509 | ||
|
|
415e452988 | ||
|
|
2d180006b6 | ||
|
|
8f51ed1158 | ||
|
|
7080b51dfc | ||
|
|
2eda94baba | ||
|
|
eb23d16ad5 | ||
|
|
fe232b8cba | ||
|
|
64d6e87ca2 | ||
|
|
06c1310455 | ||
|
|
585692bb1d | ||
|
|
d1f3a4c27e | ||
|
|
29dfcc5440 | ||
|
|
03bb55e62a | ||
|
|
9c679765e5 | ||
|
|
60928b0521 | ||
| 72f6c9974a | |||
| 6cbe3b28f2 | |||
|
|
19bba3d8a9 | ||
|
|
e45bb2fbcd | ||
|
|
4e6fedcffd | ||
|
|
717db418f9 | ||
|
|
b8da9d99eb | ||
| 264fced5a6 | |||
| 3e3466237a | |||
|
|
45ef0d2fe9 | ||
|
|
d37234d7d8 | ||
|
|
b7f6a5ee2a | ||
|
|
63baf4b2e9 | ||
|
|
33ec6a4acb | ||
|
|
979e0c2174 | ||
|
|
2788546cc8 | ||
|
|
627bc8c4df | ||
|
|
735e50dc0f | ||
|
|
1f525f4c80 | ||
|
|
499e08919d | ||
|
|
734734c9dc | ||
|
|
b1effc128a | ||
|
|
207ce8a960 | ||
|
|
443d2bab77 | ||
|
|
01e1d2f82a | ||
|
|
2167c7e897 | ||
|
|
09c7b48223 | ||
|
|
e46032a00b | ||
|
|
29692ac78e | ||
|
|
486236f0a8 | ||
|
|
65fd3ebe28 | ||
|
|
8f6589cf1c | ||
|
|
3afb81d801 | ||
|
|
0f886374cf | ||
|
|
ada4a75ecb | ||
|
|
ec48bdc3d8 | ||
|
|
c94b2fb2e7 | ||
|
|
530932f32a | ||
|
|
42ea4a7586 | ||
|
|
fb6246a998 | ||
|
|
270e611ec0 | ||
|
|
5fb61d6c63 | ||
|
|
1d3045f946 | ||
|
|
ee863face2 | ||
|
|
9a46b755bf | ||
|
|
8cbabf48fe | ||
|
|
e3186ddc60 | ||
|
|
576fa80a41 | ||
|
|
d412ddac0a | ||
|
|
130b1953de | ||
|
|
9d4d261d1d | ||
|
|
2147f54724 | ||
|
|
9840a3e4b7 | ||
|
|
06043197bd | ||
|
|
92b36e502e | ||
|
|
59417c6f91 | ||
|
|
a3403109ae | ||
|
|
3aa3fd8ae7 | ||
|
|
26d312559f | ||
|
|
affec1bf37 | ||
|
|
c620ce5f18 | ||
|
|
7682c7d080 | ||
|
|
dc68970809 | ||
|
|
166a2212b9 | ||
|
|
b57e51e8e7 | ||
|
|
4785781cac | ||
|
|
bccb8370af | ||
|
|
4ba34d594d | ||
|
|
46c562871f | ||
|
|
143e099e13 | ||
|
|
5574f50586 | ||
|
|
070a4be373 | ||
|
|
82e95b1593 | ||
|
|
30e204219a | ||
|
|
d260336313 | ||
|
|
39c2aead8a | ||
|
|
09f5098b39 | ||
|
|
260091c2ae | ||
|
|
19222ee946 | ||
|
|
dd880f0ca2 | ||
|
|
768159918f | ||
|
|
e30b5a9092 | ||
|
|
291dfc8896 | ||
|
|
bc22a8c9d8 | ||
|
|
be2beb04f0 | ||
|
|
8a47572677 | ||
|
|
4f4cd0c985 | ||
|
|
90c3ab1ba1 | ||
|
|
3d5fafc4bf | ||
|
|
c7f2b16feb | ||
|
|
890263c586 | ||
|
|
28cf7ecf11 | ||
|
|
420180f20c | ||
|
|
c6bcbcd702 | ||
|
|
a9ea8ea1f7 | ||
|
|
cd66578138 | ||
|
|
8433960d0d | ||
|
|
6bee9c19cf | ||
|
|
d3b6f46368 | ||
|
|
eeedc2ad6f |
15
.ae_brief
Normal file
15
.ae_brief
Normal file
@@ -0,0 +1,15 @@
|
||||
# Aether Project Brief: aether_api_fastapi
|
||||
**Last Updated:** 2026-01-16 17:22:55
|
||||
**Current Agent:** mcp_agent
|
||||
|
||||
## 🛠️ What I Just Did
|
||||
1. Resolved 'Bootstrap Paradox' bug in lib_config_v3.py (hosted file path fix). 2. Developed Aether Field Manager (ae_field_manage.py) with table/view snapshotting and complex view detection. 3. Verified infrastructure and dry-run logic for vertical-slice field management.
|
||||
|
||||
## 🚧 Current Blockers
|
||||
None. Awaiting user verification of the first 'execute' run for the Field Manager.
|
||||
|
||||
## ➡️ Exact Next Steps
|
||||
1. Execute real-world test of ae_field_manage.py with user. 2. Proceed with Journal Management architecture review (Task 155435511). 3. Initiate Pydantic V2 migration impact analysis.
|
||||
|
||||
---
|
||||
*Generated by ae_brief*
|
||||
164
.gitignore
vendored
Normal file → Executable file
164
.gitignore
vendored
Normal file → Executable file
@@ -1,33 +1,109 @@
|
||||
# These are some examples of commonly ignored file patterns.
|
||||
# You should customize this list as applicable to your project.
|
||||
# Learn more about .gitignore:
|
||||
# https://www.atlassian.com/git/tutorials/saving-changes/gitignore
|
||||
|
||||
# Node artifact files
|
||||
node_modules/
|
||||
dist/
|
||||
|
||||
# Compiled Java class files
|
||||
*.class
|
||||
|
||||
# Compiled Python bytecode
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# Log files
|
||||
*.log
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Package files
|
||||
*.jar
|
||||
|
||||
# Maven
|
||||
target/
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# JetBrains IDE
|
||||
.idea/
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Unit test reports
|
||||
TEST*.xml
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.env.dev
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
environment/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
|
||||
# Generated by MacOS
|
||||
.DS_Store
|
||||
@@ -35,15 +111,33 @@ TEST*.xml
|
||||
# Generated by Windows
|
||||
Thumbs.db
|
||||
|
||||
# Applications
|
||||
*.app
|
||||
*.exe
|
||||
*.war
|
||||
# Added by Scott Idem
|
||||
# Updated 2024-10-09
|
||||
# https://github.com/github/gitignore
|
||||
|
||||
# Large media files
|
||||
*.mp4
|
||||
*.tiff
|
||||
*.avi
|
||||
*.flv
|
||||
*.mov
|
||||
*.wmv
|
||||
*.sock
|
||||
*.bak
|
||||
*.cfg
|
||||
*.ini
|
||||
*.kate-swp
|
||||
*.pid
|
||||
|
||||
*.csv
|
||||
# *.pdf
|
||||
*.xlsx
|
||||
|
||||
.directory
|
||||
.vscode
|
||||
flask_config.py
|
||||
config.py
|
||||
# config.cfg
|
||||
# users.cfg
|
||||
|
||||
backups/
|
||||
development/
|
||||
log/
|
||||
logs/
|
||||
myapp/files/
|
||||
myapp/file_distribution/
|
||||
temp/
|
||||
tmp/
|
||||
110
GEMINI.md
Normal file
110
GEMINI.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# Gemini Agent Context: Aether API Orchestrator
|
||||
|
||||
> **Template Version:** 1.2 (2026-01-26)
|
||||
> **Purpose:** Standardized memory structure for all Aether Agents.
|
||||
> **Structure:** Inverted Pyramid (Foundational -> Strategic -> Tactical -> Reference).
|
||||
|
||||
## 1. 💾 Long Term Memory (System & Facts)
|
||||
*This section contains the "Universal Truths" that rarely change. It grounds the agent in the user's reality.*
|
||||
|
||||
### 🤖 Agent Identity & Role
|
||||
- **Agent Name:** Aether API Orchestrator (mcp_agent)
|
||||
- **Primary Role:** Backend Development, System Orchestration, and API Stabilization.
|
||||
- **Scope:** `/home/scott/OSIT_dev/aether_api_fastapi` and Aether Platform backend infrastructure.
|
||||
|
||||
### 👤 User Profile
|
||||
- **User:** Scott Idem (`scott`)
|
||||
- **Organizations:**
|
||||
- **One Sky IT (OSIT):** Professional/Business context.
|
||||
- **Danger Zone (DgrZone):** Personal/Home context.
|
||||
- **Aether Platform (AE):** Scott's (One Sky IT) platform developed for OSIT.
|
||||
- **Preferences:**
|
||||
- **Editor:** `vim` (Terminal), VS Code (GUI).
|
||||
- **Communication:** Direct, concise, professional CLI tone.
|
||||
- **Safety:** "Recycle Bin" (`~/tmp/gemini_trash`) instead of `rm`. Explain destructive actions first.
|
||||
- **Hardware/OS:**
|
||||
- **Host:** Linux (Ubuntu/Arch context)
|
||||
|
||||
### 🏗️ Aether Architecture (V3)
|
||||
- **Concept:** Unified AI-driven platform for business/personal management.
|
||||
- **Backend:** FastAPI (v4.9.0) + Pydantic V1 + SQLAlchemy + MariaDB (Remote).
|
||||
- **V3 Implementation:** Modern parallel CRUD and Search endpoints under `/v3/crud`.
|
||||
- **Core Principle:** "Agent Bridge" - Distributed agents coordinating via file-based messaging (`~/agents_sync`).
|
||||
|
||||
### 📜 Core Protocols
|
||||
- **RAR Protocol:** Request -> Ack -> Result.
|
||||
- **V3 CRUD Paradigm:** JSON metadata via `/v3/crud/`, binary actions (Upload/Download) via `/v3/action/`.
|
||||
- **Fail Fast & Transparently:** API returns `500` on hard errors; avoid silent failures (confirmed in `sql_select`).
|
||||
- **Bite-Sized Data:** Avoid monolithic files (>1MB).
|
||||
- **Source of Truth:** `~/agents_sync` is the shared brain. `~/OSIT_dev` is the local development environment.
|
||||
|
||||
### 🛡️ Security & Secrets Guardrails
|
||||
- **Secrets:** NEVER read/display content from `.env` files unless explicitly debugging configuration logic.
|
||||
- **PII:** Scrub personally identifiable information if sharing logs or data across the bridge.
|
||||
- **Hiding Internal Paths:** `subdirectory_path` is hidden from public-facing API responses via Pydantic `Field(exclude=True)`.
|
||||
|
||||
### 🧠 Key Technical Learnings (Cumulative)
|
||||
- **Circular Dependencies Fixed**: Successfully resolved the fragile startup dependency chain by isolating Auth models and using strictly deferred DB imports in a dedicated `dependencies_v3.py` module.
|
||||
- **Bootstrap Paradox Solved**: Implemented a guest-access exception for `site_domain` search, allowing the frontend to resolve site context without a JWT.
|
||||
- **V3 Searchable Fields**: `searchable_fields` must explicitly include integer ID fields (e.g., `event_id`) to ensure valid numeric filters are not blocked by the V3 search security layer.
|
||||
- **NULL Logic in Filters**: Confirmed that explicit frontend filters like `hide: false` will FAIL to match `NULL` database values. Rely on the API's built-in `hidden=not_hidden` parameter for robust handling.
|
||||
- **Vision ID Safety Net**: Enhanced `lookup_id_random_pop` to resolve random string IDs found in any `*_id` field, ensuring "Vision" style payloads are correctly converted to integers.
|
||||
|
||||
---
|
||||
|
||||
## 2. 🗓️ Near Term Memory (Strategic Context)
|
||||
*This section tracks active projects (1-2 weeks scope). It answers "Why are we doing this?"*
|
||||
|
||||
### 📩 In-Flight RAR Requests
|
||||
- [ ] **mcp_agent**: Real-world test of `ae_field_manage.py` (ID: 153357623).
|
||||
- [ ] **codebase_investigator**: Review report for Aether extension and journal management (ID: 155435511).
|
||||
|
||||
### 🎯 Strategic Goals (Current Sprint)
|
||||
- **Primary:** OSIT_dev Environment Optimization & Context Stabilization (Template v1.2 Adoption).
|
||||
- **Secondary:** ID Vision Phase 2 Migration and V3 API Migration (Contacts/Clients).
|
||||
|
||||
### 🚧 Active Workstreams
|
||||
- **[ID Vision]:** Phase 2 complete. Strictly enforced string-ID standardization for Page, Post, Person, Journal, Contact, and User models. (ID: 161311118 - DONE).
|
||||
- **[Infrastructure]:** Restore AE Events Presentation Launcher (Electron) (ID: 221513945).
|
||||
- **[Infrastructure]:** Pydantic V2 Migration Impact Analysis (Technical Debt).
|
||||
- **[Journals]:** UI: Implementation of Quick Add & Append/Prepend (ID: 185821382).
|
||||
|
||||
### 🧠 Recent Decisions
|
||||
- **ID Hardening:** Modified the `map_v3_ids` root validator across core models to explicitly delete aliased integer IDs (e.g., `post_id`, `journal_id`) to prevent Pydantic coercion of legacy integers into strings.
|
||||
- **Search Optimization:** Standardized on `default_qry_str` for optimized fulltext searching. `Event_Badge_Base` is noted as a temporary outlier (`default_qry_string`) awaiting frontend alignment.
|
||||
- **Privacy & Information Hiding:** Centralized `public_read` flag in object definitions and excluded internal file sharding paths from responses.
|
||||
|
||||
---
|
||||
|
||||
## 3. 🧠 Short Term Memory (Session Context)
|
||||
*This section is the "Scratchpad" for the current interaction. It is cleared or summarized often.*
|
||||
|
||||
- **Status:** Online
|
||||
- **Last Action:** Successfully refactored `GEMINI.md` to v1.2 structure.
|
||||
- **Current Blocker:** None.
|
||||
- **Immediate Next Step:** Check for new messages in the inbox or proceed with high-priority tasks.
|
||||
|
||||
---
|
||||
|
||||
## 4. 📂 Reference: Directory & Whitelist
|
||||
*Low-density reference data. Keep at the bottom to avoid cluttering the prompt's "hot zone".*
|
||||
|
||||
### 🛡️ File Whitelist
|
||||
- `~/tmp`
|
||||
- `~/OSIT_dev/aether_api_fastapi`
|
||||
- `~/agents_sync`
|
||||
|
||||
### 🗺️ Standard Directory Map
|
||||
- **`app/methods/`**: Object-specific business logic.
|
||||
- **`app/models/`**: Pydantic schemas.
|
||||
- **`app/object_definitions/`**: V3 Metadata definitions.
|
||||
- **`app/routers/`**: API endpoints.
|
||||
|
||||
### 📋 Aether API Development Protocol
|
||||
0. **Pre-Flight Check:** Verify `git status`. Ensure all previous working changes are committed.
|
||||
1. **Strategic Plan:** Write a concise plan identifying the issue, specific files, and verification steps (curl commands/test scripts).
|
||||
2. **Implementation:** Perform atomic code modifications using `replace` or `write_file`.
|
||||
3. **Syntax Validation:** Run `python3 -m py_compile <modified_file>` immediately.
|
||||
4. **Process Cycle:** Restart the Docker FastAPI service: `docker restart aether_container_env-ae_api-2`.
|
||||
5. **Empirical Testing:** Execute `curl` commands and inspect logs: `tail -n 20 ~/OSIT_dev/aether_container_env/logs/ae_api/aether_api.log`.
|
||||
6. **Finalize:** Commit changes with a descriptive message and sync documentation.
|
||||
2
README.md
Executable file
2
README.md
Executable file
@@ -0,0 +1,2 @@
|
||||
# Aether API Python FastAPI
|
||||
The Aether API was created and is being developed by Scott Idem using the Python FastAPI framework.
|
||||
12
aether_api_fastapi.code-workspace
Normal file
12
aether_api_fastapi.code-workspace
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"cSpell.words": [
|
||||
"poolclass"
|
||||
]
|
||||
}
|
||||
}
|
||||
0
app/__init__.py
Normal file
0
app/__init__.py
Normal file
84
app/ae_obj_types_def.py
Normal file
84
app/ae_obj_types_def.py
Normal file
@@ -0,0 +1,84 @@
|
||||
"""
|
||||
This file centralizes the object type definitions for the Aether API.
|
||||
It merges definitions from modular files in app/object_definitions/ to support
|
||||
both V2 (legacy) and V3 CRUD operations.
|
||||
"""
|
||||
|
||||
# Restore blanket imports for legacy compatibility (V1 and V2 rely on these)
|
||||
from app.models.response_models import *
|
||||
from app.models.api_crud_models import *
|
||||
from app.models.account_models import *
|
||||
from app.models.account_cfg_models import *
|
||||
from app.models.activity_log_models import *
|
||||
from app.models.address_models import *
|
||||
from app.models.archive_models import *
|
||||
from app.models.archive_content_models import *
|
||||
from app.models.contact_models import *
|
||||
from app.models.cont_edu_cert_models import *
|
||||
from app.models.cont_edu_cert_person_models import *
|
||||
from app.models.data_store_models import *
|
||||
from app.models.event_models import *
|
||||
from app.models.event_abstract_models import *
|
||||
from app.models.event_badge_models import *
|
||||
from app.models.event_badge_template_models import *
|
||||
from app.models.event_device_models import *
|
||||
from app.models.event_exhibit_models import *
|
||||
from app.models.event_exhibit_tracking_models import *
|
||||
from app.models.event_file_models import *
|
||||
from app.models.event_location_models import *
|
||||
from app.models.event_person_models import *
|
||||
from app.models.event_person_tracking_models import *
|
||||
from app.models.event_presentation_models import *
|
||||
from app.models.event_presenter_models import *
|
||||
from app.models.event_registration_models import *
|
||||
from app.models.event_session_models import *
|
||||
from app.models.event_track_models import *
|
||||
from app.models.grant_models import *
|
||||
from app.models.hosted_file_models import *
|
||||
from app.models.journal_models import *
|
||||
from app.models.journal_entry_models import *
|
||||
from app.models.log_client_viewing_models import Log_Client_Viewing_Base
|
||||
from app.models.membership_cfg_models import *
|
||||
from app.models.membership_group_models import *
|
||||
from app.models.membership_person_group_models import *
|
||||
from app.models.membership_person_models import *
|
||||
from app.models.membership_person_profile_models import *
|
||||
from app.models.membership_type_models import *
|
||||
from app.models.membership_person_type_models import *
|
||||
from app.models.order_models import *
|
||||
from app.models.order_cart_models import *
|
||||
from app.models.organization_models import *
|
||||
from app.models.page_models import *
|
||||
from app.models.person_models import *
|
||||
from app.models.product_models import *
|
||||
from app.models.post_models import *
|
||||
from app.models.post_comment_models import *
|
||||
from app.models.site_models import *
|
||||
from app.models.site_domain_models import *
|
||||
from app.models.sponsorship_cfg_models import *
|
||||
from app.models.sponsorship_models import *
|
||||
from app.models.user_models import *
|
||||
from app.models.user_role_models import *
|
||||
from app.models.e_stripe_models import *
|
||||
|
||||
# Modularized definitions
|
||||
from app.object_definitions.core import core_obj_li
|
||||
from app.object_definitions.events import event_obj_li
|
||||
from app.object_definitions.journals import journal_obj_li
|
||||
from app.object_definitions.orders import order_obj_li
|
||||
from app.object_definitions.cms import cms_obj_li
|
||||
from app.object_definitions.lookups import lu_obj_li
|
||||
from app.object_definitions.membership import membership_obj_li
|
||||
from app.object_definitions.other import other_obj_li
|
||||
|
||||
# Merge all modular definitions into the main registry
|
||||
obj_type_kv_li = {
|
||||
**core_obj_li,
|
||||
**event_obj_li,
|
||||
**journal_obj_li,
|
||||
**order_obj_li,
|
||||
**cms_obj_li,
|
||||
**lu_obj_li,
|
||||
**membership_obj_li,
|
||||
**other_obj_li,
|
||||
}
|
||||
71
app/config.py.default
Normal file
71
app/config.py.default
Normal file
@@ -0,0 +1,71 @@
|
||||
# Configuration file for this FastAPI app.
|
||||
import os
|
||||
from pydantic import BaseSettings
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
|
||||
class Settings(BaseSettings):
|
||||
AETHER_CFG: Dict[str, Any] = {
|
||||
"id": os.getenv('AE_CFG_ID', '0')
|
||||
}
|
||||
|
||||
JWT_KEY: str = os.getenv('AE_API_JWT_KEY', 'fake-super-secret-token')
|
||||
|
||||
# Database Connection
|
||||
DB_SERVER: str = os.getenv('AE_DB_SERVER', 'mariadb')
|
||||
DB_PORT: str = os.getenv('AE_DB_PORT', '3306')
|
||||
DB_NAME: str = os.getenv('AE_DB_NAME', 'aether_dev')
|
||||
DB_USER: str = os.getenv('AE_DB_USERNAME', 'aether_dev')
|
||||
DB_PASS: str = os.getenv('AE_DB_PASSWORD', '')
|
||||
|
||||
@property
|
||||
def SQLALCHEMY_DB_URI(self) -> str:
|
||||
return f"mysql://{self.DB_USER}:{self.DB_PASS}@{self.DB_SERVER}:{self.DB_PORT}/{self.DB_NAME}"
|
||||
|
||||
@property
|
||||
def DB(self) -> Dict[str, Any]:
|
||||
return {
|
||||
"server": self.DB_SERVER,
|
||||
"port": self.DB_PORT,
|
||||
"name": self.DB_NAME,
|
||||
"username": self.DB_USER,
|
||||
"password": self.DB_PASS,
|
||||
"connect_timeout": int(os.getenv('AE_DB_CONNECTION_TIMEOUT', 20)),
|
||||
"pool_recycle": int(os.getenv('AE_DB_POOL_RECYCLE', 1800))
|
||||
}
|
||||
|
||||
# Logging
|
||||
LOG_PATH: Dict[str, str] = {
|
||||
"app": os.getenv('AE_API_LOG_PATH', '/logs/aether_api.log')
|
||||
}
|
||||
|
||||
# Redis
|
||||
REDIS: Dict[str, str] = {
|
||||
"server": os.getenv('AE_REDIS_SERVER', 'redis'),
|
||||
"port": os.getenv('AE_REDIS_PORT', '6379')
|
||||
}
|
||||
|
||||
# --- CRITICAL CONFIGURATIONS ---
|
||||
# Send SMTP Email
|
||||
SMTP: Dict[str, str] = {
|
||||
"server": os.getenv('AE_SMTP_SERVER', ''),
|
||||
"port": os.getenv('AE_SMTP_PORT', '465'),
|
||||
"username": os.getenv('AE_SMTP_USERNAME', ''),
|
||||
"password": os.getenv('AE_SMTP_PASSWORD', '')
|
||||
}
|
||||
|
||||
# Server Hosted File Paths
|
||||
FILES_PATH: Dict[str, str] = {
|
||||
"hosted_files_root": os.getenv('AE_FILES_PATH_ROOT', '/srv/hosted_files'),
|
||||
"hosted_tmp_root": os.getenv('AE_FILES_PATH_TMP', '/srv/hosted_tmp')
|
||||
}
|
||||
# --- END CRITICAL CONFIGURATIONS ---
|
||||
|
||||
# CORS
|
||||
ORIGINS_REGEX: str = os.getenv('AE_API_ORIGINS_REGEX', '(https://.*\.oneskyit\.com)|(https://.*\.oneskyit\.com:4443)')
|
||||
ORIGINS: List[str] = [
|
||||
'https://oneskyit.com',
|
||||
'http://fastapi.localhost',
|
||||
'http://svelte.oneskyit.local:5555',
|
||||
]
|
||||
|
||||
settings = Settings()
|
||||
28
app/db_connection.py
Normal file
28
app/db_connection.py
Normal file
@@ -0,0 +1,28 @@
|
||||
"""
|
||||
Independent database connection module to prevent circular imports.
|
||||
"""
|
||||
import logging
|
||||
from sqlalchemy import create_engine
|
||||
from app.config import settings
|
||||
|
||||
# Use local logger to avoid importing app.log (which might create cycles)
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
db_uri = settings.SQLALCHEMY_DB_URI
|
||||
engine = create_engine(
|
||||
url = db_uri,
|
||||
echo = False,
|
||||
pool_use_lifo = True,
|
||||
pool_pre_ping = True,
|
||||
pool_recycle = settings.DB['pool_recycle'],
|
||||
isolation_level = 'READ COMMITTED',
|
||||
connect_args = {'connect_timeout': settings.DB['connect_timeout']}
|
||||
)
|
||||
|
||||
log.info('DB Connection initializing...')
|
||||
db = None
|
||||
try:
|
||||
db = engine.connect()
|
||||
log.info(f'Connected to database: {db_uri}')
|
||||
except Exception:
|
||||
log.exception('Could not connect to database.')
|
||||
141
app/db_sql.py
Normal file
141
app/db_sql.py
Normal file
@@ -0,0 +1,141 @@
|
||||
import logging
|
||||
from app.log import logger_reset
|
||||
|
||||
# 1. Foundational connection and error state from SQL Core
|
||||
from app.lib_sql_core import (
|
||||
db, engine, reconnect_db, sql_connect,
|
||||
get_last_sql_error, set_last_sql_error
|
||||
)
|
||||
|
||||
# 2. Foundational CRUD logic from SQL Crud library
|
||||
from app.lib_sql_crud import (
|
||||
sql_insert, sql_update, sql_insert_or_update,
|
||||
sql_select, run_sql_select, sql_delete
|
||||
)
|
||||
|
||||
# 3. Search logic parts (delegated from search library)
|
||||
from app.lib_sql_search import (
|
||||
sql_limit_offset_part as _sql_limit_offset_part,
|
||||
sql_and_like_part as _sql_and_like_part,
|
||||
sql_or_like_part as _sql_or_like_part,
|
||||
sql_and_in_dict_li_part as _sql_and_in_dict_li_part,
|
||||
sql_and_qry_part as _sql_and_qry_part,
|
||||
sql_fulltext_qry_part as _sql_fulltext_qry_part,
|
||||
sql_enable_part as _sql_enable_part,
|
||||
sql_hidden_part as _sql_hidden_part,
|
||||
sql_where_qry_part as _sql_where_qry_part,
|
||||
sql_search_qry_part as _sql_search_qry_part
|
||||
)
|
||||
|
||||
# 4. Redis and ID resolution helpers
|
||||
from app.lib_redis_helpers import (
|
||||
redis_lookup_id_random as _redis_lookup_id_random,
|
||||
get_id_random as _get_id_random,
|
||||
reset_redis as _reset_redis,
|
||||
lookup_id_random_pop as _lookup_id_random_pop
|
||||
)
|
||||
|
||||
|
||||
# ### BEGIN ### API DB SQL ### redis_lookup_id_random() ###
|
||||
@logger_reset
|
||||
def redis_lookup_id_random(
|
||||
record_id_random: int|str,
|
||||
table_name: str,
|
||||
check_int_id: bool = False,
|
||||
log_lvl: int = logging.WARNING,
|
||||
minutes: int = 30,
|
||||
reset_rate: int = 10,
|
||||
):
|
||||
return _redis_lookup_id_random(record_id_random, table_name, check_int_id, log_lvl, minutes, reset_rate)
|
||||
# ### END ### API DB SQL ### redis_lookup_id_random() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API DB SQL ### get_id_random() ###
|
||||
@logger_reset
|
||||
def get_id_random(record_id: int, table_name: str, log_lvl: int = logging.WARNING):
|
||||
return _get_id_random(record_id, table_name, log_lvl)
|
||||
# ### END ### API DB SQL ### get_id_random() ###
|
||||
|
||||
|
||||
@logger_reset
|
||||
def reset_redis():
|
||||
return _reset_redis()
|
||||
|
||||
|
||||
# ### BEGIN ### API DB SQL ### lookup_id_random_pop() ###
|
||||
@logger_reset
|
||||
def lookup_id_random_pop(obj_data: dict, log_lvl: int = logging.WARNING):
|
||||
return _lookup_id_random_pop(obj_data, log_lvl)
|
||||
# ### END ### API DB SQL ### lookup_id_random_pop() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API DB SQL Methods ### get_account_id_w_for_type_id() ###
|
||||
@logger_reset
|
||||
def get_account_id_w_for_type_id(for_type: str, for_id: int|str):
|
||||
if fid := redis_lookup_id_random(record_id_random=for_id, table_name=for_type):
|
||||
sql = f"SELECT account_id FROM `{for_type}` WHERE id = :fid LIMIT 1;"
|
||||
if result := sql_select(sql=sql, data={'fid': fid}):
|
||||
return result.get('account_id')
|
||||
return False
|
||||
# ### END ### API DB SQL Methods ### get_account_id_w_for_type_id() ###
|
||||
|
||||
|
||||
@logger_reset
|
||||
def sql_where_qry_part(qry_dict_li: list):
|
||||
return _sql_where_qry_part(qry_dict_li)
|
||||
|
||||
|
||||
@logger_reset
|
||||
def sql_fulltext_qry_part(fulltext_qry_dict: dict):
|
||||
return _sql_fulltext_qry_part(fulltext_qry_dict)
|
||||
|
||||
|
||||
@logger_reset
|
||||
def sql_and_qry_part(and_qry_dict_obj: dict):
|
||||
return _sql_and_qry_part(and_qry_dict_obj)
|
||||
|
||||
|
||||
@logger_reset
|
||||
def sql_and_like_part(and_like_dict_obj: dict):
|
||||
return _sql_and_like_part(and_like_dict_obj)
|
||||
|
||||
|
||||
@logger_reset
|
||||
def sql_or_like_part(or_like_dict_obj: dict):
|
||||
return _sql_or_like_part(or_like_dict_obj)
|
||||
|
||||
|
||||
@logger_reset
|
||||
def sql_and_in_dict_li_part(and_in_dict_li_dict_obj: dict):
|
||||
return _sql_and_in_dict_li_part(and_in_dict_li_dict_obj)
|
||||
|
||||
|
||||
@logger_reset
|
||||
def sql_enable_part(table_name: str, enabled: str):
|
||||
return _sql_enable_part(table_name, enabled)
|
||||
|
||||
|
||||
@logger_reset
|
||||
def sql_hidden_part(table_name: str, hidden: str):
|
||||
return _sql_hidden_part(table_name, hidden)
|
||||
|
||||
|
||||
@logger_reset
|
||||
def sql_limit_offset_part(limit: int, offset: int = 0):
|
||||
return _sql_limit_offset_part(limit, offset)
|
||||
|
||||
|
||||
@logger_reset
|
||||
def sql_search_qry_part(search_query: any, searchable_fields: list[str]|None = None, max_depth: int = 5, table_name: str|None = None):
|
||||
return _sql_search_qry_part(search_query, searchable_fields, max_depth, table_name)
|
||||
|
||||
__all__ = [
|
||||
'db', 'engine', 'sql_connect', 'sql_insert', 'sql_update', 'sql_select',
|
||||
'run_sql_select', 'sql_delete', 'redis_lookup_id_random', 'get_id_random',
|
||||
'reset_redis', 'lookup_id_random_pop', 'sql_where_qry_part',
|
||||
'sql_fulltext_qry_part', 'sql_and_qry_part', 'sql_and_like_part',
|
||||
'sql_or_like_part', 'sql_and_in_dict_li_part', 'sql_enable_part',
|
||||
'sql_hidden_part', 'sql_limit_offset_part', 'sql_search_qry_part',
|
||||
'sql_insert_or_update', 'get_account_id_w_for_type_id', 'reconnect_db',
|
||||
'get_last_sql_error', 'set_last_sql_error'
|
||||
]
|
||||
240
app/lib_api_crud_v3.py
Normal file
240
app/lib_api_crud_v3.py
Normal file
@@ -0,0 +1,240 @@
|
||||
from typing import Any, Dict, Optional, Union
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
|
||||
from app.lib_general_v3 import AccountContext, StatusFilterParams
|
||||
from app.models.error_models import StandardError
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
def format_db_error(raw_error: str) -> StandardError:
|
||||
"""
|
||||
Parses raw SQLAlchemy/MariaDB errors into structured StandardError objects.
|
||||
"""
|
||||
if not raw_error:
|
||||
return StandardError(
|
||||
category="unknown",
|
||||
message="An unspecified database error occurred."
|
||||
)
|
||||
|
||||
# 1. Extract Error Code and Message using regex
|
||||
# Standard MariaDB pattern: (code, "message")
|
||||
code = None
|
||||
message = raw_error
|
||||
recoverable = False
|
||||
|
||||
match = re.search(r'\((\d+),\s*["\'](.*?)["\']\s*\)', raw_error)
|
||||
if match:
|
||||
code = int(match.group(1))
|
||||
message = match.group(2).strip()
|
||||
else:
|
||||
# Fallback: remove all (parenthesized) blocks which often contain codes
|
||||
message = re.sub(r'\(.*?\)', '', raw_error).strip()
|
||||
|
||||
# 2. Categorize based on known MariaDB codes
|
||||
# Ref: https://mariadb.com/kb/en/mariadb-error-codes/
|
||||
if code in [1062]: # Duplicate Entry
|
||||
category = "database_duplicate"
|
||||
elif code in [1451, 1452]: # Foreign Key Constraint
|
||||
category = "database_constraint"
|
||||
elif code in [1045, 2002, 2003, 2006]: # Connection / Auth issues
|
||||
category = "database_connection"
|
||||
recoverable = True
|
||||
elif code in [1054, 1146]: # Unknown column / Table
|
||||
category = "database_schema"
|
||||
else:
|
||||
category = "database"
|
||||
|
||||
return StandardError(
|
||||
category=category,
|
||||
code=code,
|
||||
message=message,
|
||||
recoverable=recoverable,
|
||||
details=raw_error if category == "database" else None # Only include raw details for uncategorized errors
|
||||
)
|
||||
|
||||
def check_account_access(sql_result: Any, account: AccountContext, obj_name: str = None) -> bool:
|
||||
"""
|
||||
Enforce Multi-Tenant Data Isolation.
|
||||
|
||||
Verifies that the requested record belongs to the authenticated user's account.
|
||||
Returns True if:
|
||||
- User is a Super User or System (Bypass).
|
||||
- The record's `account_id` matches the user's `account_id`.
|
||||
"""
|
||||
if account.super or account.auth_method == 'bypass':
|
||||
return True
|
||||
if not account.account_id:
|
||||
return False
|
||||
|
||||
res_account_id = None
|
||||
if isinstance(sql_result, dict):
|
||||
if obj_name == 'account':
|
||||
res_account_id = sql_result.get('id')
|
||||
else:
|
||||
res_account_id = sql_result.get('account_id')
|
||||
|
||||
if res_account_id is not None and res_account_id != account.account_id:
|
||||
return False
|
||||
return True
|
||||
|
||||
def apply_forced_account_filter(and_qry_dict: Optional[Dict], account: AccountContext, model: Any, obj_name: str, table_name: str = None) -> Dict:
|
||||
"""
|
||||
Secure Search Filtering.
|
||||
|
||||
Automatically appends an `account_id` filter to database queries to ensure
|
||||
users only retrieve records associated with their own account.
|
||||
|
||||
Now schema-aware: checks if the column actually exists in the DB before applying.
|
||||
"""
|
||||
forced = and_qry_dict or {}
|
||||
if account.super or account.auth_method == 'bypass':
|
||||
return forced
|
||||
|
||||
# 1. Determine the target column
|
||||
target_col = 'account_id'
|
||||
if obj_name == 'account':
|
||||
target_col = 'id'
|
||||
|
||||
# 2. Check if the model even supports it
|
||||
if model and hasattr(model, '__fields__') and target_col not in model.__fields__:
|
||||
return forced
|
||||
|
||||
# 3. If we have a table name, verify the column exists in the physical DB schema
|
||||
# (Important for Views that might exclude account_id for performance/privacy)
|
||||
if table_name:
|
||||
from app import lib_sql_core
|
||||
from sqlalchemy import text
|
||||
try:
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
conn.execute(text(f"SELECT `{target_col}` FROM `{table_name}` LIMIT 0"))
|
||||
has_col = True
|
||||
except:
|
||||
has_col = False
|
||||
|
||||
forced[target_col] = account.account_id
|
||||
return forced
|
||||
|
||||
def filter_order_by(order_by_li: Any, model: Any, table_name: str = None) -> Optional[Dict[str, str]]:
|
||||
"""
|
||||
Sanitize Sorting Parameters.
|
||||
|
||||
Prevents SQL injection and logic errors by validating that requested sort columns
|
||||
actually exist in the Pydantic model and/or the database table.
|
||||
"""
|
||||
if not order_by_li or not isinstance(order_by_li, dict) or not model:
|
||||
return order_by_li
|
||||
if not hasattr(model, '__fields__'):
|
||||
return order_by_li
|
||||
|
||||
model_fields = set(model.__fields__.keys())
|
||||
model_fields.update({f.alias for f in model.__fields__.values() if f.alias})
|
||||
filtered = {k: v for k, v in order_by_li.items() if k in model_fields}
|
||||
|
||||
if table_name and filtered:
|
||||
from app.db_sql import db
|
||||
from sqlalchemy import text
|
||||
final_filtered = {}
|
||||
for column in filtered:
|
||||
try:
|
||||
# Lightweight check to see if column exists in SQL
|
||||
db.execute(text(f"SELECT `{column}` FROM `{table_name}` LIMIT 0"))
|
||||
final_filtered[column] = filtered[column]
|
||||
except Exception:
|
||||
pass
|
||||
filtered = final_filtered
|
||||
return filtered
|
||||
|
||||
def get_supported_filters(model: Any, status_filter: StatusFilterParams) -> StatusFilterParams:
|
||||
"""
|
||||
Adaptive Status Filtering.
|
||||
|
||||
Adjusts the default filters (enabled/hidden) based on whether the target object
|
||||
actually supports those concepts (i.e., has those columns).
|
||||
"""
|
||||
if not model or not hasattr(model, "__fields__"):
|
||||
return status_filter
|
||||
# We create a new instance to avoid side effects on the dependency object
|
||||
from app.routers.dependencies_v3 import StatusFilterParams as SF
|
||||
adjusted = SF()
|
||||
adjusted.enabled = status_filter.enabled
|
||||
adjusted.hidden = status_filter.hidden
|
||||
|
||||
if 'enable' not in model.__fields__:
|
||||
adjusted.enabled = 'all'
|
||||
if 'hide' not in model.__fields__:
|
||||
adjusted.hidden = 'all'
|
||||
return adjusted
|
||||
|
||||
def safe_json_loads(json_str: Optional[str]) -> Any:
|
||||
if not json_str or json_str == 'undefined': return None
|
||||
try: return json.loads(json_str)
|
||||
except: return None
|
||||
|
||||
def sanitize_payload(data: dict, model: Any, ignore_extra: bool = False) -> None:
|
||||
"""
|
||||
Sanitizes an input payload before database insertion or update.
|
||||
|
||||
1. Resolves ID strings to integers:
|
||||
- Handles legacy `*_id_random` fields.
|
||||
- Handles Vision `*_id` fields where the value is a string (e.g., account_id: "random_str").
|
||||
2. Removes virtual lookup fields (ending in `_id_random`) after resolution.
|
||||
3. Removes fields explicitly marked for exclusion in the model's
|
||||
`fields_to_exclude_from_db` ClassVar (e.g., view-only fields).
|
||||
4. If `ignore_extra` is True, removes all fields NOT present in the model definition.
|
||||
|
||||
Modifies the `data` dictionary in-place.
|
||||
"""
|
||||
if not isinstance(data, dict):
|
||||
return
|
||||
|
||||
from app.db_sql import redis_lookup_id_random
|
||||
|
||||
# Resolve ID strings to integers
|
||||
for k, v in list(data.items()):
|
||||
if not v or not isinstance(v, str):
|
||||
continue
|
||||
|
||||
target_id_field = None
|
||||
obj_type_lookup = None
|
||||
|
||||
# Scenario A: Legacy suffix (e.g., account_id_random: "abc")
|
||||
if k.endswith('_id_random') and k != 'id_random':
|
||||
target_id_field = k.replace('_id_random', '_id')
|
||||
obj_type_lookup = k.replace('_id_random', '')
|
||||
|
||||
# Scenario B: Vision naming (e.g., account_id: "abc")
|
||||
# We only resolve if it's a string of the correct length (random ID format)
|
||||
elif k.endswith('_id') and 11 <= len(v) <= 22:
|
||||
target_id_field = k
|
||||
obj_type_lookup = k.replace('_id', '')
|
||||
|
||||
if target_id_field and obj_type_lookup:
|
||||
# Special table mapping if needed
|
||||
if obj_type_lookup == 'address_location': obj_type_lookup = 'address'
|
||||
|
||||
resolved_id = redis_lookup_id_random(record_id_random=v, table_name=obj_type_lookup)
|
||||
if resolved_id:
|
||||
data[target_id_field] = resolved_id
|
||||
# If we were handling Scenario A, remove the original random key
|
||||
if k.endswith('_id_random'):
|
||||
del data[k]
|
||||
|
||||
# Filter out model-specific excluded fields (e.g., view-only fields)
|
||||
if hasattr(model, 'fields_to_exclude_from_db'):
|
||||
for k in model.fields_to_exclude_from_db:
|
||||
if k in data:
|
||||
del data[k]
|
||||
|
||||
# If permissive mode is on, remove any field not in the Pydantic model
|
||||
if ignore_extra and model and hasattr(model, '__fields__'):
|
||||
model_fields = set(model.__fields__.keys())
|
||||
# Also check for aliases
|
||||
for f in model.__fields__.values():
|
||||
if f.alias:
|
||||
model_fields.add(f.alias)
|
||||
|
||||
extra_keys = [k for k in data.keys() if k not in model_fields]
|
||||
for k in extra_keys:
|
||||
del data[k]
|
||||
88
app/lib_config_v3.py
Normal file
88
app/lib_config_v3.py
Normal file
@@ -0,0 +1,88 @@
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
log = logging.getLogger('root')
|
||||
|
||||
def validate_critical_config(settings: Any):
|
||||
"""
|
||||
Validates that essential settings are populated and not using placeholders.
|
||||
Logs warnings or errors for missing critical infrastructure.
|
||||
"""
|
||||
log.info("Checking critical system configuration...")
|
||||
|
||||
# 1. Database Check
|
||||
db = getattr(settings, 'DB', {})
|
||||
if not db.get('server') or db.get('server') == 'mariadb':
|
||||
# 'mariadb' is the default in .env, usually fine, but worth noting
|
||||
log.info(f"Database server: {db.get('server')}")
|
||||
|
||||
# 2. SMTP Check
|
||||
smtp = getattr(settings, 'SMTP', {})
|
||||
if not smtp.get('server'):
|
||||
log.warning("CRITICAL: SMTP server not configured. Email features will fail.")
|
||||
if smtp.get('password') == 'set-in-ae-sql-db-cnf-tbl':
|
||||
log.error("CRITICAL: SMTP password is still set to placeholder. Email authentication will fail.")
|
||||
|
||||
# 3. Security Check
|
||||
jwt_key = getattr(settings, 'JWT_KEY', '')
|
||||
if not jwt_key or jwt_key == 'fake-super-secret-token':
|
||||
log.error("SECURITY: JWT_KEY is missing or using a known fake token!")
|
||||
|
||||
log.info("Configuration validation complete.")
|
||||
|
||||
def bootstrap_db_config(settings: Any) -> bool:
|
||||
"""
|
||||
Loads dynamic settings from the 'cfg' table and updates the settings object.
|
||||
Uses deferred import of sql_select to avoid circular dependencies.
|
||||
"""
|
||||
# CRITICAL: Deferred import to prevent boot-time circular dependencies
|
||||
from app.db_sql import sql_select
|
||||
|
||||
cfg_id = settings.AETHER_CFG.get('id', '0')
|
||||
log.info(f"Bootstrapping system configuration from DB (cfg_id={cfg_id})...")
|
||||
|
||||
try:
|
||||
# Fetch the config record
|
||||
aether_cfg_sql = sql_select(
|
||||
table_name='cfg',
|
||||
record_id=int(cfg_id),
|
||||
as_list=False,
|
||||
max_count=1,
|
||||
)
|
||||
|
||||
# In some cases sql_select might return a single-item list even with as_list=False
|
||||
if isinstance(aether_cfg_sql, list):
|
||||
if len(aether_cfg_sql) > 0:
|
||||
aether_cfg_sql = aether_cfg_sql[0]
|
||||
else:
|
||||
aether_cfg_sql = None
|
||||
|
||||
if not aether_cfg_sql or not isinstance(aether_cfg_sql, dict):
|
||||
log.error(f"FAILED to load system config from DB for ID {cfg_id}. Table 'cfg' might be empty or ID missing.")
|
||||
return False
|
||||
|
||||
# --- Update Database settings ---
|
||||
# Safety: Only update if the values are provided in the DB record
|
||||
if aether_cfg_sql.get('db_server'): settings.DB_SERVER = aether_cfg_sql.get('db_server')
|
||||
if aether_cfg_sql.get('db_port'): settings.DB_PORT = str(aether_cfg_sql.get('db_port'))
|
||||
if aether_cfg_sql.get('db_name'): settings.DB_NAME = aether_cfg_sql.get('db_name')
|
||||
if aether_cfg_sql.get('db_username'): settings.DB_USER = aether_cfg_sql.get('db_username')
|
||||
if aether_cfg_sql.get('db_password'): settings.DB_PASS = aether_cfg_sql.get('db_password')
|
||||
|
||||
# --- Update SMTP Settings ---
|
||||
if aether_cfg_sql.get('smtp_server'): settings.SMTP['server'] = aether_cfg_sql.get('smtp_server')
|
||||
if aether_cfg_sql.get('smtp_port'): settings.SMTP['port'] = str(aether_cfg_sql.get('smtp_port'))
|
||||
if aether_cfg_sql.get('smtp_username'): settings.SMTP['username'] = aether_cfg_sql.get('smtp_username')
|
||||
if aether_cfg_sql.get('smtp_password'): settings.SMTP['password'] = aether_cfg_sql.get('smtp_password')
|
||||
|
||||
# --- Update File Paths ---
|
||||
# DEPRECATED: Filesystem paths should be controlled by the Environment/Docker, not the DB.
|
||||
# if aether_cfg_sql.get('path_hosted_files_root'): settings.FILES_PATH['hosted_files_root'] = aether_cfg_sql.get('path_hosted_files_root')
|
||||
# if aether_cfg_sql.get('path_hosted_tmp_root'): settings.FILES_PATH['hosted_tmp_root'] = aether_cfg_sql.get('path_hosted_tmp_root')
|
||||
|
||||
log.info("System configuration successfully synchronized with DB.")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
log.exception(f"Unexpected error during system bootstrap: {e}")
|
||||
return False
|
||||
195
app/lib_email.py
Normal file
195
app/lib_email.py
Normal file
@@ -0,0 +1,195 @@
|
||||
import html2text
|
||||
import smtplib, ssl
|
||||
import logging
|
||||
from email.message import EmailMessage
|
||||
from email.headerregistry import Address
|
||||
from typing import Optional
|
||||
|
||||
from app.log import logger_reset
|
||||
from app.config import settings
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# ### BEGIN ### API Lib Email ### send_email() ###
|
||||
# Moved from lib_general.py 2026-01-07
|
||||
@logger_reset
|
||||
def send_email(
|
||||
from_email: str,
|
||||
to_email: str,
|
||||
subject: str,
|
||||
body_html: str,
|
||||
|
||||
from_name: str = '',
|
||||
reply_to_email: str = '',
|
||||
reply_to_name: str = '',
|
||||
to_name: str = '',
|
||||
cc_email: str = '',
|
||||
cc_name: str = '',
|
||||
bcc_email: str = '',
|
||||
bcc_name: str = '',
|
||||
body_text: str = '',
|
||||
|
||||
test: bool = False,
|
||||
log_lvl: int = logging.WARNING, # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
):
|
||||
log.setLevel(log_lvl)
|
||||
log.debug(locals())
|
||||
|
||||
if test:
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.debug('[TESTING] Running with send_email() in TEST mode')
|
||||
|
||||
message = EmailMessage()
|
||||
if subject:
|
||||
message['Subject'] = subject
|
||||
else:
|
||||
return False
|
||||
|
||||
if from_email and from_name:
|
||||
try:
|
||||
message['From'] = Address(display_name=from_name, addr_spec=from_email)
|
||||
except Exception as e:
|
||||
log.exception('**** *** ** * ### BEGIN ### Exception Happened: Returning False * ** *** ****')
|
||||
return False
|
||||
elif from_email:
|
||||
try:
|
||||
message['From'] = Address(display_name=from_email, addr_spec=from_email)
|
||||
except Exception as e:
|
||||
log.exception('**** *** ** * ### BEGIN ### Exception Happened: Returning False * ** *** ****')
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
if reply_to_email and reply_to_name:
|
||||
try:
|
||||
message['Reply-To'] = Address(display_name=reply_to_name, addr_spec=reply_to_email)
|
||||
except Exception as e:
|
||||
log.exception('**** *** ** * ### BEGIN ### Exception Happened: Returning False * ** *** ****')
|
||||
return False
|
||||
elif reply_to_email:
|
||||
try:
|
||||
message['Reply-To'] = Address(display_name=reply_to_email, addr_spec=reply_to_email)
|
||||
except Exception as e:
|
||||
log.exception('**** *** ** * ### BEGIN ### Exception Happened: Returning False * ** *** ****')
|
||||
return False
|
||||
|
||||
if to_email and to_name:
|
||||
try:
|
||||
message['To'] = Address(display_name=to_name, addr_spec=to_email)
|
||||
except Exception as e:
|
||||
log.exception('**** *** ** * ### BEGIN ### Exception Happened: Returning False * ** *** ****')
|
||||
return False
|
||||
elif to_email:
|
||||
try:
|
||||
message['To'] = Address(display_name=to_email, addr_spec=to_email)
|
||||
except Exception as e:
|
||||
log.exception('**** *** ** * ### BEGIN ### Exception Happened: Returning False * ** *** ****')
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
if cc_email and cc_name:
|
||||
try:
|
||||
message['Cc'] = Address(display_name=cc_name, addr_spec=cc_email)
|
||||
except Exception as e:
|
||||
log.exception('**** *** ** * ### BEGIN ### Exception Happened: Returning False * ** *** ****')
|
||||
return False
|
||||
elif cc_email:
|
||||
try:
|
||||
message['Cc'] = Address(display_name=cc_email, addr_spec=cc_email)
|
||||
except Exception as e:
|
||||
log.exception('**** *** ** * ### BEGIN ### Exception Happened: Returning False * ** *** ****')
|
||||
return False
|
||||
|
||||
if bcc_email and bcc_name:
|
||||
try:
|
||||
message['Bcc'] = Address(display_name=bcc_name, addr_spec=bcc_email)
|
||||
except Exception as e:
|
||||
log.exception('**** *** ** * ### BEGIN ### Exception Happened: Returning False * ** *** ****')
|
||||
return False
|
||||
elif bcc_email:
|
||||
try:
|
||||
message['Bcc'] = Address(display_name=bcc_email, addr_spec=bcc_email)
|
||||
except Exception as e:
|
||||
log.exception('**** *** ** * ### BEGIN ### Exception Happened: Returning False * ** *** ****')
|
||||
return False
|
||||
|
||||
html_version = """
|
||||
<html>
|
||||
<body>
|
||||
|
||||
"""+body_html+"""
|
||||
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
if body_text:
|
||||
text_version = body_text
|
||||
else:
|
||||
text_version = html2text.html2text(html_version)
|
||||
|
||||
message.set_content(text_version)
|
||||
message.add_alternative(html_version, subtype='html')
|
||||
|
||||
log.info('Sending email...')
|
||||
|
||||
# Safe access to SMTP settings
|
||||
smtp_settings = getattr(settings, 'SMTP', {})
|
||||
if not smtp_settings:
|
||||
log.error('SMTP settings not found in configuration. Returning False.')
|
||||
return False
|
||||
|
||||
log.debug(smtp_settings)
|
||||
|
||||
log.info(f'Subject: {subject}')
|
||||
log.info(f'From: {from_email} Reply To: {reply_to_email} To: {to_email} CC: {cc_email} BCC: {bcc_email}')
|
||||
|
||||
log.debug('Message:')
|
||||
log.debug(message.as_string())
|
||||
|
||||
log.info('Creating SMTP SSL connection...')
|
||||
context = ssl.create_default_context()
|
||||
|
||||
# Validate SMTP settings
|
||||
smtp_server = smtp_settings.get('server')
|
||||
smtp_port = smtp_settings.get('port')
|
||||
smtp_username = smtp_settings.get('username')
|
||||
smtp_password = smtp_settings.get('password')
|
||||
|
||||
if not smtp_server or not smtp_port:
|
||||
log.error(f'Error: SMTP server or port not configured. Server: {smtp_server}, Port: {smtp_port}')
|
||||
return False
|
||||
|
||||
try:
|
||||
smtp_port = int(smtp_port)
|
||||
except ValueError:
|
||||
log.error(f'Error: Invalid SMTP port: {smtp_port}')
|
||||
return False
|
||||
|
||||
log.info('SMTP configuration, connect, and send')
|
||||
log.info(f'Server: {smtp_server} Port: {smtp_port} Username: {smtp_username}')
|
||||
|
||||
log.info('Trying smtplib.SMTP_SSL in send_email()...')
|
||||
if test:
|
||||
log.info('[TESTING] Email will NOT actually be sent! [TEST MODE]')
|
||||
try:
|
||||
with smtplib.SMTP_SSL(smtp_server, smtp_port, context=context) as server:
|
||||
log.info('SMTP log in...')
|
||||
# Avoid logging password in debug
|
||||
log.debug(f'Server: {smtp_server} Port: {smtp_port} Username: {smtp_username}')
|
||||
|
||||
if smtp_username and smtp_password:
|
||||
server.login(smtp_username, smtp_password)
|
||||
|
||||
log.info('SMTP send message...')
|
||||
if not test:
|
||||
log.info('Email sent! Returning True')
|
||||
server.send_message(message)
|
||||
else:
|
||||
log.info('[TESTING] Email (NOT) sent! Returning True [TEST MODE]')
|
||||
return True
|
||||
except Exception as e:
|
||||
log.error(f'Error: Unable to send email. Exception: {e}')
|
||||
return False
|
||||
# ### END ### API Lib Email ### send_email() ###
|
||||
116
app/lib_export.py
Normal file
116
app/lib_export.py
Normal file
@@ -0,0 +1,116 @@
|
||||
import os
|
||||
import pandas
|
||||
import pathlib
|
||||
import logging
|
||||
from typing import Optional, Union
|
||||
|
||||
from app.log import logger_reset
|
||||
from app.config import settings
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# ### BEGIN ### API Lib Export ### create_export_file() ###
|
||||
# Moved from lib_general.py 2026-01-07
|
||||
@logger_reset
|
||||
def create_export_file(
|
||||
data_dict_list: list,
|
||||
subdir_path: str,
|
||||
filename: str,
|
||||
column_name_li: list = [],
|
||||
rm_id: bool = True,
|
||||
export_type: str = 'CSV', # CSV, Excel
|
||||
) -> Union[bool, str]:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
hosted_tmp_path = settings.FILES_PATH['hosted_tmp_root']
|
||||
log.info(f'Hosted Temp Path: {hosted_tmp_path}')
|
||||
|
||||
subdirectory_dest = os.path.join(hosted_tmp_path, subdir_path)
|
||||
log.debug(subdirectory_dest)
|
||||
pathlib.Path(subdirectory_dest).mkdir(parents=True, exist_ok=True)
|
||||
file_dest_w_subdir = os.path.join(subdirectory_dest, filename)
|
||||
log.info(f'File Dest With Subdir: {file_dest_w_subdir}')
|
||||
|
||||
if column_name_li:
|
||||
log.info('Using column name list passed')
|
||||
else:
|
||||
log.info('Using an auto generated column name list')
|
||||
column_name_li = list(data_dict_list[0].keys())
|
||||
log.debug(column_name_li)
|
||||
|
||||
if rm_id:
|
||||
for column_name in list(column_name_li):
|
||||
if column_name.endswith('_id'):
|
||||
column_name_li.remove(column_name)
|
||||
log.info(f'Removing column name: {column_name}')
|
||||
log.info(column_name_li)
|
||||
|
||||
data_dataframe = pandas.DataFrame(data_dict_list)
|
||||
log.debug(data_dataframe)
|
||||
|
||||
missing_cols = [col for col in column_name_li if col not in data_dataframe.columns]
|
||||
if missing_cols:
|
||||
column_name_li = [col for col in column_name_li if col not in missing_cols]
|
||||
|
||||
try:
|
||||
if export_type == 'CSV':
|
||||
log.info('Saving dataframe to CSV file')
|
||||
full_dest_path = file_dest_w_subdir+'.csv'
|
||||
filename_w_ext = filename+'.csv'
|
||||
tmp_file_path = os.path.join(subdir_path,filename_w_ext)
|
||||
data_dataframe.to_csv(
|
||||
full_dest_path,
|
||||
na_rep='NULL',
|
||||
columns=column_name_li,
|
||||
index=False,
|
||||
)
|
||||
elif export_type == 'Excel':
|
||||
log.info('Saving dataframe to Excel file')
|
||||
full_dest_path = file_dest_w_subdir+'.xlsx'
|
||||
filename_w_ext = filename+'.xlsx'
|
||||
tmp_file_path = os.path.join(subdir_path,filename_w_ext)
|
||||
data_dataframe.to_excel(
|
||||
full_dest_path,
|
||||
na_rep='NULL',
|
||||
columns=column_name_li,
|
||||
index=False,
|
||||
)
|
||||
except:
|
||||
log.exception('Something went wrong while trying to save the export file.')
|
||||
return False
|
||||
|
||||
log.info(f'Temp File Path: {tmp_file_path}')
|
||||
|
||||
return tmp_file_path
|
||||
# ### END ### API Lib Export ### create_export_file() ###
|
||||
|
||||
# ### BEGIN ### API Lib Export ### return_full_tmp_path() ###
|
||||
# This is for using with return FileResponse(path=full_tmp_path, filename=filename)
|
||||
# Moved from lib_general.py 2026-01-07
|
||||
@logger_reset
|
||||
def return_full_tmp_path(
|
||||
full_tmp_path: str = None,
|
||||
subdir_path: str = None,
|
||||
filename: str = None,
|
||||
) -> Union[bool, str]:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
hosted_tmp_path = settings.FILES_PATH['hosted_tmp_root']
|
||||
log.info(f'Hosted Temp Path: {hosted_tmp_path}')
|
||||
|
||||
if full_tmp_path:
|
||||
file_dest = os.path.join(hosted_tmp_path, full_tmp_path)
|
||||
return file_dest
|
||||
elif subdir_path and filename:
|
||||
subdirectory_dest = os.path.join(hosted_tmp_path, subdir_path)
|
||||
log.debug(subdirectory_dest)
|
||||
pathlib.Path(subdirectory_dest).mkdir(parents=True, exist_ok=True)
|
||||
file_dest_w_subdir = os.path.join(subdirectory_dest, filename)
|
||||
log.info(f'File Dest With Subdir: {file_dest_w_subdir}')
|
||||
|
||||
return file_dest_w_subdir
|
||||
else:
|
||||
return False
|
||||
# ### END ### API Lib Export ### return_full_tmp_path() ###
|
||||
264
app/lib_general.py
Normal file
264
app/lib_general.py
Normal file
@@ -0,0 +1,264 @@
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
import logging
|
||||
|
||||
from fastapi import Header, HTTPException, Response, status
|
||||
|
||||
from app.log import logger_reset
|
||||
from app.config import settings
|
||||
from app.db_sql import redis_lookup_id_random, sql_select
|
||||
|
||||
from app.lib_email import send_email
|
||||
from app.lib_export import create_export_file, return_full_tmp_path
|
||||
from app.lib_jwt import sign_jwt, decode_jwt
|
||||
from app.lib_hash import secure_hash_string, verify_secure_hash_string
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Lib General ### async get_token_header() ###
|
||||
def get_token_header(x_token: str = Header(...)):
|
||||
if x_token != 'fake-super-secret-token':
|
||||
raise HTTPException(status_code=400, detail='X-Token header invalid')
|
||||
# ### END ### API Lib General ### async get_token_header() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Lib General ### class Common_Route_Params ###
|
||||
# Updated 2023-01-30
|
||||
class Common_Route_Params_No_Account_ID:
|
||||
def __init__(
|
||||
self,
|
||||
x_account_id: int|None = None,
|
||||
x_account_id_random: str|None = None,
|
||||
x_no_account_id_token: str|None = None,
|
||||
enabled: str = 'enabled',
|
||||
limit: int = 10,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = False,
|
||||
response = None,
|
||||
):
|
||||
self.x_account_id = x_account_id
|
||||
self.x_account_id_random = x_account_id_random
|
||||
self.x_no_account_id_token = x_no_account_id_token
|
||||
self.enabled = enabled
|
||||
self.limit = limit
|
||||
self.offset = offset
|
||||
self.by_alias = by_alias
|
||||
self.exclude_unset = exclude_unset
|
||||
self.response = response
|
||||
# log.debug(response)
|
||||
# ### END ### API Lib General ### class Common_Route_Params ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Lib General ### common_route_params() ###
|
||||
# Updated 2023-01-30
|
||||
@logger_reset # This breaks things for some reason when the function is async. Do not use async def common_route_params()!
|
||||
def common_route_params_no_account_id(
|
||||
x_account_id: str = Header(None, min_length=11, max_length=22),
|
||||
enabled: str = 'enabled', # all, enabled, disabled
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_none: Optional[bool] = True,
|
||||
exclude_unset: bool = False,
|
||||
# NOTE: Uncommenting either exclude or include breaks the JSON body format. I do not know why? Should be: {} Becomes this: {"obj_name": {"data_name": "data_value"}} -STI 2022-01-05
|
||||
# exclude: Optional[list] = [], # Leaving this and include commented out
|
||||
# include: Optional[list] = [], # Leaving this and exclude commented out
|
||||
response: Response = Response,
|
||||
log_lvl: int = logging.WARNING, # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
) -> Common_Route_Params_No_Account_ID:
|
||||
log.setLevel(log_lvl)
|
||||
log.debug(locals())
|
||||
|
||||
log.info(f'Setting commons values: x_account_id, x_account_id_random, limit, offset, enabled, by_alias, exclude_unset, response')
|
||||
|
||||
x_account_id_random = x_account_id
|
||||
|
||||
if x_account_id := redis_lookup_id_random(table_name='account', record_id_random=x_account_id):
|
||||
log.info(f'Found the x-account-id header with the value: {x_account_id}')
|
||||
elif x_account_id is None:
|
||||
log.warning(f'No x-account-id header value passed')
|
||||
else:
|
||||
log.warning(f'The x-account-id header was found, but the Account ID was not found or is not valid. Account ID: {x_account_id}')
|
||||
raise HTTPException(status_code=403, detail='The x-account-id Account ID was not found.') # Forbidden
|
||||
|
||||
commons = Common_Route_Params_No_Account_ID( x_account_id=x_account_id, x_account_id_random=x_account_id_random, limit=limit, offset=offset, enabled=enabled, by_alias=by_alias, exclude_unset=exclude_unset, response=response )
|
||||
|
||||
log.debug(commons)
|
||||
|
||||
return commons
|
||||
# ### END ### API Lib General ### async common_route_params() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Lib General ### class Common_Route_Params ###
|
||||
# Updated 2022-01-05
|
||||
class Common_Route_Params:
|
||||
def __init__(
|
||||
self,
|
||||
x_account_id: int,
|
||||
x_account_id_random: str,
|
||||
x_no_account_id_token: str|None = None,
|
||||
enabled: str = 'enabled',
|
||||
limit: int = 10,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = False,
|
||||
response = None,
|
||||
):
|
||||
self.x_account_id = x_account_id
|
||||
self.x_account_id_random = x_account_id_random
|
||||
self.x_no_account_id_token = x_no_account_id_token
|
||||
self.enabled = enabled
|
||||
self.limit = limit
|
||||
self.offset = offset
|
||||
self.by_alias = by_alias
|
||||
self.exclude_unset = exclude_unset
|
||||
self.response = response
|
||||
# log.debug(response)
|
||||
# ### END ### API Lib General ### class Common_Route_Params ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Lib General ### common_route_params() ###
|
||||
# Updated 2022-02-15
|
||||
@logger_reset # This breaks things for some reason when the function is async. Do not use async def common_route_params()!
|
||||
def common_route_params(
|
||||
# x_account_id: str = Header(..., min_length=11, max_length=22), # NOTE WARNING: Commented out 2023-08-17
|
||||
x_account_id: str = Header(None, min_length=11, max_length=22), # NOTE WARNING: Changed to this 2023-08-17
|
||||
x_no_account_id: str = Header(None, min_length=11, max_length=22), # NOTE WARNING: Changed to this 2023-08-17
|
||||
# x_aether_api_key: Optional[str] = Header(..., min_length=11, max_length=22),
|
||||
# x_aether_api_token: Optional[str] = Header(..., min_length=11, max_length=22),
|
||||
# x_aether_jwt_token: Optional[str] = Header(..., min_length=11, max_length=50),
|
||||
x_no_account_id_token: str|None = None, # NOTE: Not a header value! Added 2023-08-17
|
||||
enabled: str = 'enabled', # all, enabled, disabled
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = False,
|
||||
exclude_defaults: Optional[bool] = False,
|
||||
exclude_none: Optional[bool] = False,
|
||||
# NOTE: Uncommenting either exclude or include breaks the JSON body format. I do not know why? Should be: {} Becomes this: {"obj_name": {"data_name": "data_value"}} -STI 2022-01-05
|
||||
# exclude: Optional[list] = [], # Leaving this and include commented out
|
||||
# include: Optional[list] = [], # Leaving this and exclude commented out
|
||||
response: Response = Response,
|
||||
log_lvl: int = logging.WARNING, # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
) -> Common_Route_Params|Common_Route_Params_No_Account_ID:
|
||||
log.setLevel(log_lvl)
|
||||
log.debug(locals())
|
||||
|
||||
log.info(f'Setting commons values: x_account_id, x_account_id_random, limit, offset, enabled, by_alias, exclude_unset, response')
|
||||
|
||||
x_account_id_random = x_account_id
|
||||
|
||||
if x_account_id:
|
||||
if x_account_id := redis_lookup_id_random(table_name='account', record_id_random=x_account_id):
|
||||
log.info(f'Found the x-account-id header with the value: {x_account_id}')
|
||||
else:
|
||||
log.warning(f'The x-account-id header was found, but the Account ID was not found or is not valid. Account ID: {x_account_id}')
|
||||
raise HTTPException(status_code=403, detail='The x-account-id Account ID was not found.') # Forbidden
|
||||
elif x_no_account_id and len(x_no_account_id) > 10:
|
||||
log.warning(f'Found the x_no_account_id header param with the value: {x_no_account_id}')
|
||||
|
||||
x_account_id = None
|
||||
x_account_id_random = '--- NOT SET ---'
|
||||
|
||||
elif x_no_account_id_token and len(x_no_account_id_token) > 10: # NOTE: Not a header value!
|
||||
# NOTE WARNING: This token should be verified and able to be disabled quickly.
|
||||
log.warning(f'Found the x_no_account_id_token URL param with the value: {x_no_account_id_token}')
|
||||
|
||||
if x_account_id := redis_lookup_id_random(table_name='account', record_id_random=x_no_account_id_token):
|
||||
log.info(f'Found the x-account-id header with the value: {x_account_id}')
|
||||
x_account_id_random = x_no_account_id_token
|
||||
else:
|
||||
x_account_id = 0
|
||||
x_account_id_random = ''
|
||||
|
||||
x_account_id = 0
|
||||
x_account_id_random = '--- NOT SET ---'
|
||||
else:
|
||||
log.warning(f'The x-account-id and x-no-account-id-token headers were not found.')
|
||||
raise HTTPException(status_code=403, detail='The x-account-id and x-no-account-id-token headers were not found.') # Forbidden
|
||||
|
||||
if x_account_id:
|
||||
commons = Common_Route_Params( x_account_id=x_account_id, x_account_id_random=x_account_id_random, x_no_account_id_token=x_no_account_id_token, limit=limit, offset=offset, enabled=enabled, by_alias=by_alias, exclude_unset=exclude_unset, response=response )
|
||||
else:
|
||||
commons = Common_Route_Params_No_Account_ID( x_account_id=None, x_account_id_random=None, x_no_account_id_token=x_no_account_id_token, limit=limit, offset=offset, enabled=enabled, by_alias=by_alias, exclude_unset=exclude_unset, response=response )
|
||||
|
||||
log.debug(commons)
|
||||
|
||||
return commons
|
||||
# ### END ### API Lib General ### async common_route_params() ###
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Lib General ### class Common_Route_Params_Min ###
|
||||
# Updated 2022-01-05
|
||||
# NOTE: Is this essentially the same as Common_Route_Params_No_Account_ID above?
|
||||
class Common_Route_Params_Min:
|
||||
def __init__(
|
||||
self,
|
||||
x_account_id: int = None,
|
||||
x_account_id_random: str = None,
|
||||
enabled: str = 'enabled',
|
||||
limit: int = 10,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = False,
|
||||
response = None,
|
||||
):
|
||||
self.x_account_id = x_account_id
|
||||
self.x_account_id_random = x_account_id_random
|
||||
self.enabled = enabled
|
||||
self.limit = limit
|
||||
self.offset = offset
|
||||
self.by_alias = by_alias
|
||||
self.exclude_unset = exclude_unset
|
||||
self.response = response
|
||||
# log.debug(response)
|
||||
# ### END ### API Lib General ### class Common_Route_Params_Min ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Lib General ### common_route_params_min() ###
|
||||
# Updated 2022-02-15
|
||||
# NOTE: Is this essentially the same as common_route_params_no_account_id above?
|
||||
@logger_reset # This breaks things for some reason when the function is async. Do not use async def common_route_params()!
|
||||
def common_route_params_min(
|
||||
x_account_id: str = Header(None, min_length=11, max_length=22),
|
||||
enabled: str = 'enabled', # all, enabled, disabled
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_none: Optional[bool] = True,
|
||||
exclude_unset: bool = False,
|
||||
# NOTE: Uncommenting either exclude or include breaks the JSON body format. I do not know why? Should be: {} Becomes this: {"obj_name": {"data_name": "data_value"}} -STI 2022-01-05
|
||||
# exclude: Optional[list] = [], # Leaving this and include commented out
|
||||
# include: Optional[list] = [], # Leaving this and exclude commented out
|
||||
response: Response = Response,
|
||||
log_lvl: int = logging.WARNING, # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
) -> Common_Route_Params:
|
||||
log.setLevel(log_lvl)
|
||||
log.debug(locals())
|
||||
|
||||
log.info(f'Setting commons values: x_account_id, x_account_id_random, limit, offset, enabled, by_alias, exclude_unset, response')
|
||||
|
||||
log.debug(f'X Account ID: {x_account_id}')
|
||||
|
||||
if x_account_id:
|
||||
x_account_id_random = x_account_id
|
||||
|
||||
if x_account_id := redis_lookup_id_random(table_name='account', record_id_random=x_account_id):
|
||||
log.info(f'Found the x-account-id header with the value: {x_account_id}')
|
||||
else:
|
||||
log.warning(f'The x-account-id header was found, but the Account ID was not found or is not valid. Account ID: {x_account_id}')
|
||||
raise HTTPException(status_code=403, detail='The x-account-id Account ID was not found.') # Forbidden
|
||||
else: x_account_id_random = None
|
||||
|
||||
commons = Common_Route_Params_Min( x_account_id=x_account_id, x_account_id_random=x_account_id_random, limit=limit, offset=offset, enabled=enabled, by_alias=by_alias, exclude_unset=exclude_unset, response=response )
|
||||
|
||||
log.debug(commons)
|
||||
|
||||
return commons
|
||||
# ### END ### API Lib General ### async common_route_params_min() ###
|
||||
|
||||
|
||||
|
||||
47
app/lib_general_v3.py
Normal file
47
app/lib_general_v3.py
Normal file
@@ -0,0 +1,47 @@
|
||||
"""
|
||||
This file contains general utility functions and helpers specifically for API v3.
|
||||
Refactored 2026-01-07 to move Auth logic to dependencies_v3.py to fix circular dependencies.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import (
|
||||
Any,
|
||||
Dict,
|
||||
List,
|
||||
Optional,
|
||||
Union,
|
||||
)
|
||||
|
||||
from fastapi import (
|
||||
APIRouter,
|
||||
Depends,
|
||||
Header,
|
||||
HTTPException,
|
||||
Query,
|
||||
Request,
|
||||
Response,
|
||||
status,
|
||||
)
|
||||
from pydantic import (
|
||||
BaseModel,
|
||||
Field,
|
||||
)
|
||||
|
||||
# Re-import from the new central auth models
|
||||
from app.models.auth_models import AccountContext
|
||||
# Import the dependency functions for backward compatibility in existing v3 routes
|
||||
from app.routers.dependencies_v3 import (
|
||||
get_account_context,
|
||||
get_account_context_optional,
|
||||
PaginationParams,
|
||||
StatusFilterParams,
|
||||
SerializationParams,
|
||||
DelayParams
|
||||
)
|
||||
|
||||
from app.config import settings
|
||||
from app.log import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
# Note: Dependency function implementations have moved to app/routers/dependencies_v3.py
|
||||
171
app/lib_general_v3.py.snapshot
Normal file
171
app/lib_general_v3.py.snapshot
Normal file
@@ -0,0 +1,171 @@
|
||||
"""
|
||||
This file contains general utility functions and helpers specifically for API v3.
|
||||
It aims to provide a clean slate for new methods and refactor existing ones from lib_general.py
|
||||
that are relevant to the v3 API, while removing unused or outdated functionalities.
|
||||
"""
|
||||
|
||||
# Standard library imports
|
||||
import time
|
||||
import logging
|
||||
from typing import (
|
||||
Any,
|
||||
Dict,
|
||||
List,
|
||||
Optional,
|
||||
Union,
|
||||
)
|
||||
|
||||
# Third-party imports
|
||||
from fastapi import (
|
||||
APIRouter,
|
||||
Depends,
|
||||
Header,
|
||||
HTTPException,
|
||||
Query,
|
||||
Request,
|
||||
Response,
|
||||
status,
|
||||
)
|
||||
from pydantic import (
|
||||
BaseModel,
|
||||
Field,
|
||||
ValidationError,
|
||||
computed_field,
|
||||
model_validator,
|
||||
)
|
||||
|
||||
# Internal imports (from this project)
|
||||
from app.config import settings
|
||||
from app.db_sql import redis_lookup_id_random
|
||||
from app.log import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
# --- Pydantic Model for Account Context ---
|
||||
class AccountContext(BaseModel):
|
||||
account_id: Optional[int]
|
||||
account_id_random: Optional[str]
|
||||
|
||||
|
||||
# --- Dependency Function for Account Context ---
|
||||
def get_account_context(
|
||||
x_account_id: Optional[str] = Header(None, min_length=11, max_length=22),
|
||||
x_no_account_id: Optional[str] = Header(None, min_length=3, max_length=100), # Assuming 'bypass' or similar string
|
||||
x_no_account_id_token: Optional[str] = Query(None, min_length=11, max_length=22),
|
||||
) -> AccountContext:
|
||||
"""
|
||||
Resolves the account context from headers/query parameters with defined precedence.
|
||||
Precedence: x_account_id (header) > x_no_account_id_token (query) > x_no_account_id (header flag)
|
||||
Raises HTTPException 403 if no valid account is found and no bypass is indicated.
|
||||
"""
|
||||
logger.setLevel(logging.DEBUG) # Adjust as needed
|
||||
logger.debug(locals())
|
||||
|
||||
resolved_account_id = None
|
||||
resolved_account_id_random = None
|
||||
|
||||
if x_account_id:
|
||||
# Primary check: x_account_id header
|
||||
resolved_account_id_random = x_account_id
|
||||
if looked_up_id := redis_lookup_id_random(table_name='account', record_id_random=x_account_id):
|
||||
resolved_account_id = looked_up_id
|
||||
logger.info(f'Found account from x_account_id header: {resolved_account_id}')
|
||||
else:
|
||||
logger.warning(f'Invalid x_account_id header provided: {x_account_id}')
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail='Invalid X-Account-ID header.')
|
||||
elif x_no_account_id_token:
|
||||
# Secondary check: x_no_account_id_token query parameter
|
||||
resolved_account_id_random = x_no_account_id_token
|
||||
if looked_up_id := redis_lookup_id_random(table_name='account', record_id_random=x_no_account_id_token):
|
||||
resolved_account_id = looked_up_id
|
||||
logger.info(f'Found account from x_no_account_id_token query: {resolved_account_id}')
|
||||
else:
|
||||
logger.warning(f'Invalid x_no_account_id_token query provided: {x_no_account_id_token}')
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail='Invalid X-No-Account-ID-Token query parameter.')
|
||||
elif x_no_account_id:
|
||||
# Tertiary check: x_no_account_id header for bypass
|
||||
# For now, just presence indicates bypass. Can add a specific value check later if needed.
|
||||
logger.info(f'X-No-Account-ID header found: {x_no_account_id}. Proceeding without specific account context.')
|
||||
resolved_account_id = None # Explicitly None for "no specific account"
|
||||
resolved_account_id_random = '--- NO ACCOUNT ---'
|
||||
else:
|
||||
logger.warning('No valid account context provided via X-Account-ID, X-No-Account-ID-Token, or X-No-Account-ID.')
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail='Account context required. Please provide X-Account-ID, X-No-Account-ID-Token, or X-No-Account-ID.')
|
||||
|
||||
return AccountContext(account_id=resolved_account_id, account_id_random=resolved_account_id_random)
|
||||
|
||||
|
||||
# --- Pydantic Model for Pagination ---
|
||||
class PaginationParams(BaseModel):
|
||||
limit: int = 100 # Default limit
|
||||
offset: int = 0
|
||||
|
||||
# --- Dependency Function for Pagination ---
|
||||
def get_pagination_params(
|
||||
limit: int = Query(100, ge=0, description="Maximum number of items to return"),
|
||||
offset: int = Query(0, ge=0, description="Number of items to skip (for pagination)"),
|
||||
) -> PaginationParams:
|
||||
return PaginationParams(limit=limit, offset=offset)
|
||||
|
||||
|
||||
# --- Pydantic Model for Status Filtering ---
|
||||
class StatusFilterParams(BaseModel):
|
||||
enabled: str = 'enabled' # 'enabled', 'disabled', 'all'
|
||||
hidden: str = 'not_hidden' # 'hidden', 'not_hidden', 'all'
|
||||
|
||||
# --- Dependency Function for Status Filtering ---
|
||||
def get_status_filter_params(
|
||||
enabled: str = Query('enabled', description="Filter by object enabled status ('enabled', 'disabled', 'all')"),
|
||||
hidden: str = Query('not_hidden', description="Filter by object hidden status ('hidden', 'not_hidden', 'all')"),
|
||||
) -> StatusFilterParams:
|
||||
allowed_enabled_values = {'enabled', 'disabled', 'all'}
|
||||
allowed_hidden_values = {'hidden', 'not_hidden', 'all'}
|
||||
|
||||
if enabled not in allowed_enabled_values:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f"Invalid value for 'enabled'. Must be one of {list(allowed_enabled_values)}."
|
||||
)
|
||||
if hidden not in allowed_hidden_values:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f"Invalid value for 'hidden'. Must be one of {list(allowed_hidden_values)}."
|
||||
)
|
||||
return StatusFilterParams(enabled=enabled, hidden=hidden)
|
||||
|
||||
|
||||
# --- Pydantic Model for Serialization Options ---
|
||||
class SerializationParams(BaseModel):
|
||||
by_alias: bool = True
|
||||
exclude_unset: bool = False
|
||||
exclude_defaults: bool = False # Added based on common_route_params
|
||||
exclude_none: bool = False # Added based on common_route_params
|
||||
|
||||
# --- Dependency Function for Serialization Options ---
|
||||
def get_serialization_params(
|
||||
by_alias: bool = Query(True, description="Whether to use field aliases for serialization"),
|
||||
exclude_unset: bool = Query(False, description="Whether to exclude unset fields from the response"),
|
||||
exclude_defaults: bool = Query(False, description="Whether to exclude fields with their default values from the response"),
|
||||
exclude_none: bool = Query(False, description="Whether to exclude fields that are None from the response"),
|
||||
) -> SerializationParams:
|
||||
return SerializationParams(
|
||||
by_alias=by_alias,
|
||||
exclude_unset=exclude_unset,
|
||||
exclude_defaults=exclude_defaults,
|
||||
exclude_none=exclude_none,
|
||||
)
|
||||
|
||||
|
||||
# --- Pydantic Model for Delay ---
|
||||
class DelayParams(BaseModel):
|
||||
sleep_time_ms: int = 0 # Raw delay value in ms
|
||||
sleep_time_s: float = 0.0 # Converted to seconds for time.sleep()
|
||||
|
||||
# --- Dependency Function for Delay ---
|
||||
def get_delay_params(
|
||||
x_delay_ms: Optional[int] = Header(0, alias='X-Delay-ms', description="Delay response for X milliseconds (header)"),
|
||||
delay_ms: Optional[int] = Query(0, description="Delay response for X milliseconds (query parameter)"),
|
||||
) -> DelayParams:
|
||||
calculated_delay_ms = max(x_delay_ms or 0, delay_ms or 0)
|
||||
return DelayParams(sleep_time_ms=calculated_delay_ms, sleep_time_s=calculated_delay_ms / 1000.0)
|
||||
16
app/lib_hash.py
Normal file
16
app/lib_hash.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from passlib.hash import argon2
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# Moved from lib_general.py 2026-01-07
|
||||
def secure_hash_string(string: str) -> str:
|
||||
string_hash = argon2.using(rounds=14, memory_cost=1536, parallelism=2).hash(string)
|
||||
return string_hash
|
||||
|
||||
# Moved from lib_general.py 2026-01-07
|
||||
def verify_secure_hash_string(string: str, string_hash: str) -> bool:
|
||||
if argon2.verify(string, string_hash):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
130
app/lib_id_resolver.py
Normal file
130
app/lib_id_resolver.py
Normal file
@@ -0,0 +1,130 @@
|
||||
"""
|
||||
Centralized ID random to integer ID resolution.
|
||||
"""
|
||||
import logging
|
||||
import datetime
|
||||
import random
|
||||
import redis
|
||||
from app.config import settings
|
||||
from app.db_connection import db
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
def redis_lookup_id_random(
|
||||
record_id_random: int|str,
|
||||
table_name: str,
|
||||
check_int_id: bool = False,
|
||||
log_lvl: int = logging.WARNING,
|
||||
minutes: int = 30,
|
||||
reset_rate: int = 10,
|
||||
) -> str|int|bool|None:
|
||||
"""
|
||||
Looks up a record ID in Redis, falling back to SQL if not found.
|
||||
Resolves 'id_random' (URL-safe string) to internal integer 'id'.
|
||||
"""
|
||||
from app.db_sql import sql_select, get_id_random
|
||||
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
if isinstance(record_id_random, str) and 11 <= len(record_id_random) <= 22:
|
||||
pass
|
||||
elif isinstance(record_id_random, int):
|
||||
if check_int_id:
|
||||
if get_id_random(record_id=record_id_random, table_name=table_name):
|
||||
return record_id_random
|
||||
return False
|
||||
return record_id_random
|
||||
elif record_id_random is None:
|
||||
return None
|
||||
else:
|
||||
log.error(f'Unexpected data type: {type(record_id_random)}. Expected string (11-22 chars) or int.')
|
||||
return False
|
||||
|
||||
if not table_name:
|
||||
log.error(f'Missing table_name for id_random lookup: {record_id_random}')
|
||||
return False
|
||||
|
||||
r = redis.Redis(host=settings.REDIS['server'], port=settings.REDIS['port'], db=7, password=None, decode_responses=True)
|
||||
key_name = f'{table_name}:{record_id_random}'
|
||||
|
||||
record_id = r.get(key_name)
|
||||
|
||||
# Periodic cache refresh
|
||||
if record_id and random.randint(1, reset_rate) == 1:
|
||||
log.warning(f'Redis: Randomly (1/{reset_rate}) refreshing cache for Key="{key_name}"')
|
||||
record_id = None
|
||||
|
||||
if record_id:
|
||||
r.setex(key_name, datetime.timedelta(minutes=minutes), value=record_id)
|
||||
return int(record_id)
|
||||
else:
|
||||
data = { 'id_random': record_id_random }
|
||||
sql = f"SELECT id FROM `{table_name}` WHERE id_random = :id_random;"
|
||||
|
||||
if select_results := sql_select(sql=sql, data=data):
|
||||
if isinstance(select_results, dict):
|
||||
if rid := select_results.get('id'):
|
||||
r.setex(key_name, datetime.timedelta(minutes=minutes), value=rid)
|
||||
return int(rid)
|
||||
log.error('SQL result missing ID field.')
|
||||
return False
|
||||
else:
|
||||
log.error(f'SQL: Duplicate id_random found in "{table_name}". Retrying...')
|
||||
return redis_lookup_id_random(record_id_random=record_id_random, table_name=table_name)
|
||||
else:
|
||||
log.warning(f'SQL: ID Random "{record_id_random}" not found in "{table_name}".')
|
||||
return None
|
||||
|
||||
def lookup_id_random_pop(
|
||||
obj_data: dict,
|
||||
log_lvl: int = logging.WARNING,
|
||||
):
|
||||
"""
|
||||
Resolves any *_id_random fields in a dict to their integer IDs and removes the random keys.
|
||||
"""
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
# List of common prefix patterns to resolve
|
||||
id_patterns = [
|
||||
'account', 'activity_log', 'address', 'archive', 'contact', 'cont_edu_cert',
|
||||
'cont_edu_cert_person', 'event', 'event_abstract', 'event_badge',
|
||||
'event_badge_template', 'event_exhibit', 'event_file', 'event_location',
|
||||
'event_person', 'event_person_profile', 'event_presentation',
|
||||
'event_presenter', 'event_registration', 'event_session', 'event_track',
|
||||
'grant', 'hosted_file', 'journal', 'journal_entry', 'membership_group',
|
||||
'membership_person_group', 'membership_person', 'membership_type',
|
||||
'membership_person_type', 'order', 'order_line', 'order_cart',
|
||||
'order_cart_line', 'organization', 'page', 'person', 'post', 'product',
|
||||
'sponsorship', 'sponsorship_cfg', 'site', 'user'
|
||||
]
|
||||
|
||||
for prefix in id_patterns:
|
||||
key = f'{prefix}_id_random'
|
||||
if key in obj_data:
|
||||
table = prefix
|
||||
if prefix == 'address_location': table = 'address'
|
||||
if prefix in ['contact_1', 'contact_2']: table = 'contact'
|
||||
if prefix == 'event_id_random_only': table = 'event'
|
||||
|
||||
resolved_id = redis_lookup_id_random(record_id_random=obj_data[key], table_name=table)
|
||||
obj_data[f'{prefix}_id'] = resolved_id
|
||||
obj_data.pop(key)
|
||||
|
||||
# Handle polymorphic link fields
|
||||
polymorphic = [
|
||||
('for_type', 'for_id_random', 'for_id'),
|
||||
('link_to_type', 'link_to_id_random', 'link_to_id'),
|
||||
('object_type', 'object_id_random', 'object_id'),
|
||||
('to_object_type', 'to_object_id_random', 'to_object_id'),
|
||||
('from_object_type', 'from_object_id_random', 'from_object_id')
|
||||
]
|
||||
|
||||
for type_key, rand_key, id_key in polymorphic:
|
||||
if type_key in obj_data and rand_key in obj_data:
|
||||
obj_data[id_key] = redis_lookup_id_random(
|
||||
record_id_random=obj_data[rand_key],
|
||||
table_name=obj_data[type_key]
|
||||
)
|
||||
obj_data.pop(rand_key)
|
||||
|
||||
return obj_data
|
||||
82
app/lib_jwt.py
Normal file
82
app/lib_jwt.py
Normal file
@@ -0,0 +1,82 @@
|
||||
import jwt
|
||||
import time
|
||||
import logging
|
||||
from typing import Dict, Optional
|
||||
|
||||
from app.log import logger_reset
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# ### BEGIN ### API Lib JWT ### sign_jwt() ###
|
||||
# Moved from lib_general.py 2026-01-07
|
||||
@logger_reset
|
||||
def sign_jwt(
|
||||
secret_key: str, # Secret/Private/Password
|
||||
ttl: int = 60, # Default to 60 seconds
|
||||
max_renew: int = 0, # Default to 0
|
||||
public_key: str = None, # Will be part of the token. Use to look up secret when verifying.???
|
||||
account_id: str = None,
|
||||
person_id: str = None,
|
||||
user_id: str = None,
|
||||
json_str: str = None,
|
||||
b64_str: str = None,
|
||||
**kwargs # Allow arbitrary claims
|
||||
) -> str:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# SECURITY CHECK: Ensure we are not signing numeric IDs
|
||||
for label, val in [('account_id', account_id), ('person_id', person_id), ('user_id', user_id)]:
|
||||
if val is not None:
|
||||
if isinstance(val, int) or (isinstance(val, str) and val.isdigit()):
|
||||
log.critical(f"SECURITY BREACH: Attempted to sign a numeric ID for {label}='{val}'. Only random string IDs allowed.")
|
||||
# For now we log and proceed, but in Phase 3 we should raise an Exception
|
||||
# raise ValueError(f"Numeric IDs cannot be signed in JWTs.")
|
||||
|
||||
payload = {
|
||||
'iat': time.time(), # Issued at
|
||||
'eat': time.time() + ttl, # Expires at
|
||||
'max_renew': max_renew, # Number of times allowed to request renew without API secret key
|
||||
'public_key': public_key, # Use to lookup the secret/private/password key when verifying
|
||||
'account_id': account_id,
|
||||
'person_id': person_id,
|
||||
'user_id': user_id,
|
||||
'json_str': json_str,
|
||||
'b64_str': b64_str,
|
||||
}
|
||||
|
||||
# Merge additional claims
|
||||
if kwargs:
|
||||
payload.update(kwargs)
|
||||
|
||||
secret = secret_key
|
||||
algorithm = 'HS256'
|
||||
token = jwt.encode(payload, secret, algorithm=algorithm)
|
||||
|
||||
log.debug(token)
|
||||
|
||||
return token
|
||||
# ### END ### API Lib JWT ### sign_jwt() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Lib JWT ### decode_jwt() ###
|
||||
# Moved from lib_general.py 2026-01-07
|
||||
@logger_reset
|
||||
def decode_jwt(
|
||||
secret_key: str,
|
||||
token: str,
|
||||
) -> Optional[dict]:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
secret = secret_key
|
||||
algorithm = 'HS256'
|
||||
|
||||
try:
|
||||
decoded_token = jwt.decode(token, secret, algorithms=[algorithm])
|
||||
log.debug(decoded_token)
|
||||
if decoded_token['eat'] >= time.time(): return decoded_token
|
||||
else: return False
|
||||
except:
|
||||
return None
|
||||
# ### END ### API Lib JWT ### decode_jwt() ###
|
||||
77
app/lib_log_v3.py
Normal file
77
app/lib_log_v3.py
Normal file
@@ -0,0 +1,77 @@
|
||||
import functools
|
||||
import logging
|
||||
import logging.config
|
||||
from typing import Any
|
||||
|
||||
# Global logger instance used throughout the app
|
||||
log = logging.getLogger('root')
|
||||
|
||||
def get_logger(name: str):
|
||||
"""Returns a logger instance by name."""
|
||||
return logging.getLogger(name)
|
||||
|
||||
def setup_logging(settings: Any):
|
||||
"""
|
||||
Configures logging based on provided settings.
|
||||
Moving this here prevents immediate execution on module import.
|
||||
"""
|
||||
log_file_path = getattr(settings, 'LOG_PATH', {}).get('app', '/logs/aether_api.log')
|
||||
|
||||
try:
|
||||
logging.config.dictConfig({
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False, # Critical to not kill FastAPI/Uvicorn loggers
|
||||
'formatters': {
|
||||
'default': {'format': '[%(asctime)s] %(levelname)s @ %(module)s.%(funcName)s()#%(lineno)d: %(message)s'},
|
||||
'long': {'format': '[%(asctime)s] %(levelname)s @ %(module)s.%(funcName)s()#%(lineno)d: %(message)s', 'datefmt': '%Y-%m-%d %H:%M:%S'},
|
||||
'short': {'format': '[%(asctime)s] %(levelname)s @ %(module)s.%(funcName)s()#%(lineno)d: %(message)s', 'datefmt': '%H:%M:%S'},
|
||||
},
|
||||
'handlers': {
|
||||
'console': {
|
||||
'class': 'logging.StreamHandler',
|
||||
'stream': 'ext://sys.stderr',
|
||||
'formatter': 'short',
|
||||
},
|
||||
'log_file_all': {
|
||||
'level': 'NOTSET',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
'formatter': 'long',
|
||||
'filename': log_file_path,
|
||||
'maxBytes': 10485760, # 10 MB
|
||||
'backupCount': 9
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'uvicorn': {'handlers': ['console'], 'level': 'INFO'},
|
||||
},
|
||||
'root': {
|
||||
'handlers': ['log_file_all'],
|
||||
'level': 'WARNING',
|
||||
}
|
||||
})
|
||||
log.info(f"Logging successfully configured. Path: {log_file_path}")
|
||||
except Exception as e:
|
||||
print(f"Error configuring logging: {e}")
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
|
||||
def logger_reset(func):
|
||||
"""
|
||||
Decorator to log function entry/exit and reset log levels.
|
||||
"""
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
# Local safer access to root logger
|
||||
root_log = logging.getLogger('root')
|
||||
|
||||
if func.__name__ not in ['redis_lookup_id_random', 'sql_enable_part', 'sql_hidden_part']:
|
||||
root_log.info(f'*** Function: "{func.__name__}()"')
|
||||
|
||||
root_log.debug(f'*** Function Positional Args: {args}\nFunction Key Args: {kwargs}')
|
||||
init_log_level = root_log.level
|
||||
|
||||
returned_result = func(*args, **kwargs)
|
||||
|
||||
# Reset level in case it was changed during func execution
|
||||
root_log.setLevel(init_log_level)
|
||||
return returned_result
|
||||
return wrapper
|
||||
247
app/lib_redis_helpers.py
Normal file
247
app/lib_redis_helpers.py
Normal file
@@ -0,0 +1,247 @@
|
||||
"""
|
||||
Redis-based ID resolution and caching helpers for Aether.
|
||||
"""
|
||||
import datetime
|
||||
import random
|
||||
import redis
|
||||
import logging
|
||||
|
||||
from app.config import settings
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
def redis_lookup_id_random(
|
||||
record_id_random: int|str,
|
||||
table_name: str,
|
||||
check_int_id: bool = False,
|
||||
log_lvl: int = logging.WARNING, # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
minutes: int = 30, # Expire the Redis key after 8 minutes
|
||||
reset_rate: int = 10, # 1 in 10 chance of resetting the Redis key
|
||||
) -> str|int|bool|None:
|
||||
"""
|
||||
Looks up a record ID in Redis, falling back to SQL if not found.
|
||||
Resolves 'id_random' (URL-safe string) to internal integer 'id'.
|
||||
"""
|
||||
from app.db_sql import sql_select, get_id_random
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
if isinstance(record_id_random, str) and len(record_id_random) >= 11 and len(record_id_random) <= 22: pass
|
||||
elif isinstance(record_id_random, int):
|
||||
record_id = record_id_random
|
||||
if check_int_id:
|
||||
log.info(f'Checking the int ID if exists. Table Name: {table_name} ID: {record_id}')
|
||||
if get_id_random_result := get_id_random(
|
||||
record_id = record_id,
|
||||
table_name = table_name,
|
||||
):
|
||||
log.info(f'The int ID exists. Returning the int ID. ID Random: {get_id_random_result}')
|
||||
return record_id
|
||||
else:
|
||||
log.info(f'The int ID does not exists. Returning False. Table Name: {table_name} ID: {record_id}')
|
||||
return False
|
||||
else:
|
||||
log.debug(f'Not checking if the int ID exists. Returning the int ID. ID: {record_id}')
|
||||
return record_id
|
||||
elif record_id_random is None:
|
||||
log.info(f'No record ID was passed. Returning None')
|
||||
return None
|
||||
else:
|
||||
log.error(f'Unexpected data type or string format: {type(record_id_random)} Expected type is a string 11 or 22 characters long.')
|
||||
return False
|
||||
|
||||
if record_id_random and table_name:
|
||||
if len(record_id_random) < 11:
|
||||
log.error(f'The length of id_random is too short: {record_id_random} ({len(record_id_random)} chars)')
|
||||
return False
|
||||
elif len(record_id_random) > 22:
|
||||
log.error(f'The length of id_random is too long: {record_id_random} ({len(record_id_random)} chars)')
|
||||
return False
|
||||
elif record_id_random:
|
||||
log.error(f'Missing table_name to select from for id_random "{record_id_random}"')
|
||||
return False
|
||||
elif table_name:
|
||||
log.error(f'Missing id_random to select from table "{table_name}"')
|
||||
return False
|
||||
else:
|
||||
log.error('Missing table_name and record_id_random')
|
||||
return False
|
||||
|
||||
r = redis.Redis(host=settings.REDIS['server'], port=settings.REDIS['port'], db=7, password=None, decode_responses=True)
|
||||
key_name = f'{table_name}:{record_id_random}'
|
||||
|
||||
record_id = r.get(key_name)
|
||||
|
||||
if record_id and random.randint(1, reset_rate) == 1:
|
||||
log.warning(f'Redis: Randomly (1/{reset_rate}) setting record_id to None. Key="{key_name}" value="{record_id}" TTL={r.ttl(key_name)} seconds')
|
||||
record_id = None
|
||||
|
||||
if record_id:
|
||||
r.setex(key_name, datetime.timedelta(minutes=minutes), value=record_id)
|
||||
log.info(f'Redis: Entry found for: Key="{key_name}" value="{record_id}" TTL={r.ttl(key_name)} seconds')
|
||||
return int(record_id)
|
||||
elif table_name:
|
||||
data = { 'id_random': record_id_random }
|
||||
sql = f"SELECT id FROM `{table_name}` AS `table` WHERE `table`.id_random = :id_random;"
|
||||
|
||||
if select_results := sql_select(sql=sql, data=data):
|
||||
log.debug(f'SQL: SELECT result: {select_results}')
|
||||
if isinstance(select_results, dict):
|
||||
log.info(f"""SQL: Found ID Random for: {str(record_id_random)} = {str(select_results.get('id'))}""")
|
||||
if record_id := select_results.get('id'):
|
||||
r.setex(key_name, datetime.timedelta(minutes=minutes), value=record_id)
|
||||
return int(record_id)
|
||||
else:
|
||||
log.error('The SQL result was not what was expected. The ID field was not found.')
|
||||
return False
|
||||
else:
|
||||
log.error(f'SQL: More than one record found in "{table_name}". Duplicate id_random!')
|
||||
return redis_lookup_id_random(record_id_random=record_id_random, table_name=table_name)
|
||||
else:
|
||||
log.warning(f'SQL: ID Random "{record_id_random}" not found in "{table_name}". Returning None.')
|
||||
return None
|
||||
|
||||
log.error('Unexpected state in redis_lookup_id_random.')
|
||||
return False
|
||||
|
||||
|
||||
def get_id_random(
|
||||
record_id: int,
|
||||
table_name: str,
|
||||
log_lvl: int = logging.WARNING, # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
) -> str|bool|None:
|
||||
"""
|
||||
Looks up the 'id_random' for a given internal integer ID.
|
||||
"""
|
||||
from app.db_sql import sql_select
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
data = { 'id': record_id }
|
||||
sql = f"SELECT id_random FROM `{table_name}` AS `table` WHERE `table`.id = :id;"
|
||||
|
||||
if select_results := sql_select(sql=sql, data=data):
|
||||
if isinstance(select_results, dict):
|
||||
if record_id_random := select_results.get('id_random'):
|
||||
return str(record_id_random)
|
||||
else:
|
||||
log.error('The SQL result was not what was expected.')
|
||||
return False
|
||||
elif isinstance(select_results, list):
|
||||
log.exception('More than one record may have been found. Duplicate ID!')
|
||||
return False
|
||||
else:
|
||||
log.exception(f'Got an unexpected result while trying to look up the ID.')
|
||||
return False
|
||||
elif select_results is None:
|
||||
return None
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def reset_redis():
|
||||
"""Flushes the Redis database used for ID caching."""
|
||||
r = redis.Redis(host=settings.REDIS['server'], port=settings.REDIS['port'], db=7, password=None, decode_responses=True)
|
||||
r.flushdb()
|
||||
return True
|
||||
|
||||
|
||||
def lookup_id_random_pop(
|
||||
obj_data: dict,
|
||||
log_lvl: int = logging.WARNING, # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
):
|
||||
"""
|
||||
Look up and resolve id_random values to their id
|
||||
Remove the unneeded *_id_random key from the dict
|
||||
"""
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
# Common prefixes for ID resolution
|
||||
id_prefixes = [
|
||||
'account', 'activity_log', 'address', 'address_location', 'archive',
|
||||
'contact', 'contact_1', 'contact_2', 'cont_edu_cert', 'cont_edu_cert_person',
|
||||
'event', 'event_id_random_only', 'event_abstract', 'event_badge',
|
||||
'event_badge_template', 'event_exhibit', 'event_file', 'event_location',
|
||||
'event_person', 'event_person_profile', 'event_presentation',
|
||||
'event_presenter', 'event_registration', 'event_session', 'event_track',
|
||||
'grant', 'hosted_file', 'journal', 'journal_entry', 'membership_group',
|
||||
'membership_person_group', 'membership_person', 'membership_type',
|
||||
'membership_person_type', 'order', 'order_line', 'order_cart',
|
||||
'order_cart_line', 'organization', 'page', 'person', 'poc_event_person',
|
||||
'poc_person', 'post', 'product', 'sponsorship', 'sponsorship_cfg',
|
||||
'site', 'user'
|
||||
]
|
||||
|
||||
for prefix in id_prefixes:
|
||||
key_random = f'{prefix}_id_random'
|
||||
key_id = f'{prefix}_id'
|
||||
|
||||
# Table name mapping
|
||||
table = prefix
|
||||
if prefix == 'address_location': table = 'address'
|
||||
elif prefix in ['contact_1', 'contact_2']: table = 'contact'
|
||||
elif prefix == 'event_id_random_only': table = 'event'
|
||||
elif prefix == 'poc_event_person': table = 'event_person'
|
||||
elif prefix == 'poc_person': table = 'person'
|
||||
|
||||
resolved_id = None
|
||||
|
||||
# Scenario A: Legacy suffix (e.g., account_id_random: "abc")
|
||||
if key_random in obj_data:
|
||||
resolved_id = redis_lookup_id_random(record_id_random=obj_data[key_random], table_name=table)
|
||||
obj_data.pop(key_random)
|
||||
|
||||
# Scenario B: Vision naming (e.g., account_id: "abc")
|
||||
# Only resolve if it's a string of the correct length (random ID format)
|
||||
elif key_id in obj_data and isinstance(obj_data[key_id], str) and 11 <= len(obj_data[key_id]) <= 22:
|
||||
resolved_id = redis_lookup_id_random(record_id_random=obj_data[key_id], table_name=table)
|
||||
|
||||
if resolved_id is not None:
|
||||
# Set the target ID field
|
||||
target_id_key = key_id
|
||||
if prefix == 'event_id_random_only': target_id_key = 'event_id_only'
|
||||
obj_data[target_id_key] = resolved_id
|
||||
|
||||
# Removed the short prefix version (e.g., obj_data['account'] = 1)
|
||||
# as it causes 'Unknown column' errors in direct table inserts.
|
||||
|
||||
# Polymorphic links
|
||||
polymorphic = [
|
||||
('for_type', 'for_id_random', 'for_id'),
|
||||
('link_to_type', 'link_to_id_random', 'link_to_id'),
|
||||
('object_type', 'object_id_random', 'object_id'),
|
||||
('to_object_type', 'to_object_id_random', 'to_object_id'),
|
||||
('from_object_type', 'from_object_id_random', 'from_object_id')
|
||||
]
|
||||
|
||||
for type_key, rand_key, id_key in polymorphic:
|
||||
# Handle random key if present
|
||||
if type_key in obj_data and rand_key in obj_data:
|
||||
obj_data[id_key] = redis_lookup_id_random(
|
||||
record_id_random=obj_data.get(rand_key),
|
||||
table_name=obj_data.get(type_key)
|
||||
)
|
||||
obj_data.pop(rand_key)
|
||||
# Handle Vision naming (id_key contains the string)
|
||||
elif type_key in obj_data and id_key in obj_data and isinstance(obj_data[id_key], str) and 11 <= len(obj_data[id_key]) <= 22:
|
||||
obj_data[id_key] = redis_lookup_id_random(
|
||||
record_id_random=obj_data.get(id_key),
|
||||
table_name=obj_data.get(type_key)
|
||||
)
|
||||
|
||||
return obj_data
|
||||
|
||||
|
||||
def get_account_id_w_for_type_id(
|
||||
for_type: str, # This is the table name
|
||||
for_id: int|str,
|
||||
) -> bool|int|None:
|
||||
"""Helper to find an account_id associated with an object."""
|
||||
from app.db_sql import sql_select
|
||||
log.setLevel(logging.WARNING)
|
||||
|
||||
if fid := redis_lookup_id_random(record_id_random=for_id, table_name=for_type):
|
||||
data = {'for_id': fid}
|
||||
sql = f"SELECT account_id FROM `{for_type}` WHERE id = :for_id LIMIT 1;"
|
||||
if result := sql_select(data=data, sql=sql):
|
||||
return result.get('account_id')
|
||||
return False
|
||||
return None
|
||||
67
app/lib_schema_v3.py
Normal file
67
app/lib_schema_v3.py
Normal file
@@ -0,0 +1,67 @@
|
||||
from typing import Any, Dict
|
||||
from sqlalchemy import text
|
||||
from app.db_sql import db
|
||||
from app.ae_obj_types_def import obj_type_kv_li
|
||||
|
||||
def get_object_schema_info(obj_type: str, view: str = 'default', variant: str = 'base') -> Dict[str, Any]:
|
||||
"""
|
||||
Introspects an object type to return its database and model structure.
|
||||
|
||||
Args:
|
||||
obj_type: The name of the object (e.g., 'person').
|
||||
view: The SQL view to describe (default, detail, etc.).
|
||||
variant: The model variant to describe (base, in, out).
|
||||
|
||||
Returns:
|
||||
A dictionary containing database column info and Pydantic field info.
|
||||
"""
|
||||
if obj_type not in obj_type_kv_li:
|
||||
return {"error": f"Object type '{obj_type}' not found."}
|
||||
|
||||
obj_cfg = obj_type_kv_li[obj_type]
|
||||
table_name = obj_cfg.get(f'tbl_{view}', obj_cfg.get('tbl_default', obj_cfg.get('tbl')))
|
||||
model_key = f'mdl_{variant}' if variant != 'base' else 'mdl'
|
||||
model = obj_cfg.get(model_key, obj_cfg.get('mdl_default', obj_cfg.get('mdl')))
|
||||
|
||||
if not table_name:
|
||||
return {"error": f"Table configuration for '{obj_type}' is missing."}
|
||||
|
||||
schema_info = {
|
||||
"object_type": obj_type,
|
||||
"view": view,
|
||||
"variant": variant,
|
||||
"database": {"table_name": table_name, "columns": []},
|
||||
"model": {"name": model.__name__ if hasattr(model, '__name__') else str(model), "fields": {}}
|
||||
}
|
||||
|
||||
# 1. Database Introspection
|
||||
try:
|
||||
db_result = db.execute(text(f"DESCRIBE `{table_name}`"))
|
||||
for row in db_result.fetchall():
|
||||
# row format: (Field, Type, Null, Key, Default, Extra)
|
||||
schema_info["database"]["columns"].append({
|
||||
"field": row[0],
|
||||
"db_type": row[1],
|
||||
"nullable": row[2] == 'YES',
|
||||
"required": row[2] == 'NO', # Explicitly capture NOT NULL
|
||||
"key": row[3],
|
||||
"db_default": row[4],
|
||||
"extra": row[5]
|
||||
})
|
||||
except Exception as e:
|
||||
schema_info["database"]["error"] = str(e)
|
||||
|
||||
# 2. Pydantic Model Introspection
|
||||
if model and hasattr(model, "__fields__"):
|
||||
for field_name, field in model.__fields__.items():
|
||||
field_info = {
|
||||
"alias": field.alias,
|
||||
"type": str(field.outer_type_),
|
||||
"required": field.required,
|
||||
"default": field.default
|
||||
}
|
||||
if field.field_info.description:
|
||||
field_info["description"] = field.field_info.description
|
||||
schema_info["model"]["fields"][field_name] = field_info
|
||||
|
||||
return schema_info
|
||||
82
app/lib_sql_core.py
Normal file
82
app/lib_sql_core.py
Normal file
@@ -0,0 +1,82 @@
|
||||
"""
|
||||
Foundational SQL connection management for the Aether API.
|
||||
Isolates the SQLAlchemy engine and global connection state to prevent circular imports.
|
||||
"""
|
||||
import logging
|
||||
import threading
|
||||
from typing import Any, Optional
|
||||
from sqlalchemy import create_engine
|
||||
from app.config import settings
|
||||
|
||||
log = logging.getLogger('root')
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
|
||||
# 1. Thread-local storage for capturing last SQL error message
|
||||
_sql_error_state = threading.local()
|
||||
|
||||
def get_last_sql_error() -> Optional[str]:
|
||||
"""Retrieves and clears the last captured SQL error message."""
|
||||
error = getattr(_sql_error_state, 'last_error', None)
|
||||
_sql_error_state.last_error = None
|
||||
return error
|
||||
|
||||
def set_last_sql_error(error: Any):
|
||||
"""Sets the last captured SQL error message."""
|
||||
_sql_error_state.last_error = str(error)
|
||||
|
||||
|
||||
# 2. Initial Engine Setup
|
||||
db_uri = settings.SQLALCHEMY_DB_URI
|
||||
|
||||
def create_ae_engine(uri: str):
|
||||
return create_engine(
|
||||
url = uri,
|
||||
echo = False,
|
||||
pool_size = settings.DB.get('pool_size', 10),
|
||||
max_overflow = settings.DB.get('max_overflow', 20),
|
||||
pool_use_lifo = True,
|
||||
pool_pre_ping = True,
|
||||
pool_recycle = settings.DB['pool_recycle'],
|
||||
isolation_level = 'READ COMMITTED',
|
||||
connect_args = {'connect_timeout': settings.DB['connect_timeout']}
|
||||
)
|
||||
|
||||
engine = create_ae_engine(db_uri)
|
||||
|
||||
# DEPRECATED: Global shared 'db' connection. Use engine.connect() in context managers instead.
|
||||
# Keeping for legacy compatibility but will phase out usage in crud lib.
|
||||
db = engine.connect()
|
||||
|
||||
log.info('DB SQL Core: Initializing engine...')
|
||||
|
||||
|
||||
# 3. Connection Management Logic
|
||||
def reconnect_db() -> bool:
|
||||
"""
|
||||
Re-initializes the global database engine using current settings.
|
||||
Useful after bootstrapping new credentials from the 'cfg' table.
|
||||
"""
|
||||
global engine, db, db_uri
|
||||
|
||||
log.info("DB SQL Core: Refreshing database connection engine...")
|
||||
try:
|
||||
if engine:
|
||||
engine.dispose()
|
||||
log.info("DB SQL Core: Disposed of previous database engine.")
|
||||
|
||||
db_uri = settings.SQLALCHEMY_DB_URI
|
||||
engine = create_ae_engine(db_uri)
|
||||
db = engine.connect()
|
||||
|
||||
safe_uri = db_uri.split('@')[-1] if '@' in db_uri else db_uri
|
||||
log.info(f"DB SQL Core: Database engine re-established successfully: {safe_uri}")
|
||||
return True
|
||||
except Exception:
|
||||
log.exception("DB SQL Core: FAILED to refresh database engine!")
|
||||
return False
|
||||
|
||||
def sql_connect(current_db=None, log_lvl: int = logging.INFO) -> bool:
|
||||
"""Refreshes the global database connection."""
|
||||
log.setLevel(log_lvl)
|
||||
log.info('DB SQL Core: Refreshing database connection via sql_connect...')
|
||||
return reconnect_db()
|
||||
392
app/lib_sql_crud.py
Normal file
392
app/lib_sql_crud.py
Normal file
@@ -0,0 +1,392 @@
|
||||
"""
|
||||
Standardized SQL CRUD operations for the Aether API.
|
||||
Provides high-level helpers for INSERT, UPDATE, SELECT, and DELETE.
|
||||
"""
|
||||
import logging
|
||||
import json
|
||||
from typing import Any, List, Optional
|
||||
from sqlalchemy import text, Time
|
||||
from sqlalchemy.exc import IntegrityError, OperationalError, ProgrammingError
|
||||
|
||||
from app.log import log, logger_reset
|
||||
# CRITICAL: Import the core module to access current global state
|
||||
from app import lib_sql_core
|
||||
from app.lib_sql_core import sql_connect, set_last_sql_error
|
||||
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
|
||||
# Helper for resolving random IDs
|
||||
from app.lib_redis_helpers import lookup_id_random_pop
|
||||
|
||||
# ### BEGIN ### API DB SQL ### sql_insert() ###
|
||||
@logger_reset
|
||||
def sql_insert(
|
||||
sql: str|None = None,
|
||||
data: dict|None = None,
|
||||
table_name: str|None = None,
|
||||
rm_id_random: bool = False,
|
||||
id_random_length: int = 8,
|
||||
log_lvl: int = logging.WARNING,
|
||||
) -> None|bool|int:
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
if sql:
|
||||
sql_insert_stmt = text(sql)
|
||||
elif table_name and data:
|
||||
if rm_id_random:
|
||||
data = lookup_id_random_pop(obj_data=data)
|
||||
if not data.get('id_random', None) and id_random_length:
|
||||
import secrets
|
||||
data['id_random'] = secrets.token_urlsafe(id_random_length)
|
||||
|
||||
fields = []
|
||||
values = []
|
||||
for key, value in data.items():
|
||||
if key != 'id':
|
||||
fields.append('`'+str(key)+'`')
|
||||
values.append(':'+str(key))
|
||||
if isinstance(value, (dict, list)):
|
||||
data[key] = json.dumps(value)
|
||||
|
||||
sql_insert_stmt = text(f"INSERT INTO `{table_name}` ({', '.join(fields)}) VALUES ({', '.join(values)});")
|
||||
else:
|
||||
log.error('SQL INSERT statement could not be created. Missing params.')
|
||||
return False
|
||||
|
||||
trans = None
|
||||
try:
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
trans = conn.begin()
|
||||
result_insert = conn.execute(sql_insert_stmt, data)
|
||||
trans.commit()
|
||||
if result_insert.rowcount == 1 and result_insert.lastrowid > 0:
|
||||
return result_insert.lastrowid
|
||||
return False
|
||||
except IntegrityError as e:
|
||||
if trans: trans.rollback()
|
||||
log.error('Integrity error (likely duplicate). Returning None')
|
||||
log.debug(e)
|
||||
set_last_sql_error(e)
|
||||
return None
|
||||
except Exception as e:
|
||||
if trans: trans.rollback()
|
||||
log.error('Unknown exception in sql_insert. Returning False')
|
||||
log.exception(e)
|
||||
set_last_sql_error(e)
|
||||
return False
|
||||
# ### END ### API DB SQL ### sql_insert() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API DB SQL ### sql_update() ###
|
||||
@logger_reset
|
||||
def sql_update(
|
||||
sql: str|None = None,
|
||||
data: dict|None = None,
|
||||
table_name: str|None = None,
|
||||
record_id: int|None = None,
|
||||
record_id_random: str|None = None,
|
||||
rm_id_random: bool = False,
|
||||
id_random_length: None|int = None,
|
||||
log_lvl: int = logging.WARNING,
|
||||
):
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
if sql:
|
||||
sql_update_stmt = text(sql)
|
||||
elif table_name and data:
|
||||
if rm_id_random:
|
||||
data = lookup_id_random_pop(obj_data=data)
|
||||
if not data.get('id_random', None) and id_random_length:
|
||||
import secrets
|
||||
data['id_random'] = secrets.token_urlsafe(id_random_length)
|
||||
|
||||
field_list = []
|
||||
for key, value in data.items():
|
||||
if key != 'id':
|
||||
field_list.append('`'+str(key) + '` = :' + str(key))
|
||||
if isinstance(value, (dict, list)):
|
||||
data[key] = json.dumps(value)
|
||||
|
||||
sql_set = ', '.join(field_list)
|
||||
if len(sql_set) < 4:
|
||||
return None
|
||||
|
||||
if record_id:
|
||||
data['id'] = record_id
|
||||
sql_update_stmt = text(f'UPDATE `{table_name}` SET {sql_set} WHERE id = :id')
|
||||
elif record_id_random:
|
||||
data['id_random'] = record_id_random
|
||||
sql_update_stmt = text(f'UPDATE `{table_name}` SET {sql_set} WHERE id_random = :id_random')
|
||||
elif 'id' in data:
|
||||
sql_update_stmt = text(f'UPDATE `{table_name}` SET {sql_set} WHERE id = :id')
|
||||
elif 'id_random' in data:
|
||||
sql_update_stmt = text(f'UPDATE `{table_name}` SET {sql_set} WHERE id_random = :id_random')
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
trans = None
|
||||
try:
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
trans = conn.begin()
|
||||
result_update = conn.execute(sql_update_stmt, data)
|
||||
trans.commit()
|
||||
if result_update.rowcount >= 1:
|
||||
return True
|
||||
return None
|
||||
except OperationalError:
|
||||
if trans: trans.rollback()
|
||||
log.error('Operational error (gone away?). Retrying once...')
|
||||
sql_connect()
|
||||
try:
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
trans = conn.begin()
|
||||
result_update = conn.execute(sql_update_stmt, data)
|
||||
trans.commit()
|
||||
if result_update.rowcount >= 1:
|
||||
return True
|
||||
return None
|
||||
except Exception as e:
|
||||
set_last_sql_error(e)
|
||||
return False
|
||||
except Exception as e:
|
||||
if trans: trans.rollback()
|
||||
log.exception(e)
|
||||
set_last_sql_error(e)
|
||||
return False
|
||||
# ### END ### API DB SQL ### sql_update() ###
|
||||
|
||||
|
||||
# ### BEGIN ### Core Help CRUD ### sql_insert_or_update() ###
|
||||
@logger_reset
|
||||
def sql_insert_or_update(
|
||||
sql: str|None = None,
|
||||
data: dict|None = None,
|
||||
table_name: str|None = None,
|
||||
rm_id_random: bool = False,
|
||||
id_random_length: int|None = None,
|
||||
log_lvl: int = logging.DEBUG,
|
||||
):
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
if sql:
|
||||
stmt = text(sql)
|
||||
elif table_name and data:
|
||||
if rm_id_random:
|
||||
data = lookup_id_random_pop(obj_data=data)
|
||||
if not data.get('id_random', None) and id_random_length:
|
||||
import secrets
|
||||
data['id_random'] = secrets.token_urlsafe(id_random_length)
|
||||
|
||||
fields = [f'`{k}`' for k in data.keys() if k != 'id']
|
||||
placeholders = [f':{k}' for k in data.keys() if k != 'id']
|
||||
updates = [f'`{k}` = :{k}' for k in data.keys() if k != 'id']
|
||||
|
||||
for k, v in data.items():
|
||||
if isinstance(v, (dict, list)):
|
||||
data[k] = json.dumps(v)
|
||||
|
||||
stmt = text(f"INSERT INTO `{table_name}` ({', '.join(fields)}) VALUES ({', '.join(placeholders)}) "
|
||||
f"ON DUPLICATE KEY UPDATE {', '.join(updates)};")
|
||||
else:
|
||||
return False
|
||||
|
||||
trans = None
|
||||
try:
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
trans = conn.begin()
|
||||
res = conn.execute(stmt, data)
|
||||
trans.commit()
|
||||
return res.lastrowid if res.lastrowid > 0 else True
|
||||
except Exception as e:
|
||||
if trans: trans.rollback()
|
||||
log.exception(e)
|
||||
return False
|
||||
# ### END ### Core Help CRUD ### sql_insert_or_update() ###
|
||||
|
||||
|
||||
# ### BEGIN ### Core Help CRUD ### sql_select() ###
|
||||
@logger_reset
|
||||
def sql_select(
|
||||
table_name: str|None = None,
|
||||
record_id: int|None = None,
|
||||
record_id_random: str|None = None,
|
||||
field_name: str|None = None,
|
||||
field_value = None,
|
||||
enabled: str|None = None,
|
||||
hidden: str|None = None,
|
||||
qry_dict_li: dict|None = None,
|
||||
fulltext_qry_dict: dict|None = None,
|
||||
and_qry_dict: dict|None = None,
|
||||
and_like_dict: dict|None = None,
|
||||
or_like_dict: dict|None = None,
|
||||
and_in_dict_li: dict|None = None,
|
||||
search_query: Any|None = None,
|
||||
searchable_fields: List[str]|None = None,
|
||||
order_by_li: dict|None = None,
|
||||
limit: int = 9999999,
|
||||
offset: int = 0,
|
||||
sql: str|None = None,
|
||||
data: dict|None = None,
|
||||
rm_id_random: bool = False,
|
||||
as_dict: bool|None = True,
|
||||
as_list: bool|None = False,
|
||||
max_count: int = 100000,
|
||||
log_lvl: int = logging.WARNING,
|
||||
) -> None|bool|dict|list:
|
||||
from app.lib_sql_search import (
|
||||
sql_enable_part, sql_hidden_part, sql_search_qry_part,
|
||||
sql_where_qry_part, sql_fulltext_qry_part, sql_and_qry_part,
|
||||
sql_and_like_part, sql_or_like_part, sql_and_in_dict_li_part
|
||||
)
|
||||
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
sql_limit_offset = f'LIMIT {limit} OFFSET {offset}' if limit >= 0 and offset >= 0 else ''
|
||||
|
||||
sql_order_by = ''
|
||||
if order_by_li and isinstance(order_by_li, dict):
|
||||
order_by_str_li = [f'`{table_name}`.`{k}` {v}' for k, v in order_by_li.items()]
|
||||
sql_order_by = f"ORDER BY {', '.join(order_by_str_li)}"
|
||||
|
||||
if table_name and not (record_id or record_id_random or field_name or field_value or sql or data):
|
||||
data = {}
|
||||
s_en, d_en = sql_enable_part(table_name, enabled) if enabled else ('', None)
|
||||
s_hi, d_hi = sql_hidden_part(table_name, hidden) if hidden else ('', None)
|
||||
if d_en is not None: data['enabled'] = d_en
|
||||
if d_hi is not None: data['hidden'] = d_hi
|
||||
|
||||
s_search, d_search = ('', {})
|
||||
if search_query:
|
||||
s_search, d_search = sql_search_qry_part(search_query, searchable_fields, table_name=table_name)
|
||||
data.update(d_search)
|
||||
|
||||
stmt = text(f"SELECT * FROM `{table_name}` WHERE 1=1 {s_search} {s_en} {s_hi} {sql_order_by} {sql_limit_offset};")
|
||||
|
||||
elif table_name and (record_id or record_id_random) and not (field_name or field_value or sql or data):
|
||||
data = {'rid': record_id} if record_id else {'ridr': record_id_random}
|
||||
where = f"`{table_name}`.id = :rid" if record_id else f"`{table_name}`.id_random = :ridr"
|
||||
stmt = text(f"SELECT * FROM `{table_name}` WHERE {where} {sql_order_by} {sql_limit_offset};")
|
||||
|
||||
elif table_name and field_name and field_value and not (record_id or record_id_random or sql or data):
|
||||
data = {field_name: field_value}
|
||||
s_where, d_where = sql_where_qry_part(qry_dict_li) if qry_dict_li else ('', {})
|
||||
s_ft, d_ft = sql_fulltext_qry_part(fulltext_qry_dict) if fulltext_qry_dict else ('', {})
|
||||
s_and, d_and = sql_and_qry_part(and_qry_dict) if and_qry_dict else ('', {})
|
||||
s_alike, d_alike = sql_and_like_part(and_like_dict) if and_like_dict else ('', {})
|
||||
s_olike, d_olike = sql_or_like_part(or_like_dict) if or_like_dict else ('', {})
|
||||
s_in, d_in = sql_and_in_dict_li_part(and_in_dict_li) if and_in_dict_li else ('', {})
|
||||
s_search, d_search = sql_search_qry_part(search_query, searchable_fields, table_name=table_name) if search_query else ('', {})
|
||||
s_en, d_en = sql_enable_part(table_name, enabled) if enabled else ('', None)
|
||||
s_hi, d_hi = sql_hidden_part(table_name, hidden) if hidden else ('', None)
|
||||
|
||||
data.update(d_where); data.update(d_ft); data.update(d_and); data.update(d_alike)
|
||||
data.update(d_olike); data.update(d_in); data.update(d_search)
|
||||
if d_en is not None: data['enabled'] = d_en
|
||||
if d_hi is not None: data['hidden'] = d_hi
|
||||
|
||||
stmt = text(f"SELECT * FROM `{table_name}` WHERE `{table_name}`.{field_name} = :{field_name} "
|
||||
f"{s_where} {s_ft} {s_and} {s_alike} {s_olike} {s_in} {s_search} {s_en} {s_hi} {sql_order_by} {sql_limit_offset};")
|
||||
elif table_name and data and not (record_id or record_id_random or field_name or field_value or sql):
|
||||
if rm_id_random: data = lookup_id_random_pop(obj_data=data)
|
||||
where_clauses = [f"`{table_name}`.{k} = :{k}" for k in data.keys()]
|
||||
stmt = text(f"SELECT * FROM `{table_name}` WHERE {' AND '.join(where_clauses)} {sql_order_by} {sql_limit_offset};")
|
||||
elif sql:
|
||||
stmt = text(sql)
|
||||
else:
|
||||
return False
|
||||
|
||||
try:
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
result = conn.execute(stmt, data)
|
||||
if not result:
|
||||
return [] if as_list else None
|
||||
|
||||
# Fetch all rows first to determine actual count reliably
|
||||
if hasattr(result, 'returns_rows') and not result.returns_rows:
|
||||
log.warning("SQL Result does not return rows (ResourceClosedError prevented).")
|
||||
return [] if as_list else None
|
||||
|
||||
rows = result.all()
|
||||
except Exception as e:
|
||||
log.error(f"SQL Fetch Error: {e}")
|
||||
set_last_sql_error(e)
|
||||
return False
|
||||
|
||||
count = len(rows)
|
||||
|
||||
if count == 0:
|
||||
return [] if as_list else None
|
||||
|
||||
if count == 1:
|
||||
record = dict(rows[0]) if as_dict else rows[0]
|
||||
return [record] if as_list else record
|
||||
|
||||
# count > 1
|
||||
records = [dict(r) for r in rows] if as_dict else rows
|
||||
return records
|
||||
# ### END ### Core Help CRUD ### sql_select() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API DB SQL ### run_sql_select() ###
|
||||
@logger_reset
|
||||
def run_sql_select(
|
||||
sql: text,
|
||||
data: dict|None = None,
|
||||
log_lvl: int = logging.WARNING,
|
||||
) -> Any:
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
try:
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
return conn.execute(sql, data)
|
||||
except (OperationalError, ProgrammingError) as e:
|
||||
log.error(f'DB Error: {e}. Retrying once...')
|
||||
sql_connect()
|
||||
try:
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
return conn.execute(sql, data)
|
||||
except Exception as e2:
|
||||
set_last_sql_error(e2)
|
||||
raise e2 # RAISING instead of returning False
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
set_last_sql_error(e)
|
||||
raise e # RAISING instead of returning False
|
||||
# ### END ### API DB SQL ### run_sql_select() ###
|
||||
|
||||
# ### BEGIN ### Core Help CRUD ### sql_delete() ###
|
||||
@logger_reset
|
||||
def sql_delete(
|
||||
table_name: str|None = None,
|
||||
record_id: int|None = None,
|
||||
record_id_random: str|None = None,
|
||||
field_name: str|None = None,
|
||||
field_value = None,
|
||||
sql: str|None = None,
|
||||
data: dict|None = None,
|
||||
log_lvl: int = logging.INFO,
|
||||
) -> None|bool:
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
if table_name and (record_id or record_id_random) and not (field_name or field_value or sql or data):
|
||||
data = {'rid': record_id} if record_id else {'ridr': record_id_random}
|
||||
where = f"`{table_name}`.id = :rid" if record_id else f"`{table_name}`.id_random = :ridr"
|
||||
stmt = text(f"DELETE FROM `{table_name}` WHERE {where}")
|
||||
elif table_name and field_name and field_value and not (record_id or record_id_random or sql or data):
|
||||
data = {field_name: field_value}
|
||||
stmt = text(f"DELETE FROM `{table_name}` WHERE `{table_name}`.{field_name} = :{field_name}")
|
||||
elif sql:
|
||||
stmt = text(sql)
|
||||
else:
|
||||
return False
|
||||
|
||||
try:
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
result = conn.execute(stmt, data) if data else conn.execute(stmt)
|
||||
return True if result.rowcount >= 1 else None
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
return False
|
||||
# ### END ### Core Help CRUD ### sql_delete() ###
|
||||
275
app/lib_sql_search.py
Normal file
275
app/lib_sql_search.py
Normal file
@@ -0,0 +1,275 @@
|
||||
"""
|
||||
Modular search builder and query generators for Aether.
|
||||
"""
|
||||
import logging
|
||||
from typing import Any, List, Optional
|
||||
from fastapi import HTTPException
|
||||
from sqlalchemy import text
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
def sql_limit_offset_part(limit: int, offset: int = 0) -> str:
|
||||
"""Creates a partial SQL string for LIMIT and OFFSET."""
|
||||
if limit >= 0 and offset >= 0:
|
||||
log.info(f'Creating partial SQL string for LIMIT and OFFSET. Limit: {limit}; Offset: {offset}')
|
||||
return f'LIMIT {limit} OFFSET {offset}'
|
||||
else:
|
||||
return ''
|
||||
|
||||
def sql_and_like_part(and_like_dict_obj: dict) -> tuple[str, dict]:
|
||||
"""Creates a partial SQL string for AND LIKE queries."""
|
||||
data = {}
|
||||
if and_like_dict_obj and isinstance(and_like_dict_obj, dict):
|
||||
log.info('Creating partial SQL string for additional AND LIKE queries.')
|
||||
clauses = []
|
||||
for key, value in and_like_dict_obj.items():
|
||||
clauses.append(f"{key} LIKE :and_like_{key}")
|
||||
data[f'and_like_{key}'] = value
|
||||
return f"AND ({' AND '.join(clauses)})", data
|
||||
return '', {}
|
||||
|
||||
def sql_or_like_part(or_like_dict_obj: dict) -> tuple[str, dict]:
|
||||
"""Creates a partial SQL string for OR LIKE queries."""
|
||||
data = {}
|
||||
if or_like_dict_obj and isinstance(or_like_dict_obj, dict):
|
||||
log.info('Creating partial SQL string for additional OR LIKE queries.')
|
||||
clauses = []
|
||||
for key, value in or_like_dict_obj.items():
|
||||
clauses.append(f"{key} LIKE :or_like_{key}")
|
||||
data[f'or_like_{key}'] = value
|
||||
return f"AND ({' OR '.join(clauses)})", data
|
||||
return '', {}
|
||||
|
||||
def sql_and_in_dict_li_part(and_in_dict_li_dict_obj: dict) -> tuple[str, dict]:
|
||||
"""Creates a partial SQL string for AND IN queries."""
|
||||
data = {}
|
||||
if and_in_dict_li_dict_obj and isinstance(and_in_dict_li_dict_obj, dict):
|
||||
log.info('Creating partial SQL string for additional AND IN queries.')
|
||||
clauses = []
|
||||
for key, value in and_in_dict_li_dict_obj.items():
|
||||
clauses.append(f"{key} IN :and_in_{key}")
|
||||
data[f'and_in_{key}'] = value
|
||||
return f"AND ({' AND '.join(clauses)})", data
|
||||
return '', {}
|
||||
|
||||
def sql_and_qry_part(and_qry_dict_obj: dict) -> tuple[str, dict]:
|
||||
"""Creates a partial SQL string for additional AND queries (equals)."""
|
||||
data = {}
|
||||
if and_qry_dict_obj and isinstance(and_qry_dict_obj, dict):
|
||||
log.info('Creating partial SQL string for additional AND queries.')
|
||||
clauses = []
|
||||
for key, value in and_qry_dict_obj.items():
|
||||
clauses.append(f"{key} = :and_{key}")
|
||||
data[f'and_{key}'] = value
|
||||
return f"AND ({' AND '.join(clauses)})", data
|
||||
return '', {}
|
||||
|
||||
def sql_fulltext_qry_part(fulltext_qry_dict: dict) -> tuple[str, dict]:
|
||||
"""Creates a partial SQL string for fulltext search."""
|
||||
data = {}
|
||||
if fulltext_qry_dict and isinstance(fulltext_qry_dict, dict):
|
||||
log.info('Creating partial SQL string for fulltext search.')
|
||||
clauses = []
|
||||
for key, value in fulltext_qry_dict.items():
|
||||
clauses.append(f"MATCH( {key} ) AGAINST( :ft_{key} IN BOOLEAN MODE )")
|
||||
data[f'ft_{key}'] = value
|
||||
return f"AND ({' OR '.join(clauses)})", data
|
||||
return '', {}
|
||||
|
||||
def sql_enable_part(table_name: str, enabled: str) -> tuple[str, bool|None]:
|
||||
"""Handles enabled/disabled status filtering with schema check."""
|
||||
from app import lib_sql_core
|
||||
if not table_name: return '', None
|
||||
if enabled in ['enabled', 'disabled', 'not_enabled', 'all']:
|
||||
if enabled == 'all': return '', None
|
||||
try:
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
conn.execute(text(f"SELECT enable FROM `{table_name}` LIMIT 0"))
|
||||
except:
|
||||
log.warning(f"Table '{table_name}' missing 'enable' column. Skipping filter.")
|
||||
return '', None
|
||||
val = (enabled == 'enabled')
|
||||
return f"AND `{table_name}`.enable = {str(val).lower()}", val
|
||||
return '', None
|
||||
|
||||
def sql_hidden_part(table_name: str, hidden: str) -> tuple[str, bool|None]:
|
||||
"""Handles hidden status filtering with schema check."""
|
||||
from app import lib_sql_core
|
||||
if not table_name: return '', None
|
||||
if hidden in ['hidden', 'not_hidden', 'all']:
|
||||
if hidden == 'all': return '', None
|
||||
try:
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
conn.execute(text(f"SELECT hide FROM `{table_name}` LIMIT 0"))
|
||||
except:
|
||||
log.warning(f"Table '{table_name}' missing 'hide' column. Skipping filter.")
|
||||
return '', None
|
||||
if hidden == 'hidden':
|
||||
return f"AND `{table_name}`.hide = true", True
|
||||
return f"AND (`{table_name}`.hide = false OR `{table_name}`.hide IS NULL)", False
|
||||
return '', None
|
||||
|
||||
def sql_where_qry_part(qry_dict_li: list) -> tuple[str, dict]:
|
||||
"""Standard v2 style WHERE clause builder."""
|
||||
data = {}
|
||||
if qry_dict_li and isinstance(qry_dict_li, list):
|
||||
log.info('Creating partial SQL string for WHERE queries.')
|
||||
clauses = []
|
||||
for qry in qry_dict_li:
|
||||
field = qry.get('field')
|
||||
op = qry.get('operator')
|
||||
val = qry.get('value')
|
||||
type_ = qry.get('type', 'AND') or 'AND'
|
||||
if op == 'MATCH':
|
||||
clauses.append(f'{type_} MATCH( {field} ) AGAINST( :{field} IN BOOLEAN MODE )')
|
||||
else:
|
||||
clauses.append(f'{type_} {field} {op} :{field}')
|
||||
data[field] = val
|
||||
return ' '.join(clauses), data
|
||||
return '', {}
|
||||
|
||||
def sql_search_qry_part(
|
||||
search_query: Any,
|
||||
searchable_fields: List[str]|None = None,
|
||||
max_depth: int = 5,
|
||||
table_name: str|None = None,
|
||||
) -> tuple[str, dict]:
|
||||
"""Recursively builds a SQL WHERE clause from a SearchQuery model."""
|
||||
from app import lib_sql_core
|
||||
data = {}
|
||||
param_counter = [0]
|
||||
|
||||
def get_param_name():
|
||||
param_counter[0] += 1
|
||||
return f"sp_{param_counter[0]}"
|
||||
|
||||
operator_map = {
|
||||
"eq": "=", "ne": "!=", "gt": ">", "gte": ">=", "lt": "<", "lte": "<=",
|
||||
"like": "LIKE", "in": "IN", "is_null": "IS NULL", "is_not_null": "IS NOT NULL",
|
||||
"contains": "LIKE", "icontains": "LIKE", "startswith": "LIKE", "istartswith": "LIKE",
|
||||
"endswith": "LIKE", "iendswith": "LIKE"
|
||||
}
|
||||
|
||||
def process_node(query_node, current_depth: int) -> str:
|
||||
if current_depth > max_depth:
|
||||
raise HTTPException(status_code=400, detail=f"Search query too complex.")
|
||||
clauses = []
|
||||
if hasattr(query_node, 'query_string') and query_node.query_string:
|
||||
if query_node.query_string == '%': pass
|
||||
else:
|
||||
use_match = True
|
||||
if table_name:
|
||||
try:
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
conn.execute(text(f"SELECT default_qry_str FROM `{table_name}` LIMIT 0"))
|
||||
except:
|
||||
use_match = False
|
||||
else:
|
||||
use_match = False
|
||||
|
||||
if use_match:
|
||||
p_name = get_param_name()
|
||||
clauses.append(f"MATCH( default_qry_str ) AGAINST( :{p_name} IN BOOLEAN MODE )")
|
||||
data[p_name] = query_node.query_string
|
||||
elif searchable_fields:
|
||||
like_clauses = []
|
||||
# Fields to exclude from a generic text 'q' search (numeric, technical, or date fields)
|
||||
exclude_patterns = [
|
||||
'enable', 'hide', 'priority', 'sort', 'group',
|
||||
'created_on', 'updated_on'
|
||||
]
|
||||
for field in searchable_fields:
|
||||
# Exclude internal integer IDs specifically
|
||||
if field.endswith('_id') or field == 'id':
|
||||
continue
|
||||
|
||||
# Exclude other technical/meta fields
|
||||
if any(x == field for x in exclude_patterns):
|
||||
continue
|
||||
|
||||
f_p_name = get_param_name()
|
||||
like_clauses.append(f"`{field}` LIKE :{f_p_name}")
|
||||
data[f_p_name] = f"%{query_node.query_string}%"
|
||||
|
||||
if like_clauses: clauses.append(f"({' OR '.join(like_clauses)})")
|
||||
for filter_attr in ['and_filters', 'or_filters']:
|
||||
if hasattr(query_node, filter_attr) and getattr(query_node, filter_attr):
|
||||
node_clauses = []
|
||||
for item in getattr(query_node, filter_attr):
|
||||
if hasattr(item, 'field'):
|
||||
clause, item_data = process_filter(item)
|
||||
node_clauses.append(clause); data.update(item_data)
|
||||
else: node_clauses.append(f"({process_node(item, current_depth + 1)})")
|
||||
if node_clauses:
|
||||
joiner = ' AND ' if 'and' in filter_attr else ' OR '
|
||||
clauses.append(f"({joiner.join(node_clauses)})")
|
||||
return ' AND '.join(clauses)
|
||||
|
||||
def process_filter(f) -> tuple[str, dict]:
|
||||
# --- ID VISION MAPPING ---
|
||||
# If the frontend uses clean names (id, account_id),
|
||||
# map them to the database columns (id_random, account_id_random)
|
||||
# ONLY if those columns actually exist in this table/view.
|
||||
target_field = f.field
|
||||
vision_fields = [
|
||||
'id', 'account_id', 'site_id', 'person_id', 'user_id',
|
||||
'archive_id', 'archive_content_id',
|
||||
'event_id',
|
||||
'event_session_id', 'event_presentation_id', 'event_presenter_id',
|
||||
'event_device_id', 'event_location_id', 'event_track_id',
|
||||
'event_exhibit_id',
|
||||
'event_person_id', 'event_registration_id',
|
||||
'order_id', 'product_id', 'order_cart_id', 'membership_id', 'sponsorship_id',
|
||||
'journal_id', 'journal_entry_id', 'page_id',
|
||||
'post_id', 'post_comment_id',
|
||||
'organization_id', 'address_id', 'contact_id',
|
||||
'hosted_file_id'
|
||||
]
|
||||
|
||||
if target_field in vision_fields:
|
||||
# ONLY map to _random if the value is a string (looks like a random ID)
|
||||
# If it's an integer, we want to query the original integer column.
|
||||
is_int_val = isinstance(f.value, int) or (isinstance(f.value, str) and f.value.isdigit())
|
||||
|
||||
if not is_int_val:
|
||||
candidate_field = 'id_random' if target_field == 'id' else f"{target_field}_random"
|
||||
|
||||
# Schema Check: Verify if the random version exists in the current table/view
|
||||
use_random = False
|
||||
if table_name:
|
||||
try:
|
||||
with lib_sql_core.engine.connect() as conn:
|
||||
conn.execute(text(f"SELECT `{candidate_field}` FROM `{table_name}` LIMIT 0"))
|
||||
use_random = True
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if use_random:
|
||||
target_field = candidate_field
|
||||
# print(f"Search Trace: Mapping filter field '{f.field}' -> '{target_field}'", flush=True)
|
||||
else:
|
||||
# If random doesn't exist, we must stick to the integer column
|
||||
# but we'll need to resolve the string value to an integer elsewhere
|
||||
# or rely on the user providing an integer for now.
|
||||
pass
|
||||
|
||||
if searchable_fields is not None and target_field not in searchable_fields:
|
||||
# Fallback check for original field just in case
|
||||
if f.field not in searchable_fields:
|
||||
raise HTTPException(status_code=400, detail=f"Unauthorized search field '{f.field}' (mapped to '{target_field}')")
|
||||
|
||||
sql_op = operator_map.get(f.op.lower())
|
||||
if not sql_op: raise HTTPException(status_code=400, detail=f"Unsupported operator: {f.op}")
|
||||
filter_data = {}
|
||||
if f.op.lower() in ['is_null', 'is_not_null']: clause = f"`{target_field}` {sql_op}"
|
||||
else:
|
||||
p_name = get_param_name()
|
||||
if f.op.lower() == 'in': clause = f"`{target_field}` IN (:{p_name})"; filter_data[p_name] = f.value
|
||||
elif f.op.lower() in ['contains', 'icontains']: clause = f"`{target_field}` LIKE :{p_name}"; filter_data[p_name] = f"%{f.value}%"
|
||||
elif f.op.lower() in ['startswith', 'istartswith']: clause = f"`{target_field}` LIKE :{p_name}"; filter_data[p_name] = f"{f.value}%"
|
||||
elif f.op.lower() in ['endswith', 'iendswith']: clause = f"`{target_field}` LIKE :{p_name}"; filter_data[p_name] = f"%{f.value}"
|
||||
else: clause = f"`{target_field}` {sql_op} :{p_name}"; filter_data[p_name] = f.value
|
||||
return clause, filter_data
|
||||
|
||||
sql_where = process_node(search_query, 1)
|
||||
return (f"AND ({sql_where})", data) if sql_where else ("", {})
|
||||
5
app/log.py
Normal file
5
app/log.py
Normal file
@@ -0,0 +1,5 @@
|
||||
import logging
|
||||
from app.lib_log_v3 import log, logger_reset, get_logger, setup_logging
|
||||
|
||||
# Re-exporting for backward compatibility with ~200 existing imports
|
||||
__all__ = ['log', 'logging', 'logger_reset', 'get_logger', 'setup_logging']
|
||||
100
app/log.py.snapshot
Normal file
100
app/log.py.snapshot
Normal file
@@ -0,0 +1,100 @@
|
||||
import functools, logging
|
||||
|
||||
from app.config import settings
|
||||
|
||||
# stream options: 'ext://sys.stderr' or 'ext://sys.stdout'
|
||||
|
||||
# NOTE: This log config is confusing and may need work... 2022-10-07
|
||||
# 'uvicorn' under 'loggers' creates an output to the 'console' handler
|
||||
# Do not also add 'console' handler to the 'root' 'handlers' list
|
||||
# For now just using that to add or remove file logging options.
|
||||
# logging.config.dictConfig({
|
||||
# 'version': 1,
|
||||
# 'formatters': {
|
||||
# 'default': {'format': '[%(asctime)s] %(levelname)s @ %(module)s.%(funcName)s()#%(lineno)d: %(message)s'},
|
||||
# 'long': {'format': '[%(asctime)s] %(levelname)s @ %(module)s.%(funcName)s()#%(lineno)d: %(message)s', 'datefmt': '%Y-%m-%d %H:%M:%S'},
|
||||
# 'short': {'format': '[%(asctime)s] %(levelname)s @ %(module)s.%(funcName)s()#%(lineno)d: %(message)s', 'datefmt': '%H:%M:%S', 'use_colors': True},
|
||||
# },
|
||||
# #'filename': 'example.log',
|
||||
# # 'level': logging.ERROR,
|
||||
# 'handlers': {
|
||||
# 'console': {
|
||||
# 'class': 'logging.StreamHandler',
|
||||
# 'stream': 'ext://sys.stderr',
|
||||
# 'formatter': 'short',
|
||||
# },
|
||||
# 'log_file_all': {
|
||||
# 'level': 'NOTSET',
|
||||
# 'class': 'logging.handlers.RotatingFileHandler',
|
||||
# 'formatter': 'long',
|
||||
# 'filename': settings.LOG_PATH['app'],
|
||||
# 'maxBytes': 10485760, # 5,242,880 = 5 MB; 10,485,760 = 10 MB
|
||||
# 'backupCount': 9
|
||||
# },
|
||||
# # 'log_file_warning': {
|
||||
# # 'level': 'WARNING',
|
||||
# # 'class': 'logging.handlers.RotatingFileHandler',
|
||||
# # 'formatter': 'long',
|
||||
# # 'filename': settings.LOG_PATH['app_warning'],
|
||||
# # 'maxBytes': 512000, # 524,288 = 512KB
|
||||
# # 'backupCount': 9
|
||||
# # },
|
||||
# # 'test_handler': {
|
||||
# # 'class': 'logging.StreamHandler',
|
||||
# # 'level': 'INFO',
|
||||
# # 'formatter': 'short',
|
||||
# # },
|
||||
# # 'test_handler_all_rotate': {
|
||||
# # 'class': 'logging.handlers.RotatingFileHandler',
|
||||
# # 'level': 'NOTSET',
|
||||
# # 'formatter': 'short',
|
||||
# # 'filename': '/logs/test_rotate.log',
|
||||
# # 'maxBytes': 100000, # 5120000 = 5 MB
|
||||
# # 'backupCount': 2,
|
||||
# # }
|
||||
# },
|
||||
# 'loggers': {
|
||||
# # 'uvicorn': {'handlers': ['default'], 'level': 'INFO'},
|
||||
# 'uvicorn': {'handlers': ['console'], 'level': 'INFO'},
|
||||
# # 'uvicorn.error': {'level': 'INFO', 'handlers': ['default'], 'propagate': True},
|
||||
# # 'uvicorn.error': {'level': 'INFO', 'handlers': ['console'], 'propagate': True},
|
||||
# # 'uvicorn.access': {'handlers': ['access'], 'level': 'INFO', 'propagate': False},
|
||||
# # 'gunicorn': {'handlers': ['console'], 'level': 'INFO'},
|
||||
# },
|
||||
# 'root': {
|
||||
# 'handlers': ['log_file_all'], #, 'log_file_all', 'log_file_warning'],
|
||||
# # 'handlers': ['console', 'log_file_all'], #, 'log_file_all', 'log_file_warning'],
|
||||
# 'level': 'WARNING', # WARNING
|
||||
# }
|
||||
# })
|
||||
|
||||
|
||||
# log = logging.getLogger('root')
|
||||
# # log.setLevel(logging.INFO) # DEBUG > INFO > WARNING > ERROR > CRITICAL
|
||||
# # logging.basicConfig(
|
||||
# # format='[%(asctime)s] %(levelname)s @ %(module)s.%(funcName)s()#%(lineno)d: %(message)s'
|
||||
# # )
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### Log ### logger_reset() ###
|
||||
# https://realpython.com/primer-on-python-decorators/
|
||||
# Updated 2022-02-15
|
||||
# def logger_reset(func):
|
||||
# # log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# # log.info(locals())
|
||||
# @functools.wraps(func)
|
||||
# def wrapper(*args, **kwargs):
|
||||
# if func.__name__ not in ['redis_lookup_id_random', 'sql_enable_part', 'sql_hidden_part']:
|
||||
# log.info(f'*** Function: "{func.__name__}()"')
|
||||
# log.debug(f'*** Function Positional Args: {args}\nFunction Key Args: {kwargs}')
|
||||
# init_log_level = log.level
|
||||
# returned_result = func(*args, **kwargs)
|
||||
# log.debug(f'*** Function finished: "{func.__name__}()". Resetting logger level to level: {log.level} ***')
|
||||
# log.setLevel(init_log_level)
|
||||
# return returned_result
|
||||
# return wrapper
|
||||
# ### END ### Log ### logger_reset() ###
|
||||
|
||||
def get_logger(name: str) -> logging.Logger:
|
||||
return logging.getLogger(name)
|
||||
227
app/main.py
Normal file
227
app/main.py
Normal file
@@ -0,0 +1,227 @@
|
||||
import datetime, json, os, pytz, random, secrets, contextlib # , uvicorn
|
||||
|
||||
from enum import Enum
|
||||
#from datetime import datetime, time, timedelta
|
||||
from fastapi import Body, Cookie, Depends, FastAPI, File, Form, Header, HTTPException, Path, Query, Request, Response, status, UploadFile
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import FileResponse, HTMLResponse, JSONResponse, PlainTextResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from functools import lru_cache
|
||||
from pydantic import BaseModel, EmailStr, Field
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
|
||||
from . import config
|
||||
# from app.lib_general import common_route_params, Common_Route_Params
|
||||
import logging
|
||||
import app.log
|
||||
from app.log import setup_logging
|
||||
|
||||
# Import middleware with alias to avoid shadowing 'app' FastAPI instance
|
||||
from app.middleware import add_process_time_header as process_time_middleware
|
||||
|
||||
# Centralized router registry
|
||||
from app.routers.registry import setup_routers
|
||||
|
||||
from app.db_sql import sql_select, reset_redis, reconnect_db
|
||||
from app.lib_config_v3 import bootstrap_db_config, validate_critical_config
|
||||
|
||||
|
||||
print('### **** *** ** * The Aether API v4 using FastAPI is loading... * ** *** **** ###')
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
# log.setLevel(logging.DEBUG) # DEBUG > INFO > WARNING > ERROR > CRITICAL
|
||||
#logging.basicConfig(
|
||||
#format='[%(asctime)s] %(levelname)s @ %(module)s.%(funcName)s()#%(lineno)d: %(message)s'
|
||||
#)
|
||||
|
||||
@contextlib.asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
"""
|
||||
Handles application startup and shutdown lifecycle.
|
||||
"""
|
||||
# 1. Initialize Logging early but safely
|
||||
setup_logging(config.settings)
|
||||
log.info('### **** *** ** * Aether API v4 using FastAPI - Startup Lifespan Initiated * ** *** **** ###')
|
||||
|
||||
# 2. Bootstrapping Configuration from DB with robust error handling
|
||||
log.info("Bootstrapping Configuration...")
|
||||
|
||||
# Save original settings for fallback
|
||||
orig_db_server = config.settings.DB_SERVER
|
||||
orig_db_user = config.settings.DB_USER
|
||||
orig_db_pass = config.settings.DB_PASS
|
||||
orig_db_name = config.settings.DB_NAME
|
||||
orig_db_port = config.settings.DB_PORT
|
||||
|
||||
try:
|
||||
if bootstrap_db_config(config.settings):
|
||||
log.info("Successfully bootstrapped configuration from database.")
|
||||
# Re-initialize the database engine with new credentials/URI
|
||||
if reconnect_db():
|
||||
log.info("Database connection re-established with production configuration.")
|
||||
else:
|
||||
log.warning("FAILED to re-establish database connection after bootstrap. Reverting to .env settings.")
|
||||
config.settings.DB_SERVER = orig_db_server
|
||||
config.settings.DB_USER = orig_db_user
|
||||
config.settings.DB_PASS = orig_db_pass
|
||||
config.settings.DB_NAME = orig_db_name
|
||||
config.settings.DB_PORT = orig_db_port
|
||||
reconnect_db()
|
||||
else:
|
||||
log.warning("System bootstrap from DB returned no results. Using environment defaults.")
|
||||
except Exception as e:
|
||||
log.error(f"Unexpected error during configuration bootstrap: {e}. Falling back to .env settings.")
|
||||
config.settings.DB_SERVER = orig_db_server
|
||||
config.settings.DB_USER = orig_db_user
|
||||
config.settings.DB_PASS = orig_db_pass
|
||||
config.settings.DB_NAME = orig_db_name
|
||||
config.settings.DB_PORT = orig_db_port
|
||||
reconnect_db()
|
||||
|
||||
# 3. Final validation of critical infrastructure
|
||||
validate_critical_config(config.settings)
|
||||
|
||||
log.info('### **** *** ** * Aether API v4 using FastAPI - Startup Sequence Complete * ** *** **** ###')
|
||||
|
||||
yield
|
||||
|
||||
# Shutdown logic
|
||||
log.info('### **** *** ** * Aether API v4 using FastAPI - Shutdown Lifespan Initiated * ** *** **** ###')
|
||||
log.info('The Aether FastAPI API is shutting down...')
|
||||
|
||||
|
||||
print('### **** *** ** * Aether API v4 using FastAPI - About to try FastAPI() while loading... * ** *** **** ###')
|
||||
app = FastAPI(
|
||||
# debug = True,
|
||||
title = 'Aether API',
|
||||
description = 'One Sky IT\'s Aether API v4 using FastAPI.',
|
||||
version = '4.9.0',
|
||||
operationsSorter = 'method',
|
||||
lifespan = lifespan,
|
||||
)
|
||||
|
||||
|
||||
# @lru_cache()
|
||||
# def get_settings():
|
||||
# return config.Settings()
|
||||
|
||||
|
||||
app.mount('/static', StaticFiles(directory='static'), name='static')
|
||||
|
||||
|
||||
# Register all application routes
|
||||
setup_routers(app)
|
||||
|
||||
|
||||
# BEGIN: CORS
|
||||
# NOTE: Eventually this should query the DB for the specific list based on the cfg table and or site_domain table. That way it is dynamic and only allowing those defined in the DB. No wildcards or regex.
|
||||
# NOTE: Need to include .localhost for less browser restrictions! Mainly for audio and video.
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
# allow_origins = origins,
|
||||
allow_origins = config.settings.ORIGINS,
|
||||
allow_origin_regex = config.settings.ORIGINS_REGEX,
|
||||
# allow_origin_regex = 'https://.*\.oneskyit\.com',
|
||||
allow_credentials = True,
|
||||
allow_methods = ['*'],
|
||||
allow_headers = ['*'],
|
||||
#expose_headers = [],
|
||||
#max_age = 600,
|
||||
)
|
||||
# END: CORS
|
||||
|
||||
|
||||
# Register utility middleware from external module
|
||||
app.middleware('http')(process_time_middleware)
|
||||
|
||||
|
||||
# ### BEGIN ### API Main ### fastapi_root() ###
|
||||
@app.get('/', tags=['Root'], response_class=PlainTextResponse)
|
||||
async def fastapi_root(response: Response = Response):
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARN, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# log.info(config.settings.APP_NAME)
|
||||
log.info('One Sky IT\'s Aether API root (FastAPI)')
|
||||
|
||||
log.info('***')
|
||||
log.debug('This is debug') # 10 DEBUG
|
||||
log.info('This is info') # 20 INFO
|
||||
log.warning('This is a warning') # 30 WARNING (and WARN)
|
||||
log.error('This is an error') # 40 ERROR
|
||||
log.exception('This is an exception') # 40 ERROR
|
||||
log.critical('This is critical') # 50 CRITICAL
|
||||
log.info('^^^')
|
||||
|
||||
log.warning('Resetting Redis...')
|
||||
reset_redis()
|
||||
log.info('Reset Redis')
|
||||
|
||||
response_data = {}
|
||||
response_data['message'] = 'This is One Sky IT\'s Aether API root (FastAPI).'
|
||||
|
||||
|
||||
current_datetime = datetime.datetime.now()
|
||||
current_datetime_string = current_datetime.isoformat()
|
||||
|
||||
timezone = pytz.timezone("America/New_York")
|
||||
current_datetime_tz = timezone.localize(current_datetime)
|
||||
current_datetime_tz_string = current_datetime_tz.isoformat()
|
||||
|
||||
current_datetime_utc = datetime.datetime.utcnow()
|
||||
current_datetime_utc_string = current_datetime_utc.isoformat()
|
||||
|
||||
current_datetime_utc_localize = pytz.utc.localize(current_datetime_utc)
|
||||
current_datetime_utc_localize_string = current_datetime_utc_localize.isoformat()
|
||||
|
||||
current_datetime_utc_localize_pst = current_datetime_utc_localize.astimezone(pytz.timezone("America/Los_Angeles"))
|
||||
current_datetime_utc_localize_pst_string = current_datetime_utc_localize_pst.isoformat()
|
||||
|
||||
response_data['datetime'] = current_datetime_string
|
||||
response_data['datetime_tz'] = current_datetime_tz_string
|
||||
response_data['datetime_utc'] = current_datetime_utc_string
|
||||
response_data['datetime_utc_localize'] = current_datetime_utc_localize_string
|
||||
response_data['datetime_utc_localize_pst'] = current_datetime_utc_localize_pst_string
|
||||
|
||||
response_data['url_safe_string_4_bytes_1'] = secrets.token_urlsafe(4)
|
||||
|
||||
response_data['url_safe_string_8_bytes_1'] = secrets.token_urlsafe(8)
|
||||
response_data['url_safe_string_8_bytes_2'] = secrets.token_urlsafe(8)
|
||||
response_data['url_safe_string_8_bytes_3'] = secrets.token_urlsafe(8)
|
||||
response_data['url_safe_string_8_bytes_4'] = secrets.token_urlsafe(8)
|
||||
response_data['url_safe_string_8_bytes_5'] = secrets.token_urlsafe(8)
|
||||
|
||||
response_data['url_safe_string_16_bytes_1'] = secrets.token_urlsafe(16)
|
||||
response_data['url_safe_string_16_bytes_2'] = secrets.token_urlsafe(16)
|
||||
response_data['url_safe_string_16_bytes_3'] = secrets.token_urlsafe(16)
|
||||
response_data['url_safe_string_16_bytes_4'] = secrets.token_urlsafe(16)
|
||||
response_data['url_safe_string_16_bytes_5'] = secrets.token_urlsafe(16)
|
||||
|
||||
response_data['hex_string_4_bytes_1'] = secrets.token_hex(4)
|
||||
response_data['hex_string_8_bytes_1'] = secrets.token_hex(8)
|
||||
response_data['hex_string_16_bytes_1'] = secrets.token_hex(16)
|
||||
response_data['hex_string_32_bytes_1'] = secrets.token_hex(32)
|
||||
|
||||
log.debug(json.dumps(response_data, indent=4))
|
||||
return json.dumps(response_data, indent=4) # , sort_keys=True
|
||||
# ### END ### API Main ### fastapi_root() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Main ### generate_id_random() ###
|
||||
# NOTE: This is just a quick utility function to generate a bunch of random IDs.
|
||||
# Updated 2022-03-30
|
||||
@app.get('/generate_id_random', tags=['Root'], response_class=PlainTextResponse)
|
||||
async def generate_id_random(response: Response = Response):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARN, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
response_data = {}
|
||||
|
||||
html_list = '<ul>'
|
||||
for x in range(50):
|
||||
html_list += f'<li>{secrets.token_urlsafe(8)}</li>'
|
||||
html_list += '</ul>'
|
||||
|
||||
return HTMLResponse(content=html_list, status_code=200)
|
||||
# ### END ### API Main ### generate_id_random() ###
|
||||
625
app/main.py.snapshot
Normal file
625
app/main.py.snapshot
Normal file
@@ -0,0 +1,625 @@
|
||||
import datetime, json, os, pytz, random, secrets # , uvicorn
|
||||
|
||||
from enum import Enum
|
||||
#from datetime import datetime, time, timedelta
|
||||
from fastapi import Body, Cookie, Depends, FastAPI, File, Form, Header, HTTPException, Path, Query, Request, Response, status, UploadFile
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import FileResponse, HTMLResponse, JSONResponse, PlainTextResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from functools import lru_cache
|
||||
from pydantic import BaseModel, EmailStr, Field
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
|
||||
from . import config
|
||||
|
||||
from app.log import log, logging
|
||||
|
||||
# Import the routers here first:
|
||||
from app.routers import ae_obj, aether_cfg, api_crud, api_crud_v2, api_crud_v3, api, importing, sql, account, activity_log, address, archive, archive_content, contact, cont_edu_cert, cont_edu_cert_person, data_store, event, event_abstract, event_badge, event_badge_importing, event_badge_template, event_device, event_exhibit, event_exhibit_tracking, event_file, event_importing, event_location, event_person, event_person_detail, event_person_tracking, event_presentation, event_presenter, event_registration, event_session, flask_cfg, fundraising, grant, hosted_file, journal, journal_entry, log_client_viewing, lookup, membership_cfg, membership_group, membership_person_group, membership_person, membership_person_profile, membership_type, membership_person_type, order, order_v3, order_line, order_cart, organization, page, person, person_user, post, post_comment, product, qr, site, site_domain, user, util_email, websockets_redis, e_confex, e_cvent, c_idaa, e_impexium, e_stripe
|
||||
|
||||
# from app.routers import aether_cfg, sql
|
||||
|
||||
from app.db_sql import sql_select, reset_redis # , sql_connect
|
||||
|
||||
|
||||
print('### **** *** ** * The Aether API v4 using FastAPI is loading... * ** *** **** ###')
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
app = FastAPI(
|
||||
# debug = True,
|
||||
title = 'Aether API',
|
||||
description = 'One Sky IT\'s Aether API v4 using FastAPI.',
|
||||
version = '4.9.0',
|
||||
operationsSorter = 'method',
|
||||
)
|
||||
|
||||
|
||||
log.setLevel(logging.INFO)
|
||||
# log.debug(config.settings)
|
||||
|
||||
if aether_cfg_sql_result := sql_select(
|
||||
table_name = 'cfg',
|
||||
record_id = config.settings.AETHER_CFG['id'],
|
||||
as_list = False,
|
||||
max_count = 1,
|
||||
):
|
||||
aether_cfg_sql = aether_cfg_sql_result
|
||||
|
||||
config.settings.DB['server'] = aether_cfg_sql.get('db_server')
|
||||
config.settings.DB['port'] = aether_cfg_sql.get('db_port')
|
||||
config.settings.DB['name'] = aether_cfg_sql.get('db_name')
|
||||
config.settings.DB['username'] = aether_cfg_sql.get('db_username')
|
||||
config.settings.DB['password'] = aether_cfg_sql.get('db_password')
|
||||
|
||||
DB = config.settings.DB
|
||||
config.settings.SQLALCHEMY_DB_URI = 'mysql://'+DB['username']+':'+DB['password']+'@'+DB['server']+'/'+DB['name']
|
||||
# db_result = sql_connect(config.settings.SQLALCHEMY_DB_URI)
|
||||
log.debug(config.settings.DB)
|
||||
|
||||
config.settings.SMTP['server'] = aether_cfg_sql.get('smtp_server')
|
||||
config.settings.SMTP['port'] = aether_cfg_sql.get('smtp_port')
|
||||
config.settings.SMTP['username'] = aether_cfg_sql.get('smtp_username')
|
||||
config.settings.SMTP['password'] = aether_cfg_sql.get('smtp_password')
|
||||
|
||||
# config.settings.FILES_PATH['hosted_files_root'] = aether_cfg_sql.get('PATH_HOSTED_FILES_ROOT')
|
||||
# config.settings.FILES_PATH['hosted_tmp_root'] = aether_cfg_sql.get('PATH_HOSTED_TMP_ROOT')
|
||||
|
||||
config.settings.FILES_PATH['hosted_files_root'] = aether_cfg_sql.get('path_hosted_files_root')
|
||||
config.settings.FILES_PATH['hosted_tmp_root'] = aether_cfg_sql.get('path_hosted_tmp_root')
|
||||
else:
|
||||
# aether_cfg_sql_result
|
||||
pass
|
||||
log.debug(aether_cfg_sql_result)
|
||||
log.debug(config.settings)
|
||||
|
||||
# @lru_cache()
|
||||
# def get_settings():
|
||||
# return config.Settings()
|
||||
|
||||
|
||||
app.mount('/static', StaticFiles(directory='static'), name='static')
|
||||
|
||||
|
||||
# Set up each route once the router has been imported
|
||||
app.include_router(
|
||||
ae_obj.router,
|
||||
prefix='/ae_obj',
|
||||
tags=['AE Object'],
|
||||
)
|
||||
app.include_router(
|
||||
aether_cfg.router,
|
||||
tags=['Aether Config'],
|
||||
)
|
||||
app.include_router(
|
||||
api_crud.router,
|
||||
prefix='/crud',
|
||||
tags=['CRUD v1.2 (Legacy)'],
|
||||
#dependencies=[Depends(get_token_header)],
|
||||
#dependencies=[Depends(get_account_header)],
|
||||
#responses={404: {'description': 'Not found'}},
|
||||
)
|
||||
app.include_router(
|
||||
api_crud_v2.router,
|
||||
prefix='/v2/crud',
|
||||
tags=['CRUD v2.5'],
|
||||
#dependencies=[Depends(get_token_header)],
|
||||
#dependencies=[Depends(get_account_header)],
|
||||
#responses={404: {'description': 'Not found'}},
|
||||
)
|
||||
app.include_router(
|
||||
api_crud_v3.router,
|
||||
prefix='/v3/crud',
|
||||
tags=['CRUD v3'],
|
||||
)
|
||||
app.include_router(
|
||||
api.router,
|
||||
prefix='/api',
|
||||
tags=['API'],
|
||||
)
|
||||
app.include_router(
|
||||
flask_cfg.router,
|
||||
prefix='/flask_cfg',
|
||||
tags=['Flask CFG'],
|
||||
)
|
||||
app.include_router(
|
||||
importing.router,
|
||||
prefix='/importing',
|
||||
tags=['Importing'],
|
||||
)
|
||||
app.include_router(
|
||||
sql.router,
|
||||
# prefix='/sql',
|
||||
tags=['SQL'],
|
||||
)
|
||||
# # app.include_router(
|
||||
# # flask_cfg.router,
|
||||
# # prefix='/redis',
|
||||
# # tags=['Redis'],
|
||||
# # )
|
||||
|
||||
app.include_router(
|
||||
account.router,
|
||||
# prefix='/account',
|
||||
tags=['Account'],
|
||||
)
|
||||
app.include_router(
|
||||
activity_log.router,
|
||||
prefix='/activity_log',
|
||||
tags=['Activity Log'],
|
||||
)
|
||||
app.include_router(
|
||||
address.router,
|
||||
prefix='/address',
|
||||
tags=['Address'],
|
||||
)
|
||||
app.include_router(
|
||||
archive.router,
|
||||
# prefix='/archive',
|
||||
tags=['Archive'],
|
||||
)
|
||||
app.include_router(
|
||||
archive_content.router,
|
||||
prefix='/archive/content',
|
||||
tags=['Archive Content'],
|
||||
)
|
||||
app.include_router(
|
||||
contact.router,
|
||||
prefix='/contact',
|
||||
tags=['Contact'],
|
||||
)
|
||||
app.include_router(
|
||||
cont_edu_cert.router,
|
||||
tags=['Cont Edu Cert'],
|
||||
)
|
||||
app.include_router(
|
||||
cont_edu_cert_person.router,
|
||||
tags=['Cont Edu Cert Person'],
|
||||
)
|
||||
app.include_router(
|
||||
data_store.router,
|
||||
# prefix='/data_store',
|
||||
tags=['Data Store'],
|
||||
)
|
||||
app.include_router(
|
||||
event.router,
|
||||
# prefix='/event',
|
||||
tags=['Event'],
|
||||
)
|
||||
app.include_router(
|
||||
event_abstract.router,
|
||||
tags=['Event Abstract'],
|
||||
)
|
||||
app.include_router(
|
||||
event_badge.router,
|
||||
tags=['Event Badge'],
|
||||
)
|
||||
app.include_router(
|
||||
event_badge_importing.router,
|
||||
tags=['Event Badge Importing'],
|
||||
)
|
||||
app.include_router(
|
||||
event_badge_template.router,
|
||||
# prefix='/event/badge/template',
|
||||
tags=['Event Badge Template'],
|
||||
)
|
||||
app.include_router(
|
||||
event_device.router,
|
||||
# prefix='/event/device',
|
||||
tags=['Event Device'],
|
||||
)
|
||||
app.include_router(
|
||||
event_exhibit.router,
|
||||
# prefix='/event/exhibit',
|
||||
tags=['Event Exhibit'],
|
||||
)
|
||||
app.include_router(
|
||||
event_exhibit_tracking.router,
|
||||
# prefix='/event/exhibit/tracking',
|
||||
tags=['Event Exhibit Tracking'],
|
||||
)
|
||||
app.include_router(
|
||||
event_file.router,
|
||||
# prefix='/event/file',
|
||||
tags=['Event File'],
|
||||
)
|
||||
app.include_router(
|
||||
event_importing.router,
|
||||
# prefix='/event/importing',
|
||||
tags=['Event Importing'],
|
||||
)
|
||||
app.include_router(
|
||||
event_location.router,
|
||||
# prefix='/event/location',
|
||||
tags=['Event Location'],
|
||||
)
|
||||
app.include_router(
|
||||
event_person.router,
|
||||
# prefix='/event/person',
|
||||
tags=['Event Person'],
|
||||
)
|
||||
app.include_router(
|
||||
event_person.router,
|
||||
prefix='/event/person/detail',
|
||||
tags=['Event Person Detail'],
|
||||
)
|
||||
app.include_router(
|
||||
event_person_tracking.router,
|
||||
tags=['Event Person Tracking'],
|
||||
)
|
||||
app.include_router(
|
||||
event_presentation.router,
|
||||
# prefix='/event/presentation',
|
||||
tags=['Event Presentation'],
|
||||
)
|
||||
app.include_router(
|
||||
event_presenter.router,
|
||||
prefix='/event/presenter',
|
||||
tags=['Event Presenter'],
|
||||
)
|
||||
app.include_router(
|
||||
event_registration.router,
|
||||
prefix='/event/registration',
|
||||
tags=['Event Registration'],
|
||||
)
|
||||
app.include_router(
|
||||
event_session.router,
|
||||
# prefix='/event/session',
|
||||
tags=['Event Session'],
|
||||
)
|
||||
app.include_router(
|
||||
fundraising.router,
|
||||
tags=['Fundraising'],
|
||||
)
|
||||
app.include_router(
|
||||
grant.router,
|
||||
tags=['Grant'],
|
||||
)
|
||||
app.include_router(
|
||||
hosted_file.router,
|
||||
prefix='/hosted_file',
|
||||
tags=['Hosted File'],
|
||||
)
|
||||
app.include_router(
|
||||
journal.router,
|
||||
prefix='/journal',
|
||||
tags=['Journal'],
|
||||
)
|
||||
app.include_router(
|
||||
journal_entry.router,
|
||||
# prefix='/journal/entry',
|
||||
tags=['Journal Entry'],
|
||||
)
|
||||
app.include_router(
|
||||
log_client_viewing.router,
|
||||
# prefix='/log/client_viewing',
|
||||
tags=['Log Client Viewing'],
|
||||
)
|
||||
app.include_router(
|
||||
lookup.router,
|
||||
prefix='/lu',
|
||||
tags=['Lookup'],
|
||||
)
|
||||
app.include_router(
|
||||
membership_cfg.router,
|
||||
tags=['Membership Config'],
|
||||
)
|
||||
app.include_router(
|
||||
membership_group.router,
|
||||
tags=['Membership Group'],
|
||||
)
|
||||
app.include_router(
|
||||
membership_person_group.router,
|
||||
tags=['Membership Group Person'],
|
||||
)
|
||||
app.include_router(
|
||||
membership_person_profile.router,
|
||||
tags=['Membership Person Profile'],
|
||||
)
|
||||
app.include_router(
|
||||
membership_person.router,
|
||||
tags=['Membership Person'],
|
||||
)
|
||||
app.include_router(
|
||||
membership_type.router,
|
||||
tags=['Membership Type'],
|
||||
)
|
||||
app.include_router(
|
||||
membership_person_type.router,
|
||||
tags=['Membership Type Person'],
|
||||
)
|
||||
app.include_router(
|
||||
order.router,
|
||||
# prefix='/order',
|
||||
tags=['Order'],
|
||||
)
|
||||
app.include_router(
|
||||
order_v3.router,
|
||||
# prefix='/order',
|
||||
tags=['Order v3'],
|
||||
)
|
||||
app.include_router(
|
||||
order_line.router,
|
||||
# prefix='/order',
|
||||
tags=['Order Line'],
|
||||
)
|
||||
app.include_router(
|
||||
order_cart.router,
|
||||
prefix='/order/cart',
|
||||
tags=['Order Cart'],
|
||||
)
|
||||
app.include_router(
|
||||
organization.router,
|
||||
prefix='/organization',
|
||||
tags=['Organization'],
|
||||
)
|
||||
app.include_router(
|
||||
page.router,
|
||||
prefix='/page',
|
||||
tags=['Page'],
|
||||
)
|
||||
app.include_router(
|
||||
person.router,
|
||||
tags=['Person'],
|
||||
)
|
||||
app.include_router(
|
||||
person_user.router,
|
||||
prefix='/person_user',
|
||||
tags=['Person User'],
|
||||
)
|
||||
app.include_router(
|
||||
post.router,
|
||||
# prefix='/post',
|
||||
tags=['Post'],
|
||||
)
|
||||
app.include_router(
|
||||
post_comment.router,
|
||||
prefix='/post/comment',
|
||||
tags=['Post Comment'],
|
||||
)
|
||||
app.include_router(
|
||||
product.router,
|
||||
# prefix='/product',
|
||||
tags=['Product'],
|
||||
)
|
||||
app.include_router(
|
||||
qr.router,
|
||||
tags=['QR'],
|
||||
)
|
||||
app.include_router(
|
||||
site.router,
|
||||
# prefix='/site',
|
||||
tags=['Site'],
|
||||
)
|
||||
app.include_router(
|
||||
site_domain.router,
|
||||
# prefix='/site/domain',
|
||||
tags=['Site Domain'],
|
||||
)
|
||||
app.include_router(
|
||||
user.router,
|
||||
tags=['User'],
|
||||
)
|
||||
app.include_router(
|
||||
util_email.router,
|
||||
tags=['Utility: Email'],
|
||||
)
|
||||
# app.include_router(
|
||||
# websockets.router,
|
||||
# # prefix='/websocket',
|
||||
# tags=['Websockets'],
|
||||
# # dependencies=[Depends(get_token_header)],
|
||||
# # responses={404: {'description': 'Not found'}},
|
||||
# )
|
||||
app.include_router(
|
||||
websockets_redis.router,
|
||||
tags=['Websockets (Redis)'],
|
||||
)
|
||||
app.include_router(
|
||||
e_confex.router,
|
||||
prefix='/e/confex',
|
||||
tags=['External Service: Confex'],
|
||||
)
|
||||
app.include_router(
|
||||
e_cvent.router,
|
||||
prefix='/e/cvent',
|
||||
tags=['External Service: Cvent'],
|
||||
)
|
||||
app.include_router(
|
||||
e_impexium.router,
|
||||
prefix='/e/impexium',
|
||||
tags=['External Service: Impexium'],
|
||||
)
|
||||
app.include_router(
|
||||
e_stripe.router,
|
||||
prefix='/e/stripe',
|
||||
tags=['External Service: Stripe'],
|
||||
)
|
||||
|
||||
app.include_router(
|
||||
c_idaa.router,
|
||||
prefix='/c/idaa',
|
||||
tags=['Client: IDAA'],
|
||||
)
|
||||
|
||||
|
||||
# BEGIN: CORS
|
||||
# NOTE: Eventually this should query the DB for the specific list based on the cfg table and or site_domain table. That way it is dynamic and only allowing those defined in the DB. No wildcards or regex.
|
||||
# NOTE: Need to include .localhost for less browser restrictions! Mainly for audio and video.
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
# allow_origins = origins,
|
||||
allow_origins = config.settings.ORIGINS,
|
||||
allow_origin_regex = config.settings.ORIGINS_REGEX,
|
||||
# allow_origin_regex = 'https://.*\.oneskyit\.com',
|
||||
allow_credentials = True,
|
||||
allow_methods = ['*'],
|
||||
allow_headers = ['*'],
|
||||
#expose_headers = [],
|
||||
#max_age = 600,
|
||||
)
|
||||
# END: CORS
|
||||
|
||||
|
||||
@app.on_event('startup')
|
||||
async def startup():
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARN, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
log.info('The Aether FastAPI API is starting up...')
|
||||
#await database.connect()
|
||||
|
||||
|
||||
@app.on_event('shutdown')
|
||||
async def shutdown():
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARN, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
log.info('The Aether FastAPI API is shutting down...')
|
||||
#await database.disconnect()
|
||||
|
||||
|
||||
#Add the processing time to the response header.
|
||||
@app.middleware('http')
|
||||
async def add_process_time_header(request: Request, call_next):
|
||||
import time
|
||||
start_time = time.time()
|
||||
response = await call_next(request)
|
||||
process_time = time.time() - start_time
|
||||
response.headers['X-Process-Time'] = str(process_time)
|
||||
return response
|
||||
|
||||
|
||||
# ### BEGIN ### API Main ### fastapi_root() ###
|
||||
@app.get('/', tags=['Root'], response_class=PlainTextResponse)
|
||||
async def fastapi_root(response: Response = Response):
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARN, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# log.info(config.settings.APP_NAME)
|
||||
log.info('One Sky IT\'s Aether API root (FastAPI)')
|
||||
|
||||
log.info('***')
|
||||
log.debug('This is debug') # 10 DEBUG
|
||||
log.info('This is info') # 20 INFO
|
||||
log.warning('This is a warning') # 30 WARNING (and WARN)
|
||||
log.error('This is an error') # 40 ERROR
|
||||
log.exception('This is an exception') # 40 ERROR
|
||||
log.critical('This is critical') # 50 CRITICAL
|
||||
log.info('^^^')
|
||||
|
||||
log.warning('Resetting Redis...')
|
||||
reset_redis()
|
||||
log.info('Reset Redis')
|
||||
|
||||
response_data = {}
|
||||
response_data['message'] = 'This is One Sky IT\'s Aether API root (FastAPI).'
|
||||
|
||||
|
||||
current_datetime = datetime.datetime.now()
|
||||
current_datetime_string = current_datetime.isoformat()
|
||||
|
||||
timezone = pytz.timezone("America/New_York")
|
||||
current_datetime_tz = timezone.localize(current_datetime)
|
||||
current_datetime_tz_string = current_datetime_tz.isoformat()
|
||||
|
||||
current_datetime_utc = datetime.datetime.utcnow()
|
||||
current_datetime_utc_string = current_datetime_utc.isoformat()
|
||||
|
||||
current_datetime_utc_localize = pytz.utc.localize(current_datetime_utc)
|
||||
current_datetime_utc_localize_string = current_datetime_utc_localize.isoformat()
|
||||
|
||||
current_datetime_utc_localize_pst = current_datetime_utc_localize.astimezone(pytz.timezone("America/Los_Angeles"))
|
||||
current_datetime_utc_localize_pst_string = current_datetime_utc_localize_pst.isoformat()
|
||||
|
||||
response_data['datetime'] = current_datetime_string
|
||||
response_data['datetime_tz'] = current_datetime_tz_string
|
||||
response_data['datetime_utc'] = current_datetime_utc_string
|
||||
response_data['datetime_utc_localize'] = current_datetime_utc_localize_string
|
||||
response_data['datetime_utc_localize_pst'] = current_datetime_utc_localize_pst_string
|
||||
|
||||
response_data['url_safe_string_4_bytes_1'] = secrets.token_urlsafe(4)
|
||||
|
||||
response_data['url_safe_string_8_bytes_1'] = secrets.token_urlsafe(8)
|
||||
response_data['url_safe_string_8_bytes_2'] = secrets.token_urlsafe(8)
|
||||
response_data['url_safe_string_8_bytes_3'] = secrets.token_urlsafe(8)
|
||||
response_data['url_safe_string_8_bytes_4'] = secrets.token_urlsafe(8)
|
||||
response_data['url_safe_string_8_bytes_5'] = secrets.token_urlsafe(8)
|
||||
|
||||
response_data['url_safe_string_16_bytes_1'] = secrets.token_urlsafe(16)
|
||||
response_data['url_safe_string_16_bytes_2'] = secrets.token_urlsafe(16)
|
||||
response_data['url_safe_string_16_bytes_3'] = secrets.token_urlsafe(16)
|
||||
response_data['url_safe_string_16_bytes_4'] = secrets.token_urlsafe(16)
|
||||
response_data['url_safe_string_16_bytes_5'] = secrets.token_urlsafe(16)
|
||||
|
||||
response_data['hex_string_4_bytes_1'] = secrets.token_hex(4)
|
||||
response_data['hex_string_8_bytes_1'] = secrets.token_hex(8)
|
||||
response_data['hex_string_16_bytes_1'] = secrets.token_hex(16)
|
||||
response_data['hex_string_32_bytes_1'] = secrets.token_hex(32)
|
||||
|
||||
log.debug(json.dumps(response_data, indent=4))
|
||||
return json.dumps(response_data, indent=4) # , sort_keys=True
|
||||
# ### END ### API Main ### fastapi_root() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Main ### generate_id_random() ###
|
||||
# NOTE: This is just a quick utility function to generate a bunch of random IDs.
|
||||
# Updated 2022-03-30
|
||||
@app.get('/generate_id_random', tags=['Root'], response_class=PlainTextResponse)
|
||||
async def generate_id_random(response: Response = Response):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARN, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
response_data = {}
|
||||
|
||||
html_list = '<ul>'
|
||||
for x in range(50):
|
||||
html_list += f'<li>{secrets.token_urlsafe(8)}</li>'
|
||||
html_list += '</ul>'
|
||||
|
||||
return HTMLResponse(content=html_list, status_code=200)
|
||||
# ### END ### API Main ### generate_id_random() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Main ### sql_test() ###
|
||||
# ### TEST TEST TEST ### #
|
||||
@app.get('/sql_test', tags=['Testing'], response_class=PlainTextResponse)
|
||||
async def sql_test(response: Response = Response):
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARN, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
return mk_resp(data=False, status_code=501, response=response)
|
||||
|
||||
log.info('Getting all accounts from DB...')
|
||||
|
||||
sql = text(
|
||||
"""
|
||||
SELECT id, id_random, name, enable
|
||||
FROM `account`
|
||||
"""
|
||||
)
|
||||
try:
|
||||
result = db.execute(sql)
|
||||
except Exception as e:
|
||||
log.error('*** An exception happened. ***')
|
||||
log.error(repr(e))
|
||||
log.error('***')
|
||||
log.error(str(e))
|
||||
log.error('^^^ exception ^^^')
|
||||
else:
|
||||
if result.rowcount:
|
||||
record_li = [dict(record) for record in result.fetchall()]
|
||||
log.debug(record_li)
|
||||
else:
|
||||
log.error('No records found. Something went wrong.')
|
||||
|
||||
log.info('Got the account list')
|
||||
|
||||
response_data = {}
|
||||
response_data['message'] = 'This is the Aether API using FastAPI.'
|
||||
response_data['data'] = record_li
|
||||
|
||||
return json.dumps(response_data, indent=4) # , sort_keys=True
|
||||
# ### END ### API Main ### sql_test() ###
|
||||
65
app/methods/account_cfg_methods.py
Normal file
65
app/methods/account_cfg_methods.py
Normal file
@@ -0,0 +1,65 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_select
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.methods.membership_cfg_methods import load_membership_cfg_obj
|
||||
|
||||
from app.models.account_cfg_models import Account_Cfg_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Account Cfg Methods ### load_account_cfg_obj() ###
|
||||
@logger_reset
|
||||
def load_account_cfg_obj(
|
||||
account_id: int|str,
|
||||
model_as_dict: bool = False,
|
||||
# inc_event_cfg: bool = False,
|
||||
inc_fundraising_cfg: bool = False,
|
||||
inc_membership_cfg: bool = False,
|
||||
) -> Account_Cfg_Base|dict|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
|
||||
log.info(f'Getting Account CFG ID: {account_id}')
|
||||
if account_cfg_rec := sql_select(
|
||||
table_name = 'v_account_cfg', # This view should probably be cleaned up
|
||||
field_name = 'account_id',
|
||||
field_value = account_id
|
||||
): pass
|
||||
else: return False
|
||||
log.debug(account_cfg_rec)
|
||||
|
||||
try:
|
||||
account_cfg_obj = Account_Cfg_Base(**account_cfg_rec)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
log.debug(account_cfg_obj)
|
||||
|
||||
if inc_fundraising_cfg:
|
||||
if fundraising_cfg_dict := load_fundraising_cfg_obj_old(
|
||||
account_id = account_id,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
account_cfg_obj.fundraising_cfg = fundraising_cfg_dict
|
||||
else: account_cfg_obj.fundraising_cfg = None
|
||||
|
||||
if inc_membership_cfg:
|
||||
if membership_cfg_dict := load_membership_cfg_obj(
|
||||
account_id = account_id,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
account_cfg_obj.membership_cfg = membership_cfg_dict
|
||||
else: account_cfg_obj.membership_cfg = None
|
||||
|
||||
if model_as_dict:
|
||||
return account_cfg_obj.dict(by_alias=True, exclude_unset=True) # pylint: disable=no-member
|
||||
else:
|
||||
return account_cfg_obj
|
||||
# ### END ### API Account Cfg Methods ### load_account_cfg_obj() ###
|
||||
877
app/methods/account_methods.py
Normal file
877
app/methods/account_methods.py
Normal file
@@ -0,0 +1,877 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_enable_part, sql_limit_offset_part, sql_select
|
||||
from app.lib_general import log, logging
|
||||
|
||||
from app.methods.account_cfg_methods import load_account_cfg_obj
|
||||
from app.methods.address_methods import get_address_rec_list, load_address_obj
|
||||
from app.methods.archive_methods import get_archive_rec_list, load_archive_obj
|
||||
from app.methods.contact_methods import get_contact_rec_list, load_contact_obj
|
||||
from app.methods.event_methods import get_event_rec_list, load_event_obj
|
||||
from app.methods.hosted_file_methods import get_hosted_file_rec_list, load_hosted_file_obj
|
||||
from app.methods.journal_methods import get_journal_rec_list, load_journal_obj
|
||||
from app.methods.membership_cfg_methods import load_membership_cfg_obj
|
||||
from app.methods.membership_group_methods import get_membership_group_rec_list, load_membership_group_obj
|
||||
from app.methods.membership_person_methods import get_membership_person_rec_list, load_membership_person_obj
|
||||
from app.methods.membership_type_methods import get_membership_type_rec_list, load_membership_type_obj
|
||||
from app.methods.order_methods import get_order_rec_list, load_order_obj
|
||||
# from app.methods.order_cart_methods import get_order_cart_rec_list, load_order_cart_obj
|
||||
from app.methods.organization_methods import get_organization_rec_list, load_organization_obj
|
||||
from app.methods.person_methods import get_person_rec_list, load_person_obj
|
||||
from app.methods.product_methods import get_product_rec_list, load_product_obj
|
||||
from app.methods.post_methods import get_post_rec_list, load_post_obj
|
||||
from app.methods.site_methods import get_site_rec_list, load_site_obj
|
||||
from app.methods.user_methods import get_user_rec_list, load_user_obj
|
||||
|
||||
from app.models.account_models import Account_Base
|
||||
from app.models.account_cfg_models import Account_Cfg_Base
|
||||
# from app.models.membership_cfg_models import Membership_Cfg_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Account Methods ### load_account_obj() ###
|
||||
# Working well as of 2021-06-11. Using as a template for other load objects.
|
||||
def load_account_obj(
|
||||
account_id: int|str,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 1000,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
inc_account_cfg: bool = False, # Priority l1
|
||||
inc_address: bool = False, # Under contact
|
||||
inc_address_list: bool = False, # Priority l3
|
||||
inc_archive: bool = False,
|
||||
inc_archive_list: bool = False, # Priority l1
|
||||
inc_archive_content: bool = False,
|
||||
inc_archive_content_list: bool = False, # Priority l2
|
||||
inc_contact: bool = False,
|
||||
inc_contact_list: bool = False, # Priority l3
|
||||
inc_event: bool = False,
|
||||
inc_event_list: bool = False, # Priority l1
|
||||
# inc_event_abstract: bool = False,
|
||||
# inc_event_abstract_list: bool = False,
|
||||
# inc_event_badge: bool = False,
|
||||
# inc_event_badge_list: bool = False,
|
||||
inc_event_cfg: bool = False,
|
||||
# inc_event_device: bool = False,
|
||||
# inc_event_device_list: bool = False,
|
||||
inc_event_exhibit: bool = False,
|
||||
inc_event_exhibit_list: bool = False,
|
||||
inc_event_file: bool = False,
|
||||
inc_event_file_list: bool = False,
|
||||
inc_event_location: bool = False, # For event_session child object
|
||||
inc_event_location_list: bool = False,
|
||||
inc_event_person: bool = False,
|
||||
inc_event_person_list: bool = False,
|
||||
inc_event_presentation: bool = False,
|
||||
inc_event_presentation_list: bool = False,
|
||||
inc_event_presenter_cat: bool = False, # For event_session child object
|
||||
inc_event_presenter: bool = False,
|
||||
inc_event_presenter_list: bool = False,
|
||||
inc_event_registration: bool = False,
|
||||
inc_event_registration_cfg: bool = False,
|
||||
inc_event_registration_list: bool = False,
|
||||
inc_event_session: bool = False,
|
||||
inc_event_session_list: bool = False,
|
||||
# inc_event_track: bool = False, # For event_session child object
|
||||
inc_event_track_list: bool = False,
|
||||
inc_fundraising_cfg: bool = False,
|
||||
inc_hosted_file_list: bool = False,
|
||||
inc_hosted_file_link_list: bool = False,
|
||||
inc_journal_list: bool = False, # Priority l3
|
||||
inc_journal_entry_list: bool = False, # Priority l3
|
||||
inc_membership_cfg: bool = False,
|
||||
inc_membership_group_list: bool = False, # List of groups for the account
|
||||
inc_membership_person: bool = False,
|
||||
inc_membership_person_group_list: bool = False, # List of members of a group
|
||||
inc_membership_person_list: bool = False, # List of people that have membersship
|
||||
inc_membership_person_profile: bool = False,
|
||||
inc_membership_person_type: bool = False,
|
||||
inc_membership_type_list: bool = False,
|
||||
inc_order: bool = False,
|
||||
inc_order_cfg: bool = False,
|
||||
inc_order_list: bool = False, # Priority l1
|
||||
inc_order_line_list: bool = False, # Priority l2
|
||||
inc_order_cart: bool = False,
|
||||
inc_order_cart_line_list: bool = False, # Priority l2
|
||||
inc_order_cart_list: bool = False,
|
||||
inc_organization: bool = False,
|
||||
inc_organization_list: bool = False, # Priority l3
|
||||
# inc_page: bool = False,
|
||||
inc_page_list: bool = False, # Priority l3
|
||||
inc_person: bool = False,
|
||||
inc_person_list: bool = False, # Priority l2
|
||||
inc_post: bool = False,
|
||||
inc_post_list: bool = False, # Priority l1
|
||||
inc_post_comment: bool = False,
|
||||
inc_post_comment_list: bool = False,
|
||||
inc_product: bool = False,
|
||||
inc_product_list: bool = False, # Priority l3
|
||||
# inc_site: bool = False,
|
||||
inc_site_list: bool = False, # Priority l3
|
||||
inc_site_domain_list: bool = False, # Priority l3
|
||||
inc_user: bool = False,
|
||||
inc_user_list: bool = False, # Priority l2
|
||||
inc_user_role_list: bool = False,
|
||||
) -> Account_Base|dict|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
|
||||
if account_rec := sql_select(table_name='v_account', record_id=account_id): pass
|
||||
else: return False
|
||||
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(account_rec)
|
||||
|
||||
try:
|
||||
account_obj = Account_Base(**account_rec)
|
||||
log.debug(account_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
if inc_account_cfg:
|
||||
if account_cfg_dict := load_account_cfg_obj(
|
||||
account_id = account_id,
|
||||
model_as_dict = model_as_dict,
|
||||
# inc_event_cfg = inc_event_cfg,
|
||||
inc_fundraising_cfg = inc_fundraising_cfg,
|
||||
inc_membership_cfg = inc_membership_cfg,
|
||||
):
|
||||
account_obj.account_cfg = account_cfg_dict
|
||||
else: account_obj.account_cfg = None
|
||||
|
||||
# Updated 2021-06-17
|
||||
if inc_address_list:
|
||||
if address_rec_list_result := get_address_rec_list(
|
||||
for_type = 'account', # 'account' is a special case
|
||||
for_id = account_id,
|
||||
enabled = enabled,
|
||||
limit = limit,
|
||||
offset = offset,
|
||||
):
|
||||
address_dict_list = []
|
||||
for address_rec in address_rec_list_result:
|
||||
address_dict_list.append(
|
||||
load_address_obj(
|
||||
address_id = address_rec.get('address_id', None),
|
||||
enabled = enabled,
|
||||
limit = limit,
|
||||
offset = offset,
|
||||
model_as_dict = model_as_dict,
|
||||
)
|
||||
)
|
||||
account_obj.address_list = address_dict_list
|
||||
else: account_obj.address_list = []
|
||||
|
||||
# Updated 2021-06-17
|
||||
if inc_archive_list:
|
||||
if archive_rec_list_result := get_archive_rec_list(
|
||||
for_obj_type = 'account',
|
||||
for_obj_id = account_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
archive_dict_list = []
|
||||
for archive_rec in archive_rec_list_result:
|
||||
archive_dict_list.append(
|
||||
load_archive_obj(
|
||||
archive_id = archive_rec.get('archive_id', None),
|
||||
limit = limit,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
inc_archive_content_list = inc_archive_content_list,
|
||||
)
|
||||
)
|
||||
account_obj.archive_list = archive_dict_list
|
||||
else: account_obj.archive_list = []
|
||||
|
||||
# Updated 2021-06-17
|
||||
if inc_contact_list:
|
||||
if contact_rec_list_result := get_contact_rec_list(
|
||||
for_type = 'account', # 'account' is a special case
|
||||
for_id = account_id,
|
||||
enabled = enabled,
|
||||
limit = limit,
|
||||
offset = offset,
|
||||
):
|
||||
contact_dict_list = []
|
||||
for contact_rec in contact_rec_list_result:
|
||||
contact_dict_list.append(
|
||||
load_contact_obj(
|
||||
contact_id = contact_rec.get('contact_id', None),
|
||||
enabled = enabled,
|
||||
limit = limit,
|
||||
offset = offset,
|
||||
model_as_dict = model_as_dict,
|
||||
inc_address = inc_address,
|
||||
)
|
||||
)
|
||||
account_obj.contact_list = contact_dict_list
|
||||
else: account_obj.contact_list = []
|
||||
|
||||
# Updated 2021-06-17
|
||||
if inc_event_list:
|
||||
if event_rec_list_result := get_event_rec_list(
|
||||
# for_obj_type = 'account',
|
||||
# for_obj_id = account_id,
|
||||
account_id = account_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
event_dict_list = []
|
||||
for event_rec in event_rec_list_result:
|
||||
event_dict_list.append(
|
||||
load_event_obj(
|
||||
event_id = event_rec.get('event_id', None),
|
||||
limit = limit,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
# inc_location_address = inc_address,
|
||||
# inc_contact_1 = inc_contact,
|
||||
# inc_contact_2 = inc_contact,
|
||||
# inc_contact_3 = inc_contact,
|
||||
# inc_event_abstract_list = inc_event_abstract_list,
|
||||
# inc_event_badge_list = inc_event_badge_list,
|
||||
# inc_event_device_list = inc_event_device_list,
|
||||
inc_event_exhibit_list = inc_event_exhibit_list,
|
||||
inc_event_file_list = inc_event_file_list,
|
||||
inc_event_location_list = inc_event_location_list,
|
||||
inc_event_person_list = inc_event_person_list,
|
||||
inc_event_presentation_list = inc_event_presentation_list,
|
||||
inc_event_presenter_list = inc_event_presenter_list,
|
||||
inc_event_registration_list = inc_event_registration_list,
|
||||
inc_event_session_list = inc_event_session_list,
|
||||
inc_event_track_list = inc_event_track_list,
|
||||
# inc_person = inc_person,
|
||||
# inc_user = inc_user,
|
||||
)
|
||||
)
|
||||
account_obj.event_list = event_dict_list
|
||||
else: account_obj.event_list = []
|
||||
|
||||
# Updated 2021-06-18
|
||||
if inc_hosted_file_list:
|
||||
if hosted_file_rec_list_result := get_hosted_file_rec_list(
|
||||
for_obj_type = 'account',
|
||||
for_obj_id = account_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
hosted_file_dict_list = []
|
||||
for hosted_file_rec in hosted_file_rec_list_result:
|
||||
hosted_file_dict_list.append(
|
||||
load_hosted_file_obj(
|
||||
hosted_file_id = hosted_file_rec.get('hosted_file_id', None),
|
||||
limit = limit,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
inc_hosted_file_link_list = inc_hosted_file_link_list,
|
||||
)
|
||||
)
|
||||
account_obj.hosted_file_list = hosted_file_dict_list
|
||||
else: account_obj.hosted_file_list = []
|
||||
|
||||
# Updated 2021-06-18
|
||||
if inc_journal_list:
|
||||
if journal_rec_list_result := get_journal_rec_list(
|
||||
for_obj_type = 'account',
|
||||
for_obj_id = account_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
journal_dict_list = []
|
||||
for journal_rec in journal_rec_list_result:
|
||||
journal_dict_list.append(
|
||||
load_journal_obj(
|
||||
journal_id = journal_rec.get('journal_id', None),
|
||||
limit = limit,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
inc_journal_entry_list = inc_journal_entry_list,
|
||||
)
|
||||
)
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(journal_dict_list)
|
||||
|
||||
|
||||
account_obj.journal_list = journal_dict_list
|
||||
else: account_obj.journal_list = []
|
||||
|
||||
# Updated 2021-06-21
|
||||
if inc_membership_group_list:
|
||||
if membership_group_rec_list_result := get_membership_group_rec_list(
|
||||
for_obj_type = 'account',
|
||||
for_obj_id = account_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
membership_group_result_list = []
|
||||
for membership_group_rec in membership_group_rec_list_result:
|
||||
membership_group_result_list.append(
|
||||
load_membership_group_obj(
|
||||
membership_group_id = membership_group_rec.get('membership_group_id', None),
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
inc_membership_person_list = inc_membership_person_list,
|
||||
# inc_membership_person_group_list = inc_membership_person_group_list,
|
||||
inc_product_list = inc_product_list,
|
||||
)
|
||||
)
|
||||
account_obj.membership_group_list = membership_group_result_list
|
||||
else: account_obj.membership_group_list = []
|
||||
|
||||
# Updated 2021-06-21
|
||||
if inc_membership_person_list:
|
||||
if membership_person_rec_list_result := get_membership_person_rec_list(
|
||||
for_obj_type = 'account',
|
||||
for_obj_id = account_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
membership_person_result_list = []
|
||||
for membership_person_rec in membership_person_rec_list_result:
|
||||
membership_person_result_list.append(
|
||||
load_membership_person_obj(
|
||||
membership_person_id = membership_person_rec.get('membership_person_id', None),
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
inc_membership_group_list = inc_membership_group_list,
|
||||
inc_membership_person_profile = inc_membership_person_profile,
|
||||
# inc_membership_person_list = inc_membership_person_list,
|
||||
# inc_membership_person_list = inc_membership_person_list,
|
||||
# inc_product_list = inc_product_list,
|
||||
inc_person = inc_person,
|
||||
inc_user = inc_user,
|
||||
)
|
||||
)
|
||||
account_obj.membership_person_list = membership_person_result_list
|
||||
else: account_obj.membership_person_list = []
|
||||
|
||||
# Updated 2021-06-18
|
||||
if inc_membership_type_list:
|
||||
if membership_type_rec_list_result := get_membership_type_rec_list(
|
||||
for_obj_type = 'account',
|
||||
for_obj_id = account_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
membership_type_result_list = []
|
||||
for membership_type_rec in membership_type_rec_list_result:
|
||||
membership_type_result_list.append(
|
||||
load_membership_type_obj(
|
||||
membership_type_id = membership_type_rec.get('membership_type_id', None),
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
inc_membership_person_list = inc_membership_person_list,
|
||||
# inc_membership_type_member_list = inc_membership_type_member_list,
|
||||
inc_product_list = inc_product_list,
|
||||
)
|
||||
)
|
||||
account_obj.membership_type_list = membership_type_result_list
|
||||
else: account_obj.membership_type_list = []
|
||||
|
||||
# Updated 2021-06-17
|
||||
if inc_order_list:
|
||||
if order_rec_list_result := get_order_rec_list(
|
||||
for_obj_type = 'account',
|
||||
for_obj_id = account_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
order_dict_list = []
|
||||
for order_rec in order_rec_list_result:
|
||||
order_dict_list.append(
|
||||
load_order_obj(
|
||||
order_id = order_rec.get('order_id', None),
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
inc_order_line_list = inc_order_line_list,
|
||||
inc_order_cfg = inc_order_cfg,
|
||||
inc_person = inc_person,
|
||||
)
|
||||
)
|
||||
account_obj.order_list = order_dict_list
|
||||
else: account_obj.order_list = []
|
||||
|
||||
# Updated 2021-06-17
|
||||
if inc_organization_list:
|
||||
if organization_rec_list_result := get_organization_rec_list(
|
||||
for_obj_type = 'account',
|
||||
for_obj_id = account_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
organization_dict_list = []
|
||||
for organization_rec in organization_rec_list_result:
|
||||
organization_dict_list.append(
|
||||
load_organization_obj(
|
||||
organization_id = organization_rec.get('organization_id', None),
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
inc_address = inc_address,
|
||||
inc_contact = inc_contact,
|
||||
inc_person = inc_person,
|
||||
inc_user = inc_user,
|
||||
)
|
||||
)
|
||||
account_obj.organization_list = organization_dict_list
|
||||
else: account_obj.organization_list = []
|
||||
|
||||
# Updated 2021-06-17
|
||||
if inc_person_list:
|
||||
if person_rec_list_result := get_person_rec_list(
|
||||
for_obj_type = 'account',
|
||||
for_obj_id = account_id,
|
||||
enabled = enabled,
|
||||
limit = limit,
|
||||
offset = offset,
|
||||
):
|
||||
person_result_list = []
|
||||
for person_rec in person_rec_list_result:
|
||||
person_result_list.append(
|
||||
load_person_obj(
|
||||
person_id = person_rec.get('person_id', None),
|
||||
limit = limit,
|
||||
offset = offset,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
inc_address = inc_address,
|
||||
inc_contact = inc_contact,
|
||||
inc_organization = inc_organization,
|
||||
inc_user = inc_user,
|
||||
)
|
||||
)
|
||||
account_obj.person_list = person_result_list
|
||||
else: account_obj.person_list = []
|
||||
|
||||
# Updated 2021-06-18
|
||||
if inc_post_list:
|
||||
if post_rec_list_result := get_post_rec_list(
|
||||
for_obj_type = 'account',
|
||||
for_obj_id = account_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
post_result_list = []
|
||||
for post_rec in post_rec_list_result:
|
||||
post_result_list.append(
|
||||
load_post_obj(
|
||||
post_id = post_rec.get('post_id', None),
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
inc_post_comment_list = inc_post_comment_list,
|
||||
inc_person = inc_person,
|
||||
inc_user = inc_user,
|
||||
)
|
||||
)
|
||||
account_obj.post_list = post_result_list
|
||||
else: account_obj.post_list = []
|
||||
|
||||
# Updated 2021-06-17
|
||||
if inc_product_list:
|
||||
if product_rec_list_result := get_product_rec_list(
|
||||
for_obj_type = 'account',
|
||||
for_obj_id = account_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
product_result_list = []
|
||||
for product_rec in product_rec_list_result:
|
||||
product_result_list.append(
|
||||
load_product_obj(
|
||||
product_id = product_rec.get('product_id', None),
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
)
|
||||
)
|
||||
account_obj.product_list = product_result_list
|
||||
else: account_obj.product_list = []
|
||||
|
||||
# Updated 2021-06-17
|
||||
if inc_site_list:
|
||||
if site_rec_list_result := get_site_rec_list(
|
||||
for_obj_type = 'account',
|
||||
for_obj_id = account_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
site_result_list = []
|
||||
for site_rec in site_rec_list_result:
|
||||
site_result_list.append(
|
||||
load_site_obj(
|
||||
site_id = site_rec.get('site_id', None),
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
inc_site_domain_list = inc_site_domain_list,
|
||||
)
|
||||
)
|
||||
account_obj.site_list = site_result_list
|
||||
else: account_obj.site_list = []
|
||||
|
||||
# Updated 2021-12-08
|
||||
if inc_user_list:
|
||||
if user_rec_list_result := get_user_rec_list(
|
||||
account_id = account_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
user_result_list = []
|
||||
for user_rec in user_rec_list_result:
|
||||
user_result_list.append(
|
||||
load_user_obj(
|
||||
user_id = user_rec.get('user_id', None),
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
inc_address = inc_address,
|
||||
inc_contact = inc_contact,
|
||||
inc_event_list = inc_event_list,
|
||||
inc_order_list = inc_order_list,
|
||||
inc_order_cart_list = inc_order_cart_list,
|
||||
# inc_organization = inc_organization,
|
||||
inc_person = inc_person,
|
||||
inc_user_role_list = inc_user_role_list,
|
||||
)
|
||||
)
|
||||
account_obj.user_list = user_result_list
|
||||
else: account_obj.user_list = []
|
||||
|
||||
if model_as_dict:
|
||||
return account_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return account_obj
|
||||
# ### END ### API Account Methods ### load_account_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Account Methods ### get_account_rec_list() ###
|
||||
# Updated 2021-12-13
|
||||
def get_account_rec_list(
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 25,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
data = {}
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='account', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
sql = f"""
|
||||
SELECT `account`.id AS 'account_id', `account`.id_random AS 'account_id_random'
|
||||
FROM `account` AS `account`
|
||||
WHERE 1=1
|
||||
{sql_enabled}
|
||||
ORDER BY `account`.created_on DESC, `account`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if account_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
log.info('Got a list result')
|
||||
account_rec_li = account_rec_li_result
|
||||
else: # [] or False
|
||||
log.info('No results or something went wrong')
|
||||
account_rec_li = account_rec_li_result
|
||||
|
||||
log.debug(account_rec_li_result)
|
||||
|
||||
return account_rec_li
|
||||
# ### END ### API Account Methods ### get_account_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Account Methods ### load_account_obj_membership_type() ###
|
||||
# Working well as of 2021-06-11. Using as a template for other load objects.
|
||||
def load_account_obj_membership_type(
|
||||
account_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_account_cfg: bool = False, # Priority l1
|
||||
inc_address: bool = False, # Under contact
|
||||
inc_contact: bool = False,
|
||||
inc_membership_cfg: bool = False,
|
||||
inc_membership_group_list: bool = False, # List of groups for the account
|
||||
inc_membership_person_group_list: bool = False, # List of members of a group
|
||||
inc_membership_person: bool = False,
|
||||
inc_membership_person_list: bool = False, # Priority l1
|
||||
inc_membership_person_profile: bool = False,
|
||||
inc_membership_person_type: bool = False,
|
||||
inc_membership_type: bool = False,
|
||||
inc_membership_type_list: bool = False,
|
||||
inc_order: bool = False,
|
||||
inc_order_cfg: bool = False,
|
||||
inc_order_list: bool = False, # Priority l1
|
||||
inc_order_line_list: bool = False, # Priority l2
|
||||
inc_organization: bool = False,
|
||||
inc_person: bool = False,
|
||||
inc_product: bool = False,
|
||||
inc_product_list: bool = False, # Priority l3
|
||||
inc_user: bool = False,
|
||||
inc_user_list: bool = False, # Priority l2
|
||||
) -> Account_Base|dict|bool:
|
||||
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
|
||||
if account_rec := sql_select(table_name='v_account', record_id=account_id): pass
|
||||
else: return False
|
||||
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(account_rec)
|
||||
|
||||
try:
|
||||
account_obj = Account_Base(**account_rec)
|
||||
log.debug(account_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
if inc_account_cfg:
|
||||
if account_cfg_result := load_account_cfg_obj(
|
||||
account_id = account_id,
|
||||
model_as_dict = model_as_dict,
|
||||
inc_membership_cfg = inc_membership_cfg,
|
||||
):
|
||||
account_obj.account_cfg = account_cfg_result
|
||||
else: account_obj.account_cfg = None
|
||||
|
||||
if inc_membership_cfg:
|
||||
if membership_cfg_result := load_membership_cfg_obj(
|
||||
account_id = account_id,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
account_obj.membership_cfg = membership_cfg_result
|
||||
else: account_obj.membership_cfg = None
|
||||
|
||||
# Updated 2021-06-18
|
||||
if membership_type_rec_list_result := get_membership_type_rec_list(
|
||||
for_obj_type = 'account',
|
||||
for_obj_id = account_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
membership_type_result_list = []
|
||||
for membership_type_rec in membership_type_rec_list_result:
|
||||
membership_type_result_list.append(
|
||||
load_membership_type_obj(
|
||||
membership_type_id = membership_type_rec.get('membership_type_id', None),
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
inc_address = inc_address,
|
||||
inc_contact = inc_contact,
|
||||
inc_membership_person_group_list = inc_membership_person_group_list, # per member
|
||||
inc_membership_person_list = inc_membership_person_list,
|
||||
inc_membership_person_profile = inc_membership_person_profile, # per member
|
||||
inc_membership_person_type = inc_membership_person_type, # per member
|
||||
inc_product_list = inc_product_list,
|
||||
inc_person = inc_person,
|
||||
inc_user = inc_user,
|
||||
)
|
||||
)
|
||||
account_obj.membership_type_list = membership_type_result_list
|
||||
else: account_obj.membership_type_list = []
|
||||
|
||||
if model_as_dict:
|
||||
return account_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return account_obj
|
||||
# ### END ### API Account Methods ### load_account_obj_membership_type() ###
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Account Methods ### load_account_obj_membership_group() ###
|
||||
# Working well as of 2021-06-11. Using as a template for other load objects.
|
||||
def load_account_obj_membership_group(
|
||||
account_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_account_cfg: bool = False, # Priority l1
|
||||
inc_address: bool = False, # Under contact
|
||||
inc_contact: bool = False,
|
||||
inc_membership_cfg: bool = False,
|
||||
# inc_membership_group_list: bool = False, # List of groups for the account
|
||||
inc_membership_person_group_list: bool = False, # List of members of a group
|
||||
inc_membership_person: bool = False,
|
||||
# inc_membership_person_list: bool = False, # Priority l1
|
||||
inc_membership_person_profile: bool = False,
|
||||
inc_membership_type: bool = False,
|
||||
# inc_membership_type_list: bool = False,
|
||||
# inc_order: bool = False,
|
||||
# inc_order_cfg: bool = False,
|
||||
# inc_order_list: bool = False, # Priority l1
|
||||
# inc_order_line_list: bool = False, # Priority l2
|
||||
inc_organization: bool = False,
|
||||
inc_person: bool = False,
|
||||
inc_product: bool = False,
|
||||
inc_product_list: bool = False, # Priority l3
|
||||
inc_user: bool = False,
|
||||
) -> Account_Base|dict|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
|
||||
if account_rec := sql_select(table_name='v_account', record_id=account_id): pass
|
||||
else: return False
|
||||
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(account_rec)
|
||||
|
||||
try:
|
||||
account_obj = Account_Base(**account_rec)
|
||||
log.debug(account_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
if inc_account_cfg:
|
||||
if account_cfg_dict := load_account_cfg_obj(
|
||||
account_id = account_id,
|
||||
model_as_dict = model_as_dict,
|
||||
inc_membership_cfg = inc_membership_cfg,
|
||||
):
|
||||
account_obj.account_cfg = account_cfg_dict
|
||||
else: account_obj.account_cfg = None
|
||||
|
||||
if inc_membership_cfg:
|
||||
if membership_cfg_dict := load_membership_cfg_obj(
|
||||
account_id = account_id,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
account_obj.membership_cfg = membership_cfg_dict
|
||||
else: account_obj.membership_cfg = None
|
||||
|
||||
# Updated 2021-06-21
|
||||
if inc_membership_group_list:
|
||||
if membership_group_rec_list_result := get_membership_group_rec_list(
|
||||
for_obj_type = 'account',
|
||||
for_obj_id = account_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
membership_group_result_list = []
|
||||
for membership_group_rec in membership_group_rec_list_result:
|
||||
membership_group_result_list.append(
|
||||
load_membership_group_obj(
|
||||
membership_group_id = membership_group_rec.get('membership_group_id', None),
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
inc_address = inc_address,
|
||||
inc_contact = inc_contact,
|
||||
# inc_membership_person_list = inc_membership_person_list,
|
||||
inc_membership_person_group_list = inc_membership_person_group_list,
|
||||
inc_product_list = inc_product_list,
|
||||
inc_person = inc_person,
|
||||
inc_user = inc_user,
|
||||
)
|
||||
)
|
||||
account_obj.membership_group_list = membership_group_result_list
|
||||
else: account_obj.membership_group_list = []
|
||||
|
||||
# Updated 2021-06-21
|
||||
if inc_membership_person_list:
|
||||
if membership_person_rec_list_result := get_membership_person_rec_list(
|
||||
for_obj_type = 'account',
|
||||
for_obj_id = account_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
membership_person_result_list = []
|
||||
for membership_person_rec in membership_person_rec_list_result:
|
||||
membership_person_result_list.append(
|
||||
load_membership_person_obj(
|
||||
membership_person_id = membership_person_rec.get('membership_person_id', None),
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
inc_address = inc_address,
|
||||
inc_contact = inc_contact,
|
||||
inc_membership_group_list = inc_membership_group_list,
|
||||
inc_membership_person_profile = inc_membership_person_profile,
|
||||
inc_membership_type = inc_membership_type,
|
||||
inc_person = inc_person,
|
||||
inc_user = inc_user,
|
||||
)
|
||||
)
|
||||
account_obj.membership_person_list = membership_person_result_list
|
||||
else: account_obj.membership_person_list = []
|
||||
|
||||
# Updated 2021-06-18
|
||||
if inc_membership_type_list:
|
||||
if membership_type_rec_list_result := get_membership_type_rec_list(
|
||||
for_obj_type = 'account',
|
||||
for_obj_id = account_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
membership_type_result_list = []
|
||||
for membership_type_rec in membership_type_rec_list_result:
|
||||
membership_type_result_list.append(
|
||||
load_membership_type_obj(
|
||||
membership_type_id = membership_type_rec.get('membership_type_id', None),
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
inc_address = inc_address,
|
||||
inc_contact = inc_contact,
|
||||
inc_membership_person_list = inc_membership_person_list,
|
||||
# inc_membership_type_member_list = inc_membership_type_member_list,
|
||||
inc_product_list = inc_product_list,
|
||||
inc_person = inc_person,
|
||||
inc_user = inc_user,
|
||||
)
|
||||
)
|
||||
account_obj.membership_type_list = membership_type_result_list
|
||||
else: account_obj.membership_type_list = []
|
||||
|
||||
if model_as_dict:
|
||||
return account_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return account_obj
|
||||
# ### END ### API Account Methods ### load_account_obj_membership_group() ###
|
||||
99
app/methods/activity_log_methods.py
Normal file
99
app/methods/activity_log_methods.py
Normal file
@@ -0,0 +1,99 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_insert_or_update, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
from app.models.activity_log_models import Activity_Log_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Activity Log Methods ### load_activity_log_obj() ###
|
||||
def load_activity_log_obj(
|
||||
activity_log_id: int|str,
|
||||
limit: int = 10000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
) -> Activity_Log_Base|bool:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if activity_log_id := redis_lookup_id_random(record_id_random=activity_log_id, table_name='activity_log'): pass
|
||||
else: return False
|
||||
|
||||
if activity_log_rec := sql_select(table_name='v_activity_log', record_id=activity_log_id): pass
|
||||
else: return False
|
||||
|
||||
try:
|
||||
activity_log_obj = Activity_Log_Base(**activity_log_rec)
|
||||
log.debug(activity_log_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
if model_as_dict:
|
||||
return activity_log_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return activity_log_obj
|
||||
# ### END ### API Activity Log Methods ### load_activity_log_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Activity Log Methods ### get_activity_log_rec_list() ###
|
||||
# Updated 2021-12-13
|
||||
@logger_reset
|
||||
def get_activity_log_rec_list(
|
||||
account_id: str,
|
||||
from_datetime: datetime.datetime = None,
|
||||
to_datetime: datetime.datetime = None,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
data = {}
|
||||
data['account_id'] = account_id
|
||||
sql_account_id = f'`activity_log`.account_id = :account_id'
|
||||
|
||||
# if enabled in ['enabled', 'disabled', 'all']:
|
||||
# if enabled == 'enabled':
|
||||
# data['enable'] = True
|
||||
# sql_enabled = f'AND `activity_log`.enable = :enable'
|
||||
# elif enabled == 'disabled':
|
||||
# data['enable'] = False
|
||||
# sql_enabled = f'AND `activity_log`.enable = :enable'
|
||||
# elif enabled == 'all':
|
||||
# sql_enabled = ''
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `activity_log`.id AS 'activity_log_id', `activity_log`.id_random AS 'activity_log_id_random'
|
||||
FROM `activity_log` AS `activity_log`
|
||||
WHERE
|
||||
{sql_account_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `activity_log`.created_on DESC, `activity_log`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if activity_log_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
activity_log_rec_li = activity_log_rec_li_result
|
||||
else: # [] or False
|
||||
activity_log_rec_li = activity_log_rec_li_result
|
||||
|
||||
log.debug(activity_log_rec_li_result)
|
||||
|
||||
return activity_log_rec_li
|
||||
# ### END ### API Activity Log Methods ### get_activity_log_rec_list() ###
|
||||
429
app/methods/address_methods.py
Normal file
429
app/methods/address_methods.py
Normal file
@@ -0,0 +1,429 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import get_account_id_w_for_type_id, redis_lookup_id_random, sql_enable_part, sql_insert, sql_limit_offset_part, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.models.address_models import Address_Base
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
|
||||
|
||||
# ### BEGIN ### API Address Methods ### load_address_obj() ###
|
||||
@logger_reset
|
||||
def load_address_obj(
|
||||
address_id: int|str,
|
||||
enabled: str = 'enabled', # enabled, disabled, all # Probably not needed for the address
|
||||
limit: int = 100, # Probably not needed for the address
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
) -> Address_Base|dict|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if address_id := redis_lookup_id_random(record_id_random=address_id, table_name='address'): pass
|
||||
else: return False
|
||||
|
||||
if address_rec := sql_select(table_name='v_address', record_id=address_id): pass
|
||||
else: return False
|
||||
|
||||
try:
|
||||
address_obj = Address_Base(**address_rec)
|
||||
log.debug(address_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
if model_as_dict:
|
||||
return address_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return address_obj
|
||||
# ### END ### API Address Methods ### load_address_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Address Methods ### get_address_rec_list() ###
|
||||
# Updated 2022-01-07
|
||||
@logger_reset
|
||||
def get_address_rec_list(
|
||||
for_type: str, # 'account' is a special case
|
||||
for_id: str,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 500,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_id := redis_lookup_id_random(record_id_random=for_id, table_name=for_type): pass
|
||||
else: return False
|
||||
|
||||
if for_type == 'account':
|
||||
sql_for_type_id = f'`address`.account_id = :for_id'
|
||||
else:
|
||||
sql_for_type_id = f'`address`.for_type = :for_type AND `address`.for_id = :for_id'
|
||||
|
||||
data = {}
|
||||
# data[f'{for_type}_id'] = for_id
|
||||
data['for_type'] = for_type
|
||||
data['for_id'] = for_id
|
||||
# sql_obj_type_id = f'`address`.{for_type}_id = :{for_type}_id'
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='address', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
sql = f"""
|
||||
SELECT `address`.id AS 'address_id', `address`.id_random AS 'address_id_random'
|
||||
FROM `address` AS `address`
|
||||
WHERE
|
||||
{sql_for_type_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `address`.created_on DESC, `address`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if address_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
address_rec_li = address_rec_li_result
|
||||
else: # [] or False
|
||||
address_rec_li = address_rec_li_result
|
||||
|
||||
log.debug(address_rec_li_result)
|
||||
|
||||
return address_rec_li
|
||||
# ### END ### API Address Methods ### get_address_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Address Methods ### create_update_address_obj_v4() ###
|
||||
# NOTE: This will create or update an address.
|
||||
# Rewrite and updated 2021-08-25
|
||||
@logger_reset
|
||||
def create_update_address_obj_v4(
|
||||
address_dict_obj: Address_Base|dict,
|
||||
address_id: int|str = None,
|
||||
account_id: int|str = None,
|
||||
for_type: str = None,
|
||||
for_id: int|str = None,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_outline: bool = False,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
log.info('Checking requirements...')
|
||||
if address_id:
|
||||
log.info(f'Address ID passed. Update existing Address. Address ID: {address_id}')
|
||||
|
||||
if address_id := redis_lookup_id_random(record_id_random=address_id, table_name='address'): pass
|
||||
else:
|
||||
log.error('Address ID passed but is invalid. Failed requirement.')
|
||||
return False
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Account ID passed. Not required. Ignoring.')
|
||||
log.info(f'Account ID: {account_id}')
|
||||
|
||||
log.info('Attempting to get Account ID from related object.')
|
||||
if account_id := get_account_id_w_for_type_id(for_type='address', for_id=address_id): pass
|
||||
else:
|
||||
log.error('Unable to get Account ID from related object.')
|
||||
False
|
||||
|
||||
if for_id := redis_lookup_id_random(record_id_random=for_id, table_name=for_type): pass
|
||||
else:
|
||||
log.error('Missing or invalid For Type and For ID ID passed. Not required. Ignoring.')
|
||||
log.info(f'For Type: {for_type} and For ID: {for_id}')
|
||||
else:
|
||||
log.info('No Address ID passed. Create new Address. Required: Account ID, For Type, For ID')
|
||||
|
||||
if for_id := redis_lookup_id_random(record_id_random=for_id, table_name=for_type): pass
|
||||
else:
|
||||
log.error('Missing or invalid For Type and For ID ID passed. Failed requirement.')
|
||||
log.info(f'For Type: {for_type} and For ID: {for_id}')
|
||||
return False
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Account ID passed. Failed requirement.')
|
||||
log.info(f'Account ID: {account_id}')
|
||||
if for_type and for_id:
|
||||
log.info('Attempting to get Account ID from related object.')
|
||||
if account_id := get_account_id_w_for_type_id(for_type=for_type, for_id=for_id): pass
|
||||
else:
|
||||
log.error('Unable to get Account ID from related object.')
|
||||
False
|
||||
else:
|
||||
return False
|
||||
|
||||
log.debug(type(address_dict_obj))
|
||||
if isinstance(address_dict_obj, dict):
|
||||
address_dict = address_dict_obj
|
||||
if address_id:
|
||||
address_dict['address_id'] = address_id
|
||||
if account_id:
|
||||
address_dict['account_id'] = account_id
|
||||
if for_type:
|
||||
address_dict['for_type'] = for_type
|
||||
if for_id:
|
||||
address_dict['for_id'] = for_id
|
||||
try:
|
||||
address_obj = Address_Base(**address_dict)
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(address_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
address_obj = address_dict_obj
|
||||
if address_id:
|
||||
# NOTE: Can't update the ID alias if it was never set.
|
||||
address_obj.id = address_id
|
||||
if account_id:
|
||||
address_obj.account_id = account_id
|
||||
if for_type:
|
||||
address_obj.for_type = for_type
|
||||
if for_id:
|
||||
address_obj.for_id = for_id
|
||||
|
||||
address_dict = address_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'created_on', 'updated_on'})
|
||||
|
||||
if address_id:
|
||||
if address_dict_up_result := sql_update(data=address_dict, table_name='address', rm_id_random=True): pass
|
||||
else:
|
||||
log.warning(f'Address not updated. Address ID: {address_id}')
|
||||
log.debug(address_dict_up_result)
|
||||
return False
|
||||
log.debug(address_dict_up_result)
|
||||
else:
|
||||
if address_dict_in_result := sql_insert(data=address_dict, table_name='address', rm_id_random=True, id_random_length=8): pass
|
||||
else:
|
||||
log.warning(f'Address not created.')
|
||||
log.debug(address_dict_in_result)
|
||||
return False
|
||||
log.debug(address_dict_in_result)
|
||||
|
||||
address_id = address_dict_in_result
|
||||
|
||||
address_outline = {}
|
||||
address_outline['address_id'] = address_id
|
||||
# Should this outline include for_type and for_id? Probably later.
|
||||
|
||||
if return_outline:
|
||||
log.debug(f'Returning the Address Outline: {address_outline}')
|
||||
return address_outline
|
||||
else:
|
||||
log.debug(f'Returning the Address ID: {address_id}')
|
||||
return address_id
|
||||
# ### END ### API Address Methods ### create_update_address_obj_v4() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Address Methods ### create_address_obj() ###
|
||||
# Updated 2022-01-06
|
||||
@logger_reset
|
||||
def create_address_obj(
|
||||
account_id: int|str,
|
||||
address_dict_obj: Address_Base,
|
||||
for_type: str = None,
|
||||
for_id: int|str = None,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
# NOTE: Remove at future date. Is this check needed if we trust that the ID is checked ahead of time?
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
|
||||
if for_id := redis_lookup_id_random(record_id_random=for_id, table_name=for_type): pass
|
||||
else: return False
|
||||
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(address_dict_obj))
|
||||
log.debug(address_dict_obj)
|
||||
if isinstance(address_dict_obj, dict):
|
||||
address_dict = address_dict_obj
|
||||
try:
|
||||
address_obj = Contact_Base(**address_dict)
|
||||
log.debug(address_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
address_obj = address_dict_obj
|
||||
address_obj.account_id = account_id
|
||||
|
||||
address_dict = address_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'created_on', 'updated_on'})
|
||||
log.debug(address_dict)
|
||||
|
||||
# ### SECTION ### Process data
|
||||
# Look for an account_id in the address_obj
|
||||
if account_id: pass
|
||||
elif account_id := address_obj.account_id: pass
|
||||
|
||||
address_obj.account_id = account_id
|
||||
address_dict['account_id'] = account_id
|
||||
|
||||
address_obj.for_type = for_type
|
||||
address_obj.for_id = for_id
|
||||
address_dict['for_type'] = for_type
|
||||
address_dict['for_id'] = for_id
|
||||
|
||||
if address_obj.id:
|
||||
log.warning(f'There should not be an Address ID: {address_obj.id}')
|
||||
return False
|
||||
else:
|
||||
log.info(f'Should there be a check for an existing address with? For Type: {for_type}; For ID: {for_id}')
|
||||
if get_address_rec_result := get_address_rec_list(for_type=for_type, for_id=for_id):
|
||||
log.warning(f'One or more addresses were found with: For Type: {for_type}; For ID: {for_id}')
|
||||
return False
|
||||
else: log.info(f'No existing address found with: For Type: {for_type}; For ID: {for_id}')
|
||||
|
||||
if address_dict_in_result := sql_insert(
|
||||
data = address_dict,
|
||||
table_name = 'address',
|
||||
rm_id_random = True,
|
||||
id_random_length = default_num_bytes
|
||||
): pass
|
||||
else:
|
||||
return False
|
||||
|
||||
log.debug(address_dict_in_result)
|
||||
address_id = address_dict_in_result
|
||||
|
||||
log.info(f'Returning the new address_id: {address_id}')
|
||||
|
||||
return address_id
|
||||
# ### END ### API Address Methods ### create_address_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Address Methods ### update_address_obj() ###
|
||||
# Updated 2022-01-06
|
||||
@logger_reset
|
||||
def update_address_obj(
|
||||
address_id: int|str, # Ideally the int ID should be passed. This allows for updating of the id_random value.
|
||||
address_dict_obj: Address_Base,
|
||||
for_type: str = None,
|
||||
for_id: int|str = None,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
) -> bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
# NOTE: Remove at future date. Is this check needed if we trust that the ID is checked ahead of time?
|
||||
if address_id := redis_lookup_id_random(record_id_random=address_id, table_name='address'): pass
|
||||
else: return False
|
||||
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(address_dict_obj))
|
||||
if isinstance(address_dict_obj, dict):
|
||||
address_dict = address_dict_obj
|
||||
try:
|
||||
address_obj = Contact_Base(**address_dict)
|
||||
log.debug(address_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
address_obj = address_dict_obj
|
||||
|
||||
address_dict = address_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'created_on', 'updated_on'})
|
||||
|
||||
# ### SECTION ### Process data
|
||||
address_obj.id = address_id # Is this needed?
|
||||
address_dict['id'] = address_id
|
||||
|
||||
# Look for an account_id in the address_obj
|
||||
if account_id := address_obj.account_id: pass
|
||||
elif account_id := get_account_id_w_for_type_id(for_type='address', for_id=address_id): pass
|
||||
|
||||
# If for_type and for_id are passed then the address needs to be updated
|
||||
if for_type and for_id:
|
||||
address_obj.for_type = for_type
|
||||
address_obj.for_id = for_id
|
||||
address_dict['for_type'] = for_type
|
||||
address_dict['for_id'] = for_id
|
||||
|
||||
log.debug(address_dict_obj)
|
||||
# log.debug(address_dict_obj.dict(by_alias=True, exclude_unset=True))
|
||||
log.debug(address_dict_obj.dict(by_alias=False, exclude_unset=True))
|
||||
# log.debug(address_dict_obj.dict(by_alias=False, exclude_unset=False))
|
||||
|
||||
# address_dict = address_dict_obj.dict(by_alias=False, exclude_unset=True)
|
||||
|
||||
if address_dict_up_result := sql_update(
|
||||
data = address_dict,
|
||||
table_name = 'address',
|
||||
rm_id_random = True
|
||||
): pass
|
||||
else:
|
||||
log.warning(f'Address not updated.')
|
||||
log.debug(address_dict_up_result)
|
||||
return False
|
||||
|
||||
log.debug(address_dict_up_result)
|
||||
|
||||
return True
|
||||
# ### END ### API Address Methods ### update_address_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Address Methods ### create_update_address_obj() ###
|
||||
@logger_reset
|
||||
def create_update_address_obj(
|
||||
address_id: int|str|None, # Ideally the int ID should be passed. This allows for updating of the id_random value.
|
||||
address_obj: Address_Base,
|
||||
process_address: bool = False,
|
||||
process_organization: bool = False,
|
||||
) -> bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if address_id:
|
||||
if address_id := redis_lookup_id_random(record_id_random=address_id, table_name='address'): pass
|
||||
else: return False
|
||||
address_obj.id = address_id
|
||||
else:
|
||||
# Insert record now and update later
|
||||
address_dict_in = address_obj.dict(by_alias=False, exclude_unset=True)
|
||||
log.debug(address_dict_in)
|
||||
address_in_result = sql_insert(
|
||||
data = address_dict_in,
|
||||
table_name = 'address',
|
||||
rm_id_random = True,
|
||||
id_random_length = default_num_bytes,
|
||||
)
|
||||
log.debug(address_in_result)
|
||||
if isinstance(address_in_result, bool) and address_in_result is True:
|
||||
return address_in_result
|
||||
elif isinstance(address_in_result, int):
|
||||
address_id = address_in_result
|
||||
address_obj.id = address_id
|
||||
else:
|
||||
return False # This should not happen.
|
||||
|
||||
# Process address data
|
||||
address_dict_up = address_obj.dict(by_alias=False, exclude_unset=True)
|
||||
log.debug(address_dict_up)
|
||||
|
||||
# Update record
|
||||
address_up_result = sql_update(
|
||||
data = address_dict_up,
|
||||
table_name = 'address',
|
||||
rm_id_random = True,
|
||||
)
|
||||
log.debug(address_up_result)
|
||||
if isinstance(address_up_result, bool) and address_up_result is True:
|
||||
return address_id
|
||||
elif isinstance(address_up_result, bool) and address_up_result is False:
|
||||
return False
|
||||
elif isinstance(address_up_result, int):
|
||||
return address_up_result
|
||||
else:
|
||||
return False
|
||||
# ### END ### API Address Methods ### create_update_address_obj() ###
|
||||
8
app/methods/aether_api_fastapi.code-workspace
Normal file
8
app/methods/aether_api_fastapi.code-workspace
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "../.."
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
}
|
||||
109
app/methods/archive_content_methods.py
Normal file
109
app/methods/archive_content_methods.py
Normal file
@@ -0,0 +1,109 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_select
|
||||
from app.lib_general import log, logging
|
||||
|
||||
from app.models.archive_content_models import Archive_Content_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Archive Content Methods ### load_archive_content_obj() ###
|
||||
def load_archive_content_obj(
|
||||
archive_content_id: int|str,
|
||||
# limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
# enabled: str = 'enabled', # enabled, disabled, all
|
||||
# inc_archive_content_content_list: bool = False,
|
||||
) -> Archive_Content_Base|dict|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if archive_content_id := redis_lookup_id_random(record_id_random=archive_content_id, table_name='archive_content'): pass
|
||||
else: return False
|
||||
|
||||
if archive_content_rec := sql_select(
|
||||
table_name='v_archive_content',
|
||||
record_id=archive_content_id,
|
||||
): pass
|
||||
else: return False
|
||||
log.debug(archive_content_rec)
|
||||
try:
|
||||
archive_content_obj = Archive_Content_Base(**archive_content_rec)
|
||||
log.debug(archive_content_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
if model_as_dict:
|
||||
return archive_content_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return archive_content_obj
|
||||
# ### END ### API Archive Content Methods ### load_archive_content_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Archive Content Methods ### get_archive_content_rec_list() ###
|
||||
def get_archive_content_rec_list(
|
||||
for_obj_type: str,
|
||||
for_obj_id: str,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
sort_by_str: str = None,
|
||||
sort_by: str = None,
|
||||
sort_by_desc: bool = False,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
else: return False
|
||||
data = {}
|
||||
data[f'{for_obj_type}_id'] = for_obj_id
|
||||
# data['for_obj_type'] = for_obj_type
|
||||
sql_obj_type_id = f'`tbl`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
if sort_by:
|
||||
sql_order_by = f'ORDER BY `tbl`.{sort_by}'
|
||||
if sort_by_desc:
|
||||
sql_order_by = f'{sql_order_by} {DESC}'
|
||||
else:
|
||||
sql_order_by = 'ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC'
|
||||
|
||||
sql = f"""
|
||||
SELECT `tbl`.id AS 'archive_content_id', `tbl`.id_random AS 'archive_content_id_random'
|
||||
FROM `archive_content` AS `tbl`
|
||||
WHERE
|
||||
{sql_obj_type_id}
|
||||
{sql_enabled}
|
||||
{sql_order_by}
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if archive_content_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
archive_content_rec_li = archive_content_rec_li_result
|
||||
else:
|
||||
archive_content_rec_li = []
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(archive_content_rec_li_result)
|
||||
|
||||
return archive_content_rec_li
|
||||
# ### END ### API Archive Content Methods ### get_archive_content_rec_list() ###
|
||||
128
app/methods/archive_methods.py
Normal file
128
app/methods/archive_methods.py
Normal file
@@ -0,0 +1,128 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_select
|
||||
from app.lib_general import log, logging
|
||||
|
||||
from app.methods.archive_content_methods import get_archive_content_rec_list, load_archive_content_obj
|
||||
|
||||
from app.models.archive_models import Archive_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Archive Methods ### load_archive_obj() ###
|
||||
def load_archive_obj(
|
||||
archive_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
hidden: str = 'not_hidden', # hidden, not_hidden, all
|
||||
inc_archive_content_list: bool = False,
|
||||
) -> Archive_Base|dict|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if archive_id := redis_lookup_id_random(record_id_random=archive_id, table_name='archive'): pass
|
||||
else: return False
|
||||
|
||||
if archive_rec := sql_select(
|
||||
table_name='v_archive',
|
||||
record_id=archive_id,
|
||||
): pass
|
||||
else: return False
|
||||
log.debug(archive_rec)
|
||||
try:
|
||||
archive_obj = Archive_Base(**archive_rec)
|
||||
log.debug(archive_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
# Updated 2021-06-18
|
||||
if inc_archive_content_list:
|
||||
sort_by = archive_rec.get('sort_by')
|
||||
sort_by_desc = archive_rec.get('sort_by_desc')
|
||||
if archive_content_rec_list_result := get_archive_content_rec_list(
|
||||
for_obj_type = 'archive',
|
||||
for_obj_id = archive_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
sort_by = sort_by,
|
||||
sort_by_desc = sort_by_desc,
|
||||
):
|
||||
archive_content_result_list = []
|
||||
for archive_content_rec in archive_content_rec_list_result:
|
||||
archive_content_result_list.append(
|
||||
load_archive_content_obj(
|
||||
archive_content_id = archive_content_rec.get('archive_content_id', None),
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
)
|
||||
)
|
||||
archive_obj.archive_content_list = archive_content_result_list
|
||||
else: archive_obj.archive_content_list = []
|
||||
|
||||
if model_as_dict:
|
||||
return archive_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return archive_obj
|
||||
# ### END ### API Archive Methods ### load_archive_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Archive Methods ### get_archive_rec_list() ###
|
||||
def get_archive_rec_list(
|
||||
for_obj_type: str,
|
||||
for_obj_id: str,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
else: return False
|
||||
data = {}
|
||||
data[f'{for_obj_type}_id'] = for_obj_id
|
||||
# data['for_obj_type'] = for_obj_type
|
||||
sql_obj_type_id = f'`tbl`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `tbl`.id AS 'archive_id', `tbl`.id_random AS 'archive_id_random'
|
||||
FROM `archive` AS `tbl`
|
||||
WHERE
|
||||
{sql_obj_type_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if archive_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
archive_rec_li = archive_rec_li_result
|
||||
else: # [] or False
|
||||
archive_rec_li = archive_rec_li_result
|
||||
|
||||
log.debug(archive_rec_li_result)
|
||||
|
||||
return archive_rec_li
|
||||
# ### END ### API Archive Methods ### get_archive_rec_list() ###
|
||||
113
app/methods/c_idaa_methods.py
Normal file
113
app/methods/c_idaa_methods.py
Normal file
@@ -0,0 +1,113 @@
|
||||
import datetime, json, pprint, pytz, random, requests, secrets, string, time
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset, secure_hash_string, verify_secure_hash_string
|
||||
|
||||
|
||||
# ### BEGIN ### API Client: IDAA Methods ### refresh_person_group() ###
|
||||
# Updated 2022-03-16
|
||||
@logger_reset
|
||||
def refresh_person_group(
|
||||
person_id: int = None,
|
||||
):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
data = {}
|
||||
sql_person_id = ''
|
||||
if person_id:
|
||||
data['person_id'] = person_id
|
||||
sql_person_id = f'AND `person`.id = :person_id'
|
||||
log.info(f'Updating membership group for Person ID: {person_id}')
|
||||
else:
|
||||
log.info('Updating membership group for all person records.')
|
||||
|
||||
|
||||
sql = f"""
|
||||
UPDATE person
|
||||
INNER JOIN membership_person ON person.id = membership_person.person_id
|
||||
SET person.enable = 1, person.group = 'pending_member'
|
||||
WHERE person.account_id = 13
|
||||
AND membership_person.end_on >= NOW()
|
||||
AND person.status = 'pending'
|
||||
{sql_person_id};
|
||||
"""
|
||||
if person_update_result := sql_update(sql=sql, data=data, log_lvl=logging.WARNING):
|
||||
log.warning(f'Finished the SQL UPDATE of person table record(s) for pending members')
|
||||
elif person_update_result is None:
|
||||
log.warning(f'Finished the SQL UPDATE of person table record(s) for pending members, but no records needed to be updated')
|
||||
else:
|
||||
log.warning(f'The SQL UPDATE of person table record(s) failed for pending members')
|
||||
log.debug(person_update_result)
|
||||
|
||||
sql = f"""
|
||||
UPDATE person
|
||||
INNER JOIN membership_person ON person.id = membership_person.person_id
|
||||
SET person.enable = 1, person.group = 'current_member'
|
||||
WHERE person.account_id = 13
|
||||
AND membership_person.end_on >= NOW()
|
||||
AND (person.status IS NULL OR person.status = '' OR person.status = 'approved' OR person.status = 'unknown')
|
||||
{sql_person_id};
|
||||
"""
|
||||
if person_update_result := sql_update(sql=sql, data=data, log_lvl=logging.WARNING):
|
||||
log.warning(f'Finished the SQL UPDATE of person table record(s) for current members')
|
||||
elif person_update_result is None:
|
||||
log.warning(f'Finished the SQL UPDATE of person table record(s) for current members, but no records needed to be updated')
|
||||
else:
|
||||
log.warning(f'The SQL UPDATE of person table record(s) failed for current members')
|
||||
log.debug(person_update_result)
|
||||
|
||||
sql = f"""
|
||||
UPDATE person
|
||||
INNER JOIN membership_person ON person.id = membership_person.person_id
|
||||
SET person.group = 'inactive_member'
|
||||
WHERE person.account_id = 13
|
||||
AND membership_person.end_on < NOW()
|
||||
AND membership_person.end_on >= DATE(NOW() - INTERVAL 4 WEEK)
|
||||
{sql_person_id};
|
||||
"""
|
||||
if person_update_result := sql_update(sql=sql, data=data, log_lvl=logging.WARNING):
|
||||
log.warning(f'Finished the SQL UPDATE of person table record(s) for inactive members')
|
||||
elif person_update_result is None:
|
||||
log.warning(f'Finished the SQL UPDATE of person table record(s) for inactive members, but no records needed to be updated')
|
||||
else:
|
||||
log.warning(f'The SQL UPDATE of person table record(s) failed for inactive members')
|
||||
log.debug(person_update_result)
|
||||
|
||||
sql = f"""
|
||||
UPDATE person
|
||||
INNER JOIN membership_person ON person.id = membership_person.person_id
|
||||
SET person.group = 'suspended_member'
|
||||
WHERE person.account_id = 13
|
||||
AND membership_person.end_on < DATE(NOW() - INTERVAL 4 WEEK)
|
||||
{sql_person_id};
|
||||
"""
|
||||
if person_update_result := sql_update(sql=sql, data=data, log_lvl=logging.WARNING):
|
||||
log.warning(f'Finished the SQL UPDATE of person table record(s) for suspended members')
|
||||
elif person_update_result is None:
|
||||
log.warning(f'Finished the SQL UPDATE of person table record(s) for suspended members, but no records needed to be updated')
|
||||
else:
|
||||
log.warning(f'The SQL UPDATE of person table record(s) failed for suspended members')
|
||||
log.debug(person_update_result)
|
||||
|
||||
sql = f"""
|
||||
UPDATE person
|
||||
LEFT JOIN membership_person ON person.id = membership_person.person_id
|
||||
SET person.group = 'not_member'
|
||||
WHERE person.account_id = 13
|
||||
AND membership_person.id IS NULL
|
||||
{sql_person_id};
|
||||
"""
|
||||
if person_update_result := sql_update(sql=sql, data=data, log_lvl=logging.WARNING):
|
||||
log.warning(f'Finished the SQL UPDATE of person table record(s) for not members')
|
||||
elif person_update_result is None:
|
||||
log.warning(f'Finished the SQL UPDATE of person table record(s) for not members, but no records needed to be updated')
|
||||
else:
|
||||
log.warning(f'The SQL UPDATE of person table record(s) failed for not members')
|
||||
log.debug(person_update_result)
|
||||
|
||||
return True
|
||||
# ### END ### API Client: IDAA Methods ### refresh_person_group() ###
|
||||
121
app/methods/cont_edu_cert_methods.py
Normal file
121
app/methods/cont_edu_cert_methods.py
Normal file
@@ -0,0 +1,121 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
from app.models.cont_edu_cert_models import Cont_Edu_Cert_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Cont Edu Cert Methods ### load_cont_edu_cert_obj() ###
|
||||
def load_cont_edu_cert_obj(
|
||||
cont_edu_cert_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_cont_edu_cert_person_list: bool = False,
|
||||
) -> Cont_Edu_Cert_Base|dict|bool:
|
||||
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if cont_edu_cert_id := redis_lookup_id_random(record_id_random=cont_edu_cert_id, table_name='cont_edu_cert'): pass
|
||||
else: return False
|
||||
|
||||
if cont_edu_cert_rec := sql_select(table_name='v_cont_edu_cert', record_id=cont_edu_cert_id): pass
|
||||
else: return False
|
||||
|
||||
try:
|
||||
cont_edu_cert_obj = Cont_Edu_Cert_Base(**cont_edu_cert_rec)
|
||||
log.debug(cont_edu_cert_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
# Updated 2021-07-28
|
||||
if inc_cont_edu_cert_person_list:
|
||||
from app.methods.cont_edu_cert_person_methods import get_cont_edu_cert_person_rec_list, load_cont_edu_cert_person_obj
|
||||
if cont_edu_cert_person_rec_list_result := get_cont_edu_cert_person_rec_list(
|
||||
cont_edu_cert_id = cont_edu_cert_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
cont_edu_cert_person_result_list = []
|
||||
for cont_edu_cert_person_rec in cont_edu_cert_person_rec_list_result:
|
||||
if load_cont_edu_cert_person_result := load_cont_edu_cert_person_obj(
|
||||
cont_edu_cert_person_id = cont_edu_cert_person_rec.get('cont_edu_cert_person_id', None),
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
# inc_cont_edu_cert = inc_cont_edu_cert,
|
||||
):
|
||||
cont_edu_cert_person_result_list.append(load_cont_edu_cert_person_result)
|
||||
else: cont_edu_cert_person_result_list.append(None)
|
||||
cont_edu_cert_obj.cont_edu_cert_person_list = cont_edu_cert_person_result_list
|
||||
else: cont_edu_cert_obj.cont_edu_cert_person_list = []
|
||||
|
||||
if model_as_dict:
|
||||
return cont_edu_cert_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return cont_edu_cert_obj
|
||||
# ### END ### API Cont Edu Cert Methods ### load_cont_edu_cert_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Cont Edu Cert Methods ### get_cont_edu_cert_rec_list() ###
|
||||
def get_cont_edu_cert_rec_list(
|
||||
account_id: str,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
data = {}
|
||||
data['account_id'] = account_id
|
||||
sql_account_id = f'`tbl`.account_id = :account_id'
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
# sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `tbl`.id AS 'cont_edu_cert_id', `tbl`.id_random AS 'cont_edu_cert_id_random'
|
||||
FROM `cont_edu_cert` AS `tbl`
|
||||
WHERE
|
||||
{sql_account_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if cont_edu_cert_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
cont_edu_cert_rec_li = cont_edu_cert_rec_li_result
|
||||
else:
|
||||
cont_edu_cert_rec_li = []
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(cont_edu_cert_rec_li_result)
|
||||
|
||||
return cont_edu_cert_rec_li
|
||||
# ### END ### API Cont Edu Cert Methods ### get_cont_edu_cert_rec_list() ###
|
||||
147
app/methods/cont_edu_cert_person_methods.py
Normal file
147
app/methods/cont_edu_cert_person_methods.py
Normal file
@@ -0,0 +1,147 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging
|
||||
|
||||
from app.methods.cont_edu_cert_methods import load_cont_edu_cert_obj
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
from app.models.cont_edu_cert_person_models import Cont_Edu_Cert_Person_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Cont Edu Cert Person Methods ### load_cont_edu_cert_person_obj() ###
|
||||
def load_cont_edu_cert_person_obj(
|
||||
cont_edu_cert_person_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_cont_edu_cert: bool = False,
|
||||
) -> Cont_Edu_Cert_Person_Base|dict|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if cont_edu_cert_person_id := redis_lookup_id_random(record_id_random=cont_edu_cert_person_id, table_name='cont_edu_cert_person'): pass
|
||||
else: return False
|
||||
|
||||
if cont_edu_cert_person_rec := sql_select(table_name='v_cont_edu_cert_person', record_id=cont_edu_cert_person_id): pass
|
||||
else: return False
|
||||
|
||||
try:
|
||||
cont_edu_cert_person_obj = Cont_Edu_Cert_Person_Base(**cont_edu_cert_person_rec)
|
||||
log.debug(cont_edu_cert_person_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
if inc_cont_edu_cert:
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
cont_edu_cert_id = cont_edu_cert_person_rec.get('cont_edu_cert_id', None)
|
||||
log.debug(cont_edu_cert_id)
|
||||
|
||||
if cont_edu_cert_result := load_cont_edu_cert_obj(
|
||||
cont_edu_cert_id = cont_edu_cert_id,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
cont_edu_cert_person_obj.cont_edu_cert = cont_edu_cert_result
|
||||
else: cont_edu_cert_person_obj.cont_edu_cert = None
|
||||
|
||||
if model_as_dict:
|
||||
return cont_edu_cert_person_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return cont_edu_cert_person_obj
|
||||
# ### END ### API Cont Edu Cert Person Methods ### load_cont_edu_cert_person_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Cont Edu Cert Person Methods ### get_cont_edu_cert_person_rec_list() ###
|
||||
# Updated 2021-12-13
|
||||
def get_cont_edu_cert_person_rec_list(
|
||||
account_id: str = None,
|
||||
person_id: str = None,
|
||||
cont_edu_cert_id: str = None,
|
||||
given_name: str = None,
|
||||
family_name: str = None,
|
||||
from_datetime: Optional[datetime.datetime] = None, # based on created_on
|
||||
to_datetime: Optional[datetime.datetime] = None, # based on created_on
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> None|list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if cont_edu_cert_id:
|
||||
if cont_edu_cert_id := redis_lookup_id_random(record_id_random=cont_edu_cert_id, table_name='cont_edu_cert'): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
if account_id:
|
||||
data['account_id'] = account_id
|
||||
sql_where_id = f'`tbl`.account_id = :account_id'
|
||||
elif person_id:
|
||||
data['person_id'] = person_id
|
||||
sql_where_id = f'`tbl`.person_id = :person_id'
|
||||
elif cont_edu_cert_id:
|
||||
data['cont_edu_cert_id'] = cont_edu_cert_id
|
||||
sql_where_id = f'`tbl`.cont_edu_cert_id = :cont_edu_cert_id'
|
||||
else: return False
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
# sql_enabled = ''
|
||||
|
||||
if from_datetime and to_datetime:
|
||||
data['from_datetime'] = from_datetime
|
||||
data['to_datetime'] = to_datetime
|
||||
sql_from_to_datetime = f'AND `tbl`.created_on >= :from_datetime AND `tbl`.created_on <= :to_datetime'
|
||||
elif from_datetime:
|
||||
data['from_datetime'] = from_datetime
|
||||
sql_from_to_datetime = f'AND `tbl`.created_on >= :from_datetime'
|
||||
elif to_datetime:
|
||||
data['to_datetime'] = to_datetime
|
||||
sql_from_to_datetime = f'AND `tbl`.created_on <= :to_datetime'
|
||||
else:
|
||||
sql_from_to_datetime = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `tbl`.id AS 'cont_edu_cert_person_id', `tbl`.id_random AS 'cont_edu_cert_person_id_random'
|
||||
FROM `cont_edu_cert_person` AS `tbl`
|
||||
WHERE
|
||||
{sql_where_id}
|
||||
{sql_enabled}
|
||||
{sql_from_to_datetime}
|
||||
ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if cont_edu_cert_person_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
log.info('Got a list result')
|
||||
cont_edu_cert_person_rec_li = cont_edu_cert_person_rec_li_result
|
||||
else: # [] or False
|
||||
log.info('No results or something went wrong')
|
||||
cont_edu_cert_person_rec_li = cont_edu_cert_person_rec_li_result
|
||||
|
||||
log.debug(cont_edu_cert_person_rec_li_result)
|
||||
|
||||
return cont_edu_cert_person_rec_li
|
||||
# ### END ### API Cont Edu Cert Person Methods ### get_cont_edu_cert_person_rec_list() ###
|
||||
608
app/methods/contact_methods.py
Normal file
608
app/methods/contact_methods.py
Normal file
@@ -0,0 +1,608 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import get_account_id_w_for_type_id, redis_lookup_id_random, sql_enable_part, sql_insert, sql_limit_offset_part, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.methods.address_methods import create_address_obj, create_update_address_obj, create_update_address_obj_v4, update_address_obj
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
from app.models.contact_models import Contact_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Contact Methods ### load_contact_obj() ###
|
||||
@logger_reset
|
||||
def load_contact_obj(
|
||||
contact_id: int|str,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
inc_address: bool = False
|
||||
) -> Contact_Base|dict|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if contact_id := redis_lookup_id_random(record_id_random=contact_id, table_name='contact'): pass
|
||||
else: return False
|
||||
|
||||
if contact_rec := sql_select(table_name='v_contact', record_id=contact_id): pass
|
||||
else: return False
|
||||
|
||||
try:
|
||||
contact_obj = Contact_Base(**contact_rec)
|
||||
log.debug(contact_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
if inc_address:
|
||||
log.info('Need to include address data...')
|
||||
# NOTE: The address_id field needs to be removed from the contact table.
|
||||
# NOTE: This is not ideal and the view needs to be updated when possible and anything currently pointing to the original contact.address_id needs to be fixed.
|
||||
if address_id := contact_rec.get('address_id', None): pass # WARNING
|
||||
elif address_id := contact_rec.get('linked_address_id', None): pass # WARNING
|
||||
else: pass # WARNING
|
||||
# address_id = contact_rec.get('address_id', None)
|
||||
log.debug(address_id)
|
||||
from app.methods.address_methods import load_address_obj
|
||||
if address_result := load_address_obj(
|
||||
address_id = address_id,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
contact_obj.address = address_result
|
||||
else: contact_obj.address = {} # None
|
||||
|
||||
if model_as_dict:
|
||||
return contact_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return contact_obj
|
||||
# ### END ### API Contact Methods ### load_contact_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Contact Methods ### get_contact_rec_list() ###
|
||||
# Updated 2022-01-07
|
||||
@logger_reset
|
||||
def get_contact_rec_list(
|
||||
for_type: str, # 'account' is a special case
|
||||
for_id: str,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 500,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_id := redis_lookup_id_random(record_id_random=for_id, table_name=for_type): pass
|
||||
else: return False
|
||||
|
||||
if for_type == 'account':
|
||||
sql_for_type_id = f'`contact`.account_id = :for_id'
|
||||
else:
|
||||
sql_for_type_id = f'`contact`.for_type = :for_type AND `contact`.for_id = :for_id'
|
||||
|
||||
data = {}
|
||||
data['for_type'] = for_type
|
||||
data['for_id'] = for_id
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='contact', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
sql = f"""
|
||||
SELECT `contact`.id AS 'contact_id', `contact`.id_random AS 'contact_id_random'
|
||||
FROM `contact` AS `contact`
|
||||
WHERE
|
||||
{sql_for_type_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `contact`.created_on DESC, `contact`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if contact_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
contact_rec_li = contact_rec_li_result
|
||||
else: # [] or False
|
||||
contact_rec_li = contact_rec_li_result
|
||||
|
||||
log.debug(contact_rec_li_result)
|
||||
|
||||
return contact_rec_li
|
||||
# ### END ### API Contact Methods ### get_contact_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Contact Methods ### get_account_id_w_contact_id() ###
|
||||
# Updated 2021-08-24
|
||||
@logger_reset
|
||||
def get_account_id_w_contact_id(
|
||||
contact_id: int|str,
|
||||
) -> bool|int|None:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if contact_id := redis_lookup_id_random(record_id_random=contact_id, table_name='contact'): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['contact_id'] = contact_id
|
||||
|
||||
sql = f"""
|
||||
SELECT `contact`.id AS 'contact_id', `contact`.id_random AS 'contact_id_random', `contact`.account_id AS account_id
|
||||
FROM `contact` AS `contact`
|
||||
WHERE `contact`.id = :contact_id
|
||||
LIMIT 1;
|
||||
"""
|
||||
|
||||
if contact_data_result := sql_select(data=data, sql=sql):
|
||||
log.debug(contact_data_result)
|
||||
if account_id := contact_data_result.get('account_id', None): return account_id
|
||||
else: return False
|
||||
else: return None
|
||||
# ### END ### API Contact Methods ### get_account_id_w_contact_id() ###
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Contact Methods ### create_update_contact_obj_v4() ###
|
||||
# NOTE: This will create or update a contact.
|
||||
# Rewrite and updated 2021-08-25
|
||||
@logger_reset
|
||||
def create_update_contact_obj_v4(
|
||||
contact_dict_obj: Contact_Base|dict,
|
||||
contact_id: int|str = None,
|
||||
account_id: int|str = None,
|
||||
for_type: str = None,
|
||||
for_id: int|str = None,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_outline: bool = False,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
log.info('Checking requirements...')
|
||||
if contact_id:
|
||||
log.info(f'Contact ID passed. Update existing Contact. Contact ID: {contact_id}')
|
||||
|
||||
if contact_id := redis_lookup_id_random(record_id_random=contact_id, table_name='contact'): pass
|
||||
else:
|
||||
log.error('Contact ID passed but is invalid. Failed requirement.')
|
||||
return False
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Account ID passed. Not required. Ignoring.')
|
||||
log.info(f'Account ID: {account_id}')
|
||||
|
||||
log.info('Attempting to get Account ID from related object.')
|
||||
if account_id := get_account_id_w_for_type_id(for_type='contact', for_id=contact_id): pass
|
||||
else:
|
||||
log.error('Unable to get Account ID from related object.')
|
||||
False
|
||||
|
||||
if for_id := redis_lookup_id_random(record_id_random=for_id, table_name=for_type): pass
|
||||
else:
|
||||
log.error('Missing or invalid For Type and For ID passed. Not required. Ignoring.')
|
||||
log.info(f'For Type: {for_type} and For ID: {for_id}')
|
||||
else:
|
||||
log.info('No Contact ID passed. Create new Contact. Required: Account ID, For Type, For ID')
|
||||
|
||||
if for_id := redis_lookup_id_random(record_id_random=for_id, table_name=for_type): pass
|
||||
else:
|
||||
log.error('Missing or invalid For Type and For ID passed. Failed requirement.')
|
||||
log.info(f'For Type: {for_type} and For ID: {for_id}')
|
||||
return False
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Account ID passed. Failed requirement.')
|
||||
log.info(f'Account ID: {account_id}')
|
||||
if for_type and for_id:
|
||||
log.info('Attempting to get Account ID from related object.')
|
||||
if account_id := get_account_id_w_for_type_id(for_type=for_type, for_id=for_id): pass
|
||||
else:
|
||||
log.error('Unable to get Account ID from related object.')
|
||||
False
|
||||
else:
|
||||
return False
|
||||
|
||||
log.debug(type(contact_dict_obj))
|
||||
if isinstance(contact_dict_obj, dict):
|
||||
contact_dict = contact_dict_obj
|
||||
if contact_id:
|
||||
contact_dict['contact_id'] = contact_id
|
||||
if account_id:
|
||||
contact_dict['account_id'] = account_id
|
||||
if for_type:
|
||||
contact_dict['for_type'] = for_type
|
||||
if for_id:
|
||||
contact_dict['for_id'] = for_id
|
||||
try:
|
||||
contact_obj = Contact_Base(**contact_dict)
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(contact_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
contact_obj = contact_dict_obj
|
||||
if contact_id:
|
||||
# NOTE: Can't update the ID alias if it was never set.
|
||||
contact_obj.id = contact_id
|
||||
if account_id:
|
||||
contact_obj.account_id = account_id
|
||||
if for_type:
|
||||
contact_obj.for_type = for_type
|
||||
if for_id:
|
||||
contact_obj.for_id = for_id
|
||||
|
||||
contact_dict = contact_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'address', 'created_on', 'updated_on'})
|
||||
|
||||
if contact_id:
|
||||
if contact_dict_up_result := sql_update(data=contact_dict, table_name='contact', rm_id_random=True): pass
|
||||
else:
|
||||
log.warning(f'Contact not updated. Contact ID: {contact_id}')
|
||||
log.debug(contact_dict_up_result)
|
||||
return False
|
||||
log.debug(contact_dict_up_result)
|
||||
else:
|
||||
if contact_dict_in_result := sql_insert(data=contact_dict, table_name='contact', rm_id_random=True, id_random_length=8): pass
|
||||
else:
|
||||
log.warning(f'Contact not created.')
|
||||
log.debug(contact_dict_in_result)
|
||||
return False
|
||||
log.debug(contact_dict_in_result)
|
||||
|
||||
contact_id = contact_dict_in_result
|
||||
|
||||
contact_outline = {}
|
||||
contact_outline['contact_id'] = contact_id
|
||||
|
||||
# NOTE: Use object model version because of better type checking and validations
|
||||
if contact_obj.address:
|
||||
contact_outline['address_id'] = None
|
||||
address_obj = contact_obj.address
|
||||
if address_id := contact_obj.address_id: pass
|
||||
elif address_id := address_obj.id: pass
|
||||
else: address_id = None
|
||||
address_obj.id
|
||||
address_obj.for_type = 'contact'
|
||||
address_obj.for_id = contact_id
|
||||
create_update_address_obj_result = create_update_address_obj_v4(
|
||||
address_dict_obj = address_obj,
|
||||
address_id = address_id,
|
||||
account_id = account_id,
|
||||
for_type = 'contact',
|
||||
for_id = contact_id,
|
||||
fail_any = fail_any,
|
||||
return_outline = return_outline,
|
||||
)
|
||||
if isinstance(create_update_address_obj_result, int):
|
||||
address_id = create_update_address_obj_result
|
||||
elif create_update_address_obj_result == True: pass
|
||||
else:
|
||||
log.warning(f'Create or Update failed while trying create_update_address_obj_v4(): {create_update_address_obj_result}')
|
||||
address_id = None
|
||||
|
||||
contact_outline['address_id'] = address_id
|
||||
|
||||
if return_outline:
|
||||
log.debug(f'Returning the Contact Outline: {contact_outline}')
|
||||
return contact_outline
|
||||
else:
|
||||
log.debug(f'Returning the Contact ID: {contact_id}')
|
||||
return contact_id
|
||||
# ### END ### API Contact Methods ### create_update_contact_obj_v4() ###
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Contact Methods ### create_contact_obj() ###
|
||||
# NOTE: This will create a contact and then also create a linked address if contact_obj.address data is passed.
|
||||
# NOTE: In the future it should be required that account_id, for_type, and for_id should be passed separately. account_id might not be required *if* it can be looked up based on for_type and for_id.
|
||||
# Updated 2022-01-06
|
||||
@logger_reset
|
||||
def create_contact_obj(
|
||||
account_id: int|str,
|
||||
contact_dict_obj: Contact_Base,
|
||||
for_type: str = None,
|
||||
for_id: int|str = None,
|
||||
address_id: int = None,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
log_lvl: int = logging.WARNING, # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
) -> int|bool:
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
# NOTE: Remove at future date. Is this check needed if we trust that the ID is checked ahead of time?
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
|
||||
if for_id := redis_lookup_id_random(record_id_random=for_id, table_name=for_type): pass
|
||||
else: return False
|
||||
|
||||
if address_id := redis_lookup_id_random(record_id_random=address_id, table_name='address'): pass
|
||||
elif address_id is None: pass
|
||||
else: return False
|
||||
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(contact_dict_obj))
|
||||
if isinstance(contact_dict_obj, dict):
|
||||
contact_dict = contact_dict_obj
|
||||
try:
|
||||
contact_obj = Contact_Base(**contact_dict)
|
||||
log.debug(contact_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
contact_obj = contact_dict_obj
|
||||
contact_obj.account_id = account_id
|
||||
|
||||
contact_dict = contact_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'address', 'address_id', 'address_id_random', 'created_on', 'updated_on'})
|
||||
|
||||
# ### SECTION ### Process data
|
||||
# Look for an account_id in the contact_obj
|
||||
if account_id: pass
|
||||
elif account_id := contact_obj.account_id: pass
|
||||
|
||||
contact_obj.account_id = account_id
|
||||
contact_dict['account_id'] = account_id
|
||||
|
||||
contact_obj.for_type = for_type
|
||||
contact_obj.for_id = for_id
|
||||
contact_dict['for_type'] = for_type
|
||||
contact_dict['for_id'] = for_id
|
||||
|
||||
# Look for an address_id in the contact_obj if one was not passed separately
|
||||
if address_id: pass
|
||||
# elif address_id := contact_obj.address.id: pass
|
||||
|
||||
if contact_dict_in_result := sql_insert(
|
||||
data = contact_dict,
|
||||
table_name = 'contact',
|
||||
rm_id_random = True,
|
||||
id_random_length = default_num_bytes
|
||||
): pass
|
||||
else:
|
||||
return False
|
||||
|
||||
log.debug(contact_dict_in_result)
|
||||
contact_id = contact_dict_in_result
|
||||
|
||||
if address_id and contact_obj.address:
|
||||
log.info('Updating Address object')
|
||||
if address_update_result := update_address_obj(
|
||||
address_id = address_id,
|
||||
address_dict_obj = contact_obj.address,
|
||||
for_type = 'contact',
|
||||
for_id = contact_id,
|
||||
): pass
|
||||
else: return False
|
||||
elif contact_obj.address:
|
||||
log.info('Creating Address object')
|
||||
if address_create_result := create_address_obj(
|
||||
account_id = account_id,
|
||||
address_dict_obj = contact_obj.address,
|
||||
for_type = 'contact',
|
||||
for_id = contact_id,
|
||||
): pass
|
||||
else: return False
|
||||
else: pass
|
||||
|
||||
# if contact_obj.address:
|
||||
# address_obj_new = contact_obj.address
|
||||
# address_obj_new.for_type = 'contact'
|
||||
# address_obj_new.for_id = contact_id
|
||||
# create_address_obj_result = create_address_obj(
|
||||
# address_obj_new = address_obj_new,
|
||||
# account_id = account_id,
|
||||
# for_type = 'contact',
|
||||
# for_id = contact_id,
|
||||
# fail_any = fail_any,
|
||||
# )
|
||||
# if isinstance(create_address_obj_result, int):
|
||||
# address_id = create_address_obj_result
|
||||
# # NOTE: This last update should no longer be needed now that the contact_obj.address_id is not supposed to be used.
|
||||
# # Need to update the contact with the new address_id
|
||||
# contact_obj_up = {} # REMOVE
|
||||
# contact_obj_up['id'] = contact_id # REMOVE
|
||||
# contact_obj_up['address_id'] = address_id # REMOVE
|
||||
# if contact_obj_up_result := sql_update(data=contact_obj_up, table_name='contact'): pass # REMOVE
|
||||
# else: # REMOVE
|
||||
# return False # REMOVE
|
||||
# log.debug(contact_obj_up_result) # REMOVE
|
||||
# else:
|
||||
# log.debug(f'No address_id was returned when tyring to create_address_obj(): {create_address_obj_result}')
|
||||
# address_id = None
|
||||
|
||||
log.info(f'Returning the new contact_id: {contact_id}')
|
||||
|
||||
return contact_id
|
||||
# ### END ### API Contact Methods ### create_contact_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Contact Methods ### update_contact_obj() ###
|
||||
# NOTE: This will update a contact and then also create or update a linked address if contact_obj.address data is passed.
|
||||
# Updated 2022-01-06
|
||||
@logger_reset
|
||||
def update_contact_obj(
|
||||
contact_id: int|str, # Ideally the int ID should be passed. This allows for updating of the id_random value.
|
||||
contact_dict_obj: Contact_Base,
|
||||
for_type: str = None,
|
||||
for_id: int|str = None,
|
||||
address_id: int = None,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_dict: bool = False,
|
||||
log_lvl: int = logging.WARNING, # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
) -> bool:
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
# NOTE: Remove at future date. Is this check needed if we trust that the ID is checked ahead of time?
|
||||
if contact_id := redis_lookup_id_random(record_id_random=contact_id, table_name='contact'): pass
|
||||
else: return False
|
||||
|
||||
if address_id := redis_lookup_id_random(record_id_random=address_id, table_name='address'): pass
|
||||
elif address_id is None: pass
|
||||
else: return False
|
||||
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(contact_dict_obj))
|
||||
log.debug(contact_dict_obj)
|
||||
if isinstance(contact_dict_obj, dict):
|
||||
contact_dict = contact_dict_obj
|
||||
try:
|
||||
contact_obj = Contact_Base(**contact_dict)
|
||||
log.debug(contact_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
contact_obj = contact_dict_obj
|
||||
|
||||
contact_dict = contact_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'address', 'address_id', 'address_id_random', 'created_on', 'updated_on'})
|
||||
log.debug(contact_dict)
|
||||
|
||||
# ### SECTION ### Process data
|
||||
contact_obj.id = contact_id # Is this needed?
|
||||
contact_dict['id'] = contact_id
|
||||
|
||||
# Look for an account_id in the contact_obj
|
||||
if account_id := contact_obj.account_id: pass
|
||||
elif account_id := get_account_id_w_for_type_id(for_type='contact', for_id=contact_id): pass
|
||||
|
||||
# If for_type and for_id are passed then the contact needs to be updated
|
||||
if for_type and for_id:
|
||||
contact_obj.for_type = for_type
|
||||
contact_obj.for_id = for_id
|
||||
contact_dict['for_type'] = for_type
|
||||
contact_dict['for_id'] = for_id
|
||||
|
||||
# Look for an address_id in the contact_obj if one was not passed separately
|
||||
if address_id: pass
|
||||
elif address_id := contact_obj.address.id: pass
|
||||
log.debug(contact_obj.address.id)
|
||||
log.debug(contact_obj.address.id_random)
|
||||
|
||||
if contact_dict_up_result := sql_update(
|
||||
data=contact_dict,
|
||||
table_name='contact',
|
||||
rm_id_random=True
|
||||
): pass
|
||||
else:
|
||||
log.warning(f'Contact not updated.')
|
||||
log.debug(contact_dict_up_result)
|
||||
return False
|
||||
|
||||
log.debug(contact_dict_up_result)
|
||||
|
||||
if address_id and contact_obj.address:
|
||||
log.info('Updating Address object')
|
||||
if address_update_result := update_address_obj(
|
||||
address_id = address_id,
|
||||
address_dict_obj = contact_obj.address,
|
||||
for_type = 'contact',
|
||||
for_id = contact_id,
|
||||
): pass
|
||||
else: return False
|
||||
elif contact_obj.address:
|
||||
log.info('Creating Address object')
|
||||
if address_create_result := create_address_obj(
|
||||
account_id = account_id,
|
||||
address_dict_obj = contact_obj.address,
|
||||
for_type = 'contact',
|
||||
for_id = contact_id,
|
||||
): pass
|
||||
else: return False
|
||||
else: pass
|
||||
|
||||
log.debug(contact_obj.dict(by_alias=False, exclude_unset=True))
|
||||
|
||||
return True
|
||||
# ### END ### API Contact Methods ### update_contact_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Contact Methods ### create_update_contact_obj() ###
|
||||
@logger_reset
|
||||
def create_update_contact_obj(
|
||||
contact_id: int|str|None, # Ideally the int ID should be passed. This allows for updating of the id_random value.
|
||||
contact_obj: Contact_Base,
|
||||
process_address: bool = False,
|
||||
process_organization: bool = False,
|
||||
) -> bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if contact_id:
|
||||
if contact_id := redis_lookup_id_random(record_id_random=contact_id, table_name='contact'): pass
|
||||
else: return False
|
||||
contact_obj.id = contact_id
|
||||
else:
|
||||
# Insert record now and update later
|
||||
contact_dict_in = contact_obj.dict(by_alias=False, exclude_unset=True, exclude={'address', 'contact', 'organization', 'user'})
|
||||
log.debug(contact_dict_in)
|
||||
contact_in_result = sql_insert(
|
||||
data = contact_dict_in,
|
||||
table_name = 'contact',
|
||||
rm_id_random = True,
|
||||
id_random_length = default_num_bytes,
|
||||
)
|
||||
log.debug(contact_in_result)
|
||||
if isinstance(contact_in_result, bool) and contact_in_result is True:
|
||||
return contact_in_result
|
||||
elif isinstance(contact_in_result, int):
|
||||
contact_id = contact_in_result
|
||||
contact_obj.id = contact_id
|
||||
else:
|
||||
return False # This should not happen.
|
||||
|
||||
# Process address data
|
||||
if process_address and contact_obj.address:
|
||||
address_obj = contact_obj.address
|
||||
address_obj.for_type = 'contact'
|
||||
address_obj.for_id = contact_id
|
||||
address_id = contact_obj.address_id_random
|
||||
address_result = create_update_address_obj(
|
||||
address_id = address_id,
|
||||
address_obj = address_obj,
|
||||
)
|
||||
log.debug(address_result)
|
||||
if isinstance(address_result, bool) and address_result is True:
|
||||
pass # Do not need to update contact object.
|
||||
elif isinstance(address_result, bool) and address_result is False:
|
||||
pass # Do not need to update contact object.
|
||||
elif isinstance(address_result, int):
|
||||
contact_obj.address_id = address_result
|
||||
else:
|
||||
log.warning('Something may have gone wrong while trying to create or update a address.')
|
||||
|
||||
# Process contact data
|
||||
contact_dict_up = contact_obj.dict(by_alias=False, exclude_unset=True, exclude={'address'})
|
||||
log.debug(contact_dict_up)
|
||||
|
||||
# Update record
|
||||
contact_up_result = sql_update(
|
||||
data = contact_dict_up,
|
||||
table_name = 'contact',
|
||||
rm_id_random = True,
|
||||
)
|
||||
log.debug(contact_up_result)
|
||||
if isinstance(contact_up_result, bool) and contact_up_result is True:
|
||||
return contact_id
|
||||
elif isinstance(contact_up_result, bool) and contact_up_result is False:
|
||||
return False
|
||||
elif isinstance(contact_up_result, int):
|
||||
return contact_up_result
|
||||
else:
|
||||
return False
|
||||
# ### END ### API Contact Methods ### create_update_contact_obj() ###
|
||||
279
app/methods/data_store_methods.py
Normal file
279
app/methods/data_store_methods.py
Normal file
@@ -0,0 +1,279 @@
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_enable_part, sql_insert, sql_limit_offset_part, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.methods.event_cfg_methods import load_event_cfg_obj
|
||||
from app.methods.event_location_methods import load_event_location_obj
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
from app.models.data_store_models import Data_Store_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Data Store Methods ### load_data_store_obj() ###
|
||||
# Updated 2022-03-11
|
||||
@logger_reset
|
||||
def load_data_store_obj(
|
||||
data_store_id: int,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 10,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
) -> Data_Store_Base|dict|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if data_store_rec := sql_select(table_name='v_data_store', record_id=data_store_id): pass
|
||||
else: return False
|
||||
|
||||
log.debug(data_store_rec)
|
||||
|
||||
try:
|
||||
data_store_obj = Data_Store_Base(**data_store_rec)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
log.debug(data_store_obj)
|
||||
|
||||
if model_as_dict:
|
||||
return data_store_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return data_store_obj
|
||||
# ### END ### API Data Store Methods ### load_data_store_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Data Store Methods ### load_data_store_obj_w_code() ###
|
||||
# NOTE: This is customized to look for records with or without an account_id and some code. By default only the first sorted result will be returned.
|
||||
# NOTE: By default the first sorted result should be the one for a specific account with some code. If a result with a null account_id and some code is found it will be returned if no account_id specific results are found.
|
||||
# Updated 2022-03-11
|
||||
@logger_reset
|
||||
def load_data_store_obj_w_code(
|
||||
account_id: int,
|
||||
code: str,
|
||||
for_type: int = None,
|
||||
for_id: int = None,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 1,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True, # NOTE: For now this is ignored
|
||||
exclude_unset: bool = True, # NOTE: For now this is ignored
|
||||
model_as_dict: bool = False, # NOTE: For now this is ignored
|
||||
) -> Data_Store_Base|dict|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
log.info(f'Getting Data Store record with code: {code} for Account ID: {account_id} and For Type: {for_type} and For ID: {for_id}')
|
||||
|
||||
data = {}
|
||||
data['account_id'] = account_id
|
||||
data['code'] = code
|
||||
data['for_type'] = for_type
|
||||
data['for_id'] = for_id
|
||||
|
||||
log.debug(data)
|
||||
# log.warning(f'Can we get past this?????????? {code}')
|
||||
# if for_id := redis_lookup_id_random(record_id_random=for_id, table_name=for_type): pass
|
||||
# else: return False
|
||||
|
||||
if for_type and for_id:
|
||||
sql_for_type_id = 'AND `data_store`.for_type = :for_type AND `data_store`.for_id = :for_id'
|
||||
else:
|
||||
sql_for_type_id = 'AND `data_store`.for_type IS NULL AND `data_store`.for_id IS NULL'
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='data_store', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
log.debug(data)
|
||||
|
||||
sql = f"""
|
||||
SELECT *
|
||||
FROM `v_data_store` AS `data_store`
|
||||
WHERE
|
||||
(
|
||||
`data_store`.account_id = :account_id
|
||||
OR `data_store`.account_id IS NULL
|
||||
)
|
||||
AND `data_store`.code = :code
|
||||
{sql_for_type_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `data_store`.account_id DESC, `data_store`.created_on DESC, `data_store`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(sql)
|
||||
|
||||
|
||||
if data_store_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
data_store_rec_li = data_store_rec_li_result
|
||||
else: # [] or False
|
||||
data_store_rec_li = data_store_rec_li_result
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.info(f'No Data Store records found with code: {code} for Account ID: {account_id} and For Type: {for_type} and For ID: {for_id}')
|
||||
|
||||
log.debug(data_store_rec_li_result)
|
||||
|
||||
data_store_obj_li = []
|
||||
if data_store_rec_li:
|
||||
for data_store_rec in data_store_rec_li:
|
||||
try:
|
||||
data_store_obj = Data_Store_Base(**data_store_rec)
|
||||
data_store_obj_li.append(data_store_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
data_store_obj_li.append(None)
|
||||
# return False
|
||||
log.debug(data_store_obj)
|
||||
else: pass
|
||||
|
||||
log.info(f'Found {len(data_store_obj_li)} Data Store records with code: {code} for Account ID: {account_id} and For Type: {for_type} and For ID: {for_id}')
|
||||
log.debug(data_store_obj_li)
|
||||
return data_store_obj_li
|
||||
# ### END ### API Data Store Methods ### load_data_store_obj_w_code() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Data Store Methods ### get_data_store_rec_list() ###
|
||||
# Updated 2022-03-11
|
||||
@logger_reset
|
||||
def get_data_store_rec_list(
|
||||
account_id: int,
|
||||
for_type: str, # 'account' is a special case
|
||||
for_id: int,
|
||||
person_id: int = None,
|
||||
user_id: int = None,
|
||||
code: str = None,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# if for_type and for_id:
|
||||
# if for_id := redis_lookup_id_random(record_id_random=for_id, table_name=for_type): pass
|
||||
# else: return False
|
||||
|
||||
if account_id:
|
||||
sql_account_id = f'`data_store`.account_id = :account_id'
|
||||
# if code:
|
||||
# sql_code = f'`data_store`.code = :code'
|
||||
|
||||
data = {}
|
||||
data['account_id'] = account_id
|
||||
data['code'] = code
|
||||
# data['for_type'] = for_type
|
||||
# data['for_id'] = for_id
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='data_store', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
sql = f"""
|
||||
SELECT `data_store`.id AS 'data_store_id', `data_store`.id_random AS 'data_store_id_random'
|
||||
FROM `v_data_store` AS `data_store`
|
||||
WHERE
|
||||
{sql_account_id}
|
||||
|
||||
{sql_enabled}
|
||||
ORDER BY `data_store`.created_on DESC, `data_store`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if data_store_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
data_store_rec_li = data_store_rec_li_result
|
||||
else: # [] or False
|
||||
data_store_rec_li = data_store_rec_li_result
|
||||
|
||||
log.debug(data_store_rec_li_result)
|
||||
|
||||
return data_store_rec_li
|
||||
# ### END ### API Data Store Methods ### get_data_store_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Data Store Methods ### create_update_data_store_obj() ###
|
||||
# Updated 2022-03-11
|
||||
def create_update_data_store_obj(
|
||||
data_store_dict_obj: Data_Store_Base|dict,
|
||||
data_store_id: int|str = None,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_outline: bool = False,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
log.info('Checking requirements...')
|
||||
if data_store_id:
|
||||
log.info(f'Data Store ID passed. Update existing Data Store. Data Store ID: {data_store_id}')
|
||||
|
||||
if data_store_id := redis_lookup_id_random(record_id_random=data_store_id, table_name='data_store'): pass
|
||||
else:
|
||||
log.error('Data Store ID passed but is invalid. Failed requirement.')
|
||||
return False
|
||||
else:
|
||||
log.info('No Data Store ID passed. Create new Data Store. Required: None; Optional: Account ID, For Type, For ID, Person ID, User ID')
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
elif account_id is None: pass
|
||||
else:
|
||||
log.warning('Missing or invalid Account ID passed. Failed requirement.')
|
||||
log.info(f'Account ID: {account_id}')
|
||||
return False
|
||||
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(data_store_dict_obj))
|
||||
if isinstance(data_store_dict_obj, dict):
|
||||
data_store_dict = data_store_dict_obj
|
||||
if data_store_id:
|
||||
data_store_dict['data_store_id'] = data_store_id
|
||||
if account_id:
|
||||
account_dict['account_id'] = account_id
|
||||
try:
|
||||
data_store_obj = Data_Store_Base(**data_store_dict)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
data_store_obj = data_store_dict_obj
|
||||
if data_store_id:
|
||||
# NOTE: Can't update the ID alias if it was never set.
|
||||
data_store_obj.id = data_store_id
|
||||
if account_id:
|
||||
data_store_obj.account_id = account_id
|
||||
log.debug(data_store_obj)
|
||||
|
||||
data_store_dict = data_store_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'account', 'created_on', 'updated_on'})
|
||||
|
||||
# ### SECTION ### Process data
|
||||
if data_store_id:
|
||||
if data_store_dict_up_result := sql_update(data=data_store_dict, table_name='data_store', rm_id_random=True): pass
|
||||
else:
|
||||
log.warning(f'Data Store not updated. Data Store ID: {data_store_id}')
|
||||
log.debug(data_store_dict_up_result)
|
||||
return False
|
||||
log.debug(data_store_dict_up_result)
|
||||
else:
|
||||
if data_store_dict_in_result := sql_insert(data=data_store_dict, table_name='data_store', rm_id_random=True, id_random_length=8): pass
|
||||
else:
|
||||
log.warning(f'Data Store not created.')
|
||||
log.debug(data_store_dict_in_result)
|
||||
return False
|
||||
log.debug(data_store_dict_in_result)
|
||||
|
||||
data_store_id = data_store_dict_in_result
|
||||
|
||||
data_store_outline = {}
|
||||
data_store_outline['data_store_id'] = data_store_id
|
||||
|
||||
if return_outline:
|
||||
log.debug(f'Returning the Data Store Outline: {data_store_outline}')
|
||||
return data_store_outline
|
||||
else:
|
||||
log.debug(f'Returning the Data Store ID: {data_store_id}')
|
||||
return data_store_id
|
||||
# ### END ### API Data Store Methods ### create_update_data_store_obj() ###
|
||||
558
app/methods/e_confex_methods.py
Normal file
558
app/methods/e_confex_methods.py
Normal file
@@ -0,0 +1,558 @@
|
||||
import datetime, json, os, pprint, pytz, random, requests, shutil, string, time
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.config import settings
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.methods.event_file_methods import create_event_file_obj
|
||||
from app.methods.hosted_file_methods import create_hosted_file_obj, load_hosted_file_obj, save_file, save_file_to_hosted_file
|
||||
|
||||
from app.models.hosted_file_models import Hosted_File_Base
|
||||
from app.models.event_file_models import Event_File_Base
|
||||
|
||||
|
||||
api = {}
|
||||
# api['base_url'] = 'https://aapor.confex.com/aapor/20xx/meetingapi.cgi/[object]/[id]'
|
||||
api['base_url'] = 'https://aapor.confex.com/aapor/2024/meetingapi.cgi'
|
||||
api['headers'] = { 'Content-Type': 'application/json;charset=UTF-8' }
|
||||
api['username'] = None
|
||||
api['password'] = None
|
||||
|
||||
|
||||
# ### BEGIN ### API External Confex Methods ### get_event_session_list() ###
|
||||
# Updated 2023-04-11
|
||||
@logger_reset
|
||||
def get_event_session_list(
|
||||
):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# if result := authenticate():
|
||||
# log.debug(result)
|
||||
# else:
|
||||
# return False
|
||||
|
||||
endpoint = '/Session'
|
||||
uri = api['base_url']+endpoint
|
||||
params = {}
|
||||
|
||||
confex_session_list = None
|
||||
|
||||
try_request = True
|
||||
max_tries = 5
|
||||
try_count = 0
|
||||
while try_request and try_count <= max_tries:
|
||||
try_count = try_count + 1
|
||||
|
||||
resp = requests.get(url=uri, params=params, headers=api['headers'])
|
||||
|
||||
log.debug(f'Status Code: {resp.status_code}')
|
||||
log.debug(f'Headers: {resp.headers}')
|
||||
# log.debug(f'Encoding: {resp.encoding}')
|
||||
# log.debug('Text:')
|
||||
# log.debug(resp.text)
|
||||
# log.debug(resp.json())
|
||||
|
||||
if resp.status_code == 200:
|
||||
log.info('Status 200')
|
||||
log.debug(resp.json())
|
||||
|
||||
confex_session_list_raw = resp.json() # .get('data').get('dataList')[0]
|
||||
# log.debug(confex_session_list_raw)
|
||||
|
||||
confex_session_list = confex_session_list_raw
|
||||
log.debug(confex_session_list)
|
||||
|
||||
try_request = False
|
||||
elif resp.status_code == 404:
|
||||
log.info('No results returned (status 404)')
|
||||
try_request = False
|
||||
confex_session_list = None
|
||||
elif resp.status_code == 429:
|
||||
log.warning('Hit rate limit. Sleeping for .1 seconds...')
|
||||
time.sleep(.1)
|
||||
try_request = True
|
||||
confex_session_list = False
|
||||
else:
|
||||
log.info('Not trying again')
|
||||
try_request = False
|
||||
confex_session_list = False
|
||||
|
||||
log.warning('Something may have gone wrong during the request.')
|
||||
|
||||
# log.warning('Something may have gone wrong. Setting the API app_user_token_datetime value to None to re-authenticate with Confex on the next request.')
|
||||
# api['app_user_token_datetime'] = None # Resetting this just in case the App and or User token expired.
|
||||
|
||||
return confex_session_list
|
||||
# ### END ### API External Confex Methods ### get_event_session_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API External Confex Methods ### get_event_session_detail() ###
|
||||
# Updated 2023-04-11
|
||||
@logger_reset
|
||||
def get_event_session_detail(
|
||||
confex_session_id: str, # actually an auto number
|
||||
):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# if result := authenticate():
|
||||
# log.debug(result)
|
||||
# else:
|
||||
# return False
|
||||
|
||||
endpoint = f'/Session/{confex_session_id}'
|
||||
uri = api['base_url']+endpoint
|
||||
params = {}
|
||||
|
||||
confex_session_detail = None
|
||||
|
||||
try_request = True
|
||||
max_tries = 5
|
||||
try_count = 0
|
||||
while try_request and try_count <= max_tries:
|
||||
try_count = try_count + 1
|
||||
|
||||
resp = requests.get(url=uri, params=params, headers=api['headers'])
|
||||
|
||||
log.debug(f'Status Code: {resp.status_code}')
|
||||
log.debug(f'Headers: {resp.headers}')
|
||||
# log.debug(f'Encoding: {resp.encoding}')
|
||||
# log.debug('Text:')
|
||||
# log.debug(resp.text)
|
||||
# log.debug(resp.json())
|
||||
|
||||
if resp.status_code == 200:
|
||||
log.info('Status 200')
|
||||
log.debug(resp.json())
|
||||
|
||||
confex_session_detail_raw = resp.json() # .get('data').get('dataList')[0]
|
||||
# log.debug(confex_session_detail_raw)
|
||||
|
||||
confex_session_detail = confex_session_detail_raw
|
||||
log.debug(confex_session_detail)
|
||||
|
||||
try_request = False
|
||||
elif resp.status_code == 404:
|
||||
log.info('No results returned (status 404)')
|
||||
try_request = False
|
||||
confex_session_detail = None
|
||||
elif resp.status_code == 429:
|
||||
log.warning('Hit rate limit. Sleeping for .1 seconds...')
|
||||
time.sleep(.1)
|
||||
try_request = True
|
||||
confex_session_detail = False
|
||||
else:
|
||||
log.info('Not trying again')
|
||||
try_request = False
|
||||
confex_session_detail = False
|
||||
|
||||
log.warning('Something may have gone wrong during the request.')
|
||||
|
||||
# log.warning('Something may have gone wrong. Setting the API app_user_token_datetime value to None to re-authenticate with Confex on the next request.')
|
||||
# api['app_user_token_datetime'] = None # Resetting this just in case the App and or User token expired.
|
||||
|
||||
return confex_session_detail
|
||||
# ### END ### API External Confex Methods ### get_event_session_detail() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API External Confex Methods ### get_event_presentation_detail() ###
|
||||
# Updated 2023-04-11
|
||||
@logger_reset
|
||||
def get_event_presentation_detail(
|
||||
confex_session_id: str,
|
||||
confex_presentation_id: str, # similar to 'Paper/99999'
|
||||
):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# if result := authenticate():
|
||||
# log.debug(result)
|
||||
# else:
|
||||
# return False
|
||||
|
||||
# endpoint = f'/Session/{confex_session_id}/{confex_presentation_id}'
|
||||
endpoint = f'/{confex_presentation_id}'
|
||||
uri = api['base_url']+endpoint
|
||||
params = {}
|
||||
|
||||
confex_presentation_detail = None
|
||||
|
||||
try_request = True
|
||||
max_tries = 5
|
||||
try_count = 0
|
||||
while try_request and try_count <= max_tries:
|
||||
try_count = try_count + 1
|
||||
|
||||
resp = requests.get(url=uri, params=params, headers=api['headers'])
|
||||
|
||||
log.debug(f'Status Code: {resp.status_code}')
|
||||
log.debug(f'Headers: {resp.headers}')
|
||||
# log.debug(f'Encoding: {resp.encoding}')
|
||||
# log.debug('Text:')
|
||||
# log.debug(resp.text)
|
||||
# log.debug(resp.json())
|
||||
|
||||
if resp.status_code == 200:
|
||||
log.info('Status 200')
|
||||
log.debug(resp.json())
|
||||
|
||||
confex_presentation_detail_raw = resp.json() # .get('data').get('dataList')[0]
|
||||
# log.debug(confex_presentation_detail_raw)
|
||||
|
||||
confex_presentation_detail = confex_presentation_detail_raw
|
||||
log.debug(confex_presentation_detail)
|
||||
|
||||
try_request = False
|
||||
elif resp.status_code == 404:
|
||||
log.warning('No results returned (status 404)')
|
||||
try_request = False
|
||||
confex_presentation_detail = None
|
||||
elif resp.status_code == 429:
|
||||
log.warning('Hit rate limit. Sleeping for .1 seconds...')
|
||||
time.sleep(.1)
|
||||
try_request = True
|
||||
confex_presentation_detail = False
|
||||
else:
|
||||
log.warning('Not trying again')
|
||||
try_request = False
|
||||
confex_presentation_detail = False
|
||||
|
||||
log.warning('Something may have gone wrong during the request.')
|
||||
|
||||
# log.warning('Something may have gone wrong. Setting the API app_user_token_datetime value to None to re-authenticate with Confex on the next request.')
|
||||
# api['app_user_token_datetime'] = None # Resetting this just in case the App and or User token expired.
|
||||
|
||||
return confex_presentation_detail
|
||||
# ### END ### API External Confex Methods ### get_event_presentation_detail() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API External Confex Methods ### get_event_presenter_detail() ###
|
||||
# Updated 2023-04-11
|
||||
@logger_reset
|
||||
def get_event_presenter_detail(
|
||||
confex_session_id: str,
|
||||
confex_presentation_id: str, # similar to 'Paper/99999'
|
||||
confex_presenter_id: str, # similar to 'Person/99999'
|
||||
):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# if result := authenticate():
|
||||
# log.debug(result)
|
||||
# else:
|
||||
# return False
|
||||
|
||||
endpoint = f'/Session/{confex_session_id}/{confex_presentation_id}/{confex_presenter_id}'
|
||||
uri = api['base_url']+endpoint
|
||||
params = {}
|
||||
|
||||
confex_presenter_detail = None
|
||||
|
||||
try_request = True
|
||||
max_tries = 5
|
||||
try_count = 0
|
||||
while try_request and try_count <= max_tries:
|
||||
try_count = try_count + 1
|
||||
|
||||
resp = requests.get(url=uri, params=params, headers=api['headers'])
|
||||
|
||||
log.debug(f'Status Code: {resp.status_code}')
|
||||
log.debug(f'Headers: {resp.headers}')
|
||||
# log.debug(f'Encoding: {resp.encoding}')
|
||||
# log.debug('Text:')
|
||||
# log.debug(resp.text)
|
||||
# log.debug(resp.json())
|
||||
|
||||
if resp.status_code == 200:
|
||||
log.info('Status 200')
|
||||
log.debug(resp.json())
|
||||
|
||||
confex_presenter_detail_raw = resp.json() # .get('data').get('dataList')[0]
|
||||
# log.debug(confex_presenter_detail_raw)
|
||||
|
||||
confex_presenter_detail = confex_presenter_detail_raw
|
||||
log.debug(confex_presenter_detail)
|
||||
|
||||
try_request = False
|
||||
elif resp.status_code == 404:
|
||||
log.info('No results returned (status 404)')
|
||||
try_request = False
|
||||
confex_presenter_detail = None
|
||||
elif resp.status_code == 429:
|
||||
log.warning('Hit rate limit. Sleeping for .1 seconds...')
|
||||
time.sleep(.1)
|
||||
try_request = True
|
||||
confex_presenter_detail = False
|
||||
else:
|
||||
log.warning('Not trying again')
|
||||
try_request = False
|
||||
confex_presenter_detail = False
|
||||
|
||||
log.warning('Something may have gone wrong during the request.')
|
||||
|
||||
# log.warning('Something may have gone wrong. Setting the API app_user_token_datetime value to None to re-authenticate with Confex on the next request.')
|
||||
# api['app_user_token_datetime'] = None # Resetting this just in case the App and or User token expired.
|
||||
|
||||
return confex_presenter_detail
|
||||
# ### END ### API External Confex Methods ### get_event_presenter_detail() ###
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API External Confex Methods ### get_event_file_detail() ###
|
||||
# Updated 2023-04-30
|
||||
@logger_reset
|
||||
def get_event_file_detail(
|
||||
confex_file_id: str, # similar to 'FileMap/Paper1928_Presentation2'
|
||||
):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
endpoint = f'/{confex_file_id}'
|
||||
uri = api['base_url']+endpoint
|
||||
params = {}
|
||||
|
||||
confex_file_detail = None
|
||||
|
||||
try_request = True
|
||||
max_tries = 5
|
||||
try_count = 0
|
||||
while try_request and try_count <= max_tries:
|
||||
try_count = try_count + 1
|
||||
|
||||
resp = requests.get(url=uri, params=params, headers=api['headers'])
|
||||
|
||||
log.debug(f'Status Code: {resp.status_code}')
|
||||
log.debug(f'Headers: {resp.headers}')
|
||||
|
||||
if resp.status_code == 200:
|
||||
log.info('Status 200')
|
||||
log.debug(resp.json())
|
||||
|
||||
confex_file_detail_raw = resp.json()
|
||||
# log.debug(confex_file_detail_raw)
|
||||
|
||||
confex_file_detail = confex_file_detail_raw
|
||||
log.debug(confex_file_detail)
|
||||
|
||||
try_request = False
|
||||
elif resp.status_code == 404:
|
||||
log.warning('No results returned (status 404)')
|
||||
try_request = False
|
||||
confex_file_detail = None
|
||||
elif resp.status_code == 429:
|
||||
log.warning('Hit rate limit. Sleeping for .1 seconds...')
|
||||
time.sleep(.1)
|
||||
try_request = True
|
||||
confex_file_detail = False
|
||||
else:
|
||||
log.warning('Not trying again')
|
||||
try_request = False
|
||||
confex_file_detail = False
|
||||
|
||||
log.warning('Something may have gone wrong during the request.')
|
||||
|
||||
return confex_file_detail
|
||||
# ### END ### API External Confex Methods ### get_event_file_detail() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API External Confex Methods ### get_event_slot_data() ###
|
||||
# Updated 2023-05-01
|
||||
@logger_reset
|
||||
def get_event_slot_data(
|
||||
confex_slot_id: str, # similar to 'SlotData/Session1110_Slot119'
|
||||
):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
endpoint = f'/{confex_slot_id}'
|
||||
uri = api['base_url']+endpoint
|
||||
params = {}
|
||||
|
||||
confex_slot_data = None
|
||||
|
||||
try_request = True
|
||||
max_tries = 5
|
||||
try_count = 0
|
||||
while try_request and try_count <= max_tries:
|
||||
try_count = try_count + 1
|
||||
|
||||
resp = requests.get(url=uri, params=params, headers=api['headers'])
|
||||
|
||||
log.debug(f'Status Code: {resp.status_code}')
|
||||
log.debug(f'Headers: {resp.headers}')
|
||||
|
||||
if resp.status_code == 200:
|
||||
log.info('Status 200')
|
||||
log.debug(resp.json())
|
||||
|
||||
confex_slot_data_raw = resp.json()
|
||||
|
||||
confex_slot_data = confex_slot_data_raw
|
||||
log.debug(confex_slot_data)
|
||||
|
||||
try_request = False
|
||||
elif resp.status_code == 404:
|
||||
log.warning('No results returned (status 404)')
|
||||
try_request = False
|
||||
confex_slot_data = None
|
||||
elif resp.status_code == 429:
|
||||
log.warning('Hit rate limit. Sleeping for .1 seconds...')
|
||||
time.sleep(.1)
|
||||
try_request = True
|
||||
confex_slot_data = False
|
||||
else:
|
||||
log.warning('Not trying again')
|
||||
try_request = False
|
||||
confex_slot_data = False
|
||||
|
||||
log.warning('Something may have gone wrong during the request.')
|
||||
|
||||
return confex_slot_data
|
||||
# ### END ### API External Confex Methods ### get_event_slot_data() ###
|
||||
|
||||
|
||||
# Updated 2023-05-01
|
||||
@logger_reset
|
||||
async def get_event_file_save_local(
|
||||
url: str,
|
||||
confex_file_info: dict,
|
||||
account_id: int,
|
||||
link_to_type: str,
|
||||
link_to_id: int,
|
||||
event_id: int = None,
|
||||
event_location_id: int = None,
|
||||
event_presentation_id: int = None,
|
||||
event_presenter_id: int = None,
|
||||
event_session_id: int = None,
|
||||
event_track_id: int = None,
|
||||
) -> None|bool|dict:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
|
||||
# *** Part 1: *** First download the file to tmp and then save the hashed file to hosted_files directory.
|
||||
|
||||
hosted_tmp_path = settings.FILES_PATH['hosted_tmp_root']
|
||||
log.info(f'Hosted Tmp Path: {hosted_tmp_path}')
|
||||
log.debug(shutil.disk_usage(hosted_tmp_path))
|
||||
|
||||
hosted_tmp_path_w_filename = os.path.join(hosted_tmp_path, 'confex', 'confex_temp.file')
|
||||
# hosted_tmp_path_w_filename = os.path.join(hosted_tmp_path, 'confex_temp.file')
|
||||
|
||||
# return True
|
||||
|
||||
# response = requests.get(url)
|
||||
response = requests.get(url, stream=True)
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(response)
|
||||
# log.debug(dir(response))
|
||||
|
||||
# file_obj = open(local_path, 'wb')
|
||||
|
||||
with open(hosted_tmp_path_w_filename, 'wb') as f:
|
||||
for chunk in response.iter_content(chunk_size=1024):
|
||||
if chunk:
|
||||
f.write(chunk)
|
||||
|
||||
# *** Part 2: *** Save the hashed file to hosted_files directory.
|
||||
|
||||
file_info = await save_file_to_hosted_file(
|
||||
file_path = hosted_tmp_path_w_filename,
|
||||
filename = confex_file_info.get('filename'),
|
||||
extension = confex_file_info.get('extension'),
|
||||
account_id = account_id,
|
||||
link_to_type = link_to_type,
|
||||
link_to_id = link_to_id,
|
||||
)
|
||||
|
||||
# *** Part 3: *** Save information to database in hosted_file table (hosted_file_link table will be updated by an event_file table trigger)
|
||||
|
||||
if file_info.get('saved'):
|
||||
# NOTE: Just in case look up in DB based on hash
|
||||
log.info('Look up in DB based on hash...')
|
||||
if hosted_file_sel_result := sql_select(
|
||||
table_name = 'hosted_file',
|
||||
field_name = 'hash_sha256',
|
||||
field_value = file_info['hash_sha256'],
|
||||
):
|
||||
log.warning('Found an existing host_file object_entry in the DB but the file was not found on the server!')
|
||||
# Got existing host_file object_entry!
|
||||
# Odd... the hash was found in the database, but the file had to be copied again.
|
||||
# If this happens then the file on the host server was probably deleted at some point.
|
||||
hosted_file_id = hosted_file_sel_result.get('id', None)
|
||||
hosted_file_id_random = hosted_file_sel_result.get('id_random', None)
|
||||
hosted_file_dict = load_hosted_file_obj(hosted_file_id=hosted_file_id, model_as_dict=True)
|
||||
else:
|
||||
# This is normal since the file was not found on the host server and not found in the DB.
|
||||
# Create a new host_file object entry and new host_file.id_random.
|
||||
file_info['account_id'] = account_id
|
||||
# file_info['account_id_random'] = account_id_random
|
||||
hosted_file_obj = Hosted_File_Base(**file_info)
|
||||
if hosted_file_obj_result := create_hosted_file_obj(hosted_file_obj_new=hosted_file_obj):
|
||||
hosted_file_id = hosted_file_obj_result
|
||||
hosted_file_dict = load_hosted_file_obj(hosted_file_id=hosted_file_id, model_as_dict=True)
|
||||
else:
|
||||
log.warning('For some reason a host_file object entry could not be created.')
|
||||
hosted_file_id = None
|
||||
hosted_file_dict = hosted_file_obj.dict(by_alias=True, exclude_unset=True, exclude={'id', 'id_random'}) # pylint: disable=no-member
|
||||
log.debug(hosted_file_obj_result)
|
||||
log.debug(hosted_file_sel_result)
|
||||
else: return False
|
||||
|
||||
|
||||
# *** Part 4: *** Save information to database in event_file (will trigger an update to hosted_file_link)
|
||||
|
||||
event_file_data = {}
|
||||
event_file_data['hosted_file_id'] = hosted_file_id
|
||||
# event_file_data['hosted_file_id_random'] = hosted_file_id_random
|
||||
|
||||
event_file_data['for_type'] = link_to_type
|
||||
event_file_data['for_id'] = link_to_id
|
||||
|
||||
if event_id:
|
||||
event_file_data['event_id'] = event_id
|
||||
if event_location_id:
|
||||
event_file_data['event_location_id'] = event_location_id
|
||||
if event_presentation_id:
|
||||
event_file_data['event_presentation_id'] = event_presentation_id
|
||||
if event_presenter_id:
|
||||
event_file_data['event_presenter_id'] = event_presenter_id
|
||||
if event_session_id:
|
||||
event_file_data['event_session_id'] = event_session_id
|
||||
if event_track_id:
|
||||
event_file_data['event_track_id'] = event_track_id
|
||||
|
||||
event_file_data['filename'] = file_info.get('filename')
|
||||
event_file_data['extension'] = file_info.get('extension')
|
||||
|
||||
# event_file_data['open_in_os'] = event_file_obj.open_in_os
|
||||
# event_file_data['internal_use'] = event_file_obj.internal_use
|
||||
|
||||
# event_file_data['public_use'] = hosted_file_obj.public_use
|
||||
|
||||
# event_file_data['lu_file_purpose_id'] = hosted_file_obj.lu_file_purpose_id
|
||||
# event_file_data['file_purpose'] = hosted_file_obj.file_purpose
|
||||
|
||||
# event_file_data['public'] = hosted_file_obj.public
|
||||
# event_file_data['hide'] = hosted_file_obj.hide
|
||||
event_file_data['enable'] = True # hosted_file_obj.enable
|
||||
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_file_data)
|
||||
|
||||
try:
|
||||
event_file_obj = Event_File_Base(**event_file_data)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
log.debug(event_file_obj)
|
||||
|
||||
create_event_file_obj_result = create_event_file_obj(event_file_obj_new=event_file_obj)
|
||||
log.debug(create_event_file_obj_result)
|
||||
|
||||
|
||||
return file_info
|
||||
798
app/methods/e_cvent_methods.py
Normal file
798
app/methods/e_cvent_methods.py
Normal file
@@ -0,0 +1,798 @@
|
||||
import datetime, json, pprint, pytz, random, requests, secrets, string, time
|
||||
from requests.auth import HTTPBasicAuth
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset, secure_hash_string, verify_secure_hash_string
|
||||
|
||||
from app.methods.c_idaa_methods import refresh_person_group
|
||||
from app.methods.person_methods import create_person_kiss, get_person_rec_list, get_person_rec_w_external_id, load_person_obj, update_person_kiss
|
||||
from app.methods.membership_person_methods import create_membership_person_obj, update_membership_person_obj
|
||||
|
||||
|
||||
app = {}
|
||||
app['client_id'] = '0oalt6dz82oSbN9ok1t7' # From Cvent Developer Portal
|
||||
app['secret'] = 'gQY96qffZAuB_44k73C_hn_MHeByBS8LXHj1vPRm' # From Cvent Developer Portal
|
||||
|
||||
api = {}
|
||||
api['base_url'] = 'https://api-platform.cvent.com/ea' # Including /ea as the Cvent version. EA = Early Access
|
||||
api['headers'] = {} # { 'Content-Type': content_type, 'Authorization': 'Basic '+str(cvent_authorization_base64) }
|
||||
|
||||
|
||||
# ### BEGIN ### API External Cvent Methods ### get_access_token() ###
|
||||
# Updated 2022-02-01
|
||||
@logger_reset
|
||||
def get_access_token():
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
log.debug(f'API data:\n{api}')
|
||||
|
||||
# api['access_token'] = ''
|
||||
|
||||
if 'access_token' in api:
|
||||
access_token = api.get('access_token')
|
||||
log.debug(f'Cvent Access Token found: {access_token}')
|
||||
else:
|
||||
log.info(f'Cvent Access Token was not found. Will request one.')
|
||||
if 'expire_on' in api and datetime.datetime.now() < api['expire_on']:
|
||||
expire_on = api.get('expire_on')
|
||||
log.debug(f'Cvent Access Token is current: {expire_on}')
|
||||
return api
|
||||
else:
|
||||
expire_on = api.get('expire_on')
|
||||
log.info(f'Cvent Access Token is not current. Requesting a new one. Expired On: {expire_on}')
|
||||
|
||||
endpoint = '/oauth2/token'
|
||||
uri = api['base_url']+endpoint
|
||||
|
||||
data = { 'grant_type': 'client_credentials', 'client_id': app['client_id'] }
|
||||
|
||||
log.debug(f'Oauth Token Request Data:\n{api}')
|
||||
|
||||
try_request = True
|
||||
limit = 0
|
||||
while try_request and limit < 3:
|
||||
limit = limit + 1
|
||||
|
||||
resp = requests.post(url=uri, data=data, auth=HTTPBasicAuth(app['client_id'], app['secret'])) # Sending as HTML form data
|
||||
|
||||
log.debug(f'Status Code: {resp.status_code}')
|
||||
log.debug(f'Headers: {resp.headers}')
|
||||
# log.debug(f'Encoding: {resp.encoding}')
|
||||
log.debug(f'JSON: {resp.json()}')
|
||||
# log.debug('Text:', resp.text)
|
||||
|
||||
response_data = resp.json()
|
||||
log.debug(json.dumps(response_data, indent=2, default=str))
|
||||
|
||||
if 'message' in response_data and response_data['message'] == 'Too Many Requests':
|
||||
log.warning('Hit Cvent rate limit. Sleeping for .5 seconds...')
|
||||
time.sleep(.5)
|
||||
elif 'access_token' in response_data:
|
||||
access_token = response_data.get('access_token')
|
||||
log.info(f'Got a new Access Token {access_token} from Cvent')
|
||||
try_request = False
|
||||
|
||||
api['access_token'] = response_data['access_token']
|
||||
api['expires_in'] = response_data['expires_in']
|
||||
api['token_type'] = response_data['token_type']
|
||||
|
||||
api['expire_on'] = datetime.datetime.now() + datetime.timedelta(seconds=response_data['expires_in'])
|
||||
|
||||
api['headers']['Accept'] = 'application/json'
|
||||
api['headers']['x-api-key'] = app['client_id']
|
||||
api['headers']['Authorization'] = 'Bearer '+api['access_token']
|
||||
|
||||
log.debug(api)
|
||||
|
||||
log.warning('Sleeping for .5 seconds to avoid Cvent rate limit...')
|
||||
time.sleep(.5)
|
||||
|
||||
return api
|
||||
# ### END ### API External Cvent Methods ### get_access_token() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API External Cvent Methods ### get_group_contact_list() ###
|
||||
# Updated 2022-02-09
|
||||
@logger_reset
|
||||
def get_group_contact_list(contact_group_id: str=None):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
get_access_token()
|
||||
|
||||
# Contact Group ID for IDAA Full Mailing List: UUID = '60ef4838-5340-4e2a-9d0a-b4ef310eaa69'
|
||||
|
||||
endpoint = f'/contact-groups/{contact_group_id}/contacts'
|
||||
uri = api['base_url']+endpoint
|
||||
|
||||
params = {}
|
||||
|
||||
try_request = True
|
||||
limit = 0
|
||||
next_token = None
|
||||
cvent_contact_list = []
|
||||
while try_request and limit < 100:
|
||||
limit = limit + 1
|
||||
|
||||
if next_token: params['token'] = next_token
|
||||
resp = requests.get(url=uri, headers=api['headers'], params=params)
|
||||
|
||||
response_data = resp.json()
|
||||
log.debug(json.dumps(response_data, indent=2, default=str))
|
||||
|
||||
if 'message' in response_data and response_data['message'] == 'Too Many Requests':
|
||||
log.warning('Hit Cvent rate limit. Sleeping for .5 seconds...')
|
||||
time.sleep(.5)
|
||||
elif 'paging' in response_data:
|
||||
log.debug(json.dumps(response_data.get('paging'), indent=2, default=str))
|
||||
|
||||
if total_count := response_data.get('paging').get('totalCount'):
|
||||
log.info(f'Found {total_count} Cvent Contact results in the Cvent Group')
|
||||
|
||||
cvent_contact_list = cvent_contact_list + response_data.get('data')
|
||||
|
||||
if next_token := response_data.get('paging').get('nextToken'):
|
||||
log.warning('Sleeping for .25 seconds to avoid Cvent rate limit...')
|
||||
time.sleep(.25)
|
||||
else:
|
||||
try_request = False
|
||||
else:
|
||||
log.info('No Cvent Contact results for Cvent Group')
|
||||
try_request = False
|
||||
next_token = None
|
||||
return None
|
||||
else:
|
||||
log.warning('Unexpected response from Cvent API')
|
||||
return False
|
||||
|
||||
if 'message' in response_data and response_data['message'] == 'Too Many Requests': return False
|
||||
|
||||
return cvent_contact_list
|
||||
# ### END ### API External Cvent Methods ### get_group_contact_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API External Cvent Methods ### get_contact_custom_field_list() ###
|
||||
# Updated 2022-01-31
|
||||
@logger_reset
|
||||
def get_contact_custom_field_list(api):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
endpoint = '/custom-fields'
|
||||
uri = api['base_url']+endpoint
|
||||
|
||||
params = { 'filter': "category eq 'Contact'" }
|
||||
|
||||
resp = requests.get(url=uri, headers=api['headers'], params=params)
|
||||
|
||||
log.debug('Status Code:', resp.status_code)
|
||||
log.debug('Headers:', resp.headers)
|
||||
# log.debug('Encoding:', resp.encoding)
|
||||
log.debug('JSON:', resp.json())
|
||||
# log.debug('Text:', resp.text)
|
||||
|
||||
response_data = resp.json()
|
||||
|
||||
# f = open('contact_custom_field_list.txt', 'w')
|
||||
# f.write(pprint.pformat(response_data, indent=2, width=160))
|
||||
|
||||
return response_data
|
||||
# ### END ### API External Cvent Methods ### get_contact_custom_field_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API External Cvent Methods ### get_contact_list() ###
|
||||
# Updated 2022-01-31
|
||||
@logger_reset
|
||||
def get_contact_list(external_id: str=None, email: str=None):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
get_access_token()
|
||||
|
||||
endpoint = '/contacts'
|
||||
uri = api['base_url']+endpoint
|
||||
|
||||
# External ID for IDAA: UUID = '609ab766-7d79-4a9d-a72c-f126412659ee'
|
||||
# customField.609ab766-7d79-4a9d-a72c-f126412659ee eq external_id
|
||||
|
||||
params = {}
|
||||
if external_id:
|
||||
log.info(f'Looking up Cvent Contcat with External ID: {external_id}')
|
||||
params['filter'] = f"deleted eq 'False' and customField.609ab766-7d79-4a9d-a72c-f126412659ee eq '{external_id}'"
|
||||
elif email:
|
||||
log.info(f'Looking up Cvent Contcat with Email: {email}')
|
||||
params['filter'] = f"deleted eq 'False' and email eq '{email}'"
|
||||
elif external_id is None:
|
||||
log.info(f'Looking up Cvent Contact(s) with empty Cvent custom field for external ID.')
|
||||
params['filter'] = f"deleted eq 'False' and customField.609ab766-7d79-4a9d-a72c-f126412659ee lt '1'"
|
||||
else:
|
||||
log.info(f'Looking up Cvent Contact(s) that have not been marked as deleted.')
|
||||
params['filter'] = f"deleted eq 'False'"
|
||||
|
||||
try_request = True
|
||||
limit = 0
|
||||
while try_request and limit < 3:
|
||||
limit = limit + 1
|
||||
resp = requests.get(url=uri, headers=api['headers'], params=params)
|
||||
|
||||
response_data = resp.json()
|
||||
log.debug(json.dumps(response_data, indent=2, default=str))
|
||||
|
||||
if 'message' in response_data and response_data['message'] == 'Too Many Requests':
|
||||
log.warning('Hit Cvent rate limit. Sleeping for .5 seconds...')
|
||||
time.sleep(.5)
|
||||
else:
|
||||
if 'paging' in response_data:
|
||||
current_token = response_data.get('paging').get('currentToken')
|
||||
total_count = response_data.get('paging').get('totalCount')
|
||||
log.info(f'Found {total_count} results from Cvent Contact list')
|
||||
log.debug(json.dumps(response_data.get('paging'), indent=2, default=str))
|
||||
|
||||
try_request = False
|
||||
|
||||
if 'message' in response_data and response_data['message'] == 'Too Many Requests': return False
|
||||
|
||||
return response_data
|
||||
# ### END ### API External Cvent Methods ### get_contact_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API External Cvent Methods ### get_recent_contact_list() ###
|
||||
# Updated 2022-02-02
|
||||
@logger_reset
|
||||
def get_recent_contact_list(
|
||||
from_created_on = None,
|
||||
to_created_on = None, # datetime.datetime.utcnow(),
|
||||
from_updated_on = None,
|
||||
to_updated_on = None,
|
||||
# get_only = 'created', # created, updated/modified
|
||||
):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
get_access_token()
|
||||
|
||||
endpoint = f'/contacts'
|
||||
uri = api['base_url']+endpoint
|
||||
|
||||
params = {}
|
||||
|
||||
if from_created_on:
|
||||
from_created_on_str = from_created_on.isoformat()
|
||||
log.info(f'From Created On: {from_created_on_str}')
|
||||
if to_created_on:
|
||||
to_created_on_str = to_created_on.isoformat()
|
||||
log.info(f'To Created On: {to_created_on_str}')
|
||||
|
||||
if from_updated_on:
|
||||
from_updated_on_str = from_updated_on.isoformat()
|
||||
log.info(f'From Updated On: {from_updated_on_str}')
|
||||
if to_updated_on:
|
||||
to_updated_on_str = to_updated_on.isoformat()
|
||||
log.info(f'To Updated On: {to_updated_on_str}')
|
||||
|
||||
if from_created_on and from_updated_on and to_created_on and to_updated_on:
|
||||
params['filter'] = f"deleted eq 'False' and (created gt '{from_created_on_str}Z' or lastModified gt '{from_updated_on_str}Z') and (created lt '{to_created_on_str}Z' or lastModified lt '{to_updated_on_str}Z')"
|
||||
elif from_created_on and to_created_on:
|
||||
params['filter'] = f"deleted eq 'False' and created gt '{from_created_on_str}Z' and created lt '{to_created_on_str}Z'"
|
||||
elif from_updated_on and to_updated_on:
|
||||
params['filter'] = f"deleted eq 'False' and lastModified gt '{from_updated_on_str}Z' and lastModified lt '{to_updated_on_str}Z'"
|
||||
elif from_created_on:
|
||||
params['filter'] = f"deleted eq 'False' and created gt '{from_created_on_str}Z'"
|
||||
elif from_updated_on:
|
||||
params['filter'] = f"deleted eq 'False' and lastModified gt '{from_updated_on_str}Z'"
|
||||
else:
|
||||
log.warning('Created On or Updated On is required. Returning False')
|
||||
return False
|
||||
|
||||
try_request = True
|
||||
limit = 0
|
||||
next_token = None
|
||||
cvent_contact_list = []
|
||||
while try_request and limit < 100:
|
||||
limit = limit + 1
|
||||
|
||||
if next_token: params['token'] = next_token
|
||||
resp = requests.get(url=uri, headers=api['headers'], params=params)
|
||||
|
||||
response_data = resp.json()
|
||||
log.debug(json.dumps(response_data, indent=2, default=str))
|
||||
|
||||
if 'message' in response_data and response_data['message'] == 'Too Many Requests':
|
||||
log.warning('Hit Cvent rate limit. Sleeping for .5 seconds...')
|
||||
time.sleep(.5)
|
||||
elif 'paging' in response_data:
|
||||
log.debug(json.dumps(response_data.get('paging'), indent=2, default=str))
|
||||
|
||||
if total_count := response_data.get('paging').get('totalCount'):
|
||||
log.info(f'Found {total_count} Cvent Contact results')
|
||||
|
||||
cvent_contact_list = cvent_contact_list + response_data.get('data')
|
||||
|
||||
if next_token := response_data.get('paging').get('nextToken'):
|
||||
log.warning('Sleeping for .25 seconds to avoid Cvent rate limit...')
|
||||
time.sleep(.25)
|
||||
else:
|
||||
try_request = False
|
||||
else:
|
||||
log.info('No Cvent Contact results')
|
||||
try_request = False
|
||||
next_token = None
|
||||
return None
|
||||
else:
|
||||
log.warning('Unexpected response from Cvent API')
|
||||
return False
|
||||
|
||||
# cvent_contact_list = response_data.get('data')
|
||||
|
||||
# next_token = None
|
||||
# if 'paging' in response_data:
|
||||
# if total_count := response_data.get('paging').get('totalCount'):
|
||||
# log.info(f'Found {total_count} Cvent Contact results')
|
||||
# next_token = response_data.get('paging').get('nextToken')
|
||||
# log.debug(json.dumps(response_data.get('paging'), indent=2, default=str))
|
||||
# else:
|
||||
# log.info('No Cvent Contact results')
|
||||
# next_token = None
|
||||
# return None
|
||||
|
||||
# limit = 0
|
||||
# while next_token and limit < 100:
|
||||
# limit = limit + 1
|
||||
|
||||
# params = {}
|
||||
# params['token'] = next_token
|
||||
# resp = requests.get(url=uri, headers=api['headers'], params=params)
|
||||
|
||||
# response_data = resp.json()
|
||||
# # log.debug(json.dumps(response_data, indent=2, default=str))
|
||||
|
||||
# if 'message' in response_data and response_data['message'] == 'Too Many Requests':
|
||||
# log.warning('Hit Cvent rate limit. Sleeping for .5 seconds...')
|
||||
# time.sleep(.5)
|
||||
# else:
|
||||
# cvent_contact_list = cvent_contact_list + response_data.get('data')
|
||||
|
||||
# if 'paging' in response_data:
|
||||
# next_token = response_data.get('paging').get('nextToken')
|
||||
# log.debug(json.dumps(response_data.get('paging'), indent=2, default=str))
|
||||
|
||||
# log.warning('Sleeping for .25 seconds to avoid Cvent rate limit...')
|
||||
# time.sleep(.25)
|
||||
# else:
|
||||
# next_token = None
|
||||
|
||||
# log.debug(json.dumps(cvent_contact_list, indent=2, default=str))
|
||||
# log.debug(json.dumps(response_data, indent=2, default=str))
|
||||
|
||||
if 'message' in response_data and response_data['message'] == 'Too Many Requests': return False
|
||||
|
||||
return cvent_contact_list
|
||||
# ### END ### API External Cvent Methods ### get_recent_contact_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API External Cvent Methods ### get_contact_id() ###
|
||||
# Updated 2022-02-01
|
||||
@logger_reset
|
||||
def get_contact_id(contact_id: str):
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
get_access_token()
|
||||
|
||||
endpoint = f'/contacts/{contact_id}'
|
||||
uri = api['base_url']+endpoint
|
||||
|
||||
params = {}
|
||||
|
||||
resp = requests.get(url=uri, headers=api['headers'], params=params)
|
||||
|
||||
response_data = resp.json()
|
||||
log.debug(json.dumps(response_data, indent=2, default=str))
|
||||
|
||||
if 'message' in response_data and response_data['message'] == 'Too Many Requests': return False
|
||||
|
||||
return response_data
|
||||
# ### END ### API External Cvent Methods ### get_contact_id() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API External Cvent Methods ### modify_contact_id() ###
|
||||
# Updated 2022-02-01
|
||||
@logger_reset
|
||||
def modify_contact_id(contact_id: str, field_list: list=[], custom_field_id: str=None, custom_field_value: str=None):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
get_access_token()
|
||||
|
||||
if custom_field_id:
|
||||
log.info(f'Updating Cvent Custom Field ID: {custom_field_id}')
|
||||
endpoint = f'/contacts/{contact_id}/custom-fields/{custom_field_id}/answers'
|
||||
elif field_list:
|
||||
log.info(f'Updating Cvent Field List: {field_list}')
|
||||
endpoint = f'/contacts/{contact_id}'
|
||||
else:
|
||||
log.error('Missing required parameters')
|
||||
return False
|
||||
uri = api['base_url']+endpoint
|
||||
|
||||
params = {}
|
||||
|
||||
data = {}
|
||||
if custom_field_id:
|
||||
data['id'] = custom_field_id
|
||||
data['value'] = custom_field_value
|
||||
else:
|
||||
data = field_list
|
||||
data['id'] = contact_id
|
||||
|
||||
try_request = True
|
||||
limit = 0
|
||||
while try_request and limit < 3:
|
||||
limit = limit + 1
|
||||
|
||||
|
||||
if custom_field_id:
|
||||
resp = requests.put(url=uri, headers=api['headers'], params=params, json=data)
|
||||
else:
|
||||
resp = requests.patch(url=uri, headers=api['headers'], params=params, json=data)
|
||||
|
||||
response_data = resp.json()
|
||||
log.debug(json.dumps(response_data, indent=2, default=str))
|
||||
|
||||
if 'message' in response_data and response_data['message'] == 'Too Many Requests':
|
||||
log.warning('Hit Cvent rate limit. Sleeping for .5 seconds...')
|
||||
time.sleep(.5)
|
||||
else:
|
||||
log.info('Updated Cvent Contact ID: {contact_id}')
|
||||
try_request = False
|
||||
|
||||
# log.info('Updated Cvent Contact ID: {contact_id}')
|
||||
# response_data = resp.json()
|
||||
# log.debug(json.dumps(response_data, indent=2, default=str))
|
||||
|
||||
if 'message' in response_data and response_data['message'] == 'Too Many Requests': return False
|
||||
|
||||
return response_data
|
||||
# ### END ### API External Cvent Methods ### modify_contact_id() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API External Cvent Methods ### create_update_aether_person() ###
|
||||
# Updated 2022-02-02
|
||||
@logger_reset
|
||||
def create_update_aether_person(
|
||||
cvent_contact_id: str,
|
||||
cvent_contact_obj: dict,
|
||||
|
||||
account_id: str,
|
||||
person_id: str = None,
|
||||
|
||||
idaa_refresh_person_group: bool = False,
|
||||
|
||||
log_lvl: int = logging.INFO, # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
):
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
# Important variables used more than once.
|
||||
person_external_id = None
|
||||
status = None
|
||||
log.debug(cvent_contact_obj.get('customFields'))
|
||||
if custom_field_list := cvent_contact_obj.get('customFields'): # List
|
||||
for custom_field in custom_field_list:
|
||||
# Get the External ID created by OSIT
|
||||
if custom_field.get('id') == '609ab766-7d79-4a9d-a72c-f126412659ee':
|
||||
# person_data['external_id'] = custom_field.get('value')[0]
|
||||
person_external_id = custom_field.get('value')[0]
|
||||
|
||||
# Get the (Contact) Status created by OSIT
|
||||
if custom_field.get('id') == 'e4e51781-e1ec-4f61-8329-b5d29bec6886':
|
||||
# person_data['external_id'] = custom_field.get('value')[0]
|
||||
status = custom_field.get('value')[0].lower()
|
||||
log.debug(f'Cvent Customer Custom Status: {status}')
|
||||
if status: pass
|
||||
else: status = 'unknown' # Will try to improve this guess in membership section below
|
||||
log.debug(status)
|
||||
|
||||
email = cvent_contact_obj.get('email')
|
||||
membership_person_id = None
|
||||
membership_person_type_id = None
|
||||
|
||||
person_data = {}
|
||||
person_data['external_id'] = person_external_id
|
||||
person_data['external_sys_id'] = cvent_contact_obj.get('sourceId')
|
||||
# person_data['pronouns'] = ???
|
||||
person_data['informal_name'] = cvent_contact_obj.get('nickname')
|
||||
person_data['title_names'] = cvent_contact_obj.get('prefix')
|
||||
person_data['given_name'] = cvent_contact_obj.get('firstName')
|
||||
person_data['middle_name'] = cvent_contact_obj.get('middleName')
|
||||
person_data['family_name'] = cvent_contact_obj.get('lastName')
|
||||
person_data['designations'] = cvent_contact_obj.get('designation')
|
||||
person_data['professional_title'] = cvent_contact_obj.get('title')
|
||||
person_data['affiliations'] = cvent_contact_obj.get('company')
|
||||
person_data['status'] = status
|
||||
person_data['enable'] = True
|
||||
log.debug(person_data)
|
||||
|
||||
contact_data = {}
|
||||
contact_data['email'] = cvent_contact_obj.get('email')
|
||||
contact_data['cc_email'] = cvent_contact_obj.get('ccEmail')
|
||||
contact_data['phone_mobile'] = cvent_contact_obj.get('mobilePhone')
|
||||
contact_data['phone_home'] = cvent_contact_obj.get('homePhone')
|
||||
contact_data['phone_office'] = cvent_contact_obj.get('workPhone')
|
||||
log.debug(contact_data)
|
||||
|
||||
address_data = {}
|
||||
if cvent_contact_obj.get('homeAddress'):
|
||||
address_data['line_1'] = cvent_contact_obj.get('homeAddress').get('address1')
|
||||
address_data['line_2'] = cvent_contact_obj.get('homeAddress').get('address2')
|
||||
address_data['line_3'] = cvent_contact_obj.get('homeAddress').get('address3')
|
||||
address_data['city'] = cvent_contact_obj.get('homeAddress').get('city')
|
||||
address_data['state_province'] = cvent_contact_obj.get('homeAddress').get('region')
|
||||
if cvent_contact_obj.get('homeAddress').get('countryCode') and cvent_contact_obj.get('homeAddress').get('regionCode'):
|
||||
# NOTE: There needs to be a better fix for this. Why does Cvent include the 3 character country code only sometimes???
|
||||
cvent_region_code = cvent_contact_obj.get('homeAddress').get('regionCode').replace('(AUS)', '')
|
||||
country_subdivision_code = cvent_contact_obj.get('homeAddress').get('countryCode') +'-'+ cvent_region_code
|
||||
address_data['country_subdivision_code'] = country_subdivision_code
|
||||
address_data['postal_code'] = cvent_contact_obj.get('homeAddress').get('postalCode')
|
||||
address_data['country_alpha_2_code'] = cvent_contact_obj.get('homeAddress').get('countryCode')
|
||||
address_data['country'] = cvent_contact_obj.get('homeAddress').get('country')
|
||||
address_data['country_alpha_2_code'] = cvent_contact_obj.get('homeAddress').get('countryCode')
|
||||
log.debug(address_data)
|
||||
contact_data['address'] = address_data
|
||||
person_data['contact'] = contact_data
|
||||
|
||||
user_data = {}
|
||||
# user_data['name'] =
|
||||
user_data['username'] = cvent_contact_obj.get('email')
|
||||
user_data['email'] = cvent_contact_obj.get('email')
|
||||
# random_password_string = secrets.token_urlsafe(8)
|
||||
# user_data['password'] = secure_hash_string(string=random_password_string)
|
||||
|
||||
user_data['email_verified'] = True # Assuming this is True because they came from another system where the email address is required.
|
||||
|
||||
user_data['enable'] = True
|
||||
user_data['enable_from'] = datetime.datetime.now(datetime.timezone.utc)
|
||||
user_data['enable_to'] = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=365)
|
||||
|
||||
user_data['super'] = False # This is just not allowed
|
||||
user_data['manager'] = False # This is just not allowed
|
||||
# user_data['administrator'] = False
|
||||
|
||||
user_data['public'] = False
|
||||
user_data['verified'] = True
|
||||
|
||||
person_data['user'] = user_data
|
||||
|
||||
if cvent_contact_obj.get('type'):
|
||||
# NOTE: Should this be renamed to contact_type_id and contact_type_name???
|
||||
cvent_contact_type_id = cvent_contact_obj.get('type').get('id')
|
||||
cvent_contact_type_name = cvent_contact_obj.get('type').get('name')
|
||||
log.info(f'Found Cvent Contact Type Named: {cvent_contact_type_name}')
|
||||
else:
|
||||
cvent_contact_type_id = None
|
||||
cvent_contact_type_name = None
|
||||
|
||||
# 'id': '5EB898D8-C253-482C-A93A-0B6667C26E04', 'name': 'Al-Anon Member'
|
||||
# 'id': 'A20358C5-0F6C-47AF-9843-BA9483A9D767', 'name': 'Al-Anon Non-Member'
|
||||
# 'id': 'A01900AB-496A-48A1-9B04-C2874651227E', 'name': 'Member'
|
||||
# 'id': '65437A15-39C2-4EB5-9AFE-67AF6FE41C27', 'name': 'Non-Member'
|
||||
# 'id': '03622AEE-F586-4AE5-A191-B8372543A8C8', 'name': 'Student Member'
|
||||
# 'id': 'A69FAF20-BF2A-4222-B15B-7B0C7EFBEAA7', 'name': 'Student Non-member'
|
||||
|
||||
# 'id': '54127B4D-E531-4046-AF5C-0F0D71DC39D2', 'name': 'Adult Guest Registration'
|
||||
# 'id': 'C9FA7E47-A925-44AB-B94A-9B3003CA2AC4', 'name': 'Attendee'
|
||||
# 'id': '6F06D6B6-2C23-4EF8-986F-73BF0DB2B229', 'name': "Children's Program with Jerry Moe (7-12 years)"
|
||||
# 'id': 'AADABEF0-3C84-45A2-9D9B-E2CF585D4AE5', 'name': 'General Attendee'
|
||||
# 'id': '96D5B3CC-FD4E-4957-BA71-9CEF388095EF', 'name': 'Guest'
|
||||
# 'id': '71D07118-C24D-4B2E-888D-56AC1B941495', 'name': "IDAA 20's Guest Registration"
|
||||
# 'id': 'DA17F721-9924-43E3-A31F-C567BA96DC64', 'name': 'IDAA Teen (13-19 years)'
|
||||
# 'id': 'C49439B3-5AE6-496F-A0AD-4CCB1A9000E3', 'name': 'Spouse/SO Guest Registration'
|
||||
|
||||
# Currently in use Member Type names for IDAA:
|
||||
# Member Type = Member Contact Type
|
||||
# Al-Anon Member(s) = "Al-Anon Member" and "Al-Anon Non-Member"
|
||||
# Annual Contribution(s) = "Attendee" and "Non-Member"
|
||||
# Doctoral Qualifying Member(s) = "Member" and "Non-Member"
|
||||
# Student Member(s) = "Student Member" and "Student Non-member"
|
||||
# NOTE: "Student Non-member" is NOT "Student Non-Member" (the lowercase m)
|
||||
|
||||
membership_person_data = {}
|
||||
membership_person_type_data = {}
|
||||
# if cvent_contact_type_name:
|
||||
if cvent_contact_obj.get('membership'):
|
||||
if cvent_contact_type_name == 'Al-Anon Member' or cvent_contact_type_name == 'Al-Anon Members':
|
||||
membership_person_type_data['membership_type_id'] = 6
|
||||
membership_person_type_data['product_id'] = 13
|
||||
membership_person_type_data['level'] = 1
|
||||
elif cvent_contact_type_name == 'Annual Contribution' or cvent_contact_type_name == 'Annual Contributions' or cvent_contact_type_name == 'Attendee': # Unsure... making affiliate
|
||||
membership_person_type_data['membership_type_id'] = 8
|
||||
membership_person_type_data['product_id'] = 13
|
||||
membership_person_type_data['level'] = 3
|
||||
elif cvent_contact_type_name == 'Doctoral Qualifying Member' or cvent_contact_type_name == 'Doctoral Qualifying Members' or cvent_contact_type_name == 'Member':
|
||||
membership_person_type_data['membership_type_id'] = 5
|
||||
membership_person_type_data['product_id'] = 4
|
||||
membership_person_type_data['level'] = 1
|
||||
elif cvent_contact_type_name == 'Student Member' or cvent_contact_type_name == 'Student Members':
|
||||
membership_person_type_data['membership_type_id'] = 7
|
||||
membership_person_type_data['product_id'] = 14
|
||||
membership_person_type_data['level'] = 1
|
||||
elif cvent_contact_type_name in ['Al-Anon Non-Member', 'Non-Member', 'Student Non-member', 'Student Non-Member']:
|
||||
membership_person_type_data['membership_type_id'] = 8
|
||||
membership_person_type_data['product_id'] = 13
|
||||
membership_person_type_data['level'] = 3
|
||||
else:
|
||||
log.error(f'Unknown Contact Type Name from Cvent: {cvent_contact_type_name}')
|
||||
cvent_contact_type_id = None
|
||||
cvent_contact_type_name = None
|
||||
|
||||
membership_person_type_data['first_start_on'] = datetime.datetime.strptime(cvent_contact_obj.get('membership').get('joined'), '%Y-%m-%d')
|
||||
if cvent_contact_obj.get('membership').get('lastRenewal'):
|
||||
membership_person_type_data['start_on'] = datetime.datetime.strptime(cvent_contact_obj.get('membership').get('lastRenewal'), '%Y-%m-%d')
|
||||
else:
|
||||
membership_person_type_data['start_on'] = datetime.datetime.strptime(cvent_contact_obj.get('membership').get('joined'), '%Y-%m-%d')
|
||||
membership_person_type_data['end_on'] = datetime.datetime.strptime(cvent_contact_obj.get('membership').get('expiration'), '%Y-%m-%d')
|
||||
membership_person_type_data['last_end_on'] = datetime.datetime.strptime(cvent_contact_obj.get('membership').get('expiration'), '%Y-%m-%d')
|
||||
|
||||
current_datetime = datetime.datetime.now()
|
||||
|
||||
# log.debug(status)
|
||||
# if status == 'unknown':
|
||||
# log.debug(current_datetime)
|
||||
# buffer_datetime = current_datetime - datetime.timedelta(minutes=1440) # 720 min = 12 hours
|
||||
# log.debug(buffer_datetime)
|
||||
# log.debug(membership_person_type_data['first_start_on'])
|
||||
# log.info('Status is unknown. Going to try and make a guess...')
|
||||
# if membership_person_type_data['first_start_on'] < buffer_datetime and membership_person_type_data['end_on'] >= current_datetime:
|
||||
# person_data['status'] = 'approved' # approved and current
|
||||
# elif membership_person_type_data['first_start_on'] < current_datetime and membership_person_type_data['end_on'] < current_datetime:
|
||||
# person_data['status'] = 'approved' # approved but expired
|
||||
# else:
|
||||
# person_data['status'] = 'pending' # likely new?
|
||||
# log.debug(person_data['status'])
|
||||
|
||||
if membership_person_type_data['end_on'] >= current_datetime:
|
||||
membership_person_type_data['lu_membership_type_status_id'] = 5 # 5 = active; expiration is > now
|
||||
else:
|
||||
membership_person_type_data['lu_membership_type_status_id'] = 7 # 7 = inactive; expiration is < now
|
||||
|
||||
membership_person_data['enable'] = True
|
||||
membership_person_type_data['enable'] = True
|
||||
|
||||
membership_person_data['membership_person_type'] = membership_person_type_data
|
||||
# log.debug(json.dumps(membership_person_data, indent=2, default=str))
|
||||
|
||||
# Try to look up using external ID
|
||||
if not person_id and person_external_id:
|
||||
log.info(f'Looking up person with External ID: {person_external_id}')
|
||||
if result := get_person_rec_w_external_id(account_id=account_id, external_id=person_external_id):
|
||||
log.debug(result)
|
||||
person_id = result.get('person_id')
|
||||
log.info(f'Person ID {person_id} found using external ID.')
|
||||
else: pass
|
||||
# If that fails then try to look up using email address
|
||||
if not person_id and email:
|
||||
log.info(f'Looking up person with Email Address: {email}')
|
||||
if result := get_person_rec_list(for_obj_type='account', for_obj_id=account_id, email=email):
|
||||
log.debug(result[0])
|
||||
person_id = result[0].get('person_id')
|
||||
log.info(f'Person ID {person_id} found using email address.')
|
||||
else: pass
|
||||
log.debug(f'Person ID: {person_id}; External ID: {person_external_id}; Email: {email}')
|
||||
|
||||
# ### TESTING BREAK POINT ###
|
||||
# person_data['membership_person'] = membership_person_data
|
||||
# return False
|
||||
# ### TESTING BREAK POINT ###
|
||||
|
||||
# If there is not an external ID for an existing or new person then one needs to be created.
|
||||
if not person_external_id:
|
||||
N = 8
|
||||
random_string = ''.join(random.choices(string.ascii_uppercase + string.digits, k=N))
|
||||
random_string = ''.join(random.SystemRandom().choices(string.ascii_uppercase + string.digits, k=N))
|
||||
# random_string = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(N))
|
||||
log.info(f'Created random string: {random_string}')
|
||||
|
||||
email = cvent_contact_obj.get('email')
|
||||
|
||||
person_external_id = f'{random_string}~{email}'
|
||||
log.info(f'Created new Person External ID: {person_external_id}')
|
||||
person_data['external_id'] = person_external_id
|
||||
|
||||
# NOTE: Update Cvent Contact
|
||||
custom_field_id = '609ab766-7d79-4a9d-a72c-f126412659ee' # IDAA Cvent External ID UUID
|
||||
custom_field_value = [person_external_id]
|
||||
|
||||
log.warning('Sleeping for .5 seconds to avoid Cvent rate limit...')
|
||||
time.sleep(.5)
|
||||
|
||||
contact_mod_result = modify_contact_id(
|
||||
contact_id = cvent_contact_id, # This is the Cvent Contact UUID for a person
|
||||
# field_list = field_list,
|
||||
custom_field_id = custom_field_id,
|
||||
custom_field_value = custom_field_value,
|
||||
)
|
||||
|
||||
if person_id:
|
||||
# ### SECTION ### Load person object to populate the person_data and membership_person_data dicts.
|
||||
person_obj = load_person_obj(person_id=person_id, inc_address=True, inc_contact=True, inc_membership_person=True, inc_membership_person_type=True, inc_user=True)
|
||||
log.debug(person_obj)
|
||||
|
||||
person_data['id'] = person_id
|
||||
person_data['account_id'] = account_id
|
||||
person_data['contact']['id'] = person_obj.contact.id
|
||||
person_data['contact']['address']['id'] = person_obj.contact.address.id
|
||||
if person_obj.user:
|
||||
person_data['user']['id'] = person_obj.user.id
|
||||
|
||||
if person_obj.membership_person:
|
||||
membership_person_id = person_obj.membership_person.id
|
||||
if person_obj.membership_person.membership_person_type:
|
||||
membership_person_type_id = person_obj.membership_person.membership_person_type.id
|
||||
else: membership_person_type_id = None
|
||||
|
||||
if not person_obj.external_id:
|
||||
person_data['external_id'] = person_external_id
|
||||
log.debug(person_data)
|
||||
|
||||
if update_person_kiss(person_id=person_id, person_dict_obj=person_data, set_default_password=False):
|
||||
log.info(f'Updated Person ID: {person_id}')
|
||||
else:
|
||||
log.info(f'Did not update Person ID: {person_id}')
|
||||
else:
|
||||
# ### SECTION ### Create new person and related with the person_data and membership_person_data dicts.
|
||||
|
||||
person_data['account_id'] = account_id
|
||||
person_data['notes'] = 'Created using data from Cvent'
|
||||
random_password_string = secrets.token_urlsafe(8)
|
||||
person_data['user']['password'] = secure_hash_string(string=random_password_string)
|
||||
user_data['notes'] = 'Created using data from Cvent'
|
||||
# other_data = {}
|
||||
# other_data['temp_password'] = random_password_string
|
||||
# person_data['user']['other_json'] = json.dumps(other_data, indent=4)
|
||||
log.debug(person_data)
|
||||
|
||||
if create_person_obj_result := create_person_kiss(account_id=account_id, person_dict_obj=person_data):
|
||||
person_id = create_person_obj_result
|
||||
log.info(f'Created Person ID: {person_id}')
|
||||
else:
|
||||
log.info(f'Did not create Person')
|
||||
|
||||
# ### TESTING BREAK POINT ###
|
||||
# person_data['membership_person'] = membership_person_data
|
||||
# return False
|
||||
# ### TESTING BREAK POINT ###
|
||||
|
||||
if cvent_contact_obj.get('membership'):
|
||||
if cvent_contact_type_id and membership_person_id:
|
||||
# membership_person_id = person_obj.membership_person.id
|
||||
membership_person_data['id'] = membership_person_id
|
||||
membership_person_data['membership_person_type']['id'] = membership_person_type_id
|
||||
if update_membership_person_obj(membership_person_id=membership_person_id, membership_person_dict_obj=membership_person_data):
|
||||
log.info(f'Updated Membership Person ID: {membership_person_id}')
|
||||
else:
|
||||
log.info(f'Did not update Membership Person ID: {membership_person_id}')
|
||||
elif cvent_contact_type_id:
|
||||
if create_membership_person_obj_result := create_membership_person_obj(account_id=account_id, person_id=person_id, membership_person_dict_obj=membership_person_data):
|
||||
membership_person_id = create_membership_person_obj_result
|
||||
log.info(f'Created Membership Person ID: {membership_person_id}')
|
||||
else:
|
||||
log.info(f'Did not create Membership Person')
|
||||
else:
|
||||
membership_person_data = {}
|
||||
else:
|
||||
membership_person_data = {}
|
||||
|
||||
person_data['membership_person'] = membership_person_data
|
||||
log.debug(json.dumps(person_data, indent=2, default=str))
|
||||
|
||||
if idaa_refresh_person_group:
|
||||
refresh_person_group(person_id=person_id)
|
||||
|
||||
# person_obj = load_person_obj(person_id=person_id, inc_address=True, inc_contact=True, inc_membership_person=True, inc_membership_person_type=True, inc_user=True)
|
||||
# log.debug(person_obj)
|
||||
|
||||
return person_id # True
|
||||
# ### END ### API External Cvent Methods ### create_update_aether_person() ###
|
||||
512
app/methods/e_impexium_methods.py
Normal file
512
app/methods/e_impexium_methods.py
Normal file
@@ -0,0 +1,512 @@
|
||||
import datetime, json, pprint, pytz, random, requests, string, time
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
|
||||
headers = { 'Content-Type': 'application/json;charset=UTF-8' }
|
||||
|
||||
app = {}
|
||||
app['user_email'] = 'oneskyit_integration@oneskyit.com'
|
||||
app['user_password'] = 'dAPpHDE6d5vLHjsk'
|
||||
|
||||
app['name'] = 'IshltOneSkyITLIVE'
|
||||
app['key'] = '98yp4fa57mJX6nU4'
|
||||
app['id'] = 'IshltOneSkyITLIVE'
|
||||
app['password'] = '98yp4fa57mJX6nU4'
|
||||
log.debug('App data', app)
|
||||
|
||||
api = {}
|
||||
api['base_url'] = 'https://public.impexium.com/Api/v1' # or https://ishlt.mpxapi.com:443/api/v1 ??
|
||||
api['headers'] = { 'Content-Type': 'application/json;charset=UTF-8' }
|
||||
api['access_token'] = None
|
||||
api['access_token_datetime'] = None # This is NOT generated by Impexium
|
||||
api['app_user_token_datetime'] = None # This is NOT generated by Impexium
|
||||
|
||||
|
||||
# ### BEGIN ### API External Impexium Methods ### get_access_token() ###
|
||||
# Updated 2022-03-23
|
||||
@logger_reset
|
||||
def get_access_token():
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
log.debug(f'App data:\n{app}')
|
||||
log.debug(f'API data:\n{api}')
|
||||
|
||||
endpoint = '/WebApiUrl'
|
||||
uri = api['base_url']+endpoint
|
||||
|
||||
data = { 'AppName': app['name'], 'AppKey': app['key'] }
|
||||
|
||||
resp = requests.post(url=uri, json=data, headers=api['headers'])
|
||||
|
||||
log.debug(f'Status Code: {resp.status_code}')
|
||||
log.debug(f'Headers: {resp.headers}')
|
||||
# log.debug(f'Encoding: {resp.encoding}')
|
||||
if resp.status_code == 200 and resp.json():
|
||||
log.info('Got access token. Setting API header and related...')
|
||||
log.debug(f'JSON: {resp.json()}')
|
||||
else:
|
||||
log.warning('No JSON data found')
|
||||
return False
|
||||
# log.debug('Text:', resp.text)
|
||||
|
||||
response_data = resp.json()
|
||||
log.debug(json.dumps(response_data, indent=2, default=str))
|
||||
|
||||
api['access_token'] = response_data['accessToken']
|
||||
api['headers']['AccessToken'] = response_data['accessToken']
|
||||
api['auth_uri'] = response_data['uri']
|
||||
|
||||
api['access_token_datetime'] = datetime.datetime.utcnow() # This is NOT generated by Impexium
|
||||
|
||||
log.info('Finished setting API access token information.')
|
||||
log.debug(api)
|
||||
|
||||
return True
|
||||
# ### END ### API External Impexium Methods ### get_access_token() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API External Impexium Methods ### authenticate() ###
|
||||
# Updated 2022-03-23
|
||||
@logger_reset
|
||||
def authenticate():
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if api.get('access_token') and api.get('app_user_token_datetime'):
|
||||
log.info(f'Found API Access Token and timestamps: Access={api.get("access_token_datetime")}; App/User={api.get("app_user_token_datetime")}')
|
||||
log.debug(api.get('access_token'))
|
||||
# log.debug(api.get('access_token_datetime'))
|
||||
# log.debug(api.get('app_user_token_datetime'))
|
||||
return True
|
||||
elif api.get('access_token'): # pass
|
||||
log.info('Found API Access Token but no timestamp. Need to authenticate.')
|
||||
log.debug(api.get('access_token'))
|
||||
else:
|
||||
log.warning('Access token not found. Calling get_access_token()...')
|
||||
if result := get_access_token():
|
||||
log.debug(result)
|
||||
else:
|
||||
return False
|
||||
|
||||
log.debug(f'App data:\n{app}')
|
||||
log.debug(f'API data:\n{api}')
|
||||
|
||||
data = { 'AppId': app['id'], 'AppPassword': app['password'], 'AppUserEmail': app['user_email'], 'AppUserPassword': app['user_password'] }
|
||||
|
||||
try_request = True
|
||||
max_tries = 5
|
||||
try_count = 0
|
||||
while try_request and try_count < max_tries:
|
||||
try_count = try_count + 1
|
||||
|
||||
resp = requests.post(url=api['auth_uri'], json=data, headers=api['headers'])
|
||||
|
||||
log.debug(f'Status Code: {resp.status_code}')
|
||||
log.debug(f'Headers: {resp.headers}')
|
||||
# log.debug(f'Encoding: {resp.encoding}')
|
||||
# log.debug('Text:', resp.text)
|
||||
|
||||
if resp.status_code == 200:
|
||||
log.info('Got a result from request')
|
||||
if resp.json():
|
||||
# log.debug(f'JSON: {resp.json()}')
|
||||
response_data = resp.json()
|
||||
log.debug(json.dumps(response_data, indent=2, default=str))
|
||||
else:
|
||||
log.warning('No JSON data found')
|
||||
response_data = None
|
||||
try_request = False
|
||||
elif resp.status_code == 429:
|
||||
log.warning('Hit rate limit. Sleeping for .1 seconds...')
|
||||
time.sleep(.1)
|
||||
try_request = True
|
||||
else:
|
||||
log.error('Unexpected result from request')
|
||||
try_request = False
|
||||
response_data = False
|
||||
|
||||
api['headers']['AppToken'] = response_data['appToken']
|
||||
api['headers']['UserToken'] = response_data['userToken']
|
||||
api['base_url'] = response_data['uri']
|
||||
|
||||
api['app_user_token_datetime'] = datetime.datetime.utcnow() # This is NOT generated by Impexium
|
||||
|
||||
log.debug(api)
|
||||
|
||||
return api
|
||||
# ### END ### API External Impexium Methods ### authenticate() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API External Impexium Methods ### get_custom_fields() ###
|
||||
# Updated 2022-02-18
|
||||
@logger_reset
|
||||
def get_custom_fields(api, name=None, page=1):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
endpoint = f'/Setup/customfields/{page}'
|
||||
uri = api['base_url']+endpoint
|
||||
|
||||
print('Endpoint URI', uri)
|
||||
|
||||
params = {}
|
||||
|
||||
resp = requests.get(url=uri, params=params, headers=api['headers'])
|
||||
|
||||
log.debug(f'Status Code: {resp.status_code}')
|
||||
log.debug(f'Headers: {resp.headers}')
|
||||
# log.debug(f'Encoding: {resp.encoding}')
|
||||
log.debug(f'JSON: {resp.json()}')
|
||||
# log.debug('Text:', resp.text)
|
||||
|
||||
response_data = resp.json()
|
||||
|
||||
custom_field_li = response_data
|
||||
|
||||
return custom_field_li
|
||||
# ### END ### API External Impexium Methods ### get_custom_fields() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API External Impexium Methods ### get_events() ###
|
||||
# Updated 2022-02-18
|
||||
@logger_reset
|
||||
def get_events(page=1):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
endpoint = f'/Events/All/{page}'
|
||||
uri = api['base_url']+endpoint
|
||||
|
||||
print('Endpoint URI', uri)
|
||||
|
||||
params = {}
|
||||
|
||||
resp = requests.get(url=uri, params=params, headers=api['headers'])
|
||||
|
||||
log.debug(f'Status Code: {resp.status_code}')
|
||||
log.debug(f'Headers: {resp.headers}')
|
||||
# log.debug(f'Encoding: {resp.encoding}')
|
||||
log.debug(f'JSON: {resp.json()}')
|
||||
# log.debug('Text:', resp.text)
|
||||
|
||||
response_data = resp.json()
|
||||
|
||||
# pp = pprint.PrettyPrinter(indent=2)
|
||||
# pp.pprint(response_data)
|
||||
# print('**************************')
|
||||
|
||||
event_li = response_data
|
||||
|
||||
return event_li
|
||||
# ### END ### API External Impexium Methods ### get_events() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API External Impexium Methods ### get_event_registrants() ###
|
||||
# Updated 2021-10-07
|
||||
@logger_reset
|
||||
def get_event_registrants(
|
||||
event_code: str,
|
||||
registered_since: datetime.datetime = None,
|
||||
details: bool = False,
|
||||
page: int = 0,
|
||||
# return_all: bool = False
|
||||
):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if result := authenticate():
|
||||
log.debug(result)
|
||||
else:
|
||||
return False
|
||||
|
||||
try_page = True
|
||||
|
||||
if page > 0: # Only get the specific page
|
||||
page_num = page
|
||||
max_page = page
|
||||
else: # Get all of the pages
|
||||
page = 1
|
||||
page_num = 0 # Will actually be the first page
|
||||
max_page = 45 # This may need to be increased again... was 15 then 25
|
||||
impexium_event_registration_list = []
|
||||
while try_page and page_num <= max_page:
|
||||
page_num = page_num + 1
|
||||
log.info(f'Getting page number {page_num} from Impexium... Event Code: {event_code}; Details: {details}; Registered Since: {registered_since}')
|
||||
|
||||
endpoint = f'/Events/{event_code}/Registrations/{page_num}'
|
||||
uri = api['base_url']+endpoint
|
||||
params = { 'includeDetails': details }
|
||||
if registered_since:
|
||||
params['registeredSince'] = registered_since.isoformat()
|
||||
log.debug(params)
|
||||
|
||||
try_request = True
|
||||
max_tries = 5
|
||||
try_count = 0
|
||||
while try_request and try_count <= max_tries:
|
||||
try_count = try_count + 1
|
||||
|
||||
resp = requests.get(url=uri, params=params, headers=api['headers'])
|
||||
|
||||
log.debug(f'Status Code: {resp.status_code}')
|
||||
log.debug(f'Headers: {resp.headers}')
|
||||
# log.debug(f'Encoding: {resp.encoding}')
|
||||
# log.debug('Text:')
|
||||
# log.debug(resp.text)
|
||||
|
||||
if resp.status_code == 200:
|
||||
response_data = resp.json()
|
||||
|
||||
current_page = response_data.get('pageNumber')
|
||||
log.info(f'Impexium response Current Page: {current_page}')
|
||||
|
||||
impexium_event_registration_list = impexium_event_registration_list + response_data.get('dataList')
|
||||
|
||||
try_request = False
|
||||
elif resp.status_code == 404:
|
||||
log.info('No results returned.')
|
||||
try_request = False
|
||||
try_page = False
|
||||
elif resp.status_code == 429:
|
||||
log.warning('Hit rate limit. Sleeping for .1 seconds...')
|
||||
time.sleep(.1)
|
||||
try_request = True
|
||||
response_data = False
|
||||
else:
|
||||
log.info('Not trying again')
|
||||
try_request = False
|
||||
try_page = False
|
||||
impexium_event_registration_list = False
|
||||
|
||||
log.warning('Something may have gone wrong. Setting the API app_user_token_datetime value to None to re-authenticate with Impexium on the next request.')
|
||||
api['app_user_token_datetime'] = None # Resetting this just in case the App and or User token expired.
|
||||
|
||||
return impexium_event_registration_list
|
||||
# ### END ### API Impexium Methods ### get_event_registrants() ###
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API External Impexium Methods ### get_individual_profile() ###
|
||||
# Updated 2022-04-22
|
||||
# NOTE: Without details the results are very basic. Pretty much just their name.
|
||||
# Including details adds the addresses, customFields, emails, memberships, phones, etc
|
||||
@logger_reset
|
||||
def get_individual_profile(
|
||||
individual_id: str,
|
||||
details: bool = False,
|
||||
page = 1 # page: int = 0,
|
||||
):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if result := authenticate():
|
||||
log.debug(result)
|
||||
else:
|
||||
return False
|
||||
|
||||
endpoint = f'/Individuals/Profile/{individual_id}/{page}'
|
||||
uri = api['base_url']+endpoint
|
||||
params = { 'IncludeDetails': details }
|
||||
|
||||
impexium_individual_profile = None
|
||||
|
||||
try_request = True
|
||||
max_tries = 5
|
||||
try_count = 0
|
||||
while try_request and try_count <= max_tries:
|
||||
try_count = try_count + 1
|
||||
|
||||
resp = requests.get(url=uri, params=params, headers=api['headers'])
|
||||
|
||||
log.debug(f'Status Code: {resp.status_code}')
|
||||
log.debug(f'Headers: {resp.headers}')
|
||||
# log.debug(f'Encoding: {resp.encoding}')
|
||||
# log.debug('Text:')
|
||||
# log.debug(resp.text)
|
||||
# log.debug(resp.json())
|
||||
|
||||
if resp.status_code == 200:
|
||||
log.info('Status 200')
|
||||
log.debug(resp.json())
|
||||
|
||||
impexium_individual_profile_raw = resp.json() # .get('data').get('dataList')[0]
|
||||
# log.debug(impexium_individual_profile_raw)
|
||||
|
||||
impexium_individual_profile = impexium_individual_profile_raw.get('dataList')[0]
|
||||
log.debug(impexium_individual_profile)
|
||||
|
||||
try_request = False
|
||||
elif resp.status_code == 404:
|
||||
log.info('No results returned (status 404)')
|
||||
try_request = False
|
||||
impexium_individual_profile = None
|
||||
elif resp.status_code == 429:
|
||||
log.warning('Hit rate limit. Sleeping for .1 seconds...')
|
||||
time.sleep(.1)
|
||||
try_request = True
|
||||
impexium_individual_profile = False
|
||||
else:
|
||||
log.info('Not trying again')
|
||||
try_request = False
|
||||
impexium_event_registration_list = False
|
||||
|
||||
log.warning('Something may have gone wrong. Setting the API app_user_token_datetime value to None to re-authenticate with Impexium on the next request.')
|
||||
api['app_user_token_datetime'] = None # Resetting this just in case the App and or User token expired.
|
||||
|
||||
return impexium_individual_profile
|
||||
# ### END ### API External Impexium Methods ### get_individual_profile() ###
|
||||
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API External Impexium Methods ### get_individual_registrations() ###
|
||||
# Updated 2022-02-18
|
||||
@logger_reset
|
||||
def get_individual_registrations(api, record_number, event_code=None, page=1):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
endpoint = f'/Individuals/{record_number}/Registrations/{page}'
|
||||
uri = api['base_url']+endpoint
|
||||
|
||||
params = { 'eventCode': event_code }
|
||||
|
||||
resp = requests.get(url=uri, params=params, headers=api['headers'])
|
||||
|
||||
log.debug(f'Status Code: {resp.status_code}')
|
||||
log.debug(f'Headers: {resp.headers}')
|
||||
# log.debug(f'Encoding: {resp.encoding}')
|
||||
log.debug(f'JSON: {resp.json()}')
|
||||
# log.debug('Text:', resp.text)
|
||||
|
||||
response_data = resp.json()
|
||||
|
||||
# pp = pprint.PrettyPrinter(indent=2)
|
||||
# pp.pprint(response_data)
|
||||
# print('**************************')
|
||||
|
||||
individual_registraion_li = response_data
|
||||
|
||||
return individual_registraion_li
|
||||
# ### END ### API External Impexium Methods ### get_individual_registrations() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API External Impexium Methods ### get_individual_purchases() ###
|
||||
# Updated 2022-02-18
|
||||
@logger_reset
|
||||
def get_individual_purchases(api, record_number, product_code=None, purchased_since=None, product_category_code=None, page=1):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
endpoint = f'/Individuals/{record_number}/Purchases/{page}'
|
||||
uri = api['base_url']+endpoint
|
||||
|
||||
params = { 'productCode': product_code, 'purchasedSince': purchased_since, 'productCategoryCode': product_category_code }
|
||||
|
||||
resp = requests.get(url=uri, params=params, headers=api['headers'])
|
||||
|
||||
log.debug(f'Status Code: {resp.status_code}')
|
||||
log.debug(f'Headers: {resp.headers}')
|
||||
# log.debug(f'Encoding: {resp.encoding}')
|
||||
log.debug(f'JSON: {resp.json()}')
|
||||
# log.debug('Text:', resp.text)
|
||||
|
||||
response_data = resp.json()
|
||||
|
||||
# pp = pprint.PrettyPrinter(indent=2)
|
||||
# pp.pprint(response_data)
|
||||
# print('**************************')
|
||||
|
||||
individual_purchase_li = response_data
|
||||
|
||||
return individual_purchase_li
|
||||
# ### END ### API External Impexium Methods ### get_individual_purchases() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API External Impexium Methods ### get_individual_custom_fields() ###
|
||||
# Updated 2022-03-23
|
||||
@logger_reset
|
||||
def get_individual_custom_fields(
|
||||
individual_id
|
||||
):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
endpoint = f'/Individuals/{individual_id}/CustomFields'
|
||||
uri = api['base_url']+endpoint
|
||||
params = { }
|
||||
|
||||
impexium_individual_custom_field_list = None
|
||||
|
||||
try_request = True
|
||||
max_tries = 5
|
||||
try_count = 0
|
||||
while try_request and try_count <= max_tries:
|
||||
try_count = try_count + 1
|
||||
|
||||
resp = requests.get(url=uri, params=params, headers=api['headers'])
|
||||
|
||||
log.debug(f'Status Code: {resp.status_code}')
|
||||
log.debug(f'Headers: {resp.headers}')
|
||||
# log.debug(f'Encoding: {resp.encoding}')
|
||||
# log.debug('Text:')
|
||||
# log.debug(resp.text)
|
||||
|
||||
if resp.status_code == 200:
|
||||
log.debug(resp.json)
|
||||
impexium_individual_custom_field_list = resp.json()
|
||||
try_request = False
|
||||
elif resp.status_code == 404:
|
||||
log.info('No results returned.')
|
||||
try_request = False
|
||||
impexium_individual_custom_field_list = []
|
||||
elif resp.status_code == 429:
|
||||
log.warning('Hit rate limit. Sleeping for .1 seconds...')
|
||||
time.sleep(.1)
|
||||
try_request = True
|
||||
impexium_individual_custom_field_list = False
|
||||
else:
|
||||
try_request = False
|
||||
impexium_event_registration_list = False
|
||||
|
||||
return impexium_individual_custom_field_list
|
||||
# ### END ### API External Impexium Methods ### get_individual_custom_fields() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API External Impexium Methods ### get_individual_orders_open() ###
|
||||
# Updated 2022-02-18
|
||||
@logger_reset
|
||||
def get_individual_orders_open(api, record_number, include_line_items=False, from_date=None, to_date=None, page=1):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
endpoint = f'/Individuals/{record_number}/Orders/Open/{page}'
|
||||
uri = api['base_url']+endpoint
|
||||
print(uri)
|
||||
|
||||
params = { 'includeLineItems': include_line_items, 'fromDate': from_date, 'toDate': to_date }
|
||||
|
||||
resp = requests.get(url=uri, params=params, headers=api['headers'])
|
||||
|
||||
log.debug(f'Status Code: {resp.status_code}')
|
||||
log.debug(f'Headers: {resp.headers}')
|
||||
# log.debug(f'Encoding: {resp.encoding}')
|
||||
log.debug(f'JSON: {resp.json()}')
|
||||
# log.debug('Text:', resp.text)
|
||||
|
||||
response_data = resp.json()
|
||||
|
||||
# pp = pprint.PrettyPrinter(indent=2)
|
||||
# pp.pprint(response_data)
|
||||
# print('**************************')
|
||||
|
||||
individual_orders_open_li = response_data
|
||||
|
||||
return individual_orders_open_li
|
||||
# ### END ### API External Impexium Methods ### get_individual_orders_open() ###
|
||||
514
app/methods/event_abstract_methods.py
Normal file
514
app/methods/event_abstract_methods.py
Normal file
@@ -0,0 +1,514 @@
|
||||
import datetime, json
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_delete, sql_insert, sql_select, sql_update, sql_enable_part, sql_limit_offset_part
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
# from app.methods.event_abstract_tracking_methods import get_event_abstract_tracking_rec_list, load_event_abstract_tracking_obj
|
||||
from app.methods.event_person_methods import load_event_person_obj
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
from app.models.event_abstract_models import Event_Abstract_Ext, Event_Abstract_In
|
||||
from app.methods.event_cfg_methods import load_event_cfg_obj
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Abstract Methods ### load_event_abstract_obj() ###
|
||||
# Updated 2023-03-20
|
||||
@logger_reset
|
||||
def load_event_abstract_obj(
|
||||
event_abstract_id: int|str,
|
||||
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
approved: str = 'all', # approved, not_approved, all
|
||||
hidden: str = 'not_hidden', # hidden, not_hidden, all
|
||||
review: str = 'all', # ready, not_ready, all
|
||||
|
||||
inc_event_cfg: bool = False,
|
||||
inc_event_file_list: bool = False,
|
||||
inc_event_person: bool = False,
|
||||
inc_event_person_profile: bool = False,
|
||||
inc_event_presentation_list: bool = False,
|
||||
inc_event_presenter_list: bool = False,
|
||||
inc_hosted_file: bool = False,
|
||||
|
||||
limit: int = 1500,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
) -> Event_Abstract_Ext|dict|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# if event_abstract_id := redis_lookup_id_random(record_id_random=event_abstract_id, table_name='event_abstract'): pass
|
||||
# else: return False
|
||||
|
||||
if event_abstract_rec := sql_select(table_name='v_event_abstract', record_id=event_abstract_id): pass
|
||||
else: return False
|
||||
|
||||
try:
|
||||
event_abstract_obj = Event_Abstract_Ext(**event_abstract_rec)
|
||||
log.debug(event_abstract_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
# Updated 2023-06-28
|
||||
if inc_event_cfg:
|
||||
log.info('Need to include event configuration...')
|
||||
if event_cfg_result := load_event_cfg_obj(
|
||||
event_id = event_abstract_obj.event_id,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
event_abstract_obj.event_cfg = event_cfg_result
|
||||
else: event_abstract_obj.event_cfg = {} # None
|
||||
log.debug(event_abstract_obj.event_cfg)
|
||||
|
||||
# Updated 2023-03-20
|
||||
if inc_event_file_list:
|
||||
# log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.info('Need to include event file list...')
|
||||
|
||||
from app.methods.event_file_methods import get_event_file_rec_list, load_event_file_obj
|
||||
if event_file_rec_list_result := get_event_file_rec_list(
|
||||
for_type = 'event_abstract',
|
||||
for_id = event_abstract_id,
|
||||
# file_purpose_id = event_file_file_purpose_id,
|
||||
# file_purpose = event_file_file_purpose,
|
||||
# priority = event_file_priority,
|
||||
# group = event_file_group,
|
||||
enabled = enabled,
|
||||
limit = limit,
|
||||
):
|
||||
event_file_result_list = []
|
||||
for event_file_rec in event_file_rec_list_result:
|
||||
if load_event_file_result := load_event_file_obj(
|
||||
event_file_id = event_file_rec.get('event_file_id', None),
|
||||
enabled = enabled,
|
||||
inc_hosted_file = inc_hosted_file,
|
||||
# model_as_dict = True,
|
||||
# by_alias = by_alias,
|
||||
# exclude_unset = False,
|
||||
):
|
||||
event_file_result_list.append(load_event_file_result)
|
||||
else:
|
||||
event_file_result_list.append(None)
|
||||
log.debug(event_file_result_list)
|
||||
event_abstract_obj.event_file_list = event_file_result_list
|
||||
elif isinstance(event_file_rec_list_result, list):
|
||||
event_abstract_obj.event_file_list = []
|
||||
else:
|
||||
event_abstract_obj.event_file_list = None
|
||||
|
||||
# Updated 2023-03-20
|
||||
if inc_event_person:
|
||||
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.info('Need to include event person...')
|
||||
|
||||
if event_person_obj := load_event_person_obj(
|
||||
event_person_id = event_abstract_obj.event_person_id,
|
||||
enabled = enabled,
|
||||
# inc_address = inc_address,
|
||||
# inc_contact = inc_contact,
|
||||
# inc_event_abstract = inc_event_abstract,
|
||||
inc_event_person_profile = inc_event_person_profile,
|
||||
# inc_event_registration = inc_event_registration,
|
||||
# inc_person = inc_person,
|
||||
# inc_user = inc_user,
|
||||
):
|
||||
log.debug(event_person_obj)
|
||||
event_abstract_obj.event_person = event_person_obj
|
||||
else:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_person_obj)
|
||||
event_abstract_obj.event_person = None
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
|
||||
# Updated 2023-03-20
|
||||
if inc_event_presenter_list:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.info('Need to include Event Presenter List data...')
|
||||
if event_presenter_rec_list_result := get_event_presenter_rec_list(
|
||||
event_abstract_id = event_abstract_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
hidden = hidden,
|
||||
):
|
||||
event_presenter_result_list = []
|
||||
for event_presenter_rec in event_presenter_rec_list_result:
|
||||
event_presenter_result_list.append(
|
||||
load_event_presenter_obj(
|
||||
event_presenter_id = event_presenter_rec.get('event_presenter_id'),
|
||||
inc_event_person = inc_event_person,
|
||||
)
|
||||
)
|
||||
event_abstract_obj.event_abstract_list = event_abstract_result_list
|
||||
else: event_abstract_obj.event_abstract_list = []
|
||||
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
|
||||
if model_as_dict:
|
||||
return event_abstract_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return event_abstract_obj
|
||||
# ### END ### API Event Abstract Methods ### load_event_abstract_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Abstract Methods ### get_event_abstract_rec_list() ###
|
||||
# Updated 2023-03-20
|
||||
@logger_reset
|
||||
def get_event_abstract_rec_list(
|
||||
event_id: None|str = None,
|
||||
event_person_id: None|str = None,
|
||||
|
||||
abstract_type_code: str = None, # not sure yet
|
||||
|
||||
approved: str = 'all', # not_approved, approved, all
|
||||
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 250,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
elif event_id is None: pass
|
||||
else: return False
|
||||
|
||||
if event_person_id := redis_lookup_id_random(record_id_random=event_person_id, table_name='event_person'): pass
|
||||
elif event_person_id is None: pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
# data['event_id'] = event_id
|
||||
|
||||
if event_id:
|
||||
data['event_id'] = event_id
|
||||
sql_event_id = f'`event_abstract`.event_id = :event_id'
|
||||
else: sql_event_id = '1=1'
|
||||
|
||||
if event_person_id:
|
||||
data['event_person_id'] = event_person_id
|
||||
sql_event_person_id = f'AND `event_abstract`.event_person_id = :event_person_id'
|
||||
else: sql_event_person_id = ''
|
||||
|
||||
if abstract_type_code:
|
||||
data['abstract_type_code'] = abstract_type_code
|
||||
sql_abstract_type_code = f'AND `event_abstract`.abstract_type_code = :abstract_type_code'
|
||||
else: sql_abstract_type_code = ''
|
||||
|
||||
if approved in ['not_approved', 'approved', 'all']:
|
||||
log.info(f'Creating partial SQL string for "approved" check. Printed: {approved}')
|
||||
if approved == 'not_approved':
|
||||
sql_abstract_approved = f'AND (`event_abstract`.approve IS NULL OR `event_abstract`.approved = FALSE)'
|
||||
elif approved == 'approved':
|
||||
sql_abstract_approved = f'AND `event_abstract`.approve = TRUE'
|
||||
elif approved == 'all':
|
||||
sql_abstract_approved = f'AND (`event_abstract`.approve IS NULL OR `event_abstract`.approve IS NOT NULL)'
|
||||
log.debug(sql_abstract_approved)
|
||||
else: sql_abstract_approved = ''
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='event_abstract', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_abstract`.id AS 'event_abstract_id', `event_abstract`.id_random AS 'event_abstract_id_random'
|
||||
FROM `v_event_abstract` AS `event_abstract`
|
||||
WHERE
|
||||
{sql_event_id}
|
||||
{sql_event_person_id}
|
||||
{sql_abstract_type_code}
|
||||
{sql_abstract_approved}
|
||||
{sql_enabled}
|
||||
ORDER BY event_abstract.priority DESC, event_abstract.sort DESC, event_abstract.name ASC, `event_abstract`.created_on DESC, `event_abstract`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(sql)
|
||||
|
||||
if event_abstract_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
event_abstract_rec_li = event_abstract_rec_li_result
|
||||
else: # [] or False
|
||||
event_abstract_rec_li = event_abstract_rec_li_result
|
||||
|
||||
log.debug(event_abstract_rec_li_result)
|
||||
|
||||
return event_abstract_rec_li
|
||||
# ### END ### API Event Abstract Methods ### get_event_abstract_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Abstract Methods ### create_update_event_abstract_obj() ###
|
||||
# Updated 2023-03-22
|
||||
@logger_reset
|
||||
def create_update_event_abstract_obj(
|
||||
event_abstract_obj: Event_Abstract_In,
|
||||
event_abstract_id: int = None,
|
||||
event_id: int = None,
|
||||
event_person_id: int = None,
|
||||
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_outline: bool = False,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
log.info('Checking requirements...')
|
||||
if event_abstract_id:
|
||||
log.info(f'Got: event_abstract_id={event_abstract_id}; Update existing Event Abstract')
|
||||
event_abstract_obj.id = event_abstract_id
|
||||
elif event_id and event_person_id:
|
||||
log.info(f'Got: event_id={event_id}; event_person_id={event_person_id}; Create Event Abstract')
|
||||
event_abstract_obj.event_id = event_id
|
||||
event_abstract_obj.event_person_id = event_person_id
|
||||
else:
|
||||
return False
|
||||
|
||||
log.debug(type(event_abstract_obj))
|
||||
log.debug(event_abstract_obj
|
||||
)
|
||||
|
||||
event_abstract_dict = event_abstract_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event_file_list', 'event_person', 'event_person_list', 'event_presenter_list', 'created_on', 'updated_on'})
|
||||
|
||||
# log.debug(type(event_abstract_dict.get('topics_json', None)))
|
||||
# if 'topics_json' in event_abstract_dict and (isinstance(event_abstract_dict['topics_json'], dict) or isinstance(event_abstract_dict['topics_json'], list)):
|
||||
# log.debug('Need to convert to JSON string')
|
||||
# event_abstract_dict['topics_json'] = json.dumps(event_abstract_dict['topics_json'])
|
||||
# log.debug(event_abstract_dict)
|
||||
|
||||
|
||||
if event_abstract_id:
|
||||
if event_abstract_dict_up_result := sql_update(data=event_abstract_dict, table_name='event_abstract', rm_id_random=True):
|
||||
log.info(f'Event Abstract updated. event_abstract_id={event_abstract_id}')
|
||||
pass
|
||||
else:
|
||||
log.warning(f'Event Abstract not updated. event_abstract_id={event_abstract_id}')
|
||||
log.debug(event_abstract_dict_up_result)
|
||||
return False
|
||||
log.debug(event_abstract_dict_up_result)
|
||||
else:
|
||||
if event_abstract_dict_in_result := sql_insert(data=event_abstract_dict, table_name='event_abstract', rm_id_random=True, id_random_length=None):
|
||||
log.info(f'Event Abstract created. event_abstract_id={event_abstract_dict_in_result}')
|
||||
else:
|
||||
log.warning(f'Event Abstract not created.')
|
||||
log.debug(event_abstract_dict_in_result)
|
||||
return False
|
||||
log.debug(event_abstract_dict_in_result)
|
||||
|
||||
event_abstract_id = event_abstract_dict_in_result # False, None, integer
|
||||
|
||||
event_abstract_outline = {}
|
||||
event_abstract_outline['event_id'] = event_id
|
||||
event_abstract_outline['event_abstract_id'] = event_abstract_id
|
||||
event_abstract_outline['event_person_id'] = event_person_id
|
||||
# event_abstract_outline['event_file_count'] = event_file_count
|
||||
|
||||
if return_outline:
|
||||
log.debug(f'Returning the Event Abstract Outline: {event_abstract_outline}')
|
||||
return event_abstract_outline
|
||||
else:
|
||||
log.debug(f'Returning the Event Abstract ID: {event_abstract_id}')
|
||||
return event_abstract_id
|
||||
# ### END ### API Event Abstract Methods ### create_update_event_abstract_obj() ###
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Abstract Methods ### create_update_event_abstract_obj_old() ###
|
||||
# Updated 2023-03-20
|
||||
@logger_reset
|
||||
def create_update_event_abstract_obj_old(
|
||||
event_abstract_dict_obj: Event_Abstract_In|dict,
|
||||
event_abstract_id: int|str = None,
|
||||
event_id: int|str = None,
|
||||
event_person_id: int|str = None,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_outline: bool = False,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
log.info('Checking requirements...')
|
||||
if event_abstract_id:
|
||||
log.info(f'Event Abstract ID passed. Update existing Event Abstract. Event Abstract ID: {event_abstract_id}')
|
||||
|
||||
if event_abstract_id := redis_lookup_id_random(record_id_random=event_abstract_id, table_name='event_abstract'): pass
|
||||
else:
|
||||
log.error('Event Abstract ID passed but is invalid. Failed requirement.')
|
||||
return False
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'):
|
||||
log.info(f'Event ID: {event_id}')
|
||||
elif event_id is None:
|
||||
log.error('Missing Event ID. Not required. Ignoring.')
|
||||
log.info(f'Event ID: {event_id}')
|
||||
else:
|
||||
log.error('Invalid Event ID passed. Not required. But not ignoring since it is likely invalid.')
|
||||
log.info(f'Event ID: {event_id}')
|
||||
return False
|
||||
else:
|
||||
log.info('No Event Abstract ID passed. Create new Event Abstract. Required: Event ID')
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'):
|
||||
log.info(f'Event ID: {event_id}')
|
||||
elif event_id is None:
|
||||
log.error('Missing Event ID. Failed requirement.')
|
||||
log.info(f'Event ID: {event_id}')
|
||||
return False
|
||||
else:
|
||||
log.error('Invalid Event ID passed. Failed requirement.')
|
||||
log.info(f'Event ID: {event_id}')
|
||||
return False
|
||||
# else:
|
||||
# log.error('Missing or invalid Event ID passed. Failed requirement.')
|
||||
# log.info(f'Event ID: {event_id}')
|
||||
# return False
|
||||
|
||||
log.debug(type(event_abstract_dict_obj))
|
||||
if isinstance(event_abstract_dict_obj, dict):
|
||||
event_abstract_dict = event_abstract_dict_obj
|
||||
if event_abstract_id:
|
||||
event_abstract_dict['event_abstract_id'] = event_abstract_id
|
||||
if event_id:
|
||||
event_abstract_dict['event_id'] = event_id
|
||||
if event_person_id:
|
||||
event_abstract_dict['event_person_id'] = event_person_id
|
||||
try:
|
||||
event_abstract_obj = Event_Abstract_In(**event_abstract_dict)
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_abstract_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
event_abstract_obj = event_abstract_dict_obj
|
||||
if event_abstract_id:
|
||||
# NOTE: Can't update the ID alias if it was never set.
|
||||
event_abstract_obj.id = event_abstract_id
|
||||
if event_id:
|
||||
event_abstract_obj.event_id = event_id
|
||||
if event_person_id:
|
||||
event_abstract_obj.event_person_id = event_person_id
|
||||
|
||||
event_abstract_dict = event_abstract_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event_person', 'event_person_list', 'created_on', 'updated_on'})
|
||||
|
||||
if event_abstract_id:
|
||||
if event_abstract_dict_up_result := sql_update(data=event_abstract_dict, table_name='event_abstract', rm_id_random=True): pass
|
||||
else:
|
||||
log.warning(f'Event Abstract not updated. Event Abstract ID: {event_abstract_id}')
|
||||
log.debug(event_abstract_dict_up_result)
|
||||
return False
|
||||
log.debug(event_abstract_dict_up_result)
|
||||
else:
|
||||
if event_abstract_dict_in_result := sql_insert(data=event_abstract_dict, table_name='event_abstract', rm_id_random=True, id_random_length=None): pass
|
||||
else:
|
||||
log.warning(f'Event Abstract not created.')
|
||||
log.debug(event_abstract_dict_in_result)
|
||||
return False
|
||||
log.debug(event_abstract_dict_in_result)
|
||||
|
||||
event_abstract_id = event_abstract_dict_in_result
|
||||
|
||||
event_abstract_outline = {}
|
||||
event_abstract_outline['event_id'] = event_id
|
||||
event_abstract_outline['event_abstract_id'] = event_abstract_id
|
||||
event_abstract_outline['event_person_id'] = event_person_id
|
||||
# event_abstract_outline['event_presenter_list'] = []
|
||||
|
||||
# if event_abstract_obj.event_presenter_list and isinstance(event_abstract_obj.event_presenter_list, list):
|
||||
# log.info(f'Event Presenter List was found. Loop through and create a new Event Presenter for each and link them to the new Event Abstract. Event Abstract ID: {event_abstract_id}')
|
||||
# for event_presenter_obj in event_abstract_obj.event_presenter_list:
|
||||
# # NOTE: Use object model version because of better type checking and validations
|
||||
# log.debug(event_presenter_obj)
|
||||
# if event_presenter_id := event_presenter_obj.id: pass
|
||||
# else: event_presenter_id = None
|
||||
# # event_presenter_obj.event_id = event_id
|
||||
# # event_presenter_obj.event_session_id = event_session_id
|
||||
# create_update_event_presenter_obj_result = create_update_event_presenter_obj_v4(
|
||||
# event_presenter_dict_obj = event_presenter_obj,
|
||||
# event_presenter_id = event_presenter_id,
|
||||
# event_id = event_id,
|
||||
# event_session_id = event_session_id,
|
||||
# event_abstract_id = event_abstract_id,
|
||||
# fail_any = fail_any,
|
||||
# return_outline = return_outline,
|
||||
# )
|
||||
# if isinstance(create_update_event_presenter_obj_result, int):
|
||||
# event_presenter_id = create_update_event_presenter_obj_result
|
||||
# elif create_update_event_presenter_obj_result == True: pass
|
||||
# else:
|
||||
# log.warning(f'Create or Update failed while trying create_update_event_presenter_obj_v4(): {create_update_event_presenter_obj_result}')
|
||||
# event_presenter_id = None
|
||||
|
||||
# event_abstract_outline['event_presenter_id'] = event_presenter_id
|
||||
|
||||
if return_outline:
|
||||
log.debug(f'Returning the Event Abstract Outline: {event_abstract_outline}')
|
||||
return event_abstract_outline
|
||||
else:
|
||||
log.debug(f'Returning the Event Abstract ID: {event_abstract_id}')
|
||||
return event_abstract_id
|
||||
# ### END ### API Event Abstract Methods ### create_update_event_abstract_obj_old() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Abstract Methods ### remove_event_abstract_obj() ###
|
||||
# Updated 2023-03-22
|
||||
@logger_reset
|
||||
def remove_event_abstract_obj(
|
||||
event_abstract_id: int,
|
||||
|
||||
method: None|str = None,
|
||||
|
||||
log_lvl: int = logging.INFO, # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
) -> bool|None:
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
if method is None or method == 'disable':
|
||||
data = {'enable': False}
|
||||
|
||||
if event_abstract_dict_up_result := sql_update(
|
||||
table_name = 'event_abstract',
|
||||
record_id = event_abstract_id,
|
||||
data = data,
|
||||
log_lvl = log_lvl,
|
||||
):
|
||||
log.info(f'Event Abstract was disabled.')
|
||||
return True
|
||||
else:
|
||||
log.warning(f'Event Abstract not disabled.')
|
||||
return event_abstract_dict_up_result # False or None
|
||||
elif method == 'delete':
|
||||
if event_abstract_dict_del_result := sql_delete(
|
||||
table_name = 'event_abstract',
|
||||
record_id = event_abstract_id,
|
||||
log_lvl = log_lvl,
|
||||
):
|
||||
log.info(f'Event Abstract was deleted.')
|
||||
return True
|
||||
else:
|
||||
log.warning(f'Event Abstract not deleted.')
|
||||
return event_abstract_dict_del_result # False or None
|
||||
elif method == 'hide':
|
||||
data = {'hide': True}
|
||||
|
||||
if event_abstract_dict_up_result := sql_update(
|
||||
table_name = 'event_abstract',
|
||||
record_id = event_abstract_id,
|
||||
data = data,
|
||||
log_lvl = log_lvl,
|
||||
):
|
||||
log.info(f'Event Abstract was hidden.')
|
||||
return True
|
||||
else:
|
||||
log.warning(f'Event Abstract not hidden.')
|
||||
return event_abstract_dict_up_result # False or None
|
||||
else:
|
||||
log.error('We should not be here. Something went wrong in remove_event_abstract_obj()!')
|
||||
return False
|
||||
|
||||
|
||||
# ### END ### API Event Abstract Methods ### remove_event_abstract_obj() ###
|
||||
438
app/methods/event_badge_methods.py
Normal file
438
app/methods/event_badge_methods.py
Normal file
@@ -0,0 +1,438 @@
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_enable_part, sql_insert, sql_limit_offset_part, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset, send_email
|
||||
|
||||
# from app.methods.account_cfg_methods import load_account_cfg_obj
|
||||
# from app.methods.event_methods import load_event_obj
|
||||
# from app.methods.event_badge_methods import load_event_badge_obj
|
||||
from app.methods.event_badge_template_methods import load_event_badge_template_obj
|
||||
|
||||
from app.models.event_badge_models import Event_Badge_Base, Event_Badge_Basic_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Badge Methods ### load_event_badge_obj() ###
|
||||
# Updated 2022-03-14
|
||||
@logger_reset
|
||||
def load_event_badge_obj(
|
||||
event_badge_id: int|str,
|
||||
badge_only: bool = False, # Changes the SQL view used
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_event_badge_template: bool = False,
|
||||
return_basic_model: bool = False,
|
||||
) -> Event_Badge_Base|dict|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_badge_id := redis_lookup_id_random(record_id_random=event_badge_id, table_name='event_badge'): pass
|
||||
else: return False
|
||||
|
||||
if badge_only:
|
||||
if event_badge_rec := sql_select(table_name='v_event_badge_only', record_id=event_badge_id): pass
|
||||
else: return False
|
||||
else:
|
||||
if event_badge_rec := sql_select(table_name='v_event_badge', record_id=event_badge_id): pass
|
||||
else: return False
|
||||
|
||||
if return_basic_model:
|
||||
try:
|
||||
event_badge_obj = Event_Badge_Basic_Base(**event_badge_rec)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
try:
|
||||
event_badge_obj = Event_Badge_Base(**event_badge_rec)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
log.debug(event_badge_obj)
|
||||
|
||||
if return_basic_model:
|
||||
if event_badge_obj.pronouns_override:
|
||||
event_badge_obj.pronouns = event_badge_obj.pronouns_override
|
||||
event_badge_obj.pronouns_override = None
|
||||
|
||||
if event_badge_obj.professional_title_override:
|
||||
event_badge_obj.professional_title = event_badge_obj.professional_title_override
|
||||
event_badge_obj.professional_title_override = None
|
||||
# log.debug(event_badge_obj)
|
||||
|
||||
if event_badge_obj.full_name_override:
|
||||
event_badge_obj.full_name = event_badge_obj.full_name_override
|
||||
event_badge_obj.full_name_override = None
|
||||
|
||||
if event_badge_obj.affiliations_override:
|
||||
event_badge_obj.affiliations = event_badge_obj.affiliations_override
|
||||
event_badge_obj.affiliations_override = None
|
||||
|
||||
if event_badge_obj.email_override:
|
||||
event_badge_obj.email = event_badge_obj.email_override
|
||||
event_badge_obj.email_override = None
|
||||
|
||||
if event_badge_obj.phone_override:
|
||||
event_badge_obj.phone = event_badge_obj.phone_override
|
||||
event_badge_obj.phone_override = None
|
||||
|
||||
if event_badge_obj.location_override:
|
||||
event_badge_obj.location = event_badge_obj.location_override
|
||||
event_badge_obj.location_override = None
|
||||
|
||||
log.debug(event_badge_obj.dict(by_alias=True, exclude_unset=True, exclude={'pronouns_override', 'professional_title_override', 'full_name_override', 'affiliations_override', 'email_override', 'phone_override', 'location_override'}))
|
||||
event_badge_dict = event_badge_obj.dict(by_alias=True, exclude_unset=True, exclude={'pronouns_override', 'professional_title_override', 'full_name_override', 'affiliations_override', 'email_override', 'phone_override', 'location_override'})
|
||||
|
||||
try:
|
||||
event_badge_obj = Event_Badge_Basic_Base(**event_badge_dict)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
log.debug(event_badge_obj)
|
||||
|
||||
# Updated 2022-03-14
|
||||
if inc_event_badge_template:
|
||||
log.info('Need to include event badge template data...')
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
if event_badge_template_id := event_badge_rec.get('event_badge_template_id', None): pass
|
||||
else:
|
||||
event_id = event_badge_rec.get('event_id', None)
|
||||
event_badge_template_id = get_event_badge_template_id_w_event_id(event_id=event_id)
|
||||
if event_badge_template_result := load_event_badge_template_obj(
|
||||
event_badge_template_id = event_badge_template_id
|
||||
):
|
||||
log.debug(event_badge_template_result)
|
||||
event_badge_obj.event_badge_template = event_badge_template_result
|
||||
else:
|
||||
log.warning('A event_badge object was not returned.')
|
||||
event_badge_obj.event_badge_template = None
|
||||
|
||||
if model_as_dict:
|
||||
return event_badge_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return event_badge_obj
|
||||
# ### END ### API Event Badge Methods ### load_event_badge_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Badge Methods ### get_event_badge_rec_list() ###
|
||||
# Updated 2022-06-14
|
||||
@logger_reset
|
||||
def get_event_badge_rec_list(
|
||||
event_id: str,
|
||||
badge_only: bool = False, # Changes the SQL view used
|
||||
badge_type_code: str = None, # guest, member, non-member, staff, volunteer, custom per event
|
||||
printed: str = 'not_printed', # not_printed, printed, all
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 250,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['event_id'] = event_id
|
||||
|
||||
if badge_type_code:
|
||||
data['badge_type_code'] = badge_type_code
|
||||
sql_badge_type_code = f'AND `event_badge`.badge_type_code = :badge_type_code'
|
||||
else: sql_badge_type_code = ''
|
||||
|
||||
if printed in ['not_printed', 'printed', 'all']:
|
||||
log.info(f'Creating partial SQL string for "printed" check. Printed: {printed}')
|
||||
if printed == 'not_printed':
|
||||
sql_badge_printed = f'AND (`event_badge`.print_count IS NULL OR `event_badge`.print_count = 0)'
|
||||
# printed = False
|
||||
elif printed == 'printed':
|
||||
sql_badge_printed = f'AND `event_badge`.print_count > 0'
|
||||
# printed = True
|
||||
elif printed == 'all':
|
||||
sql_badge_printed = f'AND (`event_badge`.print_count IS NULL OR `event_badge`.print_count IS NOT NULL)'
|
||||
# printed = None
|
||||
log.debug(sql_badge_printed)
|
||||
else: sql_badge_printed = ''
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='event_badge', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
if badge_only:
|
||||
sql = f"""
|
||||
SELECT `event_badge`.id AS 'event_badge_id', `event_badge`.id_random AS 'event_badge_id_random'
|
||||
FROM `v_event_badge_only` AS `event_badge`
|
||||
WHERE
|
||||
`event_badge`.event_id = :event_id
|
||||
{sql_badge_type_code}
|
||||
{sql_badge_printed}
|
||||
{sql_enabled}
|
||||
ORDER BY event_badge.family_name ASC, event_badge.given_name ASC, `event_badge`.created_on DESC, `event_badge`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
else:
|
||||
sql = f"""
|
||||
SELECT `event_badge`.id AS 'event_badge_id', `event_badge`.id_random AS 'event_badge_id_random'
|
||||
FROM `v_event_badge` AS `event_badge`
|
||||
WHERE
|
||||
`event_badge`.event_id = :event_id
|
||||
{sql_badge_type_code}
|
||||
{sql_enabled}
|
||||
ORDER BY event_badge.family_name ASC, event_badge.given_name ASC, `event_badge`.created_on DESC, `event_badge`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if event_badge_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
event_badge_rec_li = event_badge_rec_li_result
|
||||
else: # [] or False
|
||||
event_badge_rec_li = event_badge_rec_li_result
|
||||
|
||||
log.debug(event_badge_rec_li_result)
|
||||
|
||||
return event_badge_rec_li
|
||||
# ### END ### API Event Badge Methods ### get_event_badge_rec_list() ###
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Badge Methods ### get_event_badge_template_id_w_event_id() ###
|
||||
# Updated 2021-09-14
|
||||
@logger_reset
|
||||
def get_event_badge_template_id_w_event_id(
|
||||
event_id: int|str,
|
||||
) -> bool|int|None:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['event_id'] = event_id
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_badge_template`.id AS 'event_badge_template_id', `event_badge_template`.id_random AS 'event_badge_template_id_random', `event_badge_template`.event_id AS event_id
|
||||
FROM `event_badge_template` AS `event_badge_template`
|
||||
WHERE `event_badge_template`.event_id = :event_id
|
||||
LIMIT 1;
|
||||
"""
|
||||
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
if event_badge_template_data_result := sql_select(data=data, sql=sql):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_badge_template_data_result)
|
||||
if event_badge_template_id := event_badge_template_data_result.get('event_badge_template_id', None): return event_badge_template_id
|
||||
else: return False
|
||||
else: return None
|
||||
# ### END ### API Event Badge Methods ### get_event_badge_template_id_w_event_id() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Badge Methods ### get_event_person_id_w_event_badge_id() ###
|
||||
# Updated 2022-04-08
|
||||
@logger_reset
|
||||
def get_event_person_id_w_event_badge_id(
|
||||
event_badge_id: int|str,
|
||||
) -> bool|int|None:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_badge_id := redis_lookup_id_random(record_id_random=event_badge_id, table_name='event_badge'): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['event_badge_id'] = event_badge_id
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_badge`.id AS 'event_badge_id', `event_badge`.id_random AS 'event_badge_id_random', `event_badge`.event_person_id AS 'event_person_id'
|
||||
FROM `event_badge` AS `event_badge`
|
||||
WHERE `event_badge`.id = :event_badge_id
|
||||
LIMIT 1;
|
||||
"""
|
||||
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
if event_badge_data_result := sql_select(data=data, sql=sql):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_badge_data_result)
|
||||
if event_person_id := event_badge_data_result.get('event_person_id', None): return event_person_id
|
||||
else: return False
|
||||
else: return None
|
||||
# ### END ### API Event Badge Methods ### get_event_badge_template_id_w_event_id() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Badge Methods ### create_update_event_badge_obj_v4() ###
|
||||
# Updated 2022-02-23
|
||||
@logger_reset
|
||||
def create_update_event_badge_obj_v4(
|
||||
event_badge_dict_obj: Event_Badge_Base|dict,
|
||||
event_badge_id: int|str = None,
|
||||
# account_id: int = None,
|
||||
# event_id: int|str = None,
|
||||
event_person_id: int|str = None,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_outline: bool = False,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
log.info('Checking requirements...')
|
||||
if event_badge_id:
|
||||
log.info(f'Event Badge ID passed. Update existing Event Badge. Event Badge ID: {event_badge_id}')
|
||||
|
||||
if event_badge_id := redis_lookup_id_random(record_id_random=event_badge_id, table_name='event_badge'): pass
|
||||
else:
|
||||
log.error('Event Badge ID passed but is invalid. Failed requirement.')
|
||||
return False
|
||||
else:
|
||||
log.info('No Event Badge ID passed. Create new Event Badge. Required: Event Person ID')
|
||||
|
||||
if event_person_id := redis_lookup_id_random(record_id_random=event_person_id, table_name='event_person'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Event Person ID passed. Failed requirement.')
|
||||
log.info(f'Event Person ID: {event_person_id}')
|
||||
return False
|
||||
|
||||
log.debug('Create dictionary or Pydantic object')
|
||||
log.debug(type(event_badge_dict_obj))
|
||||
if isinstance(event_badge_dict_obj, dict):
|
||||
event_badge_dict = event_badge_dict_obj
|
||||
if event_badge_id:
|
||||
event_badge_dict['event_badge_id'] = event_badge_id
|
||||
try:
|
||||
event_badge_obj = Event_Badge_Base(**event_badge_dict)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
event_badge_obj = event_badge_dict_obj
|
||||
if event_badge_id:
|
||||
# NOTE: Can't update the ID alias if it was never set.
|
||||
event_badge_obj.id = event_badge_id
|
||||
log.debug(event_badge_obj)
|
||||
|
||||
event_badge_dict = event_badge_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event_badge_template', 'event_id', 'event_id_random', 'created_on', 'updated_on'})
|
||||
|
||||
# ### SECTION ### Process data
|
||||
if event_person_id: pass
|
||||
elif event_person_id := event_badge_obj.event_person_id: pass
|
||||
|
||||
if event_badge_id:
|
||||
if event_badge_dict_up_result := sql_update(data=event_badge_dict, table_name='event_badge', rm_id_random=True): pass
|
||||
else:
|
||||
log.warning(f'Event Badge not updated. Event Badge ID: {event_badge_id}')
|
||||
log.debug(event_badge_dict_up_result)
|
||||
return False
|
||||
log.debug(event_badge_dict_up_result)
|
||||
else:
|
||||
if event_badge_dict_in_result := sql_insert(data=event_badge_dict, table_name='event_badge', rm_id_random=True, id_random_length=None): pass
|
||||
else:
|
||||
log.warning(f'Event Badge not created.')
|
||||
log.debug(event_badge_dict_in_result)
|
||||
return False
|
||||
log.debug(event_badge_dict_in_result)
|
||||
|
||||
event_badge_id = event_badge_dict_in_result
|
||||
|
||||
event_badge_outline = {}
|
||||
event_badge_outline['event_badge_id'] = event_badge_id
|
||||
|
||||
if return_outline:
|
||||
log.debug(f'Returning the Event Badge Outline: {event_badge_outline}')
|
||||
return event_badge_outline
|
||||
else:
|
||||
log.debug(f'Returning the Event Badge ID: {event_badge_id}')
|
||||
return event_badge_id
|
||||
# ### END ### API Event Badge Methods ### create_update_event_badge_obj_v4() ###
|
||||
|
||||
|
||||
# ### BEGIN ### Event Badge Methods ### email_event_badge_review_url() ###
|
||||
# This emails the actual one time use sign in URL for a user.
|
||||
# Updated 2021-12-02
|
||||
def email_event_badge_review_url(
|
||||
event_badge_id: int|str,
|
||||
root_url: str,
|
||||
):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
# else: return False
|
||||
|
||||
if event_badge_id := redis_lookup_id_random(record_id_random=event_badge_id, table_name='event_badge'): pass
|
||||
else: return False
|
||||
|
||||
from app.methods.event_badge_methods import load_event_badge_obj
|
||||
if event_badge_obj := load_event_badge_obj(
|
||||
event_badge_id = event_badge_id,
|
||||
):
|
||||
log.info('Event Badge object loaded')
|
||||
else: return False
|
||||
log.debug(event_badge_obj)
|
||||
|
||||
event_id = event_badge_obj.event_id
|
||||
event_badge_id_random = event_badge_obj.id_random # Not event_badge_id_random
|
||||
|
||||
from app.methods.event_methods import load_event_obj
|
||||
if event_obj := load_event_obj(
|
||||
event_id = event_id,
|
||||
):
|
||||
log.info('Event object loaded')
|
||||
else: return False
|
||||
log.debug(event_obj)
|
||||
|
||||
account_id = event_obj.account_id
|
||||
event_name = event_obj.name
|
||||
|
||||
from app.methods.account_cfg_methods import load_account_cfg_obj
|
||||
if account_cfg := load_account_cfg_obj(
|
||||
account_id = account_id,
|
||||
):
|
||||
log.info('Account config loaded')
|
||||
else: return False
|
||||
log.debug(account_cfg)
|
||||
|
||||
from_email = account_cfg.default_no_reply_email
|
||||
from_name = account_cfg.default_no_reply_name
|
||||
|
||||
to_name = f'{event_badge_obj.given_name} {event_badge_obj.family_name}'
|
||||
to_email = event_badge_obj.email
|
||||
|
||||
bcc_email = '' # account_cfg.confirm_email
|
||||
bcc_name = '' # account_cfg.confirm_name
|
||||
|
||||
# help_tech_email = account_cfg.help_tech_email
|
||||
# help_tech_name = account_cfg.help_tech_name
|
||||
|
||||
account_short_name = account_cfg.account_short_name
|
||||
|
||||
event_badge_review_url = f'{root_url}event/badge/{event_badge_id_random}/review_badge'
|
||||
|
||||
subject = f'{event_name}: Event Badge Review Link ({event_badge_id_random})'
|
||||
|
||||
body_html = f"""
|
||||
<p>{to_name},</p>
|
||||
|
||||
<p>If you did not request this badge review link, please delete this email.</p>
|
||||
|
||||
<p>The link below will allow you to review your badge information and update some of the details if needed.</p>
|
||||
|
||||
<p><strong><a href="{event_badge_review_url}" style="appearance: button; display: inline-block; text-align: center; text-decoration: none; padding: .2rem .4rem; border: solid thin gray; border-radius: .2rem; background-color: lightyellow; color: black; font-size: larger;">Click to Review Badge</a></strong></p>
|
||||
|
||||
<p>Or copy and paste the link:<br>
|
||||
<strong style="background-color: lightyellow; color: black; font-size: larger;"><a href="{event_badge_review_url}">{event_badge_review_url}</a></strong></p>
|
||||
|
||||
<p>Thank you!</p>
|
||||
"""
|
||||
|
||||
if send_email(from_email=from_email, from_name=from_name, to_email=to_email, to_name=to_name, bcc_email=bcc_email, bcc_name=bcc_name, subject=subject, body_text=None, body_html=body_html):
|
||||
log.info(f'An email with a badge review link was sent to {to_email}.')
|
||||
return True
|
||||
else:
|
||||
log.info(f'An email with a badge review link was not sent to {to_email}.')
|
||||
return False
|
||||
# ### END ### Event Badge Methods ### email_event_badge_review_url() ###
|
||||
171
app/methods/event_badge_template_methods.py
Normal file
171
app/methods/event_badge_template_methods.py
Normal file
@@ -0,0 +1,171 @@
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_enable_part, sql_insert, sql_limit_offset_part, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.models.event_badge_template_models import Event_Badge_Template_Base, Event_Badge_Template_Base_In, Event_Badge_Template_Base_Out
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Badge Template Methods ### load_event_badge_template_obj() ###
|
||||
# Updated 2022-07-25
|
||||
@logger_reset
|
||||
def load_event_badge_template_obj(
|
||||
event_badge_template_id: int|str,
|
||||
inc_event_badge_list: bool = False,
|
||||
limit: int = 1000,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> Event_Badge_Template_Base_Out|dict|bool:
|
||||
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_badge_template_id := redis_lookup_id_random(record_id_random=event_badge_template_id, table_name='event_badge_template'): pass
|
||||
else: return False
|
||||
|
||||
if event_badge_template_rec := sql_select(table_name='event_badge_template', record_id=event_badge_template_id): pass
|
||||
else: return False
|
||||
|
||||
try:
|
||||
event_badge_template_obj = Event_Badge_Template_Base_Out(**event_badge_template_rec)
|
||||
log.debug(event_badge_template_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
if model_as_dict:
|
||||
return event_badge_template_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return event_badge_template_obj
|
||||
# ### END ### API Event Badge Template Methods ### load_event_badge_template_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Badge Template Methods ### get_event_badge_template_rec_list() ###
|
||||
# Updated 2022-07-20
|
||||
@logger_reset
|
||||
def get_event_badge_template_rec_list(
|
||||
event_id: str,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 25,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['event_id'] = event_id
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='event_badge_template', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_badge_template`.id AS 'event_badge_template_id', `event_badge_template`.id_random AS 'event_badge_template_id_random'
|
||||
FROM `v_event_badge_template` AS `event_badge_template`
|
||||
WHERE
|
||||
`event_badge_template`.event_id = :event_id
|
||||
{sql_enabled}
|
||||
ORDER BY event_badge_template.name ASC, `event_badge_template`.created_on DESC, `event_badge_template`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if event_badge_template_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
event_badge_template_rec_li = event_badge_template_rec_li_result
|
||||
else: # [] or False
|
||||
event_badge_template_rec_li = event_badge_template_rec_li_result
|
||||
|
||||
log.debug(event_badge_template_rec_li_result)
|
||||
|
||||
return event_badge_template_rec_li
|
||||
# ### END ### API Event Badge Template Methods ### get_event_badge_template_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Badge Template Methods ### create_update_event_badge_template_obj_v4() ###
|
||||
# Updated 2022-07-25
|
||||
@logger_reset
|
||||
def create_update_event_badge_template_obj_v4(
|
||||
event_badge_template_dict_obj: Event_Badge_Template_Base_In|dict,
|
||||
event_badge_template_id: int|str = None,
|
||||
event_id: int|str = None,
|
||||
return_outline: bool = False,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
log.info('Checking requirements...')
|
||||
if event_badge_template_id:
|
||||
log.info(f'Event Badge Template ID passed. Update existing Event Badge Template. Event Badge Template ID: {event_badge_template_id}')
|
||||
|
||||
if event_badge_template_id := redis_lookup_id_random(record_id_random=event_badge_template_id, table_name='event_badge_template'): pass
|
||||
else:
|
||||
log.error('Event Badge Template ID passed but is invalid. Failed requirement.')
|
||||
return False
|
||||
else:
|
||||
log.info('No Event Badge Template ID passed. Create new Event Badge Template. Required: Event ID')
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Event ID passed. Failed requirement.')
|
||||
log.info(f'Event ID: {event_id}')
|
||||
return False
|
||||
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(event_badge_template_dict_obj))
|
||||
if isinstance(event_badge_template_dict_obj, dict):
|
||||
event_badge_template_dict = event_badge_template_dict_obj
|
||||
if event_badge_template_id:
|
||||
event_badge_template_dict['event_badge_template_id'] = event_badge_template_id
|
||||
try:
|
||||
event_badge_template_obj = Event_Badge_Template_Base_In(**event_badge_template_dict)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
event_badge_template_obj = event_badge_template_dict_obj
|
||||
if event_badge_template_id:
|
||||
# NOTE: Can't update the ID alias if it was never set.
|
||||
event_badge_template_obj.id = event_badge_template_id
|
||||
log.debug(event_badge_template_obj)
|
||||
|
||||
event_badge_template_dict = event_badge_template_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event_badge_list', 'event_id_random', 'created_on', 'updated_on'})
|
||||
|
||||
# ### SECTION ### Process data
|
||||
if event_id: pass
|
||||
elif event_id := event_badge_template_obj.event_id: pass
|
||||
|
||||
if event_badge_template_id:
|
||||
if event_badge_template_dict_up_result := sql_update(data=event_badge_template_dict, table_name='event_badge_template', rm_id_random=True): pass
|
||||
else:
|
||||
log.warning(f'Event Badge Template not updated. Event Badge Template ID: {event_badge_template_id}')
|
||||
log.debug(event_badge_template_dict_up_result)
|
||||
return False
|
||||
log.debug(event_badge_template_dict_up_result)
|
||||
else:
|
||||
if event_badge_template_dict_in_result := sql_insert(data=event_badge_template_dict, table_name='event_badge_template', rm_id_random=True): pass
|
||||
else:
|
||||
log.warning(f'Event Badge Template not created.')
|
||||
log.debug(event_badge_template_dict_in_result)
|
||||
return False
|
||||
log.debug(event_badge_template_dict_in_result)
|
||||
|
||||
event_badge_template_id = event_badge_template_dict_in_result
|
||||
|
||||
event_badge_template_outline = {}
|
||||
event_badge_template_outline['event_badge_template_id'] = event_badge_template_id
|
||||
|
||||
if return_outline:
|
||||
log.debug(f'Returning the Event Badge Outline: {event_badge_template_outline}')
|
||||
return event_badge_template_outline
|
||||
else:
|
||||
log.debug(f'Returning the Event Badge ID: {event_badge_template_id}')
|
||||
return event_badge_template_id
|
||||
# ### END ### API Event Badge Methods ### create_update_event_badge_template_obj_v4() ###
|
||||
126
app/methods/event_cfg_methods.py
Normal file
126
app/methods/event_cfg_methods.py
Normal file
@@ -0,0 +1,126 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging
|
||||
|
||||
from app.methods.event_registration_cfg_methods import load_event_registration_cfg_obj
|
||||
|
||||
from app.models.event_cfg_models import Event_Cfg_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Cfg Methods ### load_event_cfg_obj() ###
|
||||
def load_event_cfg_obj(
|
||||
event_id: int|str,
|
||||
inc_event_registration_cfg: bool = False,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = False, # Including even unset fields. Prevent null value issues on the frontend.
|
||||
model_as_dict: bool = False,
|
||||
) -> Event_Cfg_Base|bool:
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else: return False
|
||||
|
||||
if event_cfg_rec := sql_select(table_name='v_event_cfg', record_id=event_id): pass
|
||||
else: return False
|
||||
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_cfg_rec)
|
||||
|
||||
try:
|
||||
event_cfg_obj = Event_Cfg_Base(**event_cfg_rec)
|
||||
log.debug(event_cfg_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
# Updated 2021-06-30
|
||||
if inc_event_registration_cfg:
|
||||
if event_registration_cfg_result := load_event_registration_cfg_obj(
|
||||
event_id = event_id,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
event_cfg_obj.event_registration_cfg = event_registration_cfg_result
|
||||
else: event_cfg_obj.event_registration_cfg = None
|
||||
|
||||
if model_as_dict:
|
||||
return event_cfg_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return event_cfg_obj
|
||||
# ### END ### API Event Cfg Methods ### load_event_cfg_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Cfg Methods ### create_update_event_cfg_obj_v4() ###
|
||||
# Updated 2021-09-28
|
||||
def create_update_event_cfg_obj_v4(
|
||||
event_cfg_dict_obj: Event_Base|dict,
|
||||
event_cfg_id: int|str|None = None,
|
||||
event_id: int|str|None = None,
|
||||
create_sub_obj: bool = False, # Is this needed for a config?
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_outline: bool = False,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
log.info('Checking requirements...')
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else: return False
|
||||
|
||||
log.debug(type(event_cfg_dict_obj))
|
||||
if isinstance(event_cfg_dict_obj, dict):
|
||||
event_cfg_dict = event_cfg_dict_obj
|
||||
if event_id:
|
||||
event_cfg_dict['event_id'] = event_id
|
||||
# if event_cfg_id:
|
||||
# event_cfg_dict['event_cfg_id'] = event_cfg_id
|
||||
try:
|
||||
event_cfg_obj = Event_Cfg_Base(**event_cfg_dict)
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_cfg_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
event_cfg_obj = event_cfg_dict_obj
|
||||
if event_id:
|
||||
# NOTE: Can't update the ID alias if it was never set.
|
||||
event_cfg_obj.id = event_id
|
||||
|
||||
event_cfg_dict = event_cfg_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'registration_cfg', 'created_on', 'updated_on'}) # NOTE this exclude list should be reviewed again
|
||||
|
||||
if event_id:
|
||||
if event_cfg_dict_up_result := sql_update(data=event_cfg_dict, table_name='event', rm_id_random=True): pass # NOTE: This is not using the event_cfg table at this time. -STI 2021-09-28
|
||||
else:
|
||||
log.warning(f'Event (Cfg) not updated. Event ID: {event_id}')
|
||||
log.debug(event_cfg_dict_up_result)
|
||||
return False
|
||||
log.debug(event_cfg_dict_up_result)
|
||||
else: # NOTE NOTE NOTE NOTE: This section is for future use NOTE NOTE NOTE NOTE
|
||||
if event_cfg_dict_in_result := sql_insert(data=event_cfg_dict, table_name='event', rm_id_random=True, id_random_length=default_num_bytes): pass # NOTE: This is not using the event_cfg table at this time. -STI 2021-09-28
|
||||
else:
|
||||
log.warning(f'Event (Cfg) not created.')
|
||||
log.debug(event_cfg_dict_in_result)
|
||||
return False
|
||||
log.debug(event_cfg_dict_in_result)
|
||||
|
||||
event_id = event_cfg_dict_in_result
|
||||
|
||||
event_outline = {}
|
||||
event_outline['event_id'] = event_id
|
||||
|
||||
if return_outline:
|
||||
log.debug(f'Returning the Event Cfg Outline: {event_cfg_outline}')
|
||||
return event_cfg_outline
|
||||
else:
|
||||
log.debug(f'Returning the Event (Cfg) ID: {event_id}')
|
||||
return event_id
|
||||
# ### END ### API Event Cfg Methods ### create_update_event_cfg_obj_v4() ###
|
||||
223
app/methods/event_device_methods.py
Normal file
223
app/methods/event_device_methods.py
Normal file
@@ -0,0 +1,223 @@
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_enable_part, sql_insert, sql_limit_offset_part, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.methods.event_cfg_methods import load_event_cfg_obj
|
||||
from app.methods.event_location_methods import load_event_location_obj
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
from app.models.event_cfg_models import Event_Cfg_Base
|
||||
from app.models.event_device_models import Event_Device_Base
|
||||
from app.models.event_location_models import Event_Location_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Device Methods ### load_event_device_obj() ###
|
||||
# Updated 2022-03-09
|
||||
@logger_reset
|
||||
def load_event_device_obj(
|
||||
event_device_id: int,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
inc_event_cfg: bool = False,
|
||||
inc_event_location: bool = False,
|
||||
) -> Event_Device_Base|dict|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_device_rec := sql_select(table_name='v_event_device', record_id=event_device_id): pass
|
||||
else: return False
|
||||
|
||||
log.debug(event_device_rec)
|
||||
|
||||
try:
|
||||
event_device_obj = Event_Device_Base(**event_device_rec)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
log.debug(event_device_obj)
|
||||
|
||||
# Updated 2022-03-09
|
||||
if inc_event_cfg:
|
||||
log.info('Need to include event configuration...')
|
||||
event_id = event_device_rec.get('event_id', None)
|
||||
log.debug(event_id)
|
||||
if event_cfg_result := load_event_cfg_obj(
|
||||
event_id = event_id,
|
||||
):
|
||||
event_device_obj.event_cfg = event_cfg_result
|
||||
else: event_device_obj.event_cfg = {} # None
|
||||
|
||||
# Updated 2022-03-09
|
||||
if inc_event_location:
|
||||
log.info('Need to include event location...')
|
||||
event_location_id = event_device_rec.get('event_location_id', None)
|
||||
log.debug(event_location_id)
|
||||
if event_location_result := load_event_location_obj(
|
||||
event_location_id = event_location_id,
|
||||
):
|
||||
event_device_obj.event_location = event_location_result
|
||||
else: event_device_obj.event_location = {} # None
|
||||
|
||||
if model_as_dict:
|
||||
return event_device_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return event_device_obj
|
||||
# ### END ### API Event Device Methods ### load_event_device_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Device Methods ### get_event_device_rec_list() ###
|
||||
# Updated 2022-03-09
|
||||
@logger_reset
|
||||
def get_event_device_rec_list(
|
||||
for_type: str, # 'account' is a special case
|
||||
for_id: str,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_id := redis_lookup_id_random(record_id_random=for_id, table_name=for_type): pass
|
||||
else: return False
|
||||
|
||||
if for_type == 'account':
|
||||
sql_for_type_id = f'`event_device`.account_id = :for_id'
|
||||
elif for_type == 'event':
|
||||
sql_for_type_id = f'`event_device`.event_id = :for_id'
|
||||
elif for_type == 'event_location':
|
||||
sql_for_type_id = f'`event_device`.event_location_id = :for_id'
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['for_type'] = for_type
|
||||
data['for_id'] = for_id
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='event_device', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_device`.id AS 'event_device_id', `event_device`.id_random AS 'event_device_id_random'
|
||||
FROM `v_event_device` AS `event_device`
|
||||
WHERE
|
||||
{sql_for_type_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `event_device`.created_on DESC, `event_device`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if event_device_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
event_device_rec_li = event_device_rec_li_result
|
||||
else: # [] or False
|
||||
event_device_rec_li = event_device_rec_li_result
|
||||
|
||||
log.debug(event_device_rec_li_result)
|
||||
|
||||
return event_device_rec_li
|
||||
# ### END ### API Event Device Methods ### get_event_device_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Device Methods ### create_update_event_device_obj() ###
|
||||
# Updated 2022-03-09
|
||||
def create_update_event_device_obj(
|
||||
event_device_dict_obj: Event_Device_Base|dict,
|
||||
event_device_id: int|str = None,
|
||||
event_id: int|str = None,
|
||||
event_location_id: int|str = None,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_outline: bool = False,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
log.info('Checking requirements...')
|
||||
if event_device_id:
|
||||
log.info(f'Event Device ID passed. Update existing Event Device. Event Device ID: {event_device_id}')
|
||||
|
||||
if event_device_id := redis_lookup_id_random(record_id_random=event_device_id, table_name='event_device'): pass
|
||||
else:
|
||||
log.error('Event Device ID passed but is invalid. Failed requirement.')
|
||||
return False
|
||||
else:
|
||||
log.info('No Event Device ID passed. Create new Event Device. Required: Event ID; Optional: Event Location ID')
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Event ID passed. Failed requirement.')
|
||||
log.info(f'Event ID: {event_id}')
|
||||
return False
|
||||
|
||||
if event_location_id := redis_lookup_id_random(record_id_random=event_location_id, table_name='event_location'): pass
|
||||
elif event_location_id is None: pass
|
||||
else:
|
||||
log.warning('Missing or invalid Event Location ID passed. Failed requirement.')
|
||||
log.info(f'Event Location ID: {event_location_id}')
|
||||
return False
|
||||
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(event_device_dict_obj))
|
||||
if isinstance(event_device_dict_obj, dict):
|
||||
event_device_dict = event_device_dict_obj
|
||||
if event_device_id:
|
||||
event_device_dict['event_device_id'] = event_device_id
|
||||
if event_id:
|
||||
event_dict['event_id'] = event_id
|
||||
if event_location_id:
|
||||
event_location_dict['event_location_id'] = event_location_id
|
||||
try:
|
||||
event_device_obj = Event_Device_Base(**event_device_dict)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
event_device_obj = event_device_dict_obj
|
||||
if event_device_id:
|
||||
# NOTE: Can't update the ID alias if it was never set.
|
||||
event_device_obj.id = event_device_id
|
||||
if event_id:
|
||||
event_device_obj.event_id = event_id
|
||||
if event_location_id:
|
||||
event_device_obj.event_location_id = event_location_id
|
||||
log.debug(event_device_obj)
|
||||
|
||||
event_device_dict = event_device_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event_cfg', 'event_location', 'account_id', 'account_id_random', 'created_on', 'updated_on'})
|
||||
|
||||
# ### SECTION ### Process data
|
||||
if event_device_id:
|
||||
if event_device_dict_up_result := sql_update(data=event_device_dict, table_name='event_device', rm_id_random=True): pass
|
||||
else:
|
||||
log.warning(f'Event Device not updated. Event Device ID: {event_device_id}')
|
||||
log.debug(event_device_dict_up_result)
|
||||
return False
|
||||
log.debug(event_device_dict_up_result)
|
||||
else:
|
||||
if event_device_dict_in_result := sql_insert(data=event_device_dict, table_name='event_device', rm_id_random=True, id_random_length=8): pass
|
||||
else:
|
||||
log.warning(f'Event Device not created.')
|
||||
log.debug(event_device_dict_in_result)
|
||||
return False
|
||||
log.debug(event_device_dict_in_result)
|
||||
|
||||
event_device_id = event_device_dict_in_result
|
||||
|
||||
event_device_outline = {}
|
||||
event_device_outline['event_device_id'] = event_device_id
|
||||
|
||||
if return_outline:
|
||||
log.debug(f'Returning the Event Device Outline: {event_device_outline}')
|
||||
return event_device_outline
|
||||
else:
|
||||
log.debug(f'Returning the Event Device ID: {event_device_id}')
|
||||
return event_device_id
|
||||
# ### END ### API Event Device Methods ### create_update_event_device_obj() ###
|
||||
272
app/methods/event_exhibit_methods.py
Normal file
272
app/methods/event_exhibit_methods.py
Normal file
@@ -0,0 +1,272 @@
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import get_account_id_w_for_type_id, redis_lookup_id_random, sql_delete, sql_enable_part, sql_delete, sql_insert, sql_limit_offset_part, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.methods.event_exhibit_tracking_methods import get_event_exhibit_tracking_rec_list, load_event_exhibit_tracking_obj
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
from app.models.event_exhibit_models import Event_Exhibit_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Exhibit Methods ### create_event_exhibit_obj() ###
|
||||
# Updated 2022-02-15
|
||||
@logger_reset
|
||||
def create_event_exhibit_obj(
|
||||
event_id: int,
|
||||
event_exhibit_dict_obj: Event_Exhibit_Base,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
log_lvl: int = logging.WARNING, # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
) -> int|bool:
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(event_exhibit_dict_obj))
|
||||
if isinstance(event_exhibit_dict_obj, dict):
|
||||
event_exhibit_dict = event_exhibit_dict_obj
|
||||
event_exhibit_dict['event_id'] = event_id
|
||||
try:
|
||||
event_exhibit_obj = Event_Exhibit_Base(**event_exhibit_dict)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
event_exhibit_obj = event_exhibit_dict_obj
|
||||
event_exhibit_obj.event_id = event_id
|
||||
log.debug(event_exhibit_obj)
|
||||
|
||||
event_exhibit_dict = event_exhibit_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event', 'event_id_random', 'created_on', 'updated_on'})
|
||||
|
||||
# ### SECTION ### Process data
|
||||
if event_exhibit_dict_in_result := sql_insert(
|
||||
data = event_exhibit_dict,
|
||||
table_name = 'event_exhibit',
|
||||
rm_id_random = True,
|
||||
id_random_length = default_num_bytes
|
||||
):
|
||||
event_exhibit_id = event_exhibit_dict_in_result
|
||||
log.info(f'Returning the new Event Exhibit ID: {event_exhibit_id}')
|
||||
return event_exhibit_id
|
||||
else:
|
||||
log.warning(f'Event Exhibit not created.')
|
||||
return event_exhibit_dict_in_result # False or None
|
||||
# ### END ### API Event Exhibit Methods ### create_event_exhibit_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Exhibit Methods ### update_event_exhibit_obj() ###
|
||||
# Updated 2022-02-15
|
||||
@logger_reset
|
||||
def update_event_exhibit_obj(
|
||||
event_exhibit_id: int,
|
||||
event_exhibit_dict_obj: Event_Exhibit_Base,
|
||||
log_lvl: int = logging.WARNING, # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
) -> bool:
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(event_exhibit_dict_obj))
|
||||
if isinstance(event_exhibit_dict_obj, dict):
|
||||
event_exhibit_dict = event_exhibit_dict_obj
|
||||
event_exhibit_dict['id'] = event_exhibit_id
|
||||
try:
|
||||
event_exhibit_obj = Person_Base(**event_exhibit_dict)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
event_exhibit_obj = event_exhibit_dict_obj
|
||||
event_exhibit_obj.id = event_exhibit_id
|
||||
log.debug(event_exhibit_obj)
|
||||
|
||||
event_exhibit_dict = event_exhibit_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event', 'event_id_random', 'created_on', 'updated_on'})
|
||||
|
||||
# ### SECTION ### Process data
|
||||
if event_exhibit_dict_up_result := sql_update(
|
||||
data = event_exhibit_dict,
|
||||
table_name = 'event_exhibit',
|
||||
rm_id_random = True,
|
||||
):
|
||||
log.info(f'Updated the Event Exhibit ID: {event_exhibit_id}')
|
||||
return event_exhibit_id
|
||||
else:
|
||||
log.warning(f'Event Exhibit not updated.')
|
||||
return event_exhibit_dict_up_result # False or None
|
||||
# ### END ### API Event Exhibit Methods ### update_event_exhibit_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Exhibit Methods ### delete_event_exhibit_obj() ###
|
||||
# Updated 2022-02-15
|
||||
@logger_reset
|
||||
def remove_event_exhibit_obj(
|
||||
event_exhibit_id: int,
|
||||
log_lvl: int = logging.DEBUG, # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
) -> bool|None:
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
if event_exhibit_dict_del_result := sql_delete(
|
||||
table_name = 'event_exhibit',
|
||||
record_id = event_exhibit_id,
|
||||
log_lvl = log_lvl,
|
||||
):
|
||||
log.info(f'Event Exhibit was deleted.')
|
||||
return True
|
||||
else:
|
||||
log.warning(f'Event Exhibit not deleted.')
|
||||
return event_exhibit_dict_del_result # False or None
|
||||
# ### END ### API Event Exhibit Methods ### delete_event_exhibit_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Exhibit Methods ### load_event_exhibit_obj() ###
|
||||
# Updated 2022-02-14
|
||||
@logger_reset
|
||||
def load_event_exhibit_obj(
|
||||
event_exhibit_id: int,
|
||||
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
approved: str = 'all', # approved, not_approved, all
|
||||
hidden: str = 'not_hidden', # hidden, not_hidden, all
|
||||
review: str = 'all', # ready, not_ready, all
|
||||
|
||||
limit: int = 1500,
|
||||
offset: int = 0,
|
||||
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
inc_address: bool = False,
|
||||
inc_contact: bool = False,
|
||||
inc_event_badge: bool = False,
|
||||
inc_event_exhibit_tracking_list: bool = False,
|
||||
inc_event_person: bool = False,
|
||||
) -> Event_Exhibit_Base|dict|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# if event_exhibit_id := redis_lookup_id_random(record_id_random=event_exhibit_id, table_name='event_exhibit'): pass
|
||||
# else: return False
|
||||
|
||||
if event_exhibit_rec := sql_select(table_name='v_event_exhibit', record_id=event_exhibit_id): pass
|
||||
else: return False
|
||||
|
||||
try:
|
||||
event_exhibit_obj = Event_Exhibit_Base(**event_exhibit_rec)
|
||||
log.debug(event_exhibit_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
# Updated 2022-02-15
|
||||
if inc_event_exhibit_tracking_list:
|
||||
log.info('Need to include Event Exhibit Tracking List data...')
|
||||
if event_exhibit_tracking_rec_list_result := get_event_exhibit_tracking_rec_list(
|
||||
event_exhibit_id = event_exhibit_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
hidden = hidden,
|
||||
):
|
||||
event_exhibit_tracking_result_list = []
|
||||
for event_exhibit_tracking_rec in event_exhibit_tracking_rec_list_result:
|
||||
event_exhibit_tracking_result_list.append(
|
||||
load_event_exhibit_tracking_obj(
|
||||
event_exhibit_tracking_id = event_exhibit_tracking_rec.get('event_exhibit_tracking_id'),
|
||||
inc_event_person = inc_event_person,
|
||||
)
|
||||
)
|
||||
event_exhibit_obj.event_exhibit_tracking_list = event_exhibit_tracking_result_list
|
||||
else: event_exhibit_obj.event_exhibit_tracking_list = []
|
||||
|
||||
if model_as_dict:
|
||||
return event_exhibit_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return event_exhibit_obj
|
||||
# ### END ### API Event Exhibit Methods ### load_event_exhibit_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Exhibit Methods ### get_event_exhibit_rec_list() ###
|
||||
# for_obj_type: account, event, event_person, event_exhibit
|
||||
# Updated 2022-02-14
|
||||
@logger_reset
|
||||
def get_event_exhibit_rec_list(
|
||||
event_id: int|str = None,
|
||||
event_exhibit_id: int|str = None,
|
||||
event_person_id: int|str = None,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
data = {}
|
||||
|
||||
sql_select_event_id = ''
|
||||
sql_select_event_exhibit_id = ''
|
||||
sql_select_event_person_id = ''
|
||||
|
||||
if event_id:
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else: return False
|
||||
|
||||
data['event_id'] = event_id
|
||||
sql_select_event_id = f'`event_exhibit`.event_id = :event_id'
|
||||
else:
|
||||
sql_select_event_id = f'`event_exhibit`.event_id IS NOT NULL'
|
||||
|
||||
if event_exhibit_id:
|
||||
if event_exhibit_id := redis_lookup_id_random(record_id_random=event_exhibit_id, table_name='event_exhibit'): pass
|
||||
else: return False
|
||||
|
||||
data['event_exhibit_id'] = event_exhibit_id
|
||||
sql_select_event_exhibit_id = f'AND `event_exhibit`.event_exhibit_id = :event_exhibit_id'
|
||||
|
||||
if event_person_id:
|
||||
if event_person_id := redis_lookup_id_random(record_id_random=event_person_id, table_name='event_person'): pass
|
||||
else: return False
|
||||
|
||||
data['event_person_id'] = event_person_id
|
||||
sql_select_event_person_id = f'AND `event_exhibit`.event_person_id = :event_person_id'
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='event_exhibit', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
if event_id or event_exhibit_id or event_person_id: pass
|
||||
else: return False
|
||||
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_exhibit`.id AS 'event_exhibit_id', `event_exhibit`.id_random AS 'event_exhibit_id_random'
|
||||
FROM `event_exhibit` AS `event_exhibit`
|
||||
WHERE
|
||||
{sql_select_event_id}
|
||||
{sql_select_event_exhibit_id}
|
||||
{sql_select_event_person_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `event_exhibit`.priority DESC, -`event_exhibit`.sort DESC, `event_exhibit`.name ASC, `event_exhibit`.created_on DESC, `event_exhibit`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if event_exhibit_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
log.info('Got a list result')
|
||||
event_exhibit_rec_li = event_exhibit_rec_li_result
|
||||
else: # [] or False
|
||||
log.info('No results or something went wrong')
|
||||
event_exhibit_rec_li = event_exhibit_rec_li_result
|
||||
|
||||
log.debug(event_exhibit_rec_li_result)
|
||||
|
||||
return event_exhibit_rec_li
|
||||
# ### END ### API Event Exhibit Methods ### get_event_exhibit_rec_list() ###
|
||||
340
app/methods/event_exhibit_tracking_methods.py
Normal file
340
app/methods/event_exhibit_tracking_methods.py
Normal file
@@ -0,0 +1,340 @@
|
||||
import datetime, json
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import get_account_id_w_for_type_id, redis_lookup_id_random, sql_enable_part, sql_delete, sql_insert, sql_limit_offset_part, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.methods.event_badge_methods import get_event_person_id_w_event_badge_id
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
from app.models.event_exhibit_tracking_models import Event_Exhibit_Tracking_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Exhibit Tracking Methods ### create_event_exhibit_tracking_obj() ###
|
||||
# Updated 2022-02-15
|
||||
@logger_reset
|
||||
def create_event_exhibit_tracking_obj(
|
||||
event_exhibit_id: int,
|
||||
event_exhibit_tracking_dict_obj: Event_Exhibit_Tracking_Base,
|
||||
event_badge_id: int = None,
|
||||
event_person_id: int = None,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
log_lvl: int = logging.INFO, # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
) -> int|bool:
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
if event_badge_id and not event_person_id:
|
||||
event_person_id = get_event_person_id_w_event_badge_id(event_badge_id)
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(event_exhibit_tracking_dict_obj))
|
||||
if isinstance(event_exhibit_tracking_dict_obj, dict):
|
||||
event_exhibit_tracking_dict = event_exhibit_tracking_dict_obj
|
||||
event_exhibit_tracking_dict['event_exhibit_id'] = event_exhibit_id
|
||||
event_exhibit_tracking_dict['event_badge_id'] = event_badge_id
|
||||
event_exhibit_tracking_dict['event_person_id'] = event_person_id
|
||||
try:
|
||||
event_exhibit_tracking_obj = Event_Exhibit_Tracking_Base(**event_exhibit_tracking_dict)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
event_exhibit_tracking_obj = event_exhibit_tracking_dict_obj
|
||||
event_exhibit_tracking_obj.event_exhibit_id = event_exhibit_id
|
||||
event_exhibit_tracking_obj.event_badge_id = event_badge_id
|
||||
event_exhibit_tracking_obj.event_person_id = event_person_id
|
||||
log.debug(event_exhibit_tracking_obj)
|
||||
|
||||
event_exhibit_tracking_dict = event_exhibit_tracking_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event_badge', 'event_badge_id_random', 'event_person', 'event_person_id_random', 'created_on', 'updated_on'})
|
||||
|
||||
# ### SECTION ### Process data
|
||||
if event_exhibit_tracking_dict_in_result := sql_insert(
|
||||
data = event_exhibit_tracking_dict,
|
||||
table_name = 'event_exhibit_tracking',
|
||||
rm_id_random = True,
|
||||
id_random_length = default_num_bytes
|
||||
):
|
||||
event_exhibit_tracking_id = event_exhibit_tracking_dict_in_result
|
||||
log.info(f'Returning the new Event Exhibit Tracking ID: {event_exhibit_tracking_id}')
|
||||
return event_exhibit_tracking_id
|
||||
else:
|
||||
log.warning(f'Event Exhibit Tracking not created.')
|
||||
return event_exhibit_tracking_dict_in_result # False or None
|
||||
# ### END ### API Event Exhibit Tracking Methods ### create_event_exhibit_tracking_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Exhibit Tracking Methods ### update_event_exhibit_tracking_obj() ###
|
||||
# Updated 2023-02-08
|
||||
@logger_reset
|
||||
def update_event_exhibit_tracking_obj(
|
||||
event_exhibit_tracking_id: int,
|
||||
event_exhibit_tracking_dict_obj: Event_Exhibit_Tracking_Base,
|
||||
log_lvl: int = logging.WARNING, # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
) -> bool:
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(event_exhibit_tracking_dict_obj))
|
||||
if isinstance(event_exhibit_tracking_dict_obj, dict):
|
||||
event_exhibit_tracking_dict = event_exhibit_tracking_dict_obj
|
||||
event_exhibit_tracking_dict['id'] = event_exhibit_tracking_id
|
||||
try:
|
||||
event_exhibit_tracking_obj = Event_Exhibit_Tracking_Base(**event_exhibit_tracking_dict)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
event_exhibit_tracking_obj = event_exhibit_tracking_dict_obj
|
||||
event_exhibit_tracking_obj.id = event_exhibit_tracking_id
|
||||
log.debug(event_exhibit_tracking_obj)
|
||||
|
||||
event_exhibit_tracking_dict = event_exhibit_tracking_obj.dict(
|
||||
by_alias = False,
|
||||
exclude_defaults = False,
|
||||
exclude_unset = True,
|
||||
exclude = {
|
||||
'event_id', 'event_id_random', 'event_badge', 'event_badge_id_random',
|
||||
'event_badge_informal_name', 'event_badge_title_names',
|
||||
'event_badge_given_name', 'event_badge_middle_name', 'event_badge_family_name',
|
||||
'event_badge_display_name', 'event_badge_full_name',
|
||||
|
||||
'event_badge_designations', 'event_badge_professional_title', 'event_badge_affiliations',
|
||||
'event_badge_email',
|
||||
'event_badge_city',
|
||||
'event_badge_country_subdivision_code', 'event_badge_state_province_abb', 'event_badge_state_province',
|
||||
'event_badge_country_alpha_2_code', 'event_badge_country',
|
||||
|
||||
'event_badge_badge_type_code', 'event_badge_badge_type', 'event_badge_registration_type_code', 'event_badge_registration_type',
|
||||
|
||||
'event_person_informal_name', 'event_person_given_name',
|
||||
'event_person_family_name', 'event_person_display_name', 'event_person_full_name',
|
||||
'event_person_affiliations', 'event_person_email',
|
||||
'event_exhibit_name',
|
||||
'event_person', 'event_person_id_random', 'created_on', 'updated_on'
|
||||
}
|
||||
)
|
||||
|
||||
# NOTE: This is needed for the SQL update to work.
|
||||
# NOTE: Should something like this be moved to the sql_update and sql_insert functions? If a field ends in _json or the field data type is a dict?
|
||||
# if responses_json := event_exhibit_tracking_dict.get('responses_json'):
|
||||
# event_exhibit_tracking_dict['responses_json'] = json.dumps(responses_json)
|
||||
|
||||
# ### SECTION ### Process data
|
||||
if event_exhibit_tracking_dict_up_result := sql_update(
|
||||
data = event_exhibit_tracking_dict,
|
||||
table_name = 'event_exhibit_tracking',
|
||||
rm_id_random = True,
|
||||
):
|
||||
log.info(f'Updated the Event Exhibit Tracking ID: {event_exhibit_tracking_id}')
|
||||
return event_exhibit_tracking_id
|
||||
else:
|
||||
log.warning(f'Event Exhibit Tracking not updated.')
|
||||
return event_exhibit_tracking_dict_up_result # False or None
|
||||
# ### END ### API Event Exhibit Tracking Methods ### update_event_exhibit_tracking_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Exhibit Tracking Methods ### delete_event_exhibit_tracking_obj() ###
|
||||
# Updated 2022-02-15
|
||||
@logger_reset
|
||||
def remove_event_exhibit_tracking_obj(
|
||||
event_exhibit_tracking_id: int,
|
||||
log_lvl: int = logging.DEBUG, # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
) -> bool|None:
|
||||
log.setLevel(log_lvl)
|
||||
|
||||
if event_exhibit_tracking_dict_del_result := sql_delete(
|
||||
table_name = 'event_exhibit_tracking',
|
||||
record_id = event_exhibit_tracking_id,
|
||||
log_lvl = log_lvl,
|
||||
):
|
||||
log.info(f'Event Exhibit Tracking was deleted.')
|
||||
return True
|
||||
else:
|
||||
log.warning(f'Event Exhibit Tracking not deleted.')
|
||||
return event_exhibit_tracking_dict_del_result # False or None
|
||||
# ### END ### API Event Exhibit Tracking Methods ### delete_event_exhibit_tracking_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Exhibit Tracking Methods ### load_event_exhibit_tracking_obj() ###
|
||||
# Updated 2022-02-15
|
||||
@logger_reset
|
||||
def load_event_exhibit_tracking_obj(
|
||||
event_exhibit_tracking_id: int,
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_address: bool = False,
|
||||
inc_contact: bool = False,
|
||||
inc_event_badge: bool = False,
|
||||
# inc_event_exhibit: bool = False,
|
||||
inc_event_person: bool = False,
|
||||
inc_event_person_profile: bool = False,
|
||||
) -> Event_Exhibit_Tracking_Base|dict|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# if event_exhibit_tracking_id := redis_lookup_id_random(record_id_random=event_exhibit_tracking_id, table_name='event_exhibit_tracking'): pass
|
||||
# else: return False
|
||||
|
||||
if event_exhibit_tracking_rec := sql_select(table_name='v_event_exhibit_tracking', record_id=event_exhibit_tracking_id): pass
|
||||
else: return False
|
||||
|
||||
try:
|
||||
event_exhibit_tracking_obj = Event_Exhibit_Tracking_Base(**event_exhibit_tracking_rec)
|
||||
log.debug(event_exhibit_tracking_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
# if inc_event_exhibit:
|
||||
# log.info('Need to include Event Exhibit data...')
|
||||
# event_exhibit_id = event_exhibit_tracking_rec.get('event_exhibit_id', None)
|
||||
# log.debug(event_exhibit_id)
|
||||
# from app.methods.event_exhibit_methods import load_event_exhibit_obj
|
||||
# if event_exhibit_result := load_event_exhibit_obj(
|
||||
# event_exhibit_id = event_exhibit_id,
|
||||
# by_alias = by_alias,
|
||||
# exclude_unset = exclude_unset,
|
||||
# model_as_dict = model_as_dict,
|
||||
# ):
|
||||
# event_exhibit_tracking_obj.event_exhibit = event_exhibit_result
|
||||
# else: event_exhibit_tracking_obj.event_exhibit = {} # None
|
||||
|
||||
if inc_event_person:
|
||||
log.info('Need to include Event Person data...')
|
||||
event_person_id = event_exhibit_tracking_rec.get('event_person_id', None)
|
||||
log.debug(event_person_id)
|
||||
from app.methods.event_person_methods import load_event_person_obj
|
||||
if event_person_result := load_event_person_obj(
|
||||
event_person_id = event_person_id,
|
||||
inc_event_badge = inc_event_badge,
|
||||
inc_event_person_profile = inc_event_person_profile,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
event_exhibit_tracking_obj.event_person = event_person_result
|
||||
else: event_exhibit_tracking_obj.event_person = {} # None
|
||||
|
||||
if model_as_dict:
|
||||
return event_exhibit_tracking_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return event_exhibit_tracking_obj
|
||||
# ### END ### API Event Exhibit Tracking Methods ### load_event_exhibit_tracking_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Exhibit Tracking Methods ### get_event_exhibit_tracking_rec_list() ###
|
||||
# for_obj_type: account, event, event_person, event_exhibit
|
||||
# Updated 2022-02-14
|
||||
@logger_reset
|
||||
def get_event_exhibit_tracking_rec_list(
|
||||
event_id: int|str = None,
|
||||
event_exhibit_id: int|str = None,
|
||||
event_badge_id: int|str = None,
|
||||
event_person_id: int|str = None,
|
||||
hidden: str = 'not_hidden', # hidden, not_hidden, all
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 1500,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
data = {}
|
||||
|
||||
sql_select_event_id = ''
|
||||
sql_select_event_exhibit_id = ''
|
||||
sql_select_event_badge_id = ''
|
||||
sql_select_event_person_id = ''
|
||||
|
||||
if event_id:
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else: return False
|
||||
|
||||
data['event_id'] = event_id
|
||||
sql_select_event_id = f'`event_exhibit_tracking`.event_id = :event_id'
|
||||
else:
|
||||
sql_select_event_id = f'`event_exhibit_tracking`.event_id IS NOT NULL'
|
||||
|
||||
if event_exhibit_id:
|
||||
if event_exhibit_id := redis_lookup_id_random(record_id_random=event_exhibit_id, table_name='event_exhibit'): pass
|
||||
else: return False
|
||||
|
||||
data['event_exhibit_id'] = event_exhibit_id
|
||||
sql_select_event_exhibit_id = f'AND `event_exhibit_tracking`.event_exhibit_id = :event_exhibit_id'
|
||||
|
||||
if event_badge_id:
|
||||
if event_badge_id := redis_lookup_id_random(record_id_random=event_badge_id, table_name='event_badge'): pass
|
||||
else: return False
|
||||
|
||||
data['event_badge_id'] = event_badge_id
|
||||
sql_select_event_badge_id = f'AND `event_exhibit_tracking`.event_badge_id = :event_badge_id'
|
||||
|
||||
if event_person_id:
|
||||
if event_person_id := redis_lookup_id_random(record_id_random=event_person_id, table_name='event_person'): pass
|
||||
else: return False
|
||||
|
||||
data['event_person_id'] = event_person_id
|
||||
sql_select_event_person_id = f'AND `event_exhibit_tracking`.event_person_id = :event_person_id'
|
||||
|
||||
sql_hidden = ''
|
||||
if hidden in ['hidden', 'not_hidden', 'all']:
|
||||
if hidden == 'hidden':
|
||||
data['hide'] = True
|
||||
sql_hidden = f'AND `event_exhibit_tracking`.hide = :hide'
|
||||
elif hidden == 'not_hidden':
|
||||
data['hide'] = False
|
||||
sql_hidden = f'AND `event_exhibit_tracking`.hide = :hide'
|
||||
elif hidden == 'all':
|
||||
sql_hidden = ''
|
||||
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='event_exhibit_tracking', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
if event_id or event_exhibit_id or event_person_id: pass
|
||||
else: return False
|
||||
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_exhibit_tracking`.id AS 'event_exhibit_tracking_id', `event_exhibit_tracking`.id_random AS 'event_exhibit_tracking_id_random', priority AS 'priority', sort AS 'sort', hide AS 'hide', enable AS 'enable'
|
||||
FROM `v_event_exhibit_tracking` AS `event_exhibit_tracking`
|
||||
WHERE
|
||||
{sql_select_event_id}
|
||||
{sql_select_event_exhibit_id}
|
||||
{sql_select_event_badge_id}
|
||||
{sql_select_event_person_id}
|
||||
{sql_hidden}
|
||||
{sql_enabled}
|
||||
AND allow_tracking = true
|
||||
ORDER BY `event_exhibit_tracking`.priority DESC, -`event_exhibit_tracking`.sort DESC, `event_exhibit_tracking`.created_on DESC, `event_exhibit_tracking`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if event_exhibit_rec_li_result := sql_select(data=data, sql=sql, as_list=True, log_lvl=logging.WARNING):
|
||||
log.info('Got a list result')
|
||||
event_exhibit_rec_li = event_exhibit_rec_li_result
|
||||
else: # [] or False
|
||||
log.info('No results or something went wrong')
|
||||
event_exhibit_rec_li = event_exhibit_rec_li_result
|
||||
|
||||
log.debug(event_exhibit_rec_li_result)
|
||||
|
||||
return event_exhibit_rec_li
|
||||
# ### END ### API Event Exhibit Tracking Methods ### get_event_exhibit_tracking_rec_list() ###
|
||||
306
app/methods/event_file_methods.py
Normal file
306
app/methods/event_file_methods.py
Normal file
@@ -0,0 +1,306 @@
|
||||
import datetime, hashlib, os, pathlib, shutil, time
|
||||
|
||||
from fastapi import File, UploadFile
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import get_id_random, redis_lookup_id_random, sql_delete, sql_enable_part, sql_insert, sql_insert_or_update, sql_limit_offset_part, sql_select, sql_update
|
||||
# from app.lib_general import log, logging, logger_reset
|
||||
from app.log import log, logging, logger_reset
|
||||
|
||||
from app.methods.hosted_file_methods import load_hosted_file_obj
|
||||
|
||||
from app.models.event_file_models import Event_File_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Event File Methods ### create_event_file_obj() ###
|
||||
@logger_reset
|
||||
def create_event_file_obj(event_file_obj_new: Event_File_Base):
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
try:
|
||||
# event_file_obj_data = event_file_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'created_on', 'updated_on'})
|
||||
event_file_obj_data = event_file_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'saved', 'already_exists', 'copy_timer', 'created_on', 'updated_on'})
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
|
||||
log.debug(event_file_obj_data)
|
||||
|
||||
if event_file_obj_in_result := sql_insert_or_update(data=event_file_obj_data, table_name='event_file', rm_id_random=True): pass
|
||||
else:
|
||||
return False
|
||||
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_file_obj_in_result)
|
||||
|
||||
event_file_id = event_file_obj_in_result
|
||||
|
||||
log.debug(f'Returning the new event_file_id: {event_file_id}')
|
||||
return event_file_id
|
||||
# ### END ### API Event File Methods ### create_event_file_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event File Methods ### load_event_file_obj() ###
|
||||
@logger_reset
|
||||
def load_event_file_obj(
|
||||
event_file_id: int|str,
|
||||
model_as_dict: bool = False, # This was defaulted to True 2022-03-07
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_hosted_file: bool = False,
|
||||
) -> Event_File_Base|dict|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_file_id := redis_lookup_id_random(record_id_random=event_file_id, table_name='event_file'): pass
|
||||
else: return False
|
||||
|
||||
# NOTE: What table or view should be used here???
|
||||
if event_file_rec := sql_select(table_name='v_event_file_simple', record_id=event_file_id):
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_file_rec)
|
||||
else:
|
||||
return False
|
||||
|
||||
if event_file_rec.get('for_type') and event_file_rec.get('for_id') and not event_file_rec.get('for_id_random'):
|
||||
event_file_rec['for_id_random'] = get_id_random(event_file_rec.get('for_id'), table_name=event_file_rec.get('for_type'))
|
||||
|
||||
hosted_file_id = event_file_rec.get('hosted_file_id', None)
|
||||
|
||||
try:
|
||||
event_file_obj = Event_File_Base(**event_file_rec)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
log.debug(event_file_obj)
|
||||
|
||||
if inc_hosted_file and hosted_file_id:
|
||||
log.info('Need to include hosted file...')
|
||||
if hosted_file_obj := load_hosted_file_obj(
|
||||
hosted_file_id = hosted_file_id,
|
||||
enabled = enabled,
|
||||
):
|
||||
event_file_obj.hosted_file = hosted_file_obj
|
||||
# event_file_obj.hosted_file = hosted_file_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset)
|
||||
else:
|
||||
event_file_obj.hosted_file = {}
|
||||
else:
|
||||
event_file_obj.hosted_file = None
|
||||
|
||||
log.debug(event_file_obj)
|
||||
|
||||
if model_as_dict:
|
||||
return event_file_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return event_file_obj
|
||||
# ### END ### API Event File Methods ### load_event_file_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event File Methods ### get_event_file_rec_list() ###
|
||||
# Updated 2021-09-10
|
||||
@logger_reset
|
||||
def get_event_file_rec_list(
|
||||
for_type: str, # NOTE: This is not for_obj_type because the field name is actually for_type
|
||||
for_id: int|str, # NOTE: This is not for_obj_id because the field name is actually for_id
|
||||
file_purpose_id: int = None, # NOTE: Not prefixed with lu_
|
||||
file_purpose: str = None,
|
||||
internal_use: bool = None, # Default to False instead of None
|
||||
priority: bool = None,
|
||||
group: str = None,
|
||||
# event_id: str = None,
|
||||
# event_person_id: str = None,
|
||||
# event_presentation_id: str = None,
|
||||
# event_presenter_id: str = None,
|
||||
# event_session_id: str = None,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_id := redis_lookup_id_random(record_id_random=for_id, table_name=for_type): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['for_type'] = for_type
|
||||
data['for_id'] = for_id
|
||||
data['file_purpose_id'] = file_purpose_id
|
||||
data['file_purpose'] = file_purpose
|
||||
data['internal_use'] = internal_use
|
||||
data['priority'] = priority
|
||||
# data['sort'] = sort
|
||||
data['group'] = group # Same or similar as file purpose?
|
||||
|
||||
sql_for_type_id = f'`event_file`.for_type = :for_type AND `event_file`.for_id = :for_id'
|
||||
|
||||
if file_purpose_id:
|
||||
sql_file_purpose_id = f'AND `event_file`.lu_file_purpose_id = :file_purpose_id'
|
||||
else:
|
||||
sql_file_purpose_id = ''
|
||||
|
||||
if file_purpose:
|
||||
sql_file_purpose = f'AND `event_file`.file_purpose = :file_purpose'
|
||||
else:
|
||||
sql_file_purpose = ''
|
||||
|
||||
if internal_use:
|
||||
sql_internal_use = f'AND `event_file`.internal_use = 1'
|
||||
elif internal_use is False:
|
||||
sql_internal_use = f'AND (`event_file`.internal_use IS NULL OR `event_file`.internal_use = 0)'
|
||||
else:
|
||||
sql_internal_use = ''
|
||||
|
||||
if priority:
|
||||
sql_priority = f'AND `event_file`.priority = :priority'
|
||||
else:
|
||||
sql_priority = ''
|
||||
|
||||
if group:
|
||||
sql_group = f'AND `event_file`.group = :group'
|
||||
else:
|
||||
sql_group = ''
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='event_file', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_file`.id AS 'event_file_id', `event_file`.id_random AS 'event_file_id_random'
|
||||
FROM `event_file` AS `event_file`
|
||||
WHERE
|
||||
{sql_for_type_id}
|
||||
{sql_file_purpose_id}
|
||||
{sql_file_purpose}
|
||||
{sql_internal_use}
|
||||
{sql_priority}
|
||||
{sql_group}
|
||||
{sql_enabled}
|
||||
ORDER BY `event_file`.priority DESC, -`event_file`.sort DESC, `event_file`.created_on DESC, `event_file`.updated_on DESC, `event_file`.filename ASC, `event_file`.extension ASC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if event_file_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
|
||||
event_file_rec_li = event_file_rec_li_result
|
||||
else:
|
||||
event_file_rec_li = []
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_file_rec_li_result)
|
||||
log.debug(type(event_file_rec_li))
|
||||
log.debug(len(event_file_rec_li))
|
||||
|
||||
return event_file_rec_li
|
||||
# ### END ### API Event File Methods ### get_event_file_rec_list() ###
|
||||
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Event File Methods ### load_event_file_obj_list() ###
|
||||
@logger_reset
|
||||
def load_event_file_obj_list(
|
||||
event_id: int|str|None = None,
|
||||
event_session_id: int|str|None = None,
|
||||
inc_hosted_file: bool = False,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 1000,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
data: dict = {}
|
||||
if event_id:
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else: return False
|
||||
data['for_type'] = 'event'
|
||||
data['for_id'] = event_id
|
||||
sql_obj_type_id = f'`tbl`.for_type = :for_type AND `tbl`.for_id = :for_id'
|
||||
elif event_session_id:
|
||||
if event_session_id := redis_lookup_id_random(record_id_random=event_session_id, table_name='event_session'): pass
|
||||
else: return False
|
||||
data['for_type'] = 'event_session'
|
||||
data['for_id'] = event_session_id
|
||||
sql_obj_type_id = f'`tbl`.for_type = :for_type AND `tbl`.for_id = :for_id'
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='event_file', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
sql = f"""
|
||||
SELECT `tbl`.id AS 'event_file_id', `tbl`.id_random AS 'event_file_id_random'
|
||||
FROM `event_file` AS `tbl`
|
||||
WHERE
|
||||
{sql_obj_type_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if event_file_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_file_rec_li_result)
|
||||
event_file_result_li = []
|
||||
for event_file_rec in event_file_rec_li_result:
|
||||
event_file_id = event_file_rec.get('event_file_id', None)
|
||||
if event_file_result := load_event_file_obj(
|
||||
event_file_id = event_file_id,
|
||||
model_as_dict = True, # NOTE: This is overriding the model_as_dict param!
|
||||
enabled = enabled,
|
||||
inc_hosted_file = inc_hosted_file,
|
||||
):
|
||||
log.debug(event_file_result)
|
||||
event_file_result_li.append(event_file_result)
|
||||
else:
|
||||
log.debug(event_file_result)
|
||||
event_file_result_li.append(None)
|
||||
# log.debug(event_file_result_li)
|
||||
else:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_file_rec_li_result)
|
||||
event_file_result_li = []
|
||||
|
||||
return event_file_result_li
|
||||
# ### END ### API Event Methods ### load_event_file_obj_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event File Methods ### handle_delete_event_file() ###
|
||||
# Updated 2022-08-18
|
||||
@logger_reset
|
||||
def handle_delete_event_file(
|
||||
event_file_id: int|str,
|
||||
|
||||
link_to_type: str = None,
|
||||
link_to_id: int|str = None,
|
||||
|
||||
rm_all_links: bool = False,
|
||||
rm_orphan: bool = False,
|
||||
):
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
# else: return False
|
||||
|
||||
if event_file_id := redis_lookup_id_random(record_id_random=event_file_id, table_name='event_file'): pass
|
||||
else: return False
|
||||
|
||||
# log.debug(event_file_id)
|
||||
|
||||
# try:
|
||||
# print('Trying to SQL DELETE!!!!')
|
||||
# event_file_delete_result = sql_delete(table_name='event_file', record_id=event_file_id)
|
||||
# print('SQL DELETE ran')
|
||||
# log.debug(event_file_delete_result)
|
||||
# except e:
|
||||
# log.exception(e)
|
||||
|
||||
if event_file_delete_result := sql_delete(table_name='event_file', record_id=event_file_id, log_lvl=logging.DEBUG):
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.info(f'Deleted Event File ID: {event_file_id}')
|
||||
return True
|
||||
else:
|
||||
log.error(f'Something went wrong will trying to delete Event File ID: {event_file_id}')
|
||||
return False
|
||||
122
app/methods/event_list_methods.py
Normal file
122
app/methods/event_list_methods.py
Normal file
@@ -0,0 +1,122 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging
|
||||
|
||||
from app.methods.event_methods import load_event_obj
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Methods ### load_event_obj_list() ###
|
||||
def load_event_obj_list(
|
||||
account_id: int|str,
|
||||
limit: int = 1000,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_contact_1: bool = False,
|
||||
inc_contact_2: bool = False,
|
||||
inc_contact_3: bool = False,
|
||||
inc_event_abstract_list: bool = False,
|
||||
inc_event_badge_list: bool = False,
|
||||
inc_event_cfg: bool = False,
|
||||
inc_event_device_list: bool = False,
|
||||
inc_event_exhibit_list: bool = False,
|
||||
inc_event_file_list: bool = False,
|
||||
inc_event_location: bool = False, # For event_session child object
|
||||
inc_event_location_list: bool = False,
|
||||
inc_event_person_list: bool = False,
|
||||
inc_event_presentation_list: bool = False,
|
||||
inc_event_presenter_cat: bool = False, # For event_session child object
|
||||
inc_event_presenter_list: bool = False,
|
||||
inc_event_registration_cfg: bool = False,
|
||||
inc_event_registration_list: bool = False,
|
||||
inc_event_session_list: bool = False,
|
||||
inc_event_track: bool = False, # For event_session child object
|
||||
inc_event_track_list: bool = False,
|
||||
inc_location_address: bool = False,
|
||||
inc_poc_event_person: bool = False,
|
||||
inc_person: bool = False,
|
||||
inc_user: bool = False,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['account_id'] = account_id
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
# else: tbl_obj['account'] = None
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `tbl`.id AS 'event_id', `tbl`.id_random AS 'event_id_random'
|
||||
FROM `event` AS `tbl`
|
||||
WHERE `tbl`.account_id = :account_id
|
||||
{sql_enabled}
|
||||
ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if event_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_rec_li_result)
|
||||
event_result_li = []
|
||||
for event_rec in event_rec_li_result:
|
||||
event_id = event_rec.get('event_id', None)
|
||||
if event_result := load_event_obj(
|
||||
event_id = event_id,
|
||||
limit = limit,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
# inc_location_address = inc_address,
|
||||
# inc_contact_1 = inc_contact,
|
||||
# inc_contact_2 = inc_contact,
|
||||
# inc_contact_3 = inc_contact,
|
||||
# inc_event_abstract_list = inc_event_abstract_list,
|
||||
# inc_event_badge_list = inc_event_badge_list,
|
||||
# inc_event_device_list = inc_event_device_list,
|
||||
inc_event_exhibit_list = inc_event_exhibit_list,
|
||||
inc_event_file_list = inc_event_file_list,
|
||||
inc_event_location_list = inc_event_location_list,
|
||||
inc_event_person_list = inc_event_person_list,
|
||||
inc_event_presentation_list = inc_event_presentation_list,
|
||||
inc_event_presenter_list = inc_event_presenter_list,
|
||||
inc_event_registration_list = inc_event_registration_list,
|
||||
inc_event_session_list = inc_event_session_list,
|
||||
inc_event_track_list = inc_event_track_list,
|
||||
# inc_person = inc_person,
|
||||
# inc_user = inc_user,
|
||||
):
|
||||
log.debug(event_result)
|
||||
event_result_li.append(event_result)
|
||||
else:
|
||||
log.debug(event_result)
|
||||
event_result_li.append(None)
|
||||
log.debug(event_result_li)
|
||||
else:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_rec_li_result)
|
||||
event_result_li = []
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
|
||||
return event_result_li
|
||||
# ### END ### API Event Methods ### load_event_obj_list() ###
|
||||
465
app/methods/event_location_methods.py
Normal file
465
app/methods/event_location_methods.py
Normal file
@@ -0,0 +1,465 @@
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_enable_part, sql_insert, sql_limit_offset_part, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
# from app.methods.event_methods import load_event_obj
|
||||
# from app.methods.event_device_methods import load_event_device_obj
|
||||
# from app.methods.event_file_methods import load_event_file_obj
|
||||
# from app.methods.event_presentation_methods import load_event_presentation_obj
|
||||
# from app.methods.event_presenter_methods import load_event_presenter_obj
|
||||
# from app.methods.event_track_methods import load_event_track_obj
|
||||
|
||||
from app.models.event_location_models import Event_Location_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Location Methods ### load_event_location_obj() ###
|
||||
# Updated 2022-09-23
|
||||
@logger_reset
|
||||
def load_event_location_obj(
|
||||
event_location_id: int|str,
|
||||
inc_event_device_list: bool = False,
|
||||
inc_event_file_list: bool = False,
|
||||
inc_event_file_internal_use_list: bool = False,
|
||||
inc_event_presentation_list: bool = False,
|
||||
inc_event_presenter_list: bool = False,
|
||||
inc_event_session_list: bool = False,
|
||||
inc_file_count: bool = False, # NOTE: file counts are from separate views
|
||||
inc_hosted_file: bool = False,
|
||||
event_file_file_purpose_id: int = None,
|
||||
event_file_file_purpose: str = None,
|
||||
event_file_priority: bool = None,
|
||||
event_file_group: str = None,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
hidden: str = 'hidden', # hidden, not_hidden, all
|
||||
limit: int = 1000,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
) -> Event_Location_Base|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_location_id := redis_lookup_id_random(record_id_random=event_location_id, table_name='event_location'): pass
|
||||
else: return False
|
||||
|
||||
if inc_file_count:
|
||||
log.info('Using view with file count')
|
||||
if event_location_rec := sql_select(table_name='v_event_location_w_file_count', record_id=event_location_id): pass
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
if event_location_rec := sql_select(table_name='v_event_location', record_id=event_location_id): pass
|
||||
else:
|
||||
return False
|
||||
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_location_rec)
|
||||
|
||||
try:
|
||||
log.info('Try to apply event location record data to Event_Location_Base...')
|
||||
event_location_obj = Event_Location_Base(**event_location_rec)
|
||||
log.debug(event_location_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
#account_id = event_location_rec.get('account_id', None)
|
||||
event_id = event_location_rec.get('event_id', None)
|
||||
|
||||
# Updated 2022-09-27
|
||||
if inc_event_device_list:
|
||||
log.info('Need to include event device list...')
|
||||
|
||||
from app.methods.event_device_methods import get_event_device_rec_list, load_event_device_obj
|
||||
if event_device_rec_list_result := get_event_device_rec_list(
|
||||
for_type = 'event_location',
|
||||
for_id = event_location_id,
|
||||
enabled = enabled,
|
||||
limit = limit,
|
||||
offset = offset,
|
||||
):
|
||||
event_device_result_list = []
|
||||
for event_device_rec in event_device_rec_list_result:
|
||||
if load_event_device_result := load_event_device_obj(
|
||||
event_device_id = event_device_rec.get('event_device_id', None),
|
||||
enabled = enabled,
|
||||
):
|
||||
event_device_result_list.append(load_event_device_result)
|
||||
else:
|
||||
event_device_result_list.append(None)
|
||||
log.debug(event_device_result_list)
|
||||
event_location_obj.event_device_list = event_device_result_list
|
||||
elif isinstance(event_device_rec_list_result, list):
|
||||
event_location_obj.event_device_list = []
|
||||
else:
|
||||
event_location_obj.event_device_list = None
|
||||
|
||||
# if inc_event_file_list: pass
|
||||
|
||||
# Updated 2021-10-21
|
||||
if inc_event_file_list:
|
||||
log.info('Need to include event file list...')
|
||||
|
||||
from app.methods.event_file_methods import get_event_file_rec_list, load_event_file_obj
|
||||
if event_file_rec_list_result := get_event_file_rec_list(
|
||||
for_type = 'event_location',
|
||||
for_id = event_location_id,
|
||||
file_purpose_id = event_file_file_purpose_id,
|
||||
file_purpose = event_file_file_purpose,
|
||||
priority = event_file_priority,
|
||||
group = event_file_group,
|
||||
enabled = enabled,
|
||||
limit = limit,
|
||||
):
|
||||
event_file_result_list = []
|
||||
for event_file_rec in event_file_rec_list_result:
|
||||
if load_event_file_result := load_event_file_obj(
|
||||
event_file_id = event_file_rec.get('event_file_id', None),
|
||||
enabled = enabled,
|
||||
# inc_hosted_file = inc_hosted_file,
|
||||
):
|
||||
event_file_result_list.append(load_event_file_result)
|
||||
else:
|
||||
event_file_result_list.append(None)
|
||||
log.debug(event_file_result_list)
|
||||
event_location_obj.event_file_list = event_file_result_list
|
||||
elif isinstance(event_file_rec_list_result, list):
|
||||
event_location_obj.event_file_list = []
|
||||
else:
|
||||
event_location_obj.event_file_list = None
|
||||
|
||||
if inc_event_file_internal_use_list:
|
||||
log.info('Need to include event file internal use list...')
|
||||
|
||||
from app.methods.event_file_methods import get_event_file_rec_list, load_event_file_obj
|
||||
if event_file_rec_list_result := get_event_file_rec_list(
|
||||
for_type = 'event_location',
|
||||
for_id = event_location_id,
|
||||
file_purpose_id = event_file_file_purpose_id,
|
||||
file_purpose = event_file_file_purpose,
|
||||
internal_use = True,
|
||||
priority = event_file_priority,
|
||||
group = event_file_group,
|
||||
enabled = enabled,
|
||||
limit = limit,
|
||||
):
|
||||
event_file_result_list = []
|
||||
for event_file_rec in event_file_rec_list_result:
|
||||
if load_event_file_result := load_event_file_obj(
|
||||
event_file_id = event_file_rec.get('event_file_id', None),
|
||||
enabled = enabled,
|
||||
inc_hosted_file = inc_hosted_file,
|
||||
):
|
||||
event_file_result_list.append(load_event_file_result)
|
||||
else:
|
||||
event_file_result_list.append(None)
|
||||
log.debug(event_file_result_list)
|
||||
event_location_obj.event_file_internal_use_list = event_file_result_list
|
||||
elif isinstance(event_file_rec_list_result, list):
|
||||
event_location_obj.event_file_internal_use_list = []
|
||||
else:
|
||||
event_location_obj.event_file_internal_use_list = None
|
||||
|
||||
if inc_event_presentation_list:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
|
||||
data = {}
|
||||
data['event_location_id'] = event_location_id
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `event_presentation`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `event_presentation`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
# else: event_location_obj['event'] = None
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_presentation`.id AS 'event_presentation_id', `event_presentation`.id_random AS 'event_presentation_id_random'
|
||||
FROM `v_event_presentation` AS `event_presentation`
|
||||
WHERE `event_presentation`.event_location_id = :event_location_id
|
||||
{sql_enabled}
|
||||
ORDER BY `event_presentation`.created_on DESC, `event_presentation`.updated_on DESC;
|
||||
"""
|
||||
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
if event_presentation_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_presentation_rec_li_result)
|
||||
event_presentation_obj_li = []
|
||||
for event_presentation_rec in event_presentation_rec_li_result:
|
||||
event_presentation_id = event_presentation_rec.get('event_presentation_id', None)
|
||||
if event_presentation_obj := load_event_presentation_obj(
|
||||
event_presentation_id=event_presentation_id,
|
||||
enabled=enabled,
|
||||
inc_event_device_list=inc_event_device_list,
|
||||
inc_event_file_list=inc_event_file_list,
|
||||
inc_event_presenter_list=inc_event_presenter_list,
|
||||
):
|
||||
data = event_presentation_obj.dict(by_alias=True, exclude_unset=True)
|
||||
event_presentation_obj_li.append(data)
|
||||
log.debug(event_presentation_obj_li)
|
||||
event_location_obj.event_presentation_list = event_presentation_obj_li
|
||||
else:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_presentation_rec_li_result)
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
|
||||
if inc_event_presenter_list: pass
|
||||
|
||||
# Updated 2021-10-09
|
||||
if inc_event_session_list:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.info('Need to include event session list...')
|
||||
|
||||
from app.methods.event_session_methods import get_event_session_rec_list, load_event_session_obj
|
||||
|
||||
if event_session_rec_list_result := get_event_session_rec_list(
|
||||
event_location_id = event_location_id,
|
||||
enabled = enabled, # enabled, disabled, all
|
||||
approved = 'all', # approve(d), not_approved, all
|
||||
hidden = hidden, # hidden, not_hidden, all
|
||||
review = 'all', # ready, not_ready, all
|
||||
limit = limit,
|
||||
):
|
||||
event_session_result_list = []
|
||||
for event_session_rec in event_session_rec_list_result:
|
||||
if load_event_session_result := load_event_session_obj(
|
||||
event_session_id = event_session_rec.get('event_session_id', None),
|
||||
enabled = enabled,
|
||||
limit = limit,
|
||||
inc_event_file_list = inc_event_file_list,
|
||||
# inc_event_presentation_list = inc_event_presentation_list,
|
||||
# inc_event_presenter_cat = inc_event_presenter_cat,
|
||||
# inc_event_presenter_list = inc_event_presenter_list,
|
||||
# inc_person = inc_person,
|
||||
# inc_poc_event_person = inc_poc_event_person,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
# model_as_dict = model_as_dict,
|
||||
):
|
||||
event_session_result_list.append(load_event_session_result)
|
||||
else:
|
||||
event_session_result_list.append(None)
|
||||
log.debug(event_session_result_list)
|
||||
event_location_obj.event_session_list = event_session_result_list
|
||||
elif isinstance(event_session_rec_list_result, list):
|
||||
event_location_obj.event_session_list = []
|
||||
else:
|
||||
event_location_obj.event_session_list = None
|
||||
|
||||
if model_as_dict:
|
||||
return event_location_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return event_location_obj
|
||||
|
||||
return event_location_obj
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Location Methods ### get_event_location_rec_list() ###
|
||||
# Updated 2021-12-13
|
||||
@logger_reset
|
||||
def get_event_location_rec_list(
|
||||
event_id: str,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
hidden: str = 'not_hidden', # hidden, not_hidden, all
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['event_id'] = event_id
|
||||
|
||||
if event_id:
|
||||
sql_where_event_id = f'`event_location`.event_id = :event_id'
|
||||
else: sql_where_event_id = ''
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `event_location`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `event_location`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
|
||||
if hidden in ['hidden', 'not_hidden', 'all']:
|
||||
if hidden == 'hidden':
|
||||
data['hide'] = True
|
||||
sql_hidden = f'AND `event_location`.hide = :hide'
|
||||
elif hidden == 'not_hidden':
|
||||
data['hide'] = False
|
||||
sql_hidden = f'AND `event_location`.hide = :hide'
|
||||
elif hidden == 'all':
|
||||
sql_hidden = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_location`.id AS 'event_location_id', `event_location`.id_random AS 'event_location_id_random'
|
||||
FROM `event_location` AS `event_location`
|
||||
WHERE
|
||||
{sql_where_event_id}
|
||||
{sql_enabled}
|
||||
{sql_hidden}
|
||||
ORDER BY `event_location`.priority DESC, -`event_location`.sort DESC, `event_location`.name ASC, `event_location`.created_on DESC, `event_location`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if event_location_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
log.info('Got a list result')
|
||||
event_location_rec_li = event_location_rec_li_result
|
||||
else: # [] or False
|
||||
log.info('No results or something went wrong')
|
||||
event_location_rec_li = event_location_rec_li_result
|
||||
|
||||
log.debug(event_location_rec_li_result)
|
||||
|
||||
return event_location_rec_li
|
||||
# ### END ### API Event Location Methods ### get_event_location_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Location Methods ### create_update_event_location_obj_v4() ###
|
||||
# NOTE: This will create or update a event_location.
|
||||
# Rewrite and updated 2021-08-25
|
||||
def create_update_event_location_obj_v4(
|
||||
event_location_dict_obj: Event_Location_Base|dict,
|
||||
event_location_id: int|str = None,
|
||||
event_id: int|str = None,
|
||||
# event_location_id: int|str = None, # For future?
|
||||
# event_track_id: int|str = None, # For future?
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_outline: bool = False,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
log.info('Checking requirements...')
|
||||
if event_location_id:
|
||||
log.info(f'Event Location ID passed. Update existing Event Location. Event Location ID: {event_location_id}')
|
||||
|
||||
if event_location_id := redis_lookup_id_random(record_id_random=event_location_id, table_name='event_location'): pass
|
||||
else:
|
||||
log.error('Event Location ID passed but is invalid. Failed requirement.')
|
||||
return False
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Event ID passed. Not required. Ignoring.')
|
||||
log.info(f'Event ID: {event_id}')
|
||||
|
||||
log.info('Attempting to get Event ID from related object.')
|
||||
from app.methods.event_methods import get_event_id_w_for_type_id
|
||||
if event_id := get_event_id_w_for_type_id(for_type='event_location', for_id=event_location_id): pass
|
||||
else:
|
||||
log.error('Unable to get Event ID from related object.')
|
||||
False
|
||||
else:
|
||||
log.info('No Event Location ID passed. Create new Event Location. Required: Account ID, Event ID')
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Event ID passed. Failed requirement.')
|
||||
log.info(f'Event ID: {event_id}')
|
||||
return False
|
||||
|
||||
log.debug(type(event_location_dict_obj))
|
||||
if isinstance(event_location_dict_obj, dict):
|
||||
event_location_dict = event_location_dict_obj
|
||||
if event_location_id:
|
||||
event_location_dict['event_location_id'] = event_location_id
|
||||
if event_id:
|
||||
event_location_dict['event_id'] = event_id
|
||||
try:
|
||||
event_location_obj = Event_Location_Base(**event_location_dict)
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_location_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
event_location_obj = event_location_dict_obj
|
||||
if event_location_id:
|
||||
# NOTE: Can't update the ID alias if it was never set.
|
||||
event_location_obj.id = event_location_id
|
||||
if event_id:
|
||||
event_location_obj.event_id = event_id
|
||||
|
||||
event_location_dict = event_location_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event_presentation', 'event_presentation_list', 'created_on', 'updated_on'})
|
||||
|
||||
if event_location_id:
|
||||
if event_location_dict_up_result := sql_update(data=event_location_dict, table_name='event_location', rm_id_random=True): pass
|
||||
else:
|
||||
log.warning(f'Event Location not updated. Event Location ID: {event_location_id}')
|
||||
log.debug(event_location_dict_up_result)
|
||||
return False
|
||||
log.debug(event_location_dict_up_result)
|
||||
else:
|
||||
if event_location_dict_in_result := sql_insert(data=event_location_dict, table_name='event_location', rm_id_random=True, id_random_length=8): pass
|
||||
else:
|
||||
log.warning(f'Event Location not created.')
|
||||
log.debug(event_location_dict_in_result)
|
||||
return False
|
||||
log.debug(event_location_dict_in_result)
|
||||
|
||||
event_location_id = event_location_dict_in_result
|
||||
|
||||
log.debug(event_location_id)
|
||||
|
||||
event_location_outline = {}
|
||||
event_location_outline['event_location_id'] = event_location_id
|
||||
event_location_outline['event_session_list'] = []
|
||||
|
||||
if event_location_obj.event_session_list and isinstance(event_location_obj.event_session_list, list):
|
||||
log.info(f'Event Session List was found. Loop through and create a new Event Session for each and link them to the new Event Location. Event Location ID: {event_location_id}')
|
||||
for event_session_obj in event_location_obj.event_session_list:
|
||||
# NOTE: Use object model version because of better type checking and validations
|
||||
log.debug(event_session_obj)
|
||||
if event_session_id := event_session_obj.id: pass
|
||||
else: event_session_id = None
|
||||
# event_session_obj.event_id = event_id
|
||||
# event_session_obj.event_location_id = event_location_id
|
||||
create_update_event_session_obj_result = create_update_event_session_obj_v4(
|
||||
event_session_dict_obj = event_session_obj,
|
||||
event_session_id = event_session_id,
|
||||
event_id = event_id,
|
||||
event_location_id = event_location_id,
|
||||
fail_any = fail_any,
|
||||
return_outline = return_outline,
|
||||
)
|
||||
if isinstance(create_update_event_session_obj_result, int):
|
||||
event_session_id = create_update_event_session_obj_result
|
||||
elif create_update_event_session_obj_result == True: pass
|
||||
else:
|
||||
log.warning(f'Create or Update failed while trying create_update_event_session_obj_v4(): {create_update_event_session_obj_result}')
|
||||
event_session_id = None
|
||||
|
||||
event_location_outline['event_session_id'] = event_session_id
|
||||
|
||||
if return_outline:
|
||||
log.debug(f'Returning the Event Location Outline: {event_location_outline}')
|
||||
return event_location_outline
|
||||
else:
|
||||
log.debug(f'Returning the Event Location ID: {event_location_id}')
|
||||
return event_location_id
|
||||
# ### END ### API Event Location Methods ### create_update_event_location_obj_v4() ###
|
||||
1030
app/methods/event_methods.py
Normal file
1030
app/methods/event_methods.py
Normal file
File diff suppressed because it is too large
Load Diff
1090
app/methods/event_person_methods.py
Normal file
1090
app/methods/event_person_methods.py
Normal file
File diff suppressed because it is too large
Load Diff
223
app/methods/event_person_profile_methods.py
Normal file
223
app/methods/event_person_profile_methods.py
Normal file
@@ -0,0 +1,223 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import get_account_id_w_for_type_id, redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging
|
||||
|
||||
from app.methods.address_methods import create_address_obj, create_update_address_obj, create_update_address_obj_v4, update_address_obj
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
from app.models.event_person_profile_models import Event_Person_Profile_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Person Profile Methods ### load_event_person_profile_obj() ###
|
||||
def load_event_person_profile_obj(
|
||||
event_person_profile_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_address: bool = False,
|
||||
inc_contact: bool = False,
|
||||
) -> Event_Person_Profile_Base|dict|bool:
|
||||
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_person_profile_id := redis_lookup_id_random(record_id_random=event_person_profile_id, table_name='event_person_profile'): pass
|
||||
else: return False
|
||||
|
||||
if event_person_profile_rec := sql_select(table_name='v_event_person_profile', record_id=event_person_profile_id): pass
|
||||
else: return False
|
||||
|
||||
try:
|
||||
event_person_profile_obj = Event_Person_Profile_Base(**event_person_profile_rec)
|
||||
log.debug(event_person_profile_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
if inc_contact:
|
||||
log.info('Need to include contact data...')
|
||||
contact_id = event_person_profile_rec.get('contact_id', None)
|
||||
log.debug(contact_id)
|
||||
from app.methods.contact_methods import load_contact_obj
|
||||
if contact_result := load_contact_obj(
|
||||
contact_id = contact_id,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
event_person_profile_obj.contact = contact_result
|
||||
else: event_person_profile_obj.contact = None
|
||||
|
||||
if model_as_dict:
|
||||
return event_person_profile_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return event_person_profile_obj
|
||||
# ### END ### API Event Person Profile Methods ### load_event_person_profile_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Person Profile Methods ### get_event_person_id_w_event_person_profile_id() ###
|
||||
# Updated 2021-09-07
|
||||
def get_event_person_id_w_event_person_profile_id(
|
||||
event_person_profile_id: int|str,
|
||||
) -> bool|int|None:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_person_profile_id := redis_lookup_id_random(record_id_random=event_person_profile_id, table_name='event_person_profile'): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['event_person_profile_id'] = event_person_profile_id
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_person_profile`.id AS 'event_person_profile_id', `event_person_profile`.id_random AS 'event_person_profile_id_random', `event_person_profile`.account_id AS account_id
|
||||
FROM `event_person_profile` AS `event_person_profile`
|
||||
WHERE `event_person_profile`.id = :event_person_profile_id
|
||||
LIMIT 1;
|
||||
"""
|
||||
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
if event_person_profile_data_result := sql_select(data=data, sql=sql):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_person_profile_data_result)
|
||||
if account_id := event_person_profile_data_result.get('account_id', None): return account_id
|
||||
else: return False
|
||||
else: return None
|
||||
# ### END ### API Event Person Profile Methods ### get_event_person_id_w_event_person_profile_id() ###
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Person Profile Methods ### create_update_event_person_profile_obj_v4() ###
|
||||
# Updated 2022-02-23
|
||||
def create_update_event_person_profile_obj_v4(
|
||||
event_person_profile_dict_obj: Event_Person_Profile_Base|dict,
|
||||
event_person_profile_id: int|str = None,
|
||||
account_id: int = None,
|
||||
# event_id: int|str = None,
|
||||
event_person_id: int|str = None,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_outline: bool = False,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
log.info('Checking requirements...')
|
||||
if event_person_profile_id:
|
||||
log.info(f'Event Person Profile ID passed. Update existing Event Person Profile. Event Person Profile ID: {event_person_profile_id}')
|
||||
|
||||
if event_person_profile_id := redis_lookup_id_random(record_id_random=event_person_profile_id, table_name='event_person_profile'): pass
|
||||
else:
|
||||
log.error('Event Person Profile ID passed but is invalid. Failed requirement.')
|
||||
return False
|
||||
else:
|
||||
log.info('No Event Person Profile ID passed. Create new Event Person Profile. Required: Event Person ID')
|
||||
|
||||
if event_person_id := redis_lookup_id_random(record_id_random=event_person_id, table_name='event_person'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Event Person ID passed. Failed requirement.')
|
||||
log.info(f'Event Person ID: {event_person_id}')
|
||||
return False
|
||||
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(event_person_profile_dict_obj))
|
||||
if isinstance(event_person_profile_dict_obj, dict):
|
||||
event_person_profile_dict = event_person_profile_dict_obj
|
||||
if event_person_profile_id:
|
||||
event_person_profile_dict['event_person_profile_id'] = event_person_profile_id
|
||||
try:
|
||||
event_person_profile_obj = Event_Person_Profile_Base(**event_person_profile_dict)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
event_person_profile_obj = event_person_profile_dict_obj
|
||||
if event_person_profile_id:
|
||||
# NOTE: Can't update the ID alias if it was never set.
|
||||
event_person_profile_obj.id = event_person_profile_id
|
||||
log.debug(event_person_profile_obj)
|
||||
|
||||
event_person_profile_dict = event_person_profile_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'account_id', 'account_id_random', 'contact', 'event_cfg', 'event_id', 'event_id_random', 'event_person_id', 'event_person_id_random', 'organization', 'created_on', 'updated_on', 'external_id_old'})
|
||||
|
||||
# ### SECTION ### Process data
|
||||
contact_id = None
|
||||
if event_person_profile_obj.contact and event_person_profile_obj.contact.id:
|
||||
contact_id = event_person_profile_obj.contact.id
|
||||
elif event_person_profile_obj.contact and event_person_profile_obj.contact_id:
|
||||
contact_id = event_person_profile_obj.contact_id
|
||||
|
||||
if event_person_profile_id:
|
||||
if event_person_profile_dict_up_result := sql_update(data=event_person_profile_dict, table_name='event_person_profile', rm_id_random=True): pass
|
||||
else:
|
||||
log.warning(f'Event Person Profile not updated. Event Person Profile ID: {event_person_profile_id}')
|
||||
log.debug(event_person_profile_dict_up_result)
|
||||
return False
|
||||
log.debug(event_person_profile_dict_up_result)
|
||||
else:
|
||||
if event_person_profile_dict_in_result := sql_insert(data=event_person_profile_dict, table_name='event_person_profile', rm_id_random=True, id_random_length=8): pass
|
||||
else:
|
||||
log.warning(f'Event Person Profile not created.')
|
||||
log.debug(event_person_profile_dict_in_result)
|
||||
return False
|
||||
log.debug(event_person_profile_dict_in_result)
|
||||
|
||||
event_person_profile_id = event_person_profile_dict_in_result
|
||||
|
||||
# NOTE: This is really only needed if a new contact is being created
|
||||
|
||||
log.info('Attempting to get Account ID from related object.')
|
||||
if account_id: pass
|
||||
elif account_id := event_person_profile_obj.account_id: pass
|
||||
# elif account_id := event_person_profile_obj.account_id_random: pass
|
||||
else:
|
||||
if event_person_id: pass
|
||||
elif event_person_id := event_person_profile_obj.event_person_id: pass
|
||||
# elif event_person_id := event_person_profile_obj.event_person_id_random: pass
|
||||
|
||||
if event_person_id:
|
||||
if account_id := get_account_id_w_for_type_id(for_type='event_person', for_id=event_person_id): pass
|
||||
else:
|
||||
log.error('Unable to get Account ID from related object.')
|
||||
False
|
||||
|
||||
event_person_profile_outline = {}
|
||||
event_person_profile_outline['event_person_profile_id'] = event_person_profile_id
|
||||
|
||||
# NOTE: Use object model version because of better type checking and validations
|
||||
if event_person_profile_obj.contact:
|
||||
event_person_profile_outline['contact_id'] = None
|
||||
contact_obj = event_person_profile_obj.contact
|
||||
contact_obj.for_type = 'event_person_profile'
|
||||
contact_obj.for_id = event_person_profile_id
|
||||
create_update_contact_obj_result = create_update_contact_obj_v4(
|
||||
contact_dict_obj = contact_obj,
|
||||
contact_id = contact_id,
|
||||
account_id = account_id,
|
||||
for_type = 'event_person_profile',
|
||||
for_id = event_person_profile_id,
|
||||
fail_any = fail_any,
|
||||
return_outline = return_outline,
|
||||
)
|
||||
if isinstance(create_update_contact_obj_result, int):
|
||||
contact_id = create_update_contact_obj_result
|
||||
elif create_update_contact_obj_result == True: pass
|
||||
else:
|
||||
log.warning(f'Create or Update failed while trying create_update_contact_obj_v4(): {create_update_contact_obj_result}')
|
||||
contact_id = None
|
||||
|
||||
event_person_profile_outline['contact_id'] = contact_id
|
||||
|
||||
if return_outline:
|
||||
log.debug(f'Returning the Event Person Profile Outline: {event_person_profile_outline}')
|
||||
return event_person_profile_outline
|
||||
else:
|
||||
log.debug(f'Returning the Event Person Profile ID: {event_person_profile_id}')
|
||||
return event_person_profile_id
|
||||
# ### END ### API Event Person Profile Methods ### create_update_event_person_profile_obj_v4() ###
|
||||
187
app/methods/event_person_tracking_methods.py
Normal file
187
app/methods/event_person_tracking_methods.py
Normal file
@@ -0,0 +1,187 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import get_account_id_w_for_type_id, redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
from app.models.event_person_tracking_models import Event_Person_Tracking_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Person Tracking Methods ### load_event_person_tracking_obj() ###
|
||||
# Updated 2021-09-21
|
||||
def load_event_person_tracking_obj(
|
||||
event_person_tracking_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_event_session: bool = False,
|
||||
inc_event_person: bool = False,
|
||||
) -> Event_Person_Tracking_Base|dict|bool:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_person_tracking_id := redis_lookup_id_random(record_id_random=event_person_tracking_id, table_name='event_person_tracking'): pass
|
||||
else: return False
|
||||
|
||||
if event_person_tracking_rec := sql_select(table_name='v_event_person_tracking', record_id=event_person_tracking_id): pass
|
||||
else: return False
|
||||
|
||||
try:
|
||||
event_person_tracking_obj = Event_Person_Tracking_Base(**event_person_tracking_rec)
|
||||
log.debug(event_person_tracking_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
if inc_event_person:
|
||||
log.info('Need to include Event Person data...')
|
||||
event_person_id = event_person_tracking_rec.get('event_person_id', None)
|
||||
log.debug(event_person_id)
|
||||
from app.methods.event_person_methods import load_event_person_obj
|
||||
if event_person_result := load_event_person_obj(
|
||||
event_person_id = event_person_id,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
event_person_tracking_obj.event_person = event_person_result
|
||||
else: event_person_tracking_obj.event_person = None
|
||||
|
||||
if inc_event_session:
|
||||
log.info('Need to include Event Session data...')
|
||||
event_session_id = event_person_tracking_rec.get('event_session_id', None)
|
||||
log.debug(event_session_id)
|
||||
from app.methods.event_session_methods import load_event_session_obj
|
||||
if event_session_result := load_event_session_obj(
|
||||
event_session_id = event_session_id,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
event_person_tracking_obj.event_session = event_session_result
|
||||
else: event_person_tracking_obj.event_session = None
|
||||
|
||||
if model_as_dict:
|
||||
return event_person_tracking_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return event_person_tracking_obj
|
||||
# ### END ### API Event Person Tracking Methods ### load_event_person_tracking_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Person Tracking Methods ### get_event_person_tracking_rec_list() ###
|
||||
# for_obj_type: account, event, event_session, event_person
|
||||
# Updated 2021-09-21
|
||||
def get_event_person_tracking_rec_list(
|
||||
account_id: int|str,
|
||||
event_id: int|str = None,
|
||||
event_person_id: int|str = None,
|
||||
event_session_id: int|str = None,
|
||||
in_out_type: str = None,
|
||||
# for_obj_type: str, # NOTE: This is not for_type because the field name generated based
|
||||
# for_obj_id: str, # NOTE: This is not for_id because the field name generated based
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 1000,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
data = {}
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
|
||||
data['account_id'] = account_id
|
||||
# sql_select_account_id = f'`event_person_tracking`.account_id = :account_id'
|
||||
sql_select_account_id = '1=1'
|
||||
|
||||
sql_select_event_id = ''
|
||||
sql_select_event_person_id = ''
|
||||
sql_select_event_session_id = ''
|
||||
|
||||
if event_id:
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else: return False
|
||||
|
||||
data['event_id'] = event_id
|
||||
sql_select_event_id = f'AND `event_person_tracking`.event_id = :event_id'
|
||||
|
||||
if event_person_id:
|
||||
if event_person_id := redis_lookup_id_random(record_id_random=event_person_id, table_name='event_person'): pass
|
||||
else: return False
|
||||
|
||||
data['event_person_id'] = event_person_id
|
||||
sql_select_event_person_id = f'AND `event_person_tracking`.event_person_id = :event_person_id'
|
||||
|
||||
if event_session_id:
|
||||
if event_session_id := redis_lookup_id_random(record_id_random=event_session_id, table_name='event_session'): pass
|
||||
else: return False
|
||||
|
||||
data['event_session_id'] = event_session_id
|
||||
sql_select_event_session_id = f'AND `event_person_tracking`.event_session_id = :event_session_id'
|
||||
|
||||
if event_id or event_person_id or event_session_id: pass
|
||||
else: return False
|
||||
|
||||
if in_out_type:
|
||||
if in_out_type == 'check':
|
||||
sql_select_in_out_type = f'AND `event_person_tracking`.check_in_out = 1'
|
||||
elif in_out_type == 'break':
|
||||
sql_select_in_out_type = f'AND `event_person_tracking`.break_in_out = 1'
|
||||
else:
|
||||
data['other_type'] = in_out_type
|
||||
sql_select_in_out_type = f'AND `event_person_tracking`.other_in_out = 1 AND `event_person_tracking`.other_type = :other_type'
|
||||
else:
|
||||
sql_select_in_out_type = f''
|
||||
|
||||
# if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
# else: return False
|
||||
|
||||
# data[f'{for_obj_type}_id'] = for_obj_id
|
||||
# sql_obj_type_id = f'`event_person_tracking`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
# if enabled in ['enabled', 'disabled', 'all']:
|
||||
# if enabled == 'enabled':
|
||||
# data['enable'] = True
|
||||
# sql_enabled = f'AND `event_person_tracking`.enable = :enable'
|
||||
# elif enabled == 'disabled':
|
||||
# data['enable'] = False
|
||||
# sql_enabled = f'AND `event_person_tracking`.enable = :enable'
|
||||
# elif enabled == 'all':
|
||||
# sql_enabled = ''
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_person_tracking`.id AS 'event_person_tracking_id', `event_person_tracking`.id_random AS 'event_person_tracking_id_random'
|
||||
FROM `event_person_tracking` AS `event_person_tracking`
|
||||
WHERE
|
||||
{sql_select_account_id}
|
||||
{sql_select_event_id}
|
||||
{sql_select_event_person_id}
|
||||
{sql_select_event_session_id}
|
||||
{sql_enabled}
|
||||
{sql_select_in_out_type}
|
||||
ORDER BY `event_person_tracking`.created_on DESC, `event_person_tracking`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if event_person_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
event_person_rec_li = event_person_rec_li_result
|
||||
else:
|
||||
event_person_rec_li = []
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_person_rec_li_result)
|
||||
|
||||
return event_person_rec_li
|
||||
# ### END ### API Event Person Tracking Methods ### get_event_person_tracking_rec_list() ###
|
||||
760
app/methods/event_presentation_methods.py
Normal file
760
app/methods/event_presentation_methods.py
Normal file
@@ -0,0 +1,760 @@
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
# from app.methods.event_methods import load_event_obj
|
||||
# from app.methods.event_file_methods import load_event_file_obj
|
||||
# from app.methods.event_location_methods import load_event_location_obj
|
||||
# from app.methods.event_presentation_methods import load_event_presentation_obj
|
||||
from app.methods.event_presenter_methods import create_event_presenter_obj, create_update_event_presenter_obj_v4, load_event_presenter_obj, update_event_presenter_obj_v3
|
||||
# from app.methods.event_session_methods import create_event_session_obj, load_event_session_obj, update_event_session_obj
|
||||
# from app.methods.person_methods import load_person_obj
|
||||
# from app.methods.user_methods import load_user_obj
|
||||
|
||||
from app.models.event_presentation_models import Event_Presentation_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Presentation Methods ### load_event_presentation_obj() ###
|
||||
@logger_reset
|
||||
def load_event_presentation_obj(
|
||||
event_presentation_id: int|str,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
hidden: str = 'not_hidden', # hidden, not_hidden, all
|
||||
inc_file_count: bool = False, # NOTE: file counts are from separate views
|
||||
event_file_file_purpose_id: int = None,
|
||||
event_file_file_purpose: str = None,
|
||||
event_file_priority: bool = None,
|
||||
event_file_group: str = None,
|
||||
inc_address: bool = False,
|
||||
inc_contact: bool = False,
|
||||
inc_event_abstract_list: bool = False,
|
||||
inc_event_badge: bool = False,
|
||||
#inc_event_badge_list: bool = False,
|
||||
inc_event_device_list: bool = False,
|
||||
inc_event_file_list: bool = False,
|
||||
inc_event_person: bool = False,
|
||||
inc_event_person_profile: bool = False,
|
||||
inc_event_person_list: bool = False,
|
||||
inc_event_presenter_list: bool = False,
|
||||
inc_event_registration: bool = False,
|
||||
#inc_event_registration_list: bool = False,
|
||||
inc_event_session: bool = False,
|
||||
inc_hosted_file: bool = False,
|
||||
inc_person: bool = False,
|
||||
inc_user: bool = False,
|
||||
limit: int = 1000,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
) -> Event_Presentation_Base|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_presentation_id := redis_lookup_id_random(record_id_random=event_presentation_id, table_name='event_presentation'): pass
|
||||
else: return False
|
||||
|
||||
if inc_file_count:
|
||||
log.info('Using view with file count')
|
||||
if event_presentation_rec := sql_select(table_name='v_event_presentation_w_file_count', record_id=event_presentation_id): pass
|
||||
else: return False
|
||||
else:
|
||||
if event_presentation_rec := sql_select(table_name='v_event_presentation', record_id=event_presentation_id): pass
|
||||
else: return False
|
||||
|
||||
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_presentation_rec)
|
||||
|
||||
try:
|
||||
log.info('Try to apply event presentation record data to Event_Presentation_Base...')
|
||||
event_presentation_obj = Event_Presentation_Base(**event_presentation_rec)
|
||||
log.debug(event_presentation_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
# account_id = event_presentation_rec.get('account_id', None)
|
||||
event_id = event_presentation_rec.get('event_id', None)
|
||||
event_abstract_id = event_presentation_rec.get('event_abstract_id', None)
|
||||
event_person_id = event_presentation_rec.get('event_person_id', None)
|
||||
event_session_id = event_presentation_rec.get('event_session_id', None)
|
||||
|
||||
# if inc_event: pass
|
||||
if inc_event_abstract_list: pass
|
||||
# if inc_event_badge_list: pass
|
||||
if inc_event_device_list: pass
|
||||
|
||||
# Updated 2021-11-05
|
||||
if inc_event_file_list:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.info('Need to include event file list...')
|
||||
|
||||
from app.methods.event_file_methods import get_event_file_rec_list, load_event_file_obj
|
||||
if event_file_rec_list_result := get_event_file_rec_list(
|
||||
for_type = 'event_presentation',
|
||||
for_id = event_presentation_id,
|
||||
file_purpose_id = event_file_file_purpose_id,
|
||||
file_purpose = event_file_file_purpose,
|
||||
priority = event_file_priority,
|
||||
group = event_file_group,
|
||||
enabled = enabled,
|
||||
limit = limit,
|
||||
):
|
||||
event_file_result_list = []
|
||||
for event_file_rec in event_file_rec_list_result:
|
||||
if load_event_file_result := load_event_file_obj(
|
||||
event_file_id = event_file_rec.get('event_file_id', None),
|
||||
enabled = enabled,
|
||||
inc_hosted_file = inc_hosted_file,
|
||||
# model_as_dict = True,
|
||||
# by_alias = by_alias,
|
||||
# exclude_unset = False,
|
||||
):
|
||||
event_file_result_list.append(load_event_file_result)
|
||||
else:
|
||||
event_file_result_list.append(None)
|
||||
log.debug(event_file_result_list)
|
||||
event_presentation_obj.event_file_list = event_file_result_list
|
||||
elif isinstance(event_file_rec_list_result, list):
|
||||
event_presentation_obj.event_file_list = []
|
||||
else:
|
||||
event_presentation_obj.event_file_list = None
|
||||
|
||||
if inc_event_person_list: pass
|
||||
|
||||
if inc_event_presenter_list:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
|
||||
data = {}
|
||||
data['event_presentation_id'] = event_presentation_id
|
||||
|
||||
if hidden in ['hidden', 'not_hidden', 'all']:
|
||||
if hidden == 'hidden':
|
||||
data['hide'] = True
|
||||
sql_hidden = f'AND `event_presenter`.hide = :hide'
|
||||
elif hidden == 'not_hidden':
|
||||
data['hide'] = False
|
||||
sql_hidden = f'AND `event_presenter`.hide = :hide'
|
||||
elif hidden == 'all':
|
||||
sql_hidden = ''
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `event_presenter`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `event_presenter`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
# else: event_obj['event_session'] = None
|
||||
|
||||
# if limit:
|
||||
# data['limit'] = limit
|
||||
# sql_limit = f'LIMIT :limit'
|
||||
# else:
|
||||
# sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_presenter`.id AS 'event_presenter_id', `event_presenter`.id_random AS 'event_presenter_id_random'
|
||||
FROM `event_presenter` AS `event_presenter`
|
||||
WHERE `event_presenter`.event_presentation_id = :event_presentation_id
|
||||
{sql_hidden}
|
||||
{sql_enabled}
|
||||
ORDER BY `event_presenter`.priority DESC, -`event_presenter`.sort DESC, `event_presenter`.family_name ASC, `event_presenter`.given_name ASC, `event_presenter`.full_name ASC, `event_presenter`.created_on DESC, `event_presenter`.updated_on DESC;
|
||||
"""
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(sql)
|
||||
log.debug(data)
|
||||
|
||||
if event_presenter_obj_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_presenter_obj_li_result)
|
||||
event_presenter_obj_li = []
|
||||
for event_presenter_obj in event_presenter_obj_li_result:
|
||||
event_presenter_id = event_presenter_obj.get('event_presenter_id', None)
|
||||
if event_presenter_obj := load_event_presenter_obj(
|
||||
event_presenter_id = event_presenter_id,
|
||||
enabled = enabled,
|
||||
# review = review,
|
||||
# approved = approved,
|
||||
hidden = hidden,
|
||||
inc_file_count = inc_file_count,
|
||||
inc_address = inc_address,
|
||||
inc_contact = inc_contact,
|
||||
inc_event_abstract_list = inc_event_abstract_list,
|
||||
inc_event_badge = inc_event_badge,
|
||||
inc_event_device_list = inc_event_device_list,
|
||||
inc_event_file_list = inc_event_file_list,
|
||||
inc_event_person = inc_event_person,
|
||||
inc_event_person_profile = inc_event_person_profile,
|
||||
inc_event_registration = inc_event_registration,
|
||||
inc_person = inc_person,
|
||||
inc_user = inc_user,
|
||||
):
|
||||
data = event_presenter_obj.dict(by_alias=True, exclude_unset=True)
|
||||
event_presenter_obj_li.append(data)
|
||||
log.debug(event_presenter_obj_li)
|
||||
event_presentation_obj.event_presenter_list = event_presenter_obj_li
|
||||
else:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_presenter_obj_li_result)
|
||||
event_presentation_obj.event_presenter_list = []
|
||||
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
|
||||
if inc_event_session:
|
||||
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
from app.methods.event_session_methods import load_event_session_obj
|
||||
|
||||
if event_session_obj := load_event_session_obj(
|
||||
event_session_id = event_session_id,
|
||||
# Don't append the presentation list and things
|
||||
):
|
||||
log.debug(event_session_obj)
|
||||
event_presentation_obj.event_session = event_session_obj
|
||||
else:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_session_obj)
|
||||
event_presentation_obj.event_session = None
|
||||
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
|
||||
if model_as_dict:
|
||||
return event_presentation_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return event_presentation_obj
|
||||
# ### END ### API Event Presentation Methods ### load_event_presentation_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Presentation Methods ### get_event_presentation_rec_list() ###
|
||||
@logger_reset
|
||||
def get_event_presentation_rec_list(
|
||||
event_person_id: str = None,
|
||||
event_session_id: str = None,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
approved: str = 'all', # approved, not_approved, all
|
||||
hidden: str = 'not_hidden', # hidden, not_hidden, all
|
||||
review: str = 'all', # ready, not_ready, all
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_person_id := redis_lookup_id_random(record_id_random=event_person_id, table_name='event_person'): pass
|
||||
else: pass
|
||||
|
||||
if event_session_id := redis_lookup_id_random(record_id_random=event_session_id, table_name='event_session'): pass
|
||||
else: pass
|
||||
|
||||
if event_person_id or event_session_id: pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['event_person_id'] = event_person_id
|
||||
data['event_session_id'] = event_session_id
|
||||
|
||||
if event_person_id:
|
||||
sql_where_event_person_id = f'`event_presentation`.event_person_id = :event_person_id'
|
||||
else: sql_where_event_person_id = ''
|
||||
if event_session_id:
|
||||
sql_where_event_session_id = f'`event_presentation`.event_session_id = :event_session_id'
|
||||
else: sql_where_event_session_id = ''
|
||||
|
||||
if hidden in ['hidden', 'not_hidden', 'all']:
|
||||
if hidden == 'hidden':
|
||||
data['hide'] = True
|
||||
sql_hidden = f'AND `event_presentation`.hide = :hide'
|
||||
elif hidden == 'not_hidden':
|
||||
data['hide'] = False
|
||||
sql_hidden = f'AND `event_presentation`.hide = :hide'
|
||||
elif hidden == 'all':
|
||||
sql_hidden = ''
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `event_presentation`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `event_presentation`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_presentation`.id AS 'event_presentation_id', `event_presentation`.id_random AS 'event_presentation_id_random'
|
||||
FROM `event_presentation` AS `event_presentation`
|
||||
WHERE
|
||||
{sql_where_event_person_id}
|
||||
{sql_where_event_session_id}
|
||||
{sql_hidden}
|
||||
{sql_enabled}
|
||||
ORDER BY `event_presentation`.priority DESC, -`event_presentation`.sort DESC, `event_presentation`.start_datetime ASC, `event_presentation`.name ASC, `event_presentation`.created_on DESC, `event_presentation`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if event_presentation_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
|
||||
event_presentation_rec_li = event_presentation_rec_li_result
|
||||
else:
|
||||
event_presentation_rec_li = []
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_presentation_rec_li_result)
|
||||
log.debug(type(event_presentation_rec_li))
|
||||
log.debug(len(event_presentation_rec_li))
|
||||
|
||||
return event_presentation_rec_li
|
||||
# ### END ### API Event Presentation Methods ### get_event_presentation_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Presentation Methods ### get_event_id_w_event_session_id() ###
|
||||
# Updated 2021-08-23
|
||||
@logger_reset
|
||||
def get_event_id_w_event_session_id(
|
||||
event_session_id: int|str,
|
||||
) -> bool|int|None:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_session_id := redis_lookup_id_random(record_id_random=event_session_id, table_name='event_session'): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['event_session_id'] = event_session_id
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_session`.id AS 'event_session_id', `event_session`.id_random AS 'event_session_id_random', `event_session`.event_id AS event_id
|
||||
FROM `event_session` AS `event_session`
|
||||
WHERE `event_session`.id = :event_session_id
|
||||
LIMIT 1;
|
||||
"""
|
||||
|
||||
if event_session_data_result := sql_select(data=data, sql=sql):
|
||||
log.debug(event_session_data_result)
|
||||
if event_id := event_session_data_result.get('event_id', None): return event_id
|
||||
else: return False
|
||||
else: return None
|
||||
# ### END ### API Event Presentation Methods ### get_event_id_w_event_session_id() ###
|
||||
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Presentation Methods ### create_update_event_presentation_obj_v4() ###
|
||||
# NOTE: This will create or update a event_presentation.
|
||||
# Rewrite and updated 2021-08-25
|
||||
@logger_reset
|
||||
def create_update_event_presentation_obj_v4(
|
||||
event_presentation_dict_obj: Event_Presentation_Base|dict,
|
||||
event_presentation_id: int|str = None,
|
||||
event_id: int|str = None,
|
||||
event_session_id: int|str = None,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_outline: bool = False,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
log.info('Checking requirements...')
|
||||
if event_presentation_id:
|
||||
log.info(f'Event Presentation ID passed. Update existing Event Presentation. Event Presentation ID: {event_presentation_id}')
|
||||
|
||||
if event_presentation_id := redis_lookup_id_random(record_id_random=event_presentation_id, table_name='event_presentation'): pass
|
||||
else:
|
||||
log.error('Event Presentation ID passed but is invalid. Failed requirement.')
|
||||
return False
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Event ID passed. Not required. Ignoring.')
|
||||
log.info(f'Event ID: {event_id}')
|
||||
|
||||
log.info('Attempting to get Event ID from related object.')
|
||||
from app.methods.event_methods import get_event_id_w_for_type_id
|
||||
if event_id := get_event_id_w_for_type_id(for_type='event_session', for_id=event_session_id): pass
|
||||
elif event_id := get_event_id_w_for_type_id(for_type='event_presentation', for_id=event_presentation_id): pass
|
||||
else:
|
||||
log.error('Unable to get Event ID from related object.')
|
||||
False
|
||||
else:
|
||||
log.info('No Event Presentation ID passed. Create new Event Presentation. Required: Account ID, Event ID')
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Event ID passed. Failed requirement.')
|
||||
log.info(f'Event ID: {event_id}')
|
||||
|
||||
log.info('Attempting to get Event ID from related object.')
|
||||
from app.methods.event_methods import get_event_id_w_for_type_id
|
||||
if event_id := get_event_id_w_for_type_id(for_type='event_session', for_id=event_session_id): pass
|
||||
else:
|
||||
log.error('Unable to get Event ID from related object.')
|
||||
False
|
||||
|
||||
log.debug(type(event_presentation_dict_obj))
|
||||
if isinstance(event_presentation_dict_obj, dict):
|
||||
event_presentation_dict = event_presentation_dict_obj
|
||||
if event_presentation_id:
|
||||
event_presentation_dict['event_presentation_id'] = event_presentation_id
|
||||
if event_session_id:
|
||||
event_presentation_dict['event_session_id'] = event_session_id
|
||||
if event_id:
|
||||
event_presentation_dict['event_id'] = event_id
|
||||
try:
|
||||
event_presentation_obj = Event_Presentation_Base(**event_presentation_dict)
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_presentation_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
event_presentation_obj = event_presentation_dict_obj
|
||||
if event_presentation_id:
|
||||
# NOTE: Can't update the ID alias if it was never set.
|
||||
event_presentation_obj.id = event_presentation_id
|
||||
if event_session_id:
|
||||
event_presentation_obj.event_session_id = event_session_id
|
||||
if event_id:
|
||||
event_presentation_obj.event_id = event_id
|
||||
|
||||
event_presentation_dict = event_presentation_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event_presenter', 'event_presenter_list', 'created_on', 'updated_on'})
|
||||
|
||||
if event_presentation_id:
|
||||
if event_presentation_dict_up_result := sql_update(data=event_presentation_dict, table_name='event_presentation', rm_id_random=True): pass
|
||||
else:
|
||||
log.warning(f'Event Presentation not updated. Event Presentation ID: {event_presentation_id}')
|
||||
log.debug(event_presentation_dict_up_result)
|
||||
return False
|
||||
log.debug(event_presentation_dict_up_result)
|
||||
else:
|
||||
if event_presentation_dict_in_result := sql_insert(data=event_presentation_dict, table_name='event_presentation', rm_id_random=True, id_random_length=8): pass
|
||||
else:
|
||||
log.warning(f'Event Presentation not created.')
|
||||
log.debug(event_presentation_dict_in_result)
|
||||
return False
|
||||
log.debug(event_presentation_dict_in_result)
|
||||
|
||||
event_presentation_id = event_presentation_dict_in_result
|
||||
|
||||
event_presentation_outline = {}
|
||||
event_presentation_outline['event_id'] = event_id
|
||||
event_presentation_outline['event_session_id'] = event_session_id
|
||||
event_presentation_outline['event_presentation_id'] = event_presentation_id
|
||||
event_presentation_outline['event_presenter_list'] = []
|
||||
|
||||
if event_presentation_obj.event_presenter_list and isinstance(event_presentation_obj.event_presenter_list, list):
|
||||
log.info(f'Event Presenter List was found. Loop through and create a new Event Presenter for each and link them to the new Event Presentation. Event Presentation ID: {event_presentation_id}')
|
||||
for event_presenter_obj in event_presentation_obj.event_presenter_list:
|
||||
# NOTE: Use object model version because of better type checking and validations
|
||||
log.debug(event_presenter_obj)
|
||||
if event_presenter_id := event_presenter_obj.id: pass
|
||||
else: event_presenter_id = None
|
||||
# event_presenter_obj.event_id = event_id
|
||||
# event_presenter_obj.event_session_id = event_session_id
|
||||
create_update_event_presenter_obj_result = create_update_event_presenter_obj_v4(
|
||||
event_presenter_dict_obj = event_presenter_obj,
|
||||
event_presenter_id = event_presenter_id,
|
||||
event_id = event_id,
|
||||
event_session_id = event_session_id,
|
||||
event_presentation_id = event_presentation_id,
|
||||
fail_any = fail_any,
|
||||
return_outline = return_outline,
|
||||
)
|
||||
if isinstance(create_update_event_presenter_obj_result, int):
|
||||
event_presenter_id = create_update_event_presenter_obj_result
|
||||
elif create_update_event_presenter_obj_result == True: pass
|
||||
else:
|
||||
log.warning(f'Create or Update failed while trying create_update_event_presenter_obj_v4(): {create_update_event_presenter_obj_result}')
|
||||
event_presenter_id = None
|
||||
|
||||
event_presentation_outline['event_presenter_id'] = event_presenter_id
|
||||
|
||||
if return_outline:
|
||||
log.debug(f'Returning the Event Presentation Outline: {event_presentation_outline}')
|
||||
return event_presentation_outline
|
||||
else:
|
||||
log.debug(f'Returning the Event Presentation ID: {event_presentation_id}')
|
||||
return event_presentation_id
|
||||
# ### END ### API Event Presentation Methods ### create_update_event_presentation_obj_v4() ###
|
||||
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Presentation Methods ### create_event_presentation_obj() ###
|
||||
# Updated 2022-04-12
|
||||
@logger_reset
|
||||
def create_event_presentation_obj(
|
||||
event_session_id: int|str,
|
||||
event_presentation_obj_new: Event_Presentation_Base,
|
||||
event_id: int|str = None, # If None then need to look up from event_session_id
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
) -> bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else:
|
||||
# from app.methods.event_session_methods import get_event_id_w_event_session_id
|
||||
if event_id := get_event_id_w_event_session_id(event_session_id): pass
|
||||
else: return event_id # False or None
|
||||
|
||||
if event_session_id := redis_lookup_id_random(record_id_random=event_session_id, table_name='event_session'): pass
|
||||
else: return False
|
||||
|
||||
# if event_id := event_presentation_obj_new.event_id: pass
|
||||
# else:
|
||||
# log.error('Event ID is required')
|
||||
# return False
|
||||
|
||||
# if event_session_id := event_presentation_obj_new.event_session_id: pass
|
||||
# else:
|
||||
# log.error('Event Session ID is required')
|
||||
# return False
|
||||
|
||||
log.debug(type(event_presentation_obj_new))
|
||||
if isinstance(event_presentation_obj_new, dict):
|
||||
event_presentation_dict = event_presentation_obj_new
|
||||
try:
|
||||
event_presentation_obj = Event_Presentation_Base(**event_presentation_dict)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
log.debug(event_presentation_obj)
|
||||
else:
|
||||
event_presentation_dict = event_presentation_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event_presenter', 'event_presenter_list', 'created_on', 'updated_on'})
|
||||
|
||||
event_presentation_dict['for_type'] = 'event_session'
|
||||
event_presentation_dict['for_id'] = event_session_id
|
||||
|
||||
event_presentation_dict['event_id'] = event_id
|
||||
event_presentation_dict['event_session_id'] = event_session_id
|
||||
|
||||
log.debug(event_presentation_dict)
|
||||
|
||||
if event_presentation_obj_in_result := sql_insert(data=event_presentation_dict, table_name='event_presentation', rm_id_random=True, id_random_length=8): pass
|
||||
else:
|
||||
log.warning(f'Event Presentation not created.')
|
||||
log.debug(event_presentation_obj_in_result)
|
||||
return False
|
||||
|
||||
event_presentation_id = event_presentation_obj_in_result
|
||||
|
||||
return_dict = {}
|
||||
return_dict['event_presentation_id'] = None
|
||||
return_dict['event_presenter_list'] = []
|
||||
|
||||
if event_presentation_obj.event_presenter_list and isinstance(event_presentation_obj.event_presenter_list, list):
|
||||
for event_presenter_obj in event_presentation_obj.event_presenter_list:
|
||||
# NOTE: This does not account for an edge case where the presenter already exists. Possibly as part of another presentation.
|
||||
if create_event_presenter_obj_result := create_event_presenter_obj(
|
||||
event_presentation_id = event_presentation_id,
|
||||
event_presenter_obj_new = event_presenter_obj,
|
||||
create_sub_obj = create_sub_obj,
|
||||
fail_any = fail_any,
|
||||
):
|
||||
if isinstance(create_event_presenter_obj_result, int):
|
||||
event_presenter_id = create_event_presenter_obj_result
|
||||
log.info(f'Event Presenter created. Event Presenter ID: {event_presenter_id}')
|
||||
else:
|
||||
log.warning(f'Event Presenter not created. Event Presentation ID: {event_presentation_id}')
|
||||
log.debug(create_event_presenter_obj_result)
|
||||
event_presenter_id = None
|
||||
if fail_any: return False
|
||||
else:
|
||||
log.warning(f'Event Presenter not created. Event Presentation ID: {event_presentation_id}')
|
||||
log.debug(create_event_presenter_obj_result)
|
||||
event_presenter_id = None
|
||||
if fail_any: return False
|
||||
return_dict['event_presenter_list'].append(event_presenter_id)
|
||||
else:
|
||||
log.info('Event Presenter List not found')
|
||||
pass
|
||||
|
||||
log.info(f'The Event Presentation has been created. Event Presentation ID: {event_presentation_id}')
|
||||
return event_presentation_id
|
||||
# ### END ### API Event Presentation Methods ### create_event_presentation_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Presentation Methods ### update_event_presentation_obj_v3() ###
|
||||
# Updated 2022-04-12
|
||||
@logger_reset
|
||||
def update_event_presentation_obj_v3(
|
||||
event_presentation_id: int|str,
|
||||
event_presentation_obj_exist: Event_Presentation_Base,
|
||||
event_session_id: int = None,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
) -> bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_presentation_id := redis_lookup_id_random(record_id_random=event_presentation_id, table_name='event_presentation'): pass
|
||||
else: return False
|
||||
|
||||
log.debug(type(event_presentation_obj_exist))
|
||||
if isinstance(event_presentation_obj_exist, dict):
|
||||
event_presentation_dict = event_presentation_obj_exist
|
||||
try:
|
||||
event_presentation_obj = Event_Presentation_Base(**event_presentation_obj_exist)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
log.debug(event_presentation_obj)
|
||||
else:
|
||||
event_presentation_dict = event_presentation_obj_exist.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event_presenter', 'event_presenter_list', 'created_on', 'updated_on'})
|
||||
|
||||
# Can't update the event_presentation_id alias if the .id was never set.
|
||||
# event_presentation_obj.event_presentation_id = event_presentation_id
|
||||
if not event_presentation_obj.id:
|
||||
event_presentation_obj.id = event_presentation_id
|
||||
|
||||
log.debug(event_presentation_dict)
|
||||
|
||||
# event_presentation_dict['event_id'] = event_id
|
||||
if event_session_id:
|
||||
event_presentation_dict['for_type'] = 'event_session'
|
||||
event_presentation_dict['for_id'] = event_session_id
|
||||
event_presentation_dict['event_session_id'] = event_session_id
|
||||
|
||||
log.debug(event_presentation_dict)
|
||||
|
||||
if event_presentation_obj_up_result := sql_update(data=event_presentation_dict, table_name='event_presentation', record_id=event_presentation_id, rm_id_random=True): pass
|
||||
else:
|
||||
log.warning(f'Event Presentation not updated.')
|
||||
log.debug(event_presentation_obj_up_result)
|
||||
return False
|
||||
|
||||
return_dict = {}
|
||||
return_dict['event_presentation_id'] = event_presentation_id
|
||||
return_dict['event_presenter_list'] = []
|
||||
|
||||
if event_presentation_obj.event_presenter_list and isinstance(event_presentation_obj.event_presenter_list, list):
|
||||
for event_presenter_obj_unknown in event_presentation_obj.event_presenter_list:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_presenter_obj_unknown)
|
||||
if event_presenter_id := event_presenter_obj_unknown.get('event_presenter_id_random', None):
|
||||
if update_event_presenter_obj_result := update_event_presenter_obj_v3(
|
||||
event_presenter_id = event_presenter_id,
|
||||
event_presenter_obj_exist = event_presenter_obj_unknown,
|
||||
create_sub_obj = create_sub_obj,
|
||||
fail_any = fail_any,
|
||||
):
|
||||
event_presenter_id = update_event_presenter_obj_result
|
||||
log.info(f'Event Presenter updated. Event Presenter ID: {event_presenter_id}')
|
||||
else:
|
||||
log.warning(f'Event Presenter not updated. Event Presentation ID: {event_presentation_id}')
|
||||
log.debug(update_event_presenter_obj_result)
|
||||
event_presenter_id = None
|
||||
if fail_any: return False
|
||||
|
||||
if isinstance(update_event_presenter_obj_result, int):
|
||||
event_presenter_id = update_event_presenter_obj_result
|
||||
log.info(f'Event Presenter updated. Event Presenter ID: {event_presenter_id}')
|
||||
else:
|
||||
log.warning(f'Event Presenter not updated. Event Presentation ID: {event_presentation_id}')
|
||||
log.debug(update_event_presenter_obj_result)
|
||||
event_presenter_id = None
|
||||
if fail_any: return False
|
||||
else:
|
||||
log.info(f'No Event Presenter ID found.')
|
||||
if create_event_presenter_obj_result := create_event_presenter_obj(
|
||||
event_presentation_id = event_presentation_id,
|
||||
event_presenter_obj_new = event_presenter_obj_unknown,
|
||||
create_sub_obj = create_sub_obj,
|
||||
fail_any = fail_any,
|
||||
):
|
||||
if isinstance(create_event_presenter_obj_result, int):
|
||||
event_presenter_id = create_event_presenter_obj_result
|
||||
log.info(f'Event Presenter created. Event Presenter ID: {event_presenter_id}')
|
||||
else:
|
||||
log.warning(f'Event Presenter not created. Event Presentation ID: {event_presentation_id}')
|
||||
log.debug(create_event_presenter_obj_result)
|
||||
event_presenter_id = None
|
||||
if fail_any: return False
|
||||
else:
|
||||
log.warning(f'Event Presenter not created. Event Presentation ID: {event_presentation_id}')
|
||||
log.debug(create_event_presenter_obj_result)
|
||||
event_presenter_id = None
|
||||
if fail_any: return False
|
||||
return_dict['event_presenter_list'].append(event_presenter_id)
|
||||
else:
|
||||
log.info('Event Presenter List not found or not in a list.')
|
||||
pass
|
||||
|
||||
log.info(f'The event presentation has been updated. Event Presentation ID: {event_presentation_id}')
|
||||
return True
|
||||
# ### END ### API Event Presentation Methods ### update_event_presentation_obj_v3() ###
|
||||
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Presentation Methods ### update_event_presentation_obj() ###
|
||||
# This will be taken over by _exist version
|
||||
# Updated 2022-04-12
|
||||
@logger_reset
|
||||
def update_event_presentation_obj(
|
||||
event_presentation_id: int|str, # Ideally the int ID should be passed. This allows for updating of the id_random value.
|
||||
event_presentation_obj_up: Event_Presentation_Base,
|
||||
create_sub_obj: bool = False,
|
||||
) -> bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_presentation_id := redis_lookup_id_random(record_id_random=event_presentation_id, table_name='event_presentation'): pass
|
||||
else: return False
|
||||
|
||||
event_presentation_obj_up.id = event_presentation_id
|
||||
|
||||
log.debug(event_presentation_obj_up)
|
||||
# log.debug(event_presentation_obj_up.dict(by_alias=True, exclude_unset=True))
|
||||
log.debug(event_presentation_obj_up.dict(by_alias=False, exclude_unset=True))
|
||||
# log.debug(event_presentation_obj_up.dict(by_alias=False, exclude_unset=False))
|
||||
|
||||
# if event_presentation_obj_up.event_session_id and event_presentation_obj_up.event_session:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# event_session_id = event_presentation_obj_up.event_session_id
|
||||
# event_session_obj_up = event_presentation_obj_up.event_session
|
||||
# log.debug(event_session_id)
|
||||
# log.debug(event_session_obj_up)
|
||||
# if event_session_obj_up_result := update_event_session_obj(
|
||||
# event_session_id=event_session_id,
|
||||
# event_session_obj_up=event_session_obj_up,
|
||||
# create_sub_obj=create_sub_obj,
|
||||
# ):
|
||||
# log.debug(event_session_obj_up_result)
|
||||
# else:
|
||||
# log.debug(event_session_obj_up_result)
|
||||
# return False
|
||||
# elif event_presentation_obj_up.event_session and not event_presentation_obj_up.event_session.id:
|
||||
# # NOTE: This will blindly create a new event_session even if there was one associated but the event_presentation.event_session_id was not found.
|
||||
# event_session_obj_in = event_presentation_obj_up.event_session
|
||||
# log.debug(event_session_obj_in)
|
||||
# if event_session_obj_in_result := create_event_session_obj(event_session_obj_new=event_session_obj_in):
|
||||
# # log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(event_session_obj_in_result)
|
||||
# event_presentation_obj_up.event_session_id = event_session_obj_in_result
|
||||
# else:
|
||||
# # log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(event_session_obj_in_result)
|
||||
# return False
|
||||
|
||||
event_presentation_dict_up = event_presentation_obj_up.dict(by_alias=False, exclude_unset=True, exclude={'event_abstract', 'event_abstract_list', 'event_file_list', 'event_location', 'event_presenter_list', 'event_session', 'event_track'})
|
||||
log.debug(event_presentation_dict_up)
|
||||
|
||||
if event_presentation_obj_up_result := sql_update(data=event_presentation_dict_up, table_name='event_presentation', rm_id_random=True):
|
||||
log.debug(event_presentation_obj_up_result)
|
||||
return True
|
||||
else:
|
||||
log.debug(event_presentation_obj_up_result)
|
||||
return False
|
||||
# ### END ### API Presentation Methods ### update_event_presentation_obj() ###
|
||||
682
app/methods/event_presenter_methods.py
Normal file
682
app/methods/event_presenter_methods.py
Normal file
@@ -0,0 +1,682 @@
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.methods.event_cfg_methods import load_event_cfg_obj
|
||||
from app.methods.event_person_methods import create_event_person_obj, load_event_person_obj, update_event_person_obj
|
||||
# from app.methods.person_methods import load_person_obj
|
||||
# from app.methods.user_methods import load_user_obj
|
||||
|
||||
from app.models.event_presenter_models import Event_Presenter_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Presenter Methods ### load_event_presenter_obj() ###
|
||||
@logger_reset
|
||||
def load_event_presenter_obj(
|
||||
event_presenter_id: int|str,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
hidden: str = 'not_hidden', # hidden, not_hidden, all
|
||||
inc_file_count: bool = False, # NOTE: file counts are from separate views
|
||||
event_file_file_purpose_id: int = None,
|
||||
event_file_file_purpose: str = None,
|
||||
event_file_priority: bool = None,
|
||||
event_file_group: str = None,
|
||||
inc_address: bool = False,
|
||||
inc_contact: bool = False,
|
||||
inc_event_abstract_list: bool = False, # For event_presenter and using load_event_person_obj
|
||||
inc_event_badge: bool = False, # Using load_event_person_obj
|
||||
inc_event_cfg: bool = False,
|
||||
inc_event_device_list: bool = False, # For event_presenter and using load_event_person_obj
|
||||
inc_event_file_list: bool = False, # For event_presenter and using load_event_person_obj
|
||||
inc_event_person: bool = False, # Using load_event_person_obj
|
||||
inc_event_person_profile: bool = False, # Using load_event_person_obj
|
||||
inc_event_presentation: bool = False,
|
||||
inc_event_presentation_list: bool = False, # Using load_event_session_obj
|
||||
inc_event_registration: bool = False, # Using load_event_person_obj
|
||||
inc_event_session: bool = False,
|
||||
inc_person: bool = False, # Using load_event_person_obj
|
||||
inc_user: bool = False, # Using load_event_person_obj
|
||||
limit: int = 1000,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = False,
|
||||
model_as_dict: bool = False,
|
||||
) -> Event_Presenter_Base|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_presenter_id := redis_lookup_id_random(record_id_random=event_presenter_id, table_name='event_presenter'): pass
|
||||
else: return False
|
||||
|
||||
if inc_file_count:
|
||||
log.info('Using view with file count')
|
||||
if event_presenter_rec := sql_select(table_name='v_event_presenter_w_file_count', record_id=event_presenter_id): pass
|
||||
else: return False
|
||||
else:
|
||||
if event_presenter_rec := sql_select(table_name='v_event_presenter', record_id=event_presenter_id): pass
|
||||
else: return False
|
||||
|
||||
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_presenter_rec)
|
||||
|
||||
try:
|
||||
log.info('Try to apply event presenter record data to Event_Presenter_Base...')
|
||||
event_presenter_obj = Event_Presenter_Base(**event_presenter_rec)
|
||||
log.debug(event_presenter_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
# event_presenter_obj = Event_Presenter_Base(**event_presenter_rec)
|
||||
# log.debug(event_presenter_obj)
|
||||
|
||||
# account_id = event_presenter_rec.get('account_id', None)
|
||||
event_id = event_presenter_rec.get('event_id', None)
|
||||
event_abstract_id = event_presenter_rec.get('event_abstract_id', None)
|
||||
event_person_id = event_presenter_rec.get('event_person_id', None)
|
||||
event_presentation_id = event_presenter_rec.get('event_presentation_id', None)
|
||||
event_session_id = event_presenter_rec.get('event_session_id', None)
|
||||
person_id = event_presenter_rec.get('person_id', None)
|
||||
user_id = event_presenter_rec.get('user_id', None)
|
||||
|
||||
# if inc_event: pass
|
||||
if inc_event_abstract_list: pass
|
||||
|
||||
# Updated 2021-11-10
|
||||
if inc_event_cfg:
|
||||
log.info('Need to include event configuration...')
|
||||
if event_cfg_result := load_event_cfg_obj(
|
||||
event_id = event_id,
|
||||
by_alias = by_alias,
|
||||
# exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
event_presenter_obj.event_cfg = event_cfg_result
|
||||
else: event_presenter_obj.event_cfg = None
|
||||
|
||||
if inc_event_device_list: pass
|
||||
|
||||
if inc_event_file_list:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.info('Need to include event file list...')
|
||||
|
||||
from app.methods.event_file_methods import get_event_file_rec_list, load_event_file_obj
|
||||
if event_file_rec_list_result := get_event_file_rec_list(
|
||||
for_type = 'event_presenter',
|
||||
for_id = event_presenter_id,
|
||||
file_purpose_id = event_file_file_purpose_id,
|
||||
file_purpose = event_file_file_purpose,
|
||||
priority = event_file_priority,
|
||||
group = event_file_group,
|
||||
enabled = enabled,
|
||||
limit = limit,
|
||||
):
|
||||
event_file_result_list = []
|
||||
for event_file_rec in event_file_rec_list_result:
|
||||
if load_event_file_result := load_event_file_obj(
|
||||
event_file_id = event_file_rec.get('event_file_id', None),
|
||||
enabled = enabled,
|
||||
# inc_hosted_file = inc_hosted_file,
|
||||
# by_alias = by_alias,
|
||||
# exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
event_file_result_list.append(load_event_file_result)
|
||||
else:
|
||||
event_file_result_list.append(None)
|
||||
log.debug(event_file_result_list)
|
||||
event_presenter_obj.event_file_list = event_file_result_list
|
||||
elif isinstance(event_file_rec_list_result, list):
|
||||
event_presenter_obj.event_file_list = []
|
||||
else:
|
||||
event_presenter_obj.event_file_list = None
|
||||
|
||||
if inc_event_person:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.info('Need to include event person...')
|
||||
|
||||
if event_person_obj := load_event_person_obj(
|
||||
event_person_id = event_person_id,
|
||||
enabled = enabled,
|
||||
inc_address = inc_address,
|
||||
inc_contact = inc_contact,
|
||||
inc_event_badge = inc_event_badge,
|
||||
inc_event_person_profile = inc_event_person_profile,
|
||||
inc_event_registration = inc_event_registration,
|
||||
inc_person = inc_person,
|
||||
inc_user = inc_user,
|
||||
):
|
||||
log.debug(event_person_obj)
|
||||
event_presenter_obj.event_person = event_person_obj
|
||||
else:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_person_obj)
|
||||
event_presenter_obj.event_person = None
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
|
||||
if inc_event_presentation:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.info('Need to include event presentation...')
|
||||
|
||||
from app.methods.event_presentation_methods import load_event_presentation_obj
|
||||
|
||||
if event_presentation_obj := load_event_presentation_obj(
|
||||
event_presentation_id = event_presentation_id,
|
||||
# Don't append the session, presentation list, and things
|
||||
):
|
||||
log.debug(event_presentation_obj)
|
||||
event_presenter_obj.event_presentation = event_presentation_obj
|
||||
else:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_presentation_obj)
|
||||
event_presenter_obj.event_presentation = None
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
|
||||
if inc_event_session:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.info('Need to include event session...')
|
||||
|
||||
from app.methods.event_session_methods import load_event_session_obj
|
||||
|
||||
if event_session_obj := load_event_session_obj(
|
||||
event_session_id = event_session_id,
|
||||
inc_event_presentation_list = inc_event_presentation_list,
|
||||
):
|
||||
log.debug(event_session_obj)
|
||||
event_presenter_obj.event_session = event_session_obj
|
||||
else:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_session_obj)
|
||||
event_presenter_obj.event_session = None
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
|
||||
if model_as_dict:
|
||||
return event_presenter_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return event_presenter_obj
|
||||
# ### END ### API Event Presenter Methods ### load_event_presenter_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Presenter Methods ### get_event_presenter_rec_list() ###
|
||||
@logger_reset
|
||||
def get_event_presenter_rec_list(
|
||||
event_person_id: str = None,
|
||||
event_presentation_id: str = None,
|
||||
hidden: str = 'not_hidden', # hidden, not_hidden, all
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_person_id := redis_lookup_id_random(record_id_random=event_person_id, table_name='event_person'): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['event_person_id'] = event_person_id
|
||||
data['event_presentation_id'] = event_presentation_id
|
||||
|
||||
if event_person_id:
|
||||
sql_where_event_person_id = f'`event_presenter`.event_person_id = :event_person_id'
|
||||
else: sql_where_event_person_id = ''
|
||||
if event_presentation_id:
|
||||
sql_where_event_presentation_id = f'`event_presenter`.event_presentation_id = :event_presentation_id'
|
||||
else: sql_where_event_presentation_id = ''
|
||||
|
||||
if hidden in ['hidden', 'not_hidden', 'all']:
|
||||
if hidden == 'hidden':
|
||||
data['hide'] = True
|
||||
sql_hidden = f'AND `event_presenter`.hide = :hide'
|
||||
elif hidden == 'not_hidden':
|
||||
data['hide'] = False
|
||||
sql_hidden = f'AND `event_presenter`.hide = :hide'
|
||||
elif hidden == 'all':
|
||||
sql_hidden = ''
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `event_presenter`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `event_presenter`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_presenter`.id AS 'event_presenter_id', `event_presenter`.id_random AS 'event_presenter_id_random'
|
||||
FROM `event_presenter` AS `event_presenter`
|
||||
WHERE
|
||||
{sql_where_event_person_id}
|
||||
{sql_where_event_presentation_id}
|
||||
{sql_hidden}
|
||||
{sql_enabled}
|
||||
ORDER BY `event_presenter`.priority DESC, -`event_presenter`.sort DESC, `event_presenter`.family_name ASC, `event_presenter`.given_name ASC, `event_presenter`.full_name ASC, `event_presenter`.created_on DESC, `event_presenter`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if event_presenter_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
|
||||
event_presenter_rec_li = event_presenter_rec_li_result
|
||||
else:
|
||||
event_presenter_rec_li = []
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_presenter_rec_li_result)
|
||||
log.debug(type(event_presenter_rec_li))
|
||||
log.debug(len(event_presenter_rec_li))
|
||||
|
||||
return event_presenter_rec_li
|
||||
# ### END ### API Event Presenter Methods ### get_event_presenter_rec_list() ###
|
||||
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Presenter Methods ### get_event_session_id_w_event_presentation_id() ###
|
||||
# Updated 2021-08-23
|
||||
@logger_reset
|
||||
def get_event_session_id_w_event_presentation_id(
|
||||
event_presentation_id: int|str,
|
||||
) -> bool|int|None:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_presentation_id := redis_lookup_id_random(record_id_random=event_presentation_id, table_name='event_presentation'): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['event_presentation_id'] = event_presentation_id
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_presentation`.id AS 'event_presentation_id', `event_presentation`.id_random AS 'event_presentation_id_random', `event_presentation`.event_id AS event_id, `event_presentation`.event_session_id AS event_session_id
|
||||
FROM `event_presentation` AS `event_presentation`
|
||||
WHERE `event_presentation`.id = :event_presentation_id
|
||||
LIMIT 1;
|
||||
"""
|
||||
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
if event_presentation_data_result := sql_select(data=data, sql=sql):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_presentation_data_result)
|
||||
if event_session_id := event_presentation_data_result.get('event_session_id', None): return event_session_id
|
||||
else: return False
|
||||
else: return None
|
||||
# ### END ### API Event Presenter Methods ### get_event_session_id_w_event_presentation_id() ###
|
||||
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Presenter Methods ### create_update_event_presenter_obj_v4() ###
|
||||
# NOTE: This will create or update a event_presenter.
|
||||
# Rewrite and updated 2021-08-25
|
||||
@logger_reset
|
||||
def create_update_event_presenter_obj_v4(
|
||||
event_presenter_dict_obj: Event_Presenter_Base|dict,
|
||||
event_presenter_id: int|str = None,
|
||||
event_id: int|str = None,
|
||||
event_session_id: int|str = None,
|
||||
event_presentation_id: int|str = None,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_outline: bool = False,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
log.info('Checking requirements...')
|
||||
if event_presenter_id:
|
||||
log.info(f'Event Presenter ID passed. Update existing Event Presenter. Event Presenter ID: {event_presenter_id}')
|
||||
|
||||
if event_presenter_id := redis_lookup_id_random(record_id_random=event_presenter_id, table_name='event_presenter'): pass
|
||||
else:
|
||||
log.error('Event Presenter ID passed but is invalid. Failed requirement.')
|
||||
return False
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Event ID passed. Not required. Ignoring.')
|
||||
log.info(f'Event ID: {event_id}')
|
||||
|
||||
log.info('Attempting to get Event ID from related object.')
|
||||
from app.methods.event_methods import get_event_id_w_for_type_id
|
||||
if event_id := get_event_id_w_for_type_id(for_type='event_session', for_id=event_session_id): pass
|
||||
elif event_id := get_event_id_w_for_type_id(for_type='event_presentation', for_id=event_presentation_id): pass
|
||||
elif event_id := get_event_id_w_for_type_id(for_type='event_presenter', for_id=event_presenter_id): pass
|
||||
else:
|
||||
log.error('Unable to get Event ID from related object.')
|
||||
False
|
||||
else:
|
||||
log.info('No Event Presenter ID passed. Create new Event Presenter. Required: Account ID, Event ID')
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Event ID passed. Failed requirement.')
|
||||
log.info(f'Event ID: {event_id}')
|
||||
|
||||
log.info('Attempting to get Event ID from related object.')
|
||||
from app.methods.event_methods import get_event_id_w_for_type_id
|
||||
if event_id := get_event_id_w_for_type_id(for_type='event_session', for_id=event_session_id): pass
|
||||
elif event_id := get_event_id_w_for_type_id(for_type='event_presentation', for_id=event_presentation_id): pass
|
||||
else:
|
||||
log.error('Unable to get Event ID from related object.')
|
||||
False
|
||||
|
||||
log.debug(type(event_presenter_dict_obj))
|
||||
if isinstance(event_presenter_dict_obj, dict):
|
||||
event_presenter_dict = event_presenter_dict_obj
|
||||
if event_presenter_id:
|
||||
event_presenter_dict['event_presenter_id'] = event_presenter_id
|
||||
if event_presentation_id:
|
||||
event_presenter_dict['event_presentation_id'] = event_presentation_id
|
||||
if event_session_id:
|
||||
event_presenter_dict['event_session_id'] = event_session_id
|
||||
if event_id:
|
||||
event_presenter_dict['event_id'] = event_id
|
||||
try:
|
||||
event_presenter_obj = Event_Presenter_Base(**event_presenter_dict)
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_presenter_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
event_presenter_obj = event_presenter_dict_obj
|
||||
if event_presenter_id:
|
||||
# NOTE: Can't update the ID alias if it was never set.
|
||||
event_presenter_obj.id = event_presenter_id
|
||||
if event_presentation_id:
|
||||
event_presenter_obj.event_presentation_id = event_presentation_id
|
||||
if event_session_id:
|
||||
event_presenter_obj.event_session_id = event_session_id
|
||||
if event_id:
|
||||
event_presenter_obj.event_id = event_id
|
||||
|
||||
event_presenter_dict = event_presenter_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'created_on', 'updated_on'})
|
||||
|
||||
if event_presenter_id:
|
||||
if event_presenter_dict_up_result := sql_update(data=event_presenter_dict, table_name='event_presenter', rm_id_random=True): pass
|
||||
else:
|
||||
log.warning(f'Event Presenter not updated. Event Presenter ID: {event_presenter_id}')
|
||||
log.debug(event_presenter_dict_up_result)
|
||||
return False
|
||||
log.debug(event_presenter_dict_up_result)
|
||||
else:
|
||||
if event_presenter_dict_in_result := sql_insert(data=event_presenter_dict, table_name='event_presenter', rm_id_random=True, id_random_length=8): pass
|
||||
else:
|
||||
log.warning(f'Event Presenter not created.')
|
||||
log.debug(event_presenter_dict_in_result)
|
||||
return False
|
||||
log.debug(event_presenter_dict_in_result)
|
||||
|
||||
event_presenter_id = event_presenter_dict_in_result
|
||||
|
||||
event_presenter_outline = {}
|
||||
event_presenter_outline['event_id'] = event_id
|
||||
event_presenter_outline['event_session_id'] = event_session_id
|
||||
event_presenter_outline['event_presentation_id'] = event_presentation_id
|
||||
event_presenter_outline['event_presenter_id'] = event_presenter_id
|
||||
|
||||
if return_outline:
|
||||
log.debug(f'Returning the Event Presenter Outline: {event_presenter_outline}')
|
||||
return event_presenter_outline
|
||||
else:
|
||||
log.debug(f'Returning the Event Presenter ID: {event_presenter_id}')
|
||||
return event_presenter_id
|
||||
# ### END ### API Event Presenter Methods ### create_update_event_presenter_obj_v4() ###
|
||||
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Presenter Methods ### create_event_presenter_obj() ###
|
||||
# Updated 2022-04-12
|
||||
@logger_reset
|
||||
def create_event_presenter_obj(
|
||||
event_presentation_id: int|str,
|
||||
event_presenter_obj_new: Event_Presenter_Base,
|
||||
event_id: int|str = None, # If None then need to look up from event_session_id
|
||||
event_session_id: int|str = None, # If None then need to look up from event_presentation_id
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
) -> bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_session_id := redis_lookup_id_random(record_id_random=event_session_id, table_name='event_session'): pass
|
||||
else:
|
||||
# from app.methods.event_presentation_methods import get_event_session_id_w_event_presentation_id
|
||||
if event_session_id := get_event_session_id_w_event_presentation_id(event_presentation_id): pass
|
||||
else:
|
||||
log.warning(f'The event_session_id was not found using the event_presentation_id. Event Presentation ID: {event_presentation_id}')
|
||||
return event_session_id # False or None
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else:
|
||||
from app.methods.event_presentation_methods import get_event_id_w_event_session_id
|
||||
if event_id := get_event_id_w_event_session_id(event_session_id): pass
|
||||
else:
|
||||
log.warning(f'The event_id was not found using the event_session_id. Event Session ID: {event_session_id}')
|
||||
return event_id # False or None
|
||||
|
||||
if event_session_id := redis_lookup_id_random(record_id_random=event_session_id, table_name='event_session'): pass
|
||||
else: return False
|
||||
|
||||
log.debug(type(event_presenter_obj_new))
|
||||
if isinstance(event_presenter_obj_new, dict):
|
||||
event_presenter_dict = event_presenter_obj_new
|
||||
try:
|
||||
event_presenter_obj = Event_Presenter_Base(**event_presenter_obj_new)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
log.debug(event_presenter_obj)
|
||||
else:
|
||||
event_presenter_dict = event_presenter_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'created_on', 'updated_on'})
|
||||
|
||||
event_presenter_dict['for_type'] = 'event_presentation'
|
||||
event_presenter_dict['for_id'] = event_presentation_id
|
||||
|
||||
event_presenter_dict['event_id'] = event_id
|
||||
event_presenter_dict['event_session_id'] = event_session_id
|
||||
event_presenter_dict['event_presentation_id'] = event_presentation_id
|
||||
|
||||
log.debug(event_presenter_dict)
|
||||
|
||||
if event_presenter_obj_in_result := sql_insert(data=event_presenter_dict, table_name='event_presenter', rm_id_random=True, id_random_length=8): pass
|
||||
else:
|
||||
log.warning(f'Event Presenter not created.')
|
||||
log.debug(event_presenter_obj_in_result)
|
||||
return False
|
||||
|
||||
event_presenter_id = event_presenter_obj_in_result
|
||||
|
||||
return_dict = {}
|
||||
return_dict['event_presenter_id'] = None
|
||||
|
||||
log.info(f'The Event Presenter has been created. Event Presenter ID: {event_presenter_id}')
|
||||
return event_presenter_id
|
||||
# ### END ### API Event Presenter Methods ### create_event_presenter_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Presenter Methods ### update_event_presenter_obj_v3() ###
|
||||
# Updated 2022-04-12
|
||||
@logger_reset
|
||||
def update_event_presenter_obj_v3(
|
||||
event_presenter_id: int|str,
|
||||
event_presenter_obj_exist: Event_Presenter_Base,
|
||||
event_presentation_id: int = None,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
) -> bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_presenter_id := redis_lookup_id_random(record_id_random=event_presenter_id, table_name='event_presenter'): pass
|
||||
else: return False
|
||||
|
||||
log.debug(type(event_presenter_obj_exist))
|
||||
if isinstance(event_presenter_obj_exist, dict):
|
||||
event_presenter_dict = event_presenter_obj_exist
|
||||
try:
|
||||
event_presenter_obj = Event_Presenter_Base(**event_presenter_obj_exist)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
log.debug(event_presenter_obj)
|
||||
else:
|
||||
event_presenter_dict = event_presenter_obj_exist.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event_presenter', 'event_presenter_list', 'created_on', 'updated_on'})
|
||||
|
||||
# Can't update the event_presenter_id alias if the .id was never set.
|
||||
# event_presenter_obj.event_presenter_id = event_presenter_id
|
||||
if not event_presenter_obj.id:
|
||||
event_presenter_obj.id = event_presenter_id
|
||||
|
||||
# event_presenter_dict['event_id'] = event_id
|
||||
# event_presenter_dict['event_session_id'] = event_session_id
|
||||
if event_presentation_id:
|
||||
event_presenter_dict['for_type'] = 'event_presentation'
|
||||
event_presenter_dict['for_id'] = event_presentation_id
|
||||
event_presenter_dict['event_presentation_id'] = event_presentation_id
|
||||
|
||||
log.debug(event_presenter_dict)
|
||||
|
||||
if event_presenter_obj_up_result := sql_update(data=event_presenter_dict, table_name='event_presenter', record_id=event_presenter_id, rm_id_random=True): pass
|
||||
else:
|
||||
log.warning(f'Event Presenter not updated.')
|
||||
log.debug(event_presenter_obj_up_result)
|
||||
return False
|
||||
|
||||
return_dict = {}
|
||||
return_dict['event_presenter_id'] = event_presenter_id
|
||||
|
||||
log.info(f'The event presenter has been updated. Event Presenter ID: {event_presenter_id}')
|
||||
return True
|
||||
# ### END ### API Event Presenter Methods ### update_event_presenter_obj_v3() ###
|
||||
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Presenter Methods ### update_event_presenter_obj() ###
|
||||
# This will be taken over by _exist version
|
||||
@logger_reset
|
||||
def update_event_presenter_obj(
|
||||
event_presenter_id: int|str, # Ideally the int ID should be passed. This allows for updating of the id_random value.
|
||||
event_presenter_obj_up: Event_Presenter_Base,
|
||||
create_sub_obj: bool = False,
|
||||
) -> bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_presenter_id := redis_lookup_id_random(record_id_random=event_presenter_id, table_name='event_presenter'): pass
|
||||
else: return False
|
||||
|
||||
event_presenter_obj_up.id = event_presenter_id
|
||||
|
||||
log.debug(event_presenter_obj_up)
|
||||
# log.debug(event_presenter_obj_up.dict(by_alias=True, exclude_unset=True))
|
||||
log.debug(event_presenter_obj_up.dict(by_alias=False, exclude_unset=True))
|
||||
# log.debug(event_presenter_obj_up.dict(by_alias=False, exclude_unset=False))
|
||||
|
||||
if event_presenter_obj_up.event_person_id and event_presenter_obj_up.event_person:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
event_person_id = event_presenter_obj_up.event_person_id
|
||||
event_person_obj_up = event_presenter_obj_up.event_person
|
||||
log.debug(event_person_id)
|
||||
log.debug(event_person_obj_up)
|
||||
if event_person_obj_up_result := update_event_person_obj(
|
||||
event_person_id=event_person_id,
|
||||
event_person_obj_up=event_person_obj_up,
|
||||
create_sub_obj=create_sub_obj,
|
||||
):
|
||||
log.debug(event_person_obj_up_result)
|
||||
else:
|
||||
log.debug(event_person_obj_up_result)
|
||||
return False
|
||||
elif event_presenter_obj_up.event_person and not event_presenter_obj_up.event_person.id:
|
||||
# NOTE: This will blindly create a new event_person even if there was one associated but the event_presenter.event_person_id was not found.
|
||||
event_person_obj_in = event_presenter_obj_up.event_person
|
||||
log.debug(event_person_obj_in)
|
||||
if event_person_obj_in_result := create_event_person_obj(event_person_obj_new=event_person_obj_in):
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_person_obj_in_result)
|
||||
event_presenter_obj_up.event_person_id = event_person_obj_in_result
|
||||
else:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_person_obj_in_result)
|
||||
return False
|
||||
|
||||
# if event_presenter_obj_up.event_presentation_id and event_presenter_obj_up.event_presentation:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# event_presentation_id = event_presenter_obj_up.event_presentation_id
|
||||
# event_presentation_obj_up = event_presenter_obj_up.event_presentation
|
||||
# log.debug(event_presentation_id)
|
||||
# log.debug(event_presentation_obj_up)
|
||||
# if event_presentation_obj_up_result := update_event_presentation_obj(
|
||||
# event_presentation_id=event_presentation_id,
|
||||
# event_presentation_obj_up=event_presentation_obj_up,
|
||||
# create_sub_obj=create_sub_obj,
|
||||
# ):
|
||||
# log.debug(event_presentation_obj_up_result)
|
||||
# else:
|
||||
# log.debug(event_presentation_obj_up_result)
|
||||
# return False
|
||||
# elif event_presenter_obj_up.event_presentation and not event_presenter_obj_up.event_presentation.id:
|
||||
# # NOTE: This will blindly create a new event_presentation even if there was one associated but the event_presenter.event_presentation_id was not found.
|
||||
# event_presentation_obj_in = event_presenter_obj_up.event_presentation
|
||||
# log.debug(event_presentation_obj_in)
|
||||
# if event_presentation_obj_in_result := create_event_presentation_obj(event_presentation_obj_new=event_presentation_obj_in):
|
||||
# # log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(event_presentation_obj_in_result)
|
||||
# event_presenter_obj_up.event_presentation_id = event_presentation_obj_in_result
|
||||
# else:
|
||||
# # log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(event_presentation_obj_in_result)
|
||||
# return False
|
||||
|
||||
# if event_presenter_obj_up.event_session_id and event_presenter_obj_up.event_session:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# event_session_id = event_presenter_obj_up.event_session_id
|
||||
# event_session_obj_up = event_presenter_obj_up.event_session
|
||||
# log.debug(event_session_id)
|
||||
# log.debug(event_session_obj_up)
|
||||
# if event_session_obj_up_result := update_event_session_obj(
|
||||
# event_session_id=event_session_id,
|
||||
# event_session_obj_up=event_session_obj_up,
|
||||
# create_sub_obj=create_sub_obj,
|
||||
# ):
|
||||
# log.debug(event_session_obj_up_result)
|
||||
# else:
|
||||
# log.debug(event_session_obj_up_result)
|
||||
# return False
|
||||
# elif event_presenter_obj_up.event_session and not event_presenter_obj_up.event_session.id:
|
||||
# # NOTE: This will blindly create a new event_session even if there was one associated but the event_presenter.event_session_id was not found.
|
||||
# event_session_obj_in = event_presenter_obj_up.event_session
|
||||
# log.debug(event_session_obj_in)
|
||||
# if event_session_obj_in_result := create_event_session_obj(event_session_obj_new=event_session_obj_in):
|
||||
# # log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(event_session_obj_in_result)
|
||||
# event_presenter_obj_up.event_session_id = event_session_obj_in_result
|
||||
# else:
|
||||
# # log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(event_session_obj_in_result)
|
||||
# return False
|
||||
|
||||
event_presenter_dict_up = event_presenter_obj_up.dict(by_alias=False, exclude_unset=True, exclude={'event_abstract', 'event_abstract_list', 'event_file_list', 'event_person', 'event_presentation', 'event_session', 'person', 'user'})
|
||||
log.debug(event_presenter_dict_up)
|
||||
|
||||
if event_presenter_obj_up_result := sql_update(data=event_presenter_dict_up, table_name='event_presenter', rm_id_random=True):
|
||||
log.debug(event_presenter_obj_up_result)
|
||||
return True
|
||||
else:
|
||||
log.debug(event_presenter_obj_up_result)
|
||||
return False
|
||||
# ### END ### API Presenter Methods ### update_event_presenter_obj() ###
|
||||
45
app/methods/event_registration_cfg_methods.py
Normal file
45
app/methods/event_registration_cfg_methods.py
Normal file
@@ -0,0 +1,45 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging
|
||||
|
||||
from app.models.event_registration_cfg_models import Event_Registration_Cfg_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Registration Cfg Methods ### load_event_registration_cfg_obj() ###
|
||||
def load_event_registration_cfg_obj(
|
||||
event_id: int|str,
|
||||
inc_event_registration_cfg: bool = False,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
) -> Event_Registration_Cfg_Base|bool:
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else: return False
|
||||
|
||||
if event_registration_cfg_rec := sql_select(table_name='event_registration_cfg', record_id=event_id): pass
|
||||
else: return False
|
||||
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_registration_cfg_rec)
|
||||
|
||||
try:
|
||||
event_registration_cfg_obj = Event_Registration_Cfg_Base(**event_registration_cfg_rec)
|
||||
log.debug(event_registration_cfg_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
if model_as_dict:
|
||||
return event_registration_cfg_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return event_registration_cfg_obj
|
||||
# ### END ### API Event Registration Cfg Methods ### load_event_registration_cfg_obj() ###
|
||||
326
app/methods/event_registration_methods.py
Normal file
326
app/methods/event_registration_methods.py
Normal file
@@ -0,0 +1,326 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging
|
||||
|
||||
# from app.methods.address_methods import load_address_obj
|
||||
# from app.methods.contact_methods import load_contact_obj
|
||||
from app.methods.event_person_methods import get_event_person_rec_list, load_event_person_obj
|
||||
from app.methods.event_registration_cfg_methods import load_event_registration_cfg_obj
|
||||
# from app.methods.person_methods import load_person_obj
|
||||
|
||||
from app.models.event_registration_models import Event_Registration_Base
|
||||
from app.models.event_cfg_models import Event_Cfg_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Registration Methods ### load_event_registration_obj() ###
|
||||
def load_event_registration_obj(
|
||||
event_registration_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_address: bool = False, # Under contact
|
||||
inc_contact: bool = False,
|
||||
# inc_event_cfg: bool = False,
|
||||
inc_event_person_list: bool = False,
|
||||
inc_event_registration_cfg: bool = False,
|
||||
# inc_event_registration_list: bool = False,
|
||||
inc_person: bool = False,
|
||||
) -> Event_Registration_Base|bool:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_registration_id := redis_lookup_id_random(record_id_random=event_registration_id, table_name='event_registration'): pass
|
||||
else: return False
|
||||
|
||||
if event_registration_rec := sql_select(table_name='v_event_registration', record_id=event_registration_id): pass
|
||||
else: return False
|
||||
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_registration_rec)
|
||||
|
||||
try:
|
||||
log.info('Try to apply event registration record data to Event_Registration_Base...')
|
||||
event_registration_obj = Event_Registration_Base(**event_registration_rec)
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_registration_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
# Updated 2021-08-17
|
||||
if inc_event_registration_cfg:
|
||||
log.info('Need to include event registration configuration...')
|
||||
event_id = event_registration_rec.get('event_id', None)
|
||||
log.info(f'Need to include event registration config for event_id {event_id}...')
|
||||
if event_registration_cfg_result := load_event_registration_cfg_obj(
|
||||
event_id = event_id,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
event_registration_obj.cfg = event_registration_cfg_result
|
||||
else: event_registration_obj.event_registration_cfg = None
|
||||
|
||||
# Updated 2021-08-17
|
||||
if inc_event_person_list:
|
||||
log.info('Need to include event person list...')
|
||||
if event_person_rec_list_result := get_event_person_rec_list(
|
||||
for_obj_type = 'event_registration',
|
||||
for_obj_id = event_registration_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
event_person_result_list = []
|
||||
for event_person_rec in event_person_rec_list_result:
|
||||
if load_event_person_result := load_event_person_obj(
|
||||
event_person_id = event_person_rec.get('event_person_id', None),
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
inc_person = inc_person,
|
||||
# inc_user = inc_user,
|
||||
):
|
||||
event_person_result_list.append(load_event_person_result)
|
||||
else: event_person_result_list.append(None)
|
||||
event_registration_obj.event_person_list = event_person_result_list
|
||||
else: event_registration_obj.event_person_list = []
|
||||
|
||||
if model_as_dict:
|
||||
return event_registration_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return event_registration_obj
|
||||
# ### END ### API Event Registration Methods ### load_event_registration_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Registration Methods ### get_event_id_w_event_person_id() ###
|
||||
# Updated 2021-08-23
|
||||
def get_event_id_w_event_person_id(
|
||||
event_person_id: int|str,
|
||||
) -> bool|int|None:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_person_id := redis_lookup_id_random(record_id_random=event_person_id, table_name='event_person'): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['event_person_id'] = event_person_id
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_person`.id AS 'event_person_id', `event_person`.id_random AS 'event_person_id_random', `event_person`.event_id AS event_id
|
||||
FROM `event_person` AS `event_person`
|
||||
WHERE `event_person`.id = :event_person_id
|
||||
LIMIT 1;
|
||||
"""
|
||||
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
if event_person_data_result := sql_select(data=data, sql=sql):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_person_data_result)
|
||||
if event_id := event_person_data_result.get('event_id', None): return event_id
|
||||
else: return False
|
||||
else: return None
|
||||
# ### END ### API Event Registration Methods ### get_event_id_w_event_person_id() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Registration Methods ### create_event_registration_obj() ###
|
||||
# Event Registration can only update the primary event_person because they should already exist before registration is started. Chicken and egg problem...
|
||||
# Event Registration can create or update the event_person_list.
|
||||
# NOTE: Should there be a check before trying to update the primary event_person if they are also in the event_person_list??? Chicken and egg problem again?
|
||||
# Updated 2021-08-25
|
||||
def create_event_registration_obj(
|
||||
event_id: int|str,
|
||||
event_person_id: int|str,
|
||||
event_registration_obj_new: Event_Registration_Base,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
) -> bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_person_id := redis_lookup_id_random(record_id_random=event_person_id, table_name='event_person'): pass
|
||||
else: return False # The event_person should be created first (before registration and similar)
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else:
|
||||
if event_id := get_event_id_w_event_person_id(event_person_id): pass
|
||||
else:
|
||||
log.warning(f'The event_id was not found using the event_person_id. Event Person ID: {event_person_id}')
|
||||
return event_id # False or None
|
||||
|
||||
log.debug(type(event_registration_obj_new))
|
||||
if isinstance(event_registration_obj_new, dict):
|
||||
try:
|
||||
event_registration_obj_new = Event_Registration_Base(**event_registration_obj_new)
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_registration_obj_new)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
event_registration_obj_new.event_id = event_id
|
||||
event_registration_obj_new.event_person_id = event_person_id
|
||||
|
||||
event_registration_obj_data = event_registration_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event_person', 'event_person_list', 'created_on', 'updated_on'})
|
||||
log.debug(event_registration_obj_data)
|
||||
|
||||
if event_registration_obj_in_result := sql_insert(data=event_registration_obj_data, table_name='event_registration', rm_id_random=True, id_random_length=8): pass
|
||||
else:
|
||||
log.warning(f'Event Registration not created.')
|
||||
log.debug(event_registration_obj_in_result)
|
||||
return False
|
||||
|
||||
event_registration_id = event_registration_obj_in_result
|
||||
|
||||
return_dict = {}
|
||||
return_dict['event_registration_id'] = None
|
||||
return_dict['event_person_id'] = None
|
||||
return_dict['event_id'] = None
|
||||
return_dict['event_person_list'] = []
|
||||
|
||||
# NOTE: Primary Event Person update check is not finished
|
||||
if event_registration_obj_new.event_person:
|
||||
# What happens here?
|
||||
# Update only... do not create a new event_person here.
|
||||
pass
|
||||
|
||||
if event_registration_obj_new.event_person_list and isinstance(event_registration_obj_new.event_person_list, list):
|
||||
for event_person_obj_new in event_registration_obj_new.event_person_list:
|
||||
# NOTE: This does not account for an edge case where the person already exists. Possibly as part of another registration, which should *not* happen.
|
||||
if create_event_person_obj_result := create_event_person_obj(
|
||||
event_registration_id = event_registration_id,
|
||||
event_person_obj_new = event_person_obj_new,
|
||||
create_sub_obj = create_sub_obj,
|
||||
fail_any = fail_any,
|
||||
):
|
||||
if isinstance(create_event_person_obj_result, int):
|
||||
event_person_id = create_event_person_obj_result
|
||||
log.info(f'Event Person created. Event Person ID: {event_person_id}')
|
||||
else:
|
||||
log.warning(f'Event Person not created. Event Registration ID: {event_registration_id}')
|
||||
log.debug(create_event_person_obj_result)
|
||||
event_person_id = None
|
||||
if fail_any: return False
|
||||
else:
|
||||
log.warning(f'Event Person not created. Event Registration ID: {event_registration_id}')
|
||||
log.debug(create_event_person_obj_result)
|
||||
event_person_id = None
|
||||
if fail_any: return False
|
||||
return_dict['event_person_list'].append(event_person_id)
|
||||
else:
|
||||
log.info('Event Person List not found')
|
||||
pass
|
||||
|
||||
log.info(f'The event registration has been created. Event Registration ID: {event_registration_id}')
|
||||
return event_registration_id
|
||||
# ### END ### API Event Registration Methods ### create_event_registration_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Registration Methods ### update_event_registration_obj_v3() ###
|
||||
# Event Registration can only update the primary event_person because they should already exist since registration is started and registration "requires" the primary event_person first. Chicken and egg problem...
|
||||
# Event Registration can create or update the event_person_list.
|
||||
# NOTE: Should there be a check before trying to update the primary event_person if they are also in the event_person_list??? Chicken and egg problem again?
|
||||
# Updated 2021-08-25
|
||||
def update_event_registration_obj_v3(
|
||||
event_registration_id: int|str,
|
||||
event_registration_obj_exist: Event_Registration_Base,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
) -> bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_registration_id := redis_lookup_id_random(record_id_random=event_registration_id, table_name='event_registration'): pass
|
||||
else: return False
|
||||
|
||||
# Can't update the event_registration_id alias if the .id was never set.
|
||||
# event_registration_obj_exist.event_registration_id = event_registration_id
|
||||
if not event_registration_obj_exist.id:
|
||||
event_registration_obj_exist.id = event_registration_id
|
||||
|
||||
event_registration_obj_data = event_registration_obj_exist.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event_person', 'event_person_list', 'created_on', 'updated_on'})
|
||||
log.debug(event_registration_obj_data)
|
||||
|
||||
if event_registration_obj_up_result := sql_update(data=event_registration_obj_data, table_name='event_registration', rm_id_random=True): pass
|
||||
else:
|
||||
log.warning(f'Event Registration not updated.')
|
||||
log.debug(event_registration_obj_up_result)
|
||||
return False
|
||||
|
||||
return_dict = {}
|
||||
return_dict['event_registration_id'] = None
|
||||
return_dict['event_person_id'] = None
|
||||
return_dict['event_id'] = None
|
||||
return_dict['event_person_list'] = []
|
||||
|
||||
# NOTE: Primary Event Person update check is not finished
|
||||
if event_registration_obj_exist.event_person:
|
||||
# What happens here?
|
||||
# Update only... do not create a new event_person here.
|
||||
pass
|
||||
|
||||
if event_registration_obj_exist.event_person_list and isinstance(event_registration_obj_exist.event_person_list, list):
|
||||
for event_person_obj_unknown in event_registration_obj_exist.event_person_list:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_person_obj_unknown)
|
||||
if event_person_id := event_person_obj_unknown.get('event_person_id_random', None):
|
||||
if update_event_person_obj_result := update_event_person_obj_v3(
|
||||
event_person_id = event_person_id,
|
||||
event_person_obj_exist = event_person_obj_unknown,
|
||||
create_sub_obj = create_sub_obj,
|
||||
fail_any = fail_any,
|
||||
):
|
||||
event_person_id = update_event_person_obj_result
|
||||
log.info(f'Event Person updated. Event Person ID: {event_person_id}')
|
||||
else:
|
||||
log.warning(f'Event Person not updated. Event Registration ID: {event_registration_id}')
|
||||
log.debug(update_event_person_obj_result)
|
||||
event_person_id = None
|
||||
if fail_any: return False
|
||||
|
||||
if isinstance(update_event_person_obj_result, int):
|
||||
event_person_id = update_event_person_obj_result
|
||||
log.info(f'Event Person updated. Event Person ID: {event_person_id}')
|
||||
else:
|
||||
log.warning(f'Event Person not updated. Event Registration ID: {event_registration_id}')
|
||||
log.debug(update_event_person_obj_result)
|
||||
event_person_id = None
|
||||
if fail_any: return False
|
||||
else:
|
||||
log.info(f'No Event Person ID found.')
|
||||
if create_event_person_obj_result := create_event_person_obj(
|
||||
event_registration_id = event_registration_id,
|
||||
event_person_obj_new = event_person_obj_unknown,
|
||||
create_sub_obj = create_sub_obj,
|
||||
fail_any = fail_any,
|
||||
):
|
||||
if isinstance(create_event_person_obj_result, int):
|
||||
event_person_id = create_event_person_obj_result
|
||||
log.info(f'Event Person created. Event Person ID: {event_person_id}')
|
||||
else:
|
||||
log.warning(f'Event Person not created. Event Registration ID: {event_registration_id}')
|
||||
log.debug(create_event_person_obj_result)
|
||||
event_person_id = None
|
||||
if fail_any: return False
|
||||
else:
|
||||
log.warning(f'Event Person not created. Event Registration ID: {event_registration_id}')
|
||||
log.debug(create_event_person_obj_result)
|
||||
event_person_id = None
|
||||
if fail_any: return False
|
||||
return_dict['event_person_list'].append(event_person_id)
|
||||
else:
|
||||
log.info('Event Person List not found or not in a list.')
|
||||
pass
|
||||
|
||||
log.info(f'The event registration has been updated. Event Registration ID: {event_registration_id}')
|
||||
return True
|
||||
# ### END ### API Event Registration Methods ### update_event_registration_obj_v3() ###
|
||||
836
app/methods/event_session_methods.py
Normal file
836
app/methods/event_session_methods.py
Normal file
@@ -0,0 +1,836 @@
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_enable_part, sql_insert, sql_limit_offset_part, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
# from app.methods.event_methods import load_event_obj
|
||||
from app.methods.event_file_methods import load_event_file_obj_list
|
||||
from app.methods.event_location_methods import load_event_location_obj, get_event_location_rec_list
|
||||
from app.methods.event_person_methods import load_event_person_obj, update_event_person_obj
|
||||
from app.methods.event_presentation_methods import create_event_presentation_obj, create_update_event_presentation_obj_v4, load_event_presentation_obj, update_event_presentation_obj_v3
|
||||
# from app.methods.event_presenter_methods import load_event_presenter_obj
|
||||
from app.methods.person_methods import load_person_obj
|
||||
# from app.methods.user_methods import load_user_obj
|
||||
|
||||
from app.models.event_session_models import Event_Session_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Session Methods ### load_event_session_obj() ###
|
||||
# Updated 2022-09-23
|
||||
@logger_reset
|
||||
def load_event_session_obj(
|
||||
event_session_id: int|str,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
hidden: str = 'not_hidden', # hidden, not_hidden, all
|
||||
inc_file_count: bool = False, # NOTE: file counts are from separate views
|
||||
event_file_file_purpose_id: int = None,
|
||||
event_file_file_purpose: str = None,
|
||||
event_file_priority: bool = None,
|
||||
event_file_group: str = None,
|
||||
inc_address: bool = False,
|
||||
inc_contact: bool = False,
|
||||
inc_event_abstract_list: bool = False,
|
||||
inc_event_badge_list: bool = False,
|
||||
inc_event_device_list: bool = False,
|
||||
inc_event_file_list: bool = False,
|
||||
inc_event_file_internal_use_list: bool = False,
|
||||
inc_event_location: bool = False,
|
||||
inc_event_location_list: bool = False,
|
||||
inc_event_person: bool = False,
|
||||
inc_event_person_profile: bool = False,
|
||||
inc_event_person_list: bool = False,
|
||||
inc_event_presentation_list: bool = False,
|
||||
inc_event_presenter_cat: bool = False, # Concatenate presenter names
|
||||
inc_event_presenter_list: bool = False,
|
||||
inc_event_registration_list: bool = False,
|
||||
inc_event_track: bool = False,
|
||||
inc_hosted_file: bool = False,
|
||||
inc_poc_event_person: bool = False,
|
||||
inc_person: bool = False,
|
||||
inc_user: bool = False,
|
||||
limit: int = 1000,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
) -> Event_Session_Base|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_session_id := redis_lookup_id_random(record_id_random=event_session_id, table_name='event_session'): pass
|
||||
else: return False
|
||||
|
||||
if inc_file_count:
|
||||
log.info('Using view with file count')
|
||||
if event_session_rec := sql_select(table_name='v_event_session_w_file_count', record_id=event_session_id): pass
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
if event_session_rec := sql_select(table_name='v_event_session', record_id=event_session_id): pass
|
||||
else:
|
||||
return False
|
||||
|
||||
log.debug(event_session_rec)
|
||||
|
||||
try:
|
||||
event_session_obj = Event_Session_Base(**event_session_rec)
|
||||
log.debug(event_session_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
account_id = event_session_rec.get('account_id', None)
|
||||
event_id = event_session_rec.get('event_id', None)
|
||||
event_location_id = event_session_rec.get('event_location_id', None)
|
||||
event_track_id = event_session_rec.get('event_track_id', None)
|
||||
poc_event_person_id = event_session_rec.get('poc_event_person_id', None)
|
||||
|
||||
#if inc_event: pass
|
||||
if inc_event_abstract_list: pass
|
||||
if inc_event_badge_list: pass
|
||||
if inc_event_device_list: pass
|
||||
|
||||
# Updated 2021-10-21
|
||||
if inc_event_file_list:
|
||||
log.info('Need to include event file list...')
|
||||
|
||||
from app.methods.event_file_methods import get_event_file_rec_list, load_event_file_obj
|
||||
if event_file_rec_list_result := get_event_file_rec_list(
|
||||
for_type = 'event_session',
|
||||
for_id = event_session_id,
|
||||
file_purpose_id = event_file_file_purpose_id,
|
||||
file_purpose = event_file_file_purpose,
|
||||
internal_use = False,
|
||||
priority = event_file_priority,
|
||||
group = event_file_group,
|
||||
enabled = enabled,
|
||||
limit = limit,
|
||||
):
|
||||
event_file_result_list = []
|
||||
for event_file_rec in event_file_rec_list_result:
|
||||
if load_event_file_result := load_event_file_obj(
|
||||
event_file_id = event_file_rec.get('event_file_id', None),
|
||||
enabled = enabled,
|
||||
inc_hosted_file = inc_hosted_file,
|
||||
):
|
||||
event_file_result_list.append(load_event_file_result)
|
||||
else:
|
||||
event_file_result_list.append(None)
|
||||
log.debug(event_file_result_list)
|
||||
event_session_obj.event_file_list = event_file_result_list
|
||||
elif isinstance(event_file_rec_list_result, list):
|
||||
event_session_obj.event_file_list = []
|
||||
else:
|
||||
event_session_obj.event_file_list = None
|
||||
|
||||
if inc_event_file_internal_use_list:
|
||||
log.info('Need to include event file internal use list...')
|
||||
|
||||
from app.methods.event_file_methods import get_event_file_rec_list, load_event_file_obj
|
||||
if event_file_rec_list_result := get_event_file_rec_list(
|
||||
for_type = 'event_session',
|
||||
for_id = event_session_id,
|
||||
file_purpose_id = event_file_file_purpose_id,
|
||||
file_purpose = event_file_file_purpose,
|
||||
internal_use = True,
|
||||
priority = event_file_priority,
|
||||
group = event_file_group,
|
||||
enabled = enabled,
|
||||
limit = limit,
|
||||
):
|
||||
event_file_result_list = []
|
||||
for event_file_rec in event_file_rec_list_result:
|
||||
if load_event_file_result := load_event_file_obj(
|
||||
event_file_id = event_file_rec.get('event_file_id', None),
|
||||
enabled = enabled,
|
||||
inc_hosted_file = inc_hosted_file,
|
||||
):
|
||||
event_file_result_list.append(load_event_file_result)
|
||||
else:
|
||||
event_file_result_list.append(None)
|
||||
log.debug(event_file_result_list)
|
||||
event_session_obj.event_file_internal_use_list = event_file_result_list
|
||||
elif isinstance(event_file_rec_list_result, list):
|
||||
event_session_obj.event_file_internal_use_list = []
|
||||
else:
|
||||
event_session_obj.event_file_internal_use_list = None
|
||||
|
||||
|
||||
log.debug(f'Get event location? Include Event Location: {inc_event_location} Event Location ID: {event_location_id}')
|
||||
if inc_event_location and event_location_id:
|
||||
log.info('Need to include event location...')
|
||||
if event_location_obj := load_event_location_obj(
|
||||
event_location_id = event_location_id,
|
||||
enabled = enabled,
|
||||
):
|
||||
event_session_obj.event_location = event_location_obj.dict(by_alias=True, exclude_unset=True)
|
||||
else:
|
||||
event_session_obj.event_location = None
|
||||
else:
|
||||
event_session_obj.event_location = None
|
||||
|
||||
# Updated 2022-09-20
|
||||
if inc_event_location_list:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.info('Need to include event location list...')
|
||||
|
||||
if event_location_rec_list_result := get_event_location_rec_list(
|
||||
event_id = event_id,
|
||||
enabled = enabled, # enabled, disabled, all
|
||||
hidden = 'all', # hidden, not_hidden, all
|
||||
limit = limit,
|
||||
):
|
||||
event_location_result_list = []
|
||||
for event_location_rec in event_location_rec_list_result:
|
||||
if load_event_location_result := load_event_location_obj(
|
||||
event_location_id = event_location_rec.get('event_location_id', None),
|
||||
enabled = enabled,
|
||||
limit = limit,
|
||||
):
|
||||
event_location_result_list.append(load_event_location_result)
|
||||
else:
|
||||
event_location_result_list.append(None)
|
||||
log.debug(event_location_result_list)
|
||||
event_session_obj.event_location_list = event_location_result_list
|
||||
elif isinstance(event_location_rec_list_result, list):
|
||||
event_session_obj.event_location_list = []
|
||||
else:
|
||||
event_session_obj.event_location_list = None
|
||||
|
||||
if inc_event_person_list: pass
|
||||
|
||||
if inc_event_presentation_list:
|
||||
log.info('Need to include event presentation list...')
|
||||
|
||||
data = {}
|
||||
data['event_session_id'] = event_session_id
|
||||
|
||||
if hidden in ['hidden', 'not_hidden', 'all']:
|
||||
if hidden == 'hidden':
|
||||
data['hide'] = True
|
||||
sql_hidden = f'AND `event_presentation`.hide = :hide'
|
||||
elif hidden == 'not_hidden':
|
||||
data['hide'] = False
|
||||
sql_hidden = f'AND `event_presentation`.hide = :hide'
|
||||
elif hidden == 'all':
|
||||
sql_hidden = ''
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `event_presentation`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `event_presentation`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
# else: event_obj['event_session'] = None
|
||||
|
||||
# if limit:
|
||||
# data['limit'] = limit
|
||||
# sql_limit = f'LIMIT :limit'
|
||||
# else:
|
||||
# sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_presentation`.id AS 'event_presentation_id', `event_presentation`.id_random AS 'event_presentation_id_random'
|
||||
FROM `event_presentation` AS `event_presentation`
|
||||
WHERE `event_presentation`.event_session_id = :event_session_id
|
||||
{sql_hidden}
|
||||
{sql_enabled}
|
||||
ORDER BY `event_presentation`.priority DESC, -`event_presentation`.sort DESC, `event_presentation`.start_datetime ASC, `event_presentation`.name ASC, `event_presentation`.created_on DESC, `event_presentation`.updated_on DESC;
|
||||
"""
|
||||
|
||||
if event_presentation_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
log.debug(event_presentation_rec_li_result)
|
||||
event_presentation_obj_li = []
|
||||
for event_presentation_rec in event_presentation_rec_li_result:
|
||||
event_presentation_id = event_presentation_rec.get('event_presentation_id', None)
|
||||
if event_presentation_obj := load_event_presentation_obj(
|
||||
event_presentation_id = event_presentation_id,
|
||||
enabled = enabled,
|
||||
# review = review,
|
||||
# approved = approved,
|
||||
hidden = hidden,
|
||||
inc_file_count = inc_file_count,
|
||||
inc_address = inc_address,
|
||||
inc_contact = inc_contact,
|
||||
inc_event_abstract_list = inc_event_abstract_list,
|
||||
inc_event_device_list = inc_event_device_list,
|
||||
inc_event_file_list = inc_event_file_list,
|
||||
inc_event_person = inc_event_person,
|
||||
inc_event_person_profile = inc_event_person_profile,
|
||||
inc_event_person_list = inc_event_person_list,
|
||||
inc_event_presenter_list = inc_event_presenter_list,
|
||||
inc_person = inc_person,
|
||||
inc_user = inc_user
|
||||
):
|
||||
data = event_presentation_obj.dict(by_alias=True, exclude_unset=True)
|
||||
event_presentation_obj_li.append(data)
|
||||
log.debug(event_presentation_obj_li)
|
||||
event_session_obj.event_presentation_list = event_presentation_obj_li
|
||||
else:
|
||||
log.debug(event_presentation_rec_li_result)
|
||||
event_session_obj.event_presentation_list = []
|
||||
|
||||
if inc_event_presenter_cat:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.info(f'Need to get event presenter cat list for session. Event Session ID: {event_session_id}')
|
||||
data = {}
|
||||
data['event_session_id'] = event_session_id
|
||||
|
||||
sql = f"""
|
||||
SELECT event_session_id, GROUP_CONCAT(given_name, ' ', family_name SEPARATOR '; ') AS 'event_presenter_names'
|
||||
FROM event_presenter
|
||||
WHERE event_session_id = :event_session_id
|
||||
GROUP BY event_session_id
|
||||
LIMIT 1
|
||||
"""
|
||||
if event_presenter_cat_rec_result := sql_select(data=data, sql=sql):
|
||||
log.debug(event_presenter_cat_rec_result.get('event_presenter_names', None))
|
||||
event_session_obj.event_presenter_cat = event_presenter_cat_rec_result.get('event_presenter_names', None)
|
||||
else:
|
||||
log.info(event_presenter_cat_rec_result)
|
||||
event_session_obj.event_presenter_cat = None
|
||||
|
||||
if inc_event_presenter_list: pass
|
||||
|
||||
if inc_poc_event_person:
|
||||
poc_event_person_obj = load_event_person_obj(
|
||||
event_person_id = poc_event_person_id,
|
||||
inc_address = inc_address,
|
||||
inc_contact = inc_contact,
|
||||
inc_person = inc_person,
|
||||
inc_user = inc_user,
|
||||
)
|
||||
log.debug(poc_event_person_obj)
|
||||
event_session_obj.poc_event_person = poc_event_person_obj
|
||||
log.debug(event_session_obj)
|
||||
|
||||
if model_as_dict:
|
||||
return event_session_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return event_session_obj
|
||||
# ### END ### API Event Session Methods ### load_event_session_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Session Methods ### get_event_session_rec_list() ###
|
||||
# Updated 2022-09-22
|
||||
@logger_reset
|
||||
def get_event_session_rec_list(
|
||||
event_id: str = None,
|
||||
event_location_id: str = None,
|
||||
event_track_id: str = None,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
approved: str = 'all', # approved, not_approved, all
|
||||
hidden: str = 'not_hidden', # hidden, not_hidden, all
|
||||
review: str = 'all', # ready, not_ready, all
|
||||
limit: int = 150,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
# else: return False
|
||||
|
||||
if event_location_id := redis_lookup_id_random(record_id_random=event_location_id, table_name='event_location'): pass
|
||||
# else: return False
|
||||
|
||||
data = {}
|
||||
|
||||
if event_id:
|
||||
data[f'event_id'] = event_id
|
||||
sql_where_type_id = f'`event_session`.event_id = :event_id'
|
||||
elif event_location_id:
|
||||
data[f'event_location_id'] = event_location_id
|
||||
sql_where_type_id = f'`event_session`.event_location_id = :event_location_id'
|
||||
|
||||
if review in ['ready', 'not_ready', 'all']:
|
||||
if review == 'ready':
|
||||
data['review'] = True
|
||||
sql_review = f'AND `event_session`.review = :review'
|
||||
elif review == 'not_ready':
|
||||
data['review'] = False
|
||||
sql_review = f'AND `event_session`.review = :review'
|
||||
elif review == 'all':
|
||||
sql_review = ''
|
||||
|
||||
if approved in ['approved', 'not_approved', 'all']:
|
||||
if approved == 'approved':
|
||||
data['approve'] = True
|
||||
sql_approved = f'AND `event_session`.approve = :approve'
|
||||
elif approved == 'not_approved':
|
||||
data['approve'] = False
|
||||
sql_approved = f'AND `event_session`.approve = :approve'
|
||||
elif approved == 'all':
|
||||
sql_approved = ''
|
||||
|
||||
if hidden in ['hidden', 'not_hidden', 'all']:
|
||||
if hidden == 'hidden':
|
||||
data['hide'] = True
|
||||
sql_hidden = f'AND `event_session`.hide = :hide'
|
||||
elif hidden == 'not_hidden':
|
||||
data['hide'] = False
|
||||
sql_hidden = f'AND `event_session`.hide = :hide'
|
||||
elif hidden == 'all':
|
||||
sql_hidden = ''
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `event_session`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `event_session`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `event_session`.id AS 'event_session_id', `event_session`.id_random AS 'event_session_id_random'
|
||||
FROM `event_session` AS `event_session`
|
||||
WHERE
|
||||
{sql_where_type_id}
|
||||
{sql_review}
|
||||
{sql_approved}
|
||||
{sql_hidden}
|
||||
{sql_enabled}
|
||||
ORDER BY `event_session`.priority DESC, -`event_session`.sort DESC, `event_session`.start_datetime ASC, `event_session`.name ASC, `event_session`.created_on DESC, `event_session`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if event_session_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
log.info('Got a list result')
|
||||
event_session_rec_li = event_session_rec_li_result
|
||||
else: # [] or False
|
||||
log.info('No results or something went wrong')
|
||||
event_session_rec_li = event_session_rec_li_result
|
||||
|
||||
log.debug(event_session_rec_li_result)
|
||||
|
||||
return event_session_rec_li
|
||||
# ### END ### API Event Session Methods ### get_event_session_rec_list() ###
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Session Methods ### create_update_event_session_obj_v4() ###
|
||||
# NOTE: This will create or update a event_session.
|
||||
# Rewrite and updated 2021-08-25
|
||||
@logger_reset
|
||||
def create_update_event_session_obj_v4(
|
||||
event_session_dict_obj: Event_Session_Base|dict,
|
||||
event_session_id: int|str = None,
|
||||
event_id: int|str = None,
|
||||
event_location_id: int|str = None, # For future?
|
||||
# event_track_id: int|str = None, # For future?
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_outline: bool = False,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
log.info('Checking requirements...')
|
||||
if event_session_id:
|
||||
log.info(f'Event Session ID passed. Update existing Event Session. Event Session ID: {event_session_id}')
|
||||
|
||||
if event_session_id := redis_lookup_id_random(record_id_random=event_session_id, table_name='event_session'): pass
|
||||
else:
|
||||
log.error('Event Session ID passed but is invalid. Failed requirement.')
|
||||
return False
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Event ID passed. Not required. Ignoring.')
|
||||
# log.info(f'Event ID: {event_id}')
|
||||
|
||||
# log.info('Attempting to get Event ID from related object.')
|
||||
# from app.methods.event_methods import get_event_id_w_for_type_id
|
||||
# if event_id := get_event_id_w_for_type_id(for_type='event_session', for_id=event_session_id): pass
|
||||
# else:
|
||||
# log.error('Unable to get Event ID from related object.')
|
||||
# False
|
||||
else:
|
||||
log.info('No Event Session ID passed. Create new Event Session. Required: Account ID, Event ID')
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Event ID passed. Failed requirement.')
|
||||
log.info(f'Event ID: {event_id}')
|
||||
return False
|
||||
|
||||
log.debug(type(event_session_dict_obj))
|
||||
if isinstance(event_session_dict_obj, dict):
|
||||
event_session_dict = event_session_dict_obj
|
||||
if event_session_id:
|
||||
event_session_dict['event_session_id'] = event_session_id
|
||||
if event_id:
|
||||
event_session_dict['event_id'] = event_id
|
||||
try:
|
||||
event_session_obj = Event_Session_Base(**event_session_dict)
|
||||
log.warning(event_session_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
event_session_obj = event_session_dict_obj
|
||||
if event_session_id:
|
||||
# NOTE: Can't update the ID alias if it was never set.
|
||||
event_session_obj.id = event_session_id
|
||||
if event_id:
|
||||
event_session_obj.event_id = event_id
|
||||
|
||||
event_session_dict = event_session_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event_presentation', 'event_presentation_list', 'created_on', 'updated_on'})
|
||||
|
||||
if event_session_id:
|
||||
if event_session_dict_up_result := sql_update(data=event_session_dict, table_name='event_session', rm_id_random=True): pass
|
||||
else:
|
||||
log.warning(f'Event Session not updated. Event Session ID: {event_session_id}')
|
||||
log.debug(event_session_dict_up_result)
|
||||
return False
|
||||
log.debug(event_session_dict_up_result)
|
||||
else:
|
||||
if event_session_dict_in_result := sql_insert(data=event_session_dict, table_name='event_session', rm_id_random=True, id_random_length=None): pass
|
||||
else:
|
||||
log.warning(f'Event Session not created.')
|
||||
log.debug(event_session_dict_in_result)
|
||||
return False
|
||||
log.debug(event_session_dict_in_result)
|
||||
|
||||
event_session_id = event_session_dict_in_result
|
||||
|
||||
log.debug(event_session_id)
|
||||
|
||||
event_session_outline = {}
|
||||
event_session_outline['event_session_id'] = event_session_id
|
||||
event_session_outline['event_presentation_list'] = []
|
||||
|
||||
if event_session_obj.event_presentation_list and isinstance(event_session_obj.event_presentation_list, list):
|
||||
log.info(f'Event Presentation List was found. Loop through and create a new Event Presentation for each and link them to the new Event Session. Event Session ID: {event_session_id}')
|
||||
for event_presentation_obj in event_session_obj.event_presentation_list:
|
||||
# NOTE: Use object model version because of better type checking and validations
|
||||
log.debug(event_presentation_obj)
|
||||
if event_presentation_id := event_presentation_obj.id: pass
|
||||
else: event_presentation_id = None
|
||||
# event_presentation_obj.event_id = event_id
|
||||
# event_presentation_obj.event_session_id = event_session_id
|
||||
create_update_event_presentation_obj_result = create_update_event_presentation_obj_v4(
|
||||
event_presentation_dict_obj = event_presentation_obj,
|
||||
event_presentation_id = event_presentation_id,
|
||||
event_id = event_id,
|
||||
# event_location_id = event_location_id,
|
||||
event_session_id = event_session_id,
|
||||
# event_track_id = event_track_id,
|
||||
fail_any = fail_any,
|
||||
return_outline = return_outline,
|
||||
)
|
||||
if isinstance(create_update_event_presentation_obj_result, int):
|
||||
event_presentation_id = create_update_event_presentation_obj_result
|
||||
elif create_update_event_presentation_obj_result == True: pass
|
||||
else:
|
||||
log.warning(f'Create or Update failed while trying create_update_event_presentation_obj_v4(): {create_update_event_presentation_obj_result}')
|
||||
event_presentation_id = None
|
||||
|
||||
event_session_outline['event_presentation_id'] = event_presentation_id
|
||||
|
||||
if return_outline:
|
||||
log.debug(f'Returning the Event Session Outline: {event_session_outline}')
|
||||
return event_session_outline
|
||||
else:
|
||||
log.debug(f'Returning the Event Session ID: {event_session_id}')
|
||||
return event_session_id
|
||||
# ### END ### API Event Session Methods ### create_update_event_session_obj_v4() ###
|
||||
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Session Methods ### create_event_session_obj() ###
|
||||
# Updated 2022-04-12
|
||||
@logger_reset
|
||||
def create_event_session_obj(
|
||||
event_id: int|str,
|
||||
event_session_obj_new: Event_Session_Base,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
) -> bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
else: return False
|
||||
|
||||
log.debug(type(event_session_obj_new))
|
||||
if isinstance(event_session_obj_new, dict):
|
||||
event_session_dict = event_session_obj_new
|
||||
try:
|
||||
event_session_obj = Event_Session_Base(**event_session_dict)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
log.debug(event_session_obj)
|
||||
else:
|
||||
event_session_dict = event_session_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event_presentation', 'event_presentation_list', 'event_presenter', 'event_presenter_list', 'created_on', 'updated_on'})
|
||||
|
||||
event_session_dict['event_id'] = event_id
|
||||
|
||||
log.debug(event_session_dict)
|
||||
|
||||
if event_session_obj_in_result := sql_insert(data=event_session_dict, table_name='event_session', rm_id_random=True, id_random_length=8): pass
|
||||
else:
|
||||
log.warning(f'Event Session not created.')
|
||||
log.debug(event_session_obj_in_result)
|
||||
return False
|
||||
|
||||
event_session_id = event_session_obj_in_result
|
||||
|
||||
return_dict = {}
|
||||
return_dict['event_session_id'] = None
|
||||
return_dict['event_presentation_list'] = []
|
||||
|
||||
if event_session_dict.get('event_presentation_list') and isinstance(event_session_dict.get('event_presentation_list'), list):
|
||||
log.info(f'Event Presentation List was found. Loop through and create a new Event Presentation for each and link them to the new Event Session. Event Session ID: {event_session_id}')
|
||||
for event_presentation_obj in event_session_dict.get('event_presentation_list'):
|
||||
# NOTE: This does not account for an edge case where the presentation already exists. Possibly as part of another session.
|
||||
if create_event_presentation_obj_result := create_event_presentation_obj(
|
||||
event_session_id = event_session_id,
|
||||
event_presentation_obj_new = event_presentation_obj,
|
||||
create_sub_obj = create_sub_obj,
|
||||
fail_any = fail_any,
|
||||
):
|
||||
if isinstance(create_event_presentation_obj_result, int):
|
||||
event_presentation_id = create_event_presentation_obj_result
|
||||
log.info(f'Event Presentation created. Event Presentation ID: {event_presentation_id}')
|
||||
else:
|
||||
log.warning(f'Event Presentation not created. Event Session ID: {event_session_id}')
|
||||
log.debug(create_event_presentation_obj_result)
|
||||
event_presentation_id = None
|
||||
if fail_any: return False
|
||||
else:
|
||||
log.warning(f'Event Presentation not created. Event Session ID: {event_session_id}')
|
||||
log.debug(create_event_presentation_obj_result)
|
||||
event_presentation_id = None
|
||||
if fail_any: return False
|
||||
return_dict['event_presentation_list'].append(event_presentation_id)
|
||||
else:
|
||||
log.info('Event Presentation List not found')
|
||||
pass
|
||||
|
||||
log.info(f'The Event Session has been created. Event Session ID: {event_session_id}')
|
||||
return event_session_id
|
||||
# ### END ### API Event Session Methods ### create_event_session_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Session Methods ### update_event_session_obj_v3() ###
|
||||
# Updated 2022-04-12
|
||||
@logger_reset
|
||||
def update_event_session_obj_v3(
|
||||
event_session_id: int|str,
|
||||
event_session_obj_exist: Event_Session_Base,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
) -> bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_session_id := redis_lookup_id_random(record_id_random=event_session_id, table_name='event_session'): pass
|
||||
else: return False
|
||||
|
||||
log.debug(type(event_session_obj_exist))
|
||||
if isinstance(event_session_obj_exist, dict):
|
||||
event_session_dict = event_session_obj_exist
|
||||
try:
|
||||
event_session_obj = Event_Session_Base(**event_session_obj_exist)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
log.debug(event_session_obj)
|
||||
else:
|
||||
event_session_dict = event_session_obj_exist.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event_presentation', 'event_presentation_list', 'event_presenter', 'event_presenter_list', 'created_on', 'updated_on'})
|
||||
|
||||
# Can't update the event_session_id alias if the .id was never set.
|
||||
# event_session_obj.event_session_id = event_session_id
|
||||
if not event_session_obj.id:
|
||||
event_session_obj.id = event_session_id
|
||||
|
||||
# event_presenter_dict['event_id'] = event_id
|
||||
# if event_track_id:
|
||||
# event_presenter_dict['for_type'] = 'event_track'
|
||||
# event_presenter_dict['for_id'] = event_track_id
|
||||
# event_presenter_dict['event_track_id'] = event_track_id
|
||||
|
||||
log.debug(event_session_dict)
|
||||
|
||||
if event_session_obj_up_result := sql_update(data=event_session_dict, table_name='event_session', record_id=event_session_id, rm_id_random=True): pass
|
||||
else:
|
||||
log.warning(f'Event Session not updated.')
|
||||
log.debug(event_session_obj_up_result)
|
||||
return False
|
||||
|
||||
return_dict = {}
|
||||
return_dict['event_session_id'] = event_session_id
|
||||
return_dict['event_presentation_list'] = []
|
||||
|
||||
if event_session_obj.event_presentation_list and isinstance(event_session_obj.event_presentation_list, list):
|
||||
for event_presentation_obj_unknown in event_session_obj.event_presentation_list:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_presentation_obj_unknown)
|
||||
if event_presentation_id := event_presentation_obj_unknown.get('event_presentation_id_random', None):
|
||||
if update_event_presentation_obj_result := update_event_presentation_obj_v3(
|
||||
event_presentation_id = event_presentation_id,
|
||||
event_presentation_obj_exist = event_presentation_obj_unknown,
|
||||
create_sub_obj = create_sub_obj,
|
||||
fail_any = fail_any,
|
||||
):
|
||||
event_presentation_id = update_event_presentation_obj_result
|
||||
log.info(f'Event Presentation updated. Event Presentation ID: {event_presentation_id}')
|
||||
else:
|
||||
log.warning(f'Event Presentation not updated. Event Session ID: {event_session_id}')
|
||||
log.debug(update_event_presentation_obj_result)
|
||||
event_presentation_id = None
|
||||
if fail_any: return False
|
||||
|
||||
if isinstance(update_event_presentation_obj_result, int):
|
||||
event_presentation_id = update_event_presentation_obj_result
|
||||
log.info(f'Event Presentation updated. Event Presentation ID: {event_presentation_id}')
|
||||
else:
|
||||
log.warning(f'Event Presentation not updated. Event Session ID: {event_session_id}')
|
||||
log.debug(update_event_presentation_obj_result)
|
||||
event_presentation_id = None
|
||||
if fail_any: return False
|
||||
else:
|
||||
log.info(f'No Event Presentation ID found.')
|
||||
if create_event_presentation_obj_result := create_event_presentation_obj(
|
||||
event_session_id = event_session_id,
|
||||
event_presentation_obj_new = event_presentation_obj_unknown,
|
||||
create_sub_obj = create_sub_obj,
|
||||
fail_any = fail_any,
|
||||
):
|
||||
if isinstance(create_event_presentation_obj_result, int):
|
||||
event_presentation_id = create_event_presentation_obj_result
|
||||
log.info(f'Event Presentation created. Event Presentation ID: {event_presentation_id}')
|
||||
else:
|
||||
log.warning(f'Event Presentation not created. Event Session ID: {event_session_id}')
|
||||
log.debug(create_event_presentation_obj_result)
|
||||
event_presentation_id = None
|
||||
if fail_any: return False
|
||||
else:
|
||||
log.warning(f'Event Presentation not created. Event Session ID: {event_session_id}')
|
||||
log.debug(create_event_presentation_obj_result)
|
||||
event_presentation_id = None
|
||||
if fail_any: return False
|
||||
return_dict['event_presentation_list'].append(event_presentation_id)
|
||||
else:
|
||||
log.info('Event Presentation List not found or not in a list.')
|
||||
pass
|
||||
|
||||
log.info(f'The event session has been updated. Event Session ID: {event_session_id}')
|
||||
return True
|
||||
# ### END ### API Event Session Methods ### update_event_session_obj_v3() ###
|
||||
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Event Session Methods ### update_event_session_obj() ###
|
||||
# This will be taken over by _exist version
|
||||
# Updated 2022-04-12
|
||||
@logger_reset
|
||||
def update_event_session_obj(
|
||||
event_session_id: int|str, # Ideally the int ID should be passed. This allows for updating of the id_random value.
|
||||
event_session_obj_up: Event_Session_Base,
|
||||
create_sub_obj: bool = False,
|
||||
) -> bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if event_session_id := redis_lookup_id_random(record_id_random=event_session_id, table_name='event_session'): pass
|
||||
else: return False
|
||||
|
||||
event_session_obj_up.id = event_session_id
|
||||
|
||||
log.debug(event_session_obj_up)
|
||||
# log.debug(event_session_obj_up.dict(by_alias=True, exclude_unset=True))
|
||||
log.debug(event_session_obj_up.dict(by_alias=False, exclude_unset=True))
|
||||
# log.debug(event_session_obj_up.dict(by_alias=False, exclude_unset=False))
|
||||
|
||||
if event_session_obj_up.poc_event_person_id and event_session_obj_up.poc_event_person:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
poc_event_person_id = event_session_obj_up.poc_event_person_id
|
||||
poc_event_person_obj_up = event_session_obj_up.poc_event_person
|
||||
log.debug(poc_event_person_id)
|
||||
log.debug(poc_event_person_obj_up)
|
||||
if poc_event_person_obj_up_result := update_event_person_obj(
|
||||
event_person_id=poc_event_person_id,
|
||||
event_person_obj_up=poc_event_person_obj_up,
|
||||
create_sub_obj=create_sub_obj,
|
||||
):
|
||||
log.debug(poc_event_person_obj_up_result)
|
||||
else:
|
||||
log.debug(poc_event_person_obj_up_result)
|
||||
return False
|
||||
elif event_session_obj_up.poc_event_person and not event_session_obj_up.poc_event_person.id:
|
||||
# NOTE: This will blindly create a new poc_event_person even if there was one associated but the event_session.poc_event_person_id was not found.
|
||||
poc_event_person_obj_in = event_session_obj_up.poc_event_person
|
||||
log.debug(poc_event_person_obj_in)
|
||||
if poc_event_person_obj_in_result := create_event_person_obj(event_person_obj_new=poc_event_person_obj_in):
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(poc_event_person_obj_in_result)
|
||||
event_session_obj_up.poc_event_person_id = poc_event_person_obj_in_result
|
||||
else:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(poc_event_person_obj_in_result)
|
||||
return False
|
||||
|
||||
if event_session_obj_up.event_presentation_id and event_session_obj_up.event_presentation:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
event_presentation_id = event_session_obj_up.event_presentation_id
|
||||
event_presentation_obj_up = event_session_obj_up.event_presentation
|
||||
log.debug(event_presentation_id)
|
||||
log.debug(event_presentation_obj_up)
|
||||
if event_presentation_obj_up_result := update_event_presentation_obj(
|
||||
event_presentation_id=event_presentation_id,
|
||||
event_presentation_obj_up=event_presentation_obj_up,
|
||||
create_sub_obj=create_sub_obj,
|
||||
):
|
||||
log.debug(event_presentation_obj_up_result)
|
||||
else:
|
||||
log.debug(event_presentation_obj_up_result)
|
||||
return False
|
||||
elif event_session_obj_up.event_presentation and not event_session_obj_up.event_presentation.id:
|
||||
# NOTE: This will blindly create a new event_presentation even if there was one associated but the event_session.event_presentation_id was not found.
|
||||
event_presentation_obj_in = event_session_obj_up.event_presentation
|
||||
log.debug(event_presentation_obj_in)
|
||||
if event_presentation_obj_in_result := create_event_presentation_obj(event_session_id=event_session, event_presentation_obj_new=event_presentation_obj_in):
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_presentation_obj_in_result)
|
||||
event_session_obj_up.event_presentation_id = event_presentation_obj_in_result
|
||||
else:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(event_presentation_obj_in_result)
|
||||
return False
|
||||
|
||||
|
||||
|
||||
event_session_dict_up = event_session_obj_up.dict(by_alias=False, exclude_unset=True, exclude={'event_abstract', 'event_abstract_list', 'event_file_list', 'event_person', 'event_presentation', 'event_session', 'person', 'user'})
|
||||
log.debug(event_session_dict_up)
|
||||
|
||||
if event_session_obj_up_result := sql_update(data=event_session_dict_up, table_name='event_session', rm_id_random=True):
|
||||
log.debug(event_session_obj_up_result)
|
||||
return True
|
||||
else:
|
||||
log.debug(event_session_obj_up_result)
|
||||
return False
|
||||
# ### END ### API Session Methods ### update_event_session_obj() ###
|
||||
73
app/methods/fundraising_cfg_methods.py
Normal file
73
app/methods/fundraising_cfg_methods.py
Normal file
@@ -0,0 +1,73 @@
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_enable_part, sql_insert, sql_limit_offset_part, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.models.fundraising_cfg_models import Fundraising_Cfg_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Fundraising Cfg Methods ### load_fundraising_cfg_obj() ###
|
||||
# Updated 2022-11-18
|
||||
def load_fundraising_cfg_obj(
|
||||
fundraising_id: int|str,
|
||||
model_as_dict: bool = False,
|
||||
) -> Fundraising_Cfg_Base|dict|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if fundraising_id := redis_lookup_id_random(record_id_random=fundraising_id, table_name='fundraising'): pass
|
||||
else: return False
|
||||
|
||||
if fundraising_cfg_rec := sql_select(
|
||||
table_name = 'v_fundraising_cfg',
|
||||
field_name = 'fundraising_id',
|
||||
field_value = fundraising_id
|
||||
): pass
|
||||
else: return False
|
||||
log.debug(fundraising_cfg_rec)
|
||||
try:
|
||||
fundraising_cfg_obj = Fundraising_Cfg_Base(**fundraising_cfg_rec)
|
||||
log.debug(fundraising_cfg_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
if model_as_dict:
|
||||
return fundraising_cfg_obj.dict(by_alias=True, exclude_unset=True) # pylint: disable=no-member
|
||||
else:
|
||||
return fundraising_cfg_obj
|
||||
# ### END ### API Fundraising Cfg Methods ### load_fundraising_cfg_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Fundraising Cfg Methods ### load_fundraising_cfg_obj_old() ###
|
||||
# Updated 2022-11-18
|
||||
def load_fundraising_cfg_obj_old(
|
||||
account_id: int|str,
|
||||
model_as_dict: bool = False,
|
||||
) -> Fundraising_Cfg_Base|dict|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
|
||||
if fundraising_cfg_rec := sql_select(
|
||||
table_name = 'v_fundraising_cfg',
|
||||
field_name = 'account_id',
|
||||
field_value = account_id
|
||||
): pass
|
||||
else: return False
|
||||
log.debug(fundraising_cfg_rec)
|
||||
try:
|
||||
fundraising_cfg_obj = Fundraising_Cfg_Base(**fundraising_cfg_rec)
|
||||
log.debug(fundraising_cfg_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
if model_as_dict:
|
||||
return fundraising_cfg_obj.dict(by_alias=True, exclude_unset=True) # pylint: disable=no-member
|
||||
else:
|
||||
return fundraising_cfg_obj
|
||||
# ### END ### API Fundraising Cfg Methods ### load_fundraising_cfg_obj_old() ###
|
||||
165
app/methods/fundraising_methods.py
Normal file
165
app/methods/fundraising_methods.py
Normal file
@@ -0,0 +1,165 @@
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_enable_part, sql_insert, sql_limit_offset_part, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.methods.fundraising_cfg_methods import load_fundraising_cfg_obj
|
||||
from app.methods.product_methods import get_product_rec_list, load_product_obj
|
||||
|
||||
from app.models.fundraising_models import Fundraising_Base
|
||||
from app.models.fundraising_cfg_models import Fundraising_Cfg_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Fundraising Cfg Methods ### load_fundraising_obj() ###
|
||||
# Updated 2022-11-18
|
||||
def load_fundraising_obj(
|
||||
fundraising_id: int|str,
|
||||
|
||||
inc_fundraising_cfg: bool = False,
|
||||
inc_product_list: bool = False,
|
||||
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
|
||||
model_as_dict: bool = False,
|
||||
) -> Fundraising_Base|dict|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if fundraising_id := redis_lookup_id_random(record_id_random=fundraising_id, table_name='fundraising'): pass
|
||||
else: return False
|
||||
|
||||
if fundraising_rec := sql_select(table_name='v_fundraising', record_id=fundraising_id): pass
|
||||
else: return False
|
||||
|
||||
log.debug(fundraising_rec)
|
||||
|
||||
try:
|
||||
fundraising_obj = Fundraising_Base(**fundraising_rec)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
log.debug(fundraising_obj)
|
||||
|
||||
# Updated 2022-11-18
|
||||
if inc_fundraising_cfg:
|
||||
log.info('Need to include fundraising configuration...')
|
||||
if fundraising_cfg_result := load_fundraising_cfg_obj(
|
||||
fundraising_id = fundraising_id,
|
||||
|
||||
# by_alias = by_alias,
|
||||
# exclude_unset = exclude_unset,
|
||||
# model_as_dict = model_as_dict,
|
||||
):
|
||||
fundraising_obj.fundraising_cfg = fundraising_cfg_result
|
||||
else: fundraising_obj.fundraising_cfg = {} # None
|
||||
log.debug(fundraising_obj.fundraising_cfg)
|
||||
|
||||
# Updated 2022-11-18
|
||||
if inc_product_list:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.info('Need to include product list...')
|
||||
|
||||
if product_rec_list_result := get_product_rec_list(
|
||||
for_obj_type = 'fundraising',
|
||||
for_obj_id = fundraising_id,
|
||||
enabled = enabled,
|
||||
):
|
||||
product_result_list = []
|
||||
for product_rec in product_rec_list_result:
|
||||
if load_product_result := load_product_obj(
|
||||
product_id = product_rec.get('product_id', None),
|
||||
):
|
||||
product_result_list.append(load_product_result)
|
||||
else:
|
||||
product_result_list.append(None)
|
||||
log.debug(product_result_list)
|
||||
fundraising_obj.product_list = product_result_list
|
||||
elif isinstance(product_rec_list_result, list):
|
||||
fundraising_obj.product_list = []
|
||||
else:
|
||||
fundraising_obj.product_list = None
|
||||
|
||||
if model_as_dict:
|
||||
return fundraising_obj.dict(by_alias=True, exclude_unset=True) # pylint: disable=no-member
|
||||
else:
|
||||
return fundraising_obj
|
||||
# ### END ### API Fundraising Cfg Methods ### load_fundraising_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Fundraising Cfg Methods ### get_fundraising_rec_list() ###
|
||||
@logger_reset
|
||||
def get_fundraising_rec_list(
|
||||
account_id: str = None,
|
||||
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
hidden: str = 'not_hidden', # hidden, not_hidden, all
|
||||
priority: str = 'all', # priority, not_priority, all
|
||||
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: pass
|
||||
|
||||
data = {}
|
||||
data['account_id'] = account_id
|
||||
|
||||
sql_where_account_id = f'`fundraising`.account_id = :account_id'
|
||||
|
||||
sql_hidden = ''
|
||||
if hidden in ['hidden', 'not_hidden', 'all']:
|
||||
if hidden == 'hidden':
|
||||
data['hide'] = True
|
||||
sql_hidden = f'AND `fundraising`.hide = :hide'
|
||||
elif hidden == 'not_hidden':
|
||||
data['hide'] = False
|
||||
sql_hidden = f'AND `fundraising`.hide = :hide'
|
||||
elif hidden == 'all':
|
||||
sql_hidden = ''
|
||||
|
||||
sql_priority = ''
|
||||
if priority in ['priority', 'not_priority', 'all']:
|
||||
if priority == 'priority':
|
||||
data['priority'] = True
|
||||
sql_priority = f'AND `fundraising`.priority = :priority'
|
||||
elif priority == 'not_priority':
|
||||
data['priority'] = False
|
||||
sql_priority = f'AND `fundraising`.priority = :priority'
|
||||
elif priority == 'all':
|
||||
sql_priority = ''
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='fundraising', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
sql = f"""
|
||||
SELECT `fundraising`.id AS 'fundraising_id', `fundraising`.id_random AS 'fundraising_id_random'
|
||||
FROM `fundraising` AS `fundraising`
|
||||
WHERE
|
||||
{sql_where_account_id}
|
||||
{sql_hidden}
|
||||
{sql_priority}
|
||||
{sql_enabled}
|
||||
ORDER BY `fundraising`.priority DESC, -`fundraising`.sort DESC, `fundraising`.title ASC, `fundraising`.created_on DESC, `fundraising`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if fundraising_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
|
||||
fundraising_rec_li = fundraising_rec_li_result
|
||||
else:
|
||||
fundraising_rec_li = []
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(fundraising_rec_li_result)
|
||||
log.debug(type(fundraising_rec_li))
|
||||
log.debug(len(fundraising_rec_li))
|
||||
|
||||
return fundraising_rec_li
|
||||
# ### END ### API Fundraising Cfg Methods ### get_fundraising_rec_list() ###
|
||||
412
app/methods/grant_methods.py
Normal file
412
app/methods/grant_methods.py
Normal file
@@ -0,0 +1,412 @@
|
||||
import datetime, json
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_delete, sql_insert, sql_select, sql_update, sql_enable_part, sql_limit_offset_part
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
from app.models.grant_models import Grant_Ext, Grant_In
|
||||
|
||||
|
||||
# ### BEGIN ### API Grant Methods ### load_grant_obj() ###
|
||||
# Updated 2023-06-23
|
||||
@logger_reset
|
||||
def load_grant_obj(
|
||||
grant_id: int|str,
|
||||
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
hidden: str = 'not_hidden', # hidden, not_hidden, all
|
||||
|
||||
inc_event_abstract: bool = False,
|
||||
|
||||
limit: int = 1500,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
) -> Grant_Ext|dict|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# if grant_id := redis_lookup_id_random(record_id_random=grant_id, table_name='grant'): pass
|
||||
# else: return False
|
||||
|
||||
if grant_rec := sql_select(table_name='v_grant', record_id=grant_id): pass
|
||||
else: return False
|
||||
|
||||
try:
|
||||
grant_obj = Grant_Ext(**grant_rec)
|
||||
log.debug(grant_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
# Updated 2023-06-23
|
||||
if inc_event_abstract:
|
||||
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.info('Need to include event abstract...')
|
||||
|
||||
if event_abstract_obj := load_event_abstract_obj(
|
||||
event_abstract_id = grant_obj.event_abstract_id,
|
||||
enabled = enabled,
|
||||
):
|
||||
log.debug(event_abstract_obj)
|
||||
grant_obj.event_abstract = event_abstract_obj
|
||||
else:
|
||||
log.debug(event_abstract_obj)
|
||||
grant_obj.event_abstract = None
|
||||
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
|
||||
if model_as_dict:
|
||||
return grant_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return grant_obj
|
||||
# ### END ### API Grant Methods ### load_grant_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Grant Methods ### get_grant_rec_list() ###
|
||||
# Updated 2023-06-23
|
||||
@logger_reset
|
||||
def get_grant_rec_list(
|
||||
account_id: None|str = None,
|
||||
event_id: None|str = None,
|
||||
|
||||
grant_type_code: str = None, # not sure yet
|
||||
|
||||
hidden: str = 'all', # hidden, not_hidden, all
|
||||
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 250,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if not account_id and not event_id: return False
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
elif account_id is None: pass
|
||||
else: return False
|
||||
|
||||
if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'): pass
|
||||
elif event_id is None: pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
if account_id:
|
||||
data['account_id'] = account_id
|
||||
sql_account_id = f'`grant`.account_id = :account_id'
|
||||
else: sql_account_id = '1=1'
|
||||
|
||||
if event_id:
|
||||
data['event_id'] = event_id
|
||||
sql_event_id = f'AND `grant`.event_id = :event_id'
|
||||
else: sql_event_id = ''
|
||||
|
||||
# if abstract_type_code:
|
||||
# data['abstract_type_code'] = abstract_type_code
|
||||
# sql_abstract_type_code = f'AND `grant`.abstract_type_code = :abstract_type_code'
|
||||
# else: sql_abstract_type_code = ''
|
||||
|
||||
if hidden in ['hidden', 'not_hidden', 'all']:
|
||||
log.info(f'Creating partial SQL string for "hidden" check. Printed: {hidden}')
|
||||
if hidden == 'not_hidden':
|
||||
sql_hidden = f'AND (`grant`.hide IS NULL OR `grant`.hide = FALSE)'
|
||||
elif hidden == 'hidden':
|
||||
sql_hidden = f'AND `grant`.hide = TRUE'
|
||||
elif hidden == 'all':
|
||||
sql_hidden = f'AND (`grant`.hide IS NULL OR `grant`.hide IS NOT NULL)'
|
||||
log.debug(sql_hidden)
|
||||
else: sql_hidden = ''
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='grant', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
sql = f"""
|
||||
SELECT `grant`.id AS 'grant_id', `grant`.id_random AS 'grant_id_random'
|
||||
FROM `v_grant` AS `grant`
|
||||
WHERE
|
||||
{sql_account_id}
|
||||
{sql_event_id}
|
||||
{sql_hidden}
|
||||
{sql_enabled}
|
||||
ORDER BY grant.priority DESC, grant.sort DESC, grant.name ASC, `grant`.created_on DESC, `grant`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(sql)
|
||||
|
||||
if grant_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
grant_rec_li = grant_rec_li_result
|
||||
else: # [] or False
|
||||
grant_rec_li = grant_rec_li_result
|
||||
|
||||
log.debug(grant_rec_li_result)
|
||||
|
||||
return grant_rec_li
|
||||
# ### END ### API Grant Methods ### get_grant_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Grant Methods ### create_update_grant_obj() ###
|
||||
# Updated 2023-06-28
|
||||
@logger_reset
|
||||
def create_update_grant_obj(
|
||||
grant_obj: Grant_In,
|
||||
grant_id: int = None,
|
||||
event_id: int = None,
|
||||
# event_person_id: int = None,
|
||||
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_outline: bool = False,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
log.info('Checking requirements...')
|
||||
if grant_id:
|
||||
log.info(f'Got: grant_id={grant_id}; Update existing Grant')
|
||||
grant_obj.id = grant_id
|
||||
elif event_id:
|
||||
log.info(f'Got: event_id={event_id}; Create Grant')
|
||||
grant_obj.event_id = event_id
|
||||
else:
|
||||
return False
|
||||
|
||||
log.debug(type(grant_obj))
|
||||
log.debug(grant_obj
|
||||
)
|
||||
|
||||
grant_dict = grant_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event_abstract', 'event_person', 'created_on', 'updated_on'})
|
||||
|
||||
if grant_id:
|
||||
if grant_dict_up_result := sql_update(data=grant_dict, table_name='grant', rm_id_random=True):
|
||||
log.info(f'Grant updated. grant_id={grant_id}')
|
||||
pass
|
||||
else:
|
||||
log.warning(f'Grant not updated. grant_id={grant_id}')
|
||||
log.debug(grant_dict_up_result)
|
||||
return False
|
||||
log.debug(grant_dict_up_result)
|
||||
else:
|
||||
if grant_dict_in_result := sql_insert(data=grant_dict, table_name='grant', rm_id_random=True, id_random_length=None):
|
||||
log.info(f'Grant created. grant_id={grant_dict_in_result}')
|
||||
else:
|
||||
log.warning(f'Grant not created.')
|
||||
log.debug(grant_dict_in_result)
|
||||
return False
|
||||
log.debug(grant_dict_in_result)
|
||||
|
||||
grant_id = grant_dict_in_result # False, None, integer
|
||||
|
||||
grant_outline = {}
|
||||
grant_outline['event_id'] = event_id
|
||||
grant_outline['grant_id'] = grant_id
|
||||
|
||||
if return_outline:
|
||||
log.debug(f'Returning the Grant Outline: {grant_outline}')
|
||||
return grant_outline
|
||||
else:
|
||||
log.debug(f'Returning the Grant ID: {grant_id}')
|
||||
return grant_id
|
||||
# ### END ### API Grant Methods ### create_update_grant_obj() ###
|
||||
|
||||
|
||||
|
||||
# # ### BEGIN ### API Grant Methods ### create_update_grant_obj_old() ###
|
||||
# # Updated 2023-03-20
|
||||
# @logger_reset
|
||||
# def create_update_grant_obj_old(
|
||||
# grant_dict_obj: Grant_In|dict,
|
||||
# grant_id: int|str = None,
|
||||
# event_id: int|str = None,
|
||||
# event_person_id: int|str = None,
|
||||
# create_sub_obj: bool = False,
|
||||
# fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
# return_outline: bool = False,
|
||||
# ) -> int|bool:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(locals())
|
||||
|
||||
# log.info('Checking requirements...')
|
||||
# if grant_id:
|
||||
# log.info(f'Grant ID passed. Update existing Grant. Grant ID: {grant_id}')
|
||||
|
||||
# if grant_id := redis_lookup_id_random(record_id_random=grant_id, table_name='grant'): pass
|
||||
# else:
|
||||
# log.error('Grant ID passed but is invalid. Failed requirement.')
|
||||
# return False
|
||||
|
||||
# if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'):
|
||||
# log.info(f'Event ID: {event_id}')
|
||||
# elif event_id is None:
|
||||
# log.error('Missing Event ID. Not required. Ignoring.')
|
||||
# log.info(f'Event ID: {event_id}')
|
||||
# else:
|
||||
# log.error('Invalid Event ID passed. Not required. But not ignoring since it is likely invalid.')
|
||||
# log.info(f'Event ID: {event_id}')
|
||||
# return False
|
||||
# else:
|
||||
# log.info('No Grant ID passed. Create new Grant. Required: Event ID')
|
||||
|
||||
# if event_id := redis_lookup_id_random(record_id_random=event_id, table_name='event'):
|
||||
# log.info(f'Event ID: {event_id}')
|
||||
# elif event_id is None:
|
||||
# log.error('Missing Event ID. Failed requirement.')
|
||||
# log.info(f'Event ID: {event_id}')
|
||||
# return False
|
||||
# else:
|
||||
# log.error('Invalid Event ID passed. Failed requirement.')
|
||||
# log.info(f'Event ID: {event_id}')
|
||||
# return False
|
||||
# # else:
|
||||
# # log.error('Missing or invalid Event ID passed. Failed requirement.')
|
||||
# # log.info(f'Event ID: {event_id}')
|
||||
# # return False
|
||||
|
||||
# log.debug(type(grant_dict_obj))
|
||||
# if isinstance(grant_dict_obj, dict):
|
||||
# grant_dict = grant_dict_obj
|
||||
# if grant_id:
|
||||
# grant_dict['grant_id'] = grant_id
|
||||
# if event_id:
|
||||
# grant_dict['event_id'] = event_id
|
||||
# if event_person_id:
|
||||
# grant_dict['event_person_id'] = event_person_id
|
||||
# try:
|
||||
# grant_obj = Grant_In(**grant_dict)
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(grant_obj)
|
||||
# except ValidationError as e:
|
||||
# log.error(e.json())
|
||||
# return False
|
||||
# else:
|
||||
# grant_obj = grant_dict_obj
|
||||
# if grant_id:
|
||||
# # NOTE: Can't update the ID alias if it was never set.
|
||||
# grant_obj.id = grant_id
|
||||
# if event_id:
|
||||
# grant_obj.event_id = event_id
|
||||
# if event_person_id:
|
||||
# grant_obj.event_person_id = event_person_id
|
||||
|
||||
# grant_dict = grant_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'event_person', 'event_person_list', 'created_on', 'updated_on'})
|
||||
|
||||
# if grant_id:
|
||||
# if grant_dict_up_result := sql_update(data=grant_dict, table_name='grant', rm_id_random=True): pass
|
||||
# else:
|
||||
# log.warning(f'Grant not updated. Grant ID: {grant_id}')
|
||||
# log.debug(grant_dict_up_result)
|
||||
# return False
|
||||
# log.debug(grant_dict_up_result)
|
||||
# else:
|
||||
# if grant_dict_in_result := sql_insert(data=grant_dict, table_name='grant', rm_id_random=True, id_random_length=None): pass
|
||||
# else:
|
||||
# log.warning(f'Grant not created.')
|
||||
# log.debug(grant_dict_in_result)
|
||||
# return False
|
||||
# log.debug(grant_dict_in_result)
|
||||
|
||||
# grant_id = grant_dict_in_result
|
||||
|
||||
# grant_outline = {}
|
||||
# grant_outline['event_id'] = event_id
|
||||
# grant_outline['grant_id'] = grant_id
|
||||
# grant_outline['event_person_id'] = event_person_id
|
||||
# # grant_outline['event_presenter_list'] = []
|
||||
|
||||
# # if grant_obj.event_presenter_list and isinstance(grant_obj.event_presenter_list, list):
|
||||
# # log.info(f'Event Presenter List was found. Loop through and create a new Event Presenter for each and link them to the new Grant. Grant ID: {grant_id}')
|
||||
# # for event_presenter_obj in grant_obj.event_presenter_list:
|
||||
# # # NOTE: Use object model version because of better type checking and validations
|
||||
# # log.debug(event_presenter_obj)
|
||||
# # if event_presenter_id := event_presenter_obj.id: pass
|
||||
# # else: event_presenter_id = None
|
||||
# # # event_presenter_obj.event_id = event_id
|
||||
# # # event_presenter_obj.event_session_id = event_session_id
|
||||
# # create_update_event_presenter_obj_result = create_update_event_presenter_obj_v4(
|
||||
# # event_presenter_dict_obj = event_presenter_obj,
|
||||
# # event_presenter_id = event_presenter_id,
|
||||
# # event_id = event_id,
|
||||
# # event_session_id = event_session_id,
|
||||
# # grant_id = grant_id,
|
||||
# # fail_any = fail_any,
|
||||
# # return_outline = return_outline,
|
||||
# # )
|
||||
# # if isinstance(create_update_event_presenter_obj_result, int):
|
||||
# # event_presenter_id = create_update_event_presenter_obj_result
|
||||
# # elif create_update_event_presenter_obj_result == True: pass
|
||||
# # else:
|
||||
# # log.warning(f'Create or Update failed while trying create_update_event_presenter_obj_v4(): {create_update_event_presenter_obj_result}')
|
||||
# # event_presenter_id = None
|
||||
|
||||
# # grant_outline['event_presenter_id'] = event_presenter_id
|
||||
|
||||
# if return_outline:
|
||||
# log.debug(f'Returning the Grant Outline: {grant_outline}')
|
||||
# return grant_outline
|
||||
# else:
|
||||
# log.debug(f'Returning the Grant ID: {grant_id}')
|
||||
# return grant_id
|
||||
# # ### END ### API Grant Methods ### create_update_grant_obj_old() ###
|
||||
|
||||
|
||||
# # ### BEGIN ### API Grant Methods ### remove_grant_obj() ###
|
||||
# # Updated 2023-03-22
|
||||
# @logger_reset
|
||||
# def remove_grant_obj(
|
||||
# grant_id: int,
|
||||
|
||||
# method: None|str = None,
|
||||
|
||||
# log_lvl: int = logging.DEBUG, # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# ) -> bool|None:
|
||||
# log.setLevel(log_lvl)
|
||||
|
||||
# if method is None or method == 'disable':
|
||||
# data = {'enable': False}
|
||||
|
||||
# if grant_dict_up_result := sql_update(
|
||||
# table_name = 'grant',
|
||||
# record_id = grant_id,
|
||||
# data = data,
|
||||
# log_lvl = log_lvl,
|
||||
# ):
|
||||
# log.info(f'Grant was disabled.')
|
||||
# return True
|
||||
# else:
|
||||
# log.warning(f'Grant not disabled.')
|
||||
# return grant_dict_up_result # False or None
|
||||
# elif method == 'delete':
|
||||
# if grant_dict_del_result := sql_delete(
|
||||
# table_name = 'grant',
|
||||
# record_id = grant_id,
|
||||
# log_lvl = log_lvl,
|
||||
# ):
|
||||
# log.info(f'Grant was deleted.')
|
||||
# return True
|
||||
# else:
|
||||
# log.warning(f'Grant not deleted.')
|
||||
# return grant_dict_del_result # False or None
|
||||
# elif method == 'hide':
|
||||
# data = {'hide': True}
|
||||
|
||||
# if grant_dict_up_result := sql_update(
|
||||
# table_name = 'grant',
|
||||
# record_id = grant_id,
|
||||
# data = data,
|
||||
# log_lvl = log_lvl,
|
||||
# ):
|
||||
# log.info(f'Grant was hidden.')
|
||||
# return True
|
||||
# else:
|
||||
# log.warning(f'Grant not hidden.')
|
||||
# return grant_dict_up_result # False or None
|
||||
# else:
|
||||
# log.error('We should not be here. Something went wrong in remove_grant_obj()!')
|
||||
# return False
|
||||
|
||||
|
||||
# # ### END ### API Grant Methods ### remove_grant_obj() ###
|
||||
873
app/methods/hosted_file_methods.py
Normal file
873
app/methods/hosted_file_methods.py
Normal file
@@ -0,0 +1,873 @@
|
||||
import datetime, hashlib, mimetypes, os, pathlib, shutil, time
|
||||
|
||||
from fastapi import File, UploadFile
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.config import settings
|
||||
from app.db_sql import redis_lookup_id_random, sql_delete, sql_enable_part, sql_insert, sql_limit_offset_part, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.models.hosted_file_models import Hosted_File_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Hosted File Methods ### create_hosted_file_obj() ###
|
||||
@logger_reset
|
||||
def create_hosted_file_obj(hosted_file_obj_new:Hosted_File_Base):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# hosted_file_obj_data = hosted_file_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'created_on', 'updated_on'})
|
||||
hosted_file_obj_data = hosted_file_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'saved', 'already_exists', 'copy_timer', 'created_on', 'updated_on'})
|
||||
|
||||
if hosted_file_obj_in_result := sql_insert(data=hosted_file_obj_data, table_name='hosted_file', rm_id_random=True, id_random_length=8): pass
|
||||
else:
|
||||
return False
|
||||
|
||||
log.debug(hosted_file_obj_in_result)
|
||||
|
||||
hosted_file_id = hosted_file_obj_in_result
|
||||
|
||||
log.debug(f'Returning the new hosted_file_id: {hosted_file_id}')
|
||||
return hosted_file_id
|
||||
# ### END ### API Hosted File Methods ### create_hosted_file_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Hosted File Methods ### load_hosted_file_obj() ###
|
||||
# Updated 2023-08-18
|
||||
@logger_reset
|
||||
def load_hosted_file_obj(
|
||||
hosted_file_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_hosted_file_link_list: bool = False,
|
||||
) -> Hosted_File_Base|dict|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if hosted_file_id := redis_lookup_id_random(record_id_random=hosted_file_id, table_name='hosted_file'): pass
|
||||
else: return False
|
||||
|
||||
if hosted_file_rec := sql_select(table_name='v_hosted_file', record_id=hosted_file_id): pass
|
||||
elif hosted_file_rec is None: return None
|
||||
else: return False
|
||||
log.debug(hosted_file_rec)
|
||||
|
||||
try:
|
||||
hosted_file_obj = Hosted_File_Base(**hosted_file_rec)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
log.info(f'Filename: {hosted_file_obj.filename}; Size: {hosted_file_obj.size}; Hash SHA256: {hosted_file_obj.hash_sha256}; ')
|
||||
log.debug(hosted_file_obj)
|
||||
|
||||
if model_as_dict:
|
||||
return hosted_file_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset)
|
||||
else:
|
||||
return hosted_file_obj
|
||||
# ### END ### API Hosted File Methods ### load_hosted_file_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Hosted File Methods ### lookup_file_hash() ###
|
||||
# Updated 2022-08-09
|
||||
@logger_reset
|
||||
def lookup_file_hash(
|
||||
file_hash: str,
|
||||
) -> Hosted_File_Base|dict|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
|
||||
sql = f"""
|
||||
SELECT id AS 'hosted_file_id', id_random AS 'hosted_file_id_random'
|
||||
FROM hosted_file
|
||||
WHERE hosted_file.hash_sha256 = :hash_sha256
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
hosted_file_data = {}
|
||||
hosted_file_data['hash_sha256'] = file_hash
|
||||
log.debug(hosted_file_data)
|
||||
|
||||
if hosted_file_select_result := sql_select(sql=sql, data=hosted_file_data):
|
||||
hosted_file_id = hosted_file_select_result.get('hosted_file_id')
|
||||
hosted_file_id_random = hosted_file_select_result.get('hosted_file_id_random')
|
||||
log.info(f'Selected Hosted File record. Hosted File ID: {hosted_file_id}')
|
||||
return hosted_file_id
|
||||
elif hosted_file_select_result is None:
|
||||
log.warning(f'Hosted File record was not found. SHA 256 Hash: {file_hash}')
|
||||
return None
|
||||
# pass
|
||||
else:
|
||||
log.error(f'Something went wrong while trying to select the hosted file record. SHA 256 Hash: {file_hash}')
|
||||
return False
|
||||
# ### END ### API Hosted File Methods ### lookup_file_hash() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Hosted File Methods ### get_file_object_hash() ###
|
||||
# Really shouldn't this be called generate_file_obj_hash() ??? -2023-05-04
|
||||
@logger_reset
|
||||
async def get_file_object_hash(file_object:File):
|
||||
#log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# 4096 bytes is the current block size on my workstation and Linode server
|
||||
# 4096 8192 16384 32768 65536 131072 262144 524288 1048576 bytes
|
||||
block_size = 131072
|
||||
hash_value = hashlib.sha256()
|
||||
|
||||
timer_start = time.process_time()
|
||||
for chunk in iter(lambda: file_object.read(block_size), b""):
|
||||
hash_value.update(chunk)
|
||||
file_hash = hash_value.hexdigest()
|
||||
file_object.seek(0) # The file will not properly save if seek is not reset to 0.
|
||||
timer_end = time.process_time()
|
||||
elapsed_time = timer_end - timer_start
|
||||
log.debug(f'Elapsed time: {elapsed_time}')
|
||||
|
||||
return file_hash
|
||||
# ### END ### API Hosted File Methods ### get_file_object_hash() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Hosted File Methods ### guess_file_extension() ###
|
||||
def guess_file_extension(filename: str):
|
||||
return filename.rsplit('.', 1)[1].lower()
|
||||
# ### END ### API Hosted File Methods ### guess_file_extension() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Hosted File Methods ### allowed_file_extension() ###
|
||||
def allowed_file_extension(extension: str, extension_list: list):
|
||||
return extension.lower() in extension_list # app.config['ALLOWED_EXTENSIONS']
|
||||
# ### END ### API Hosted File Methods ### allowed_file_extension() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Hosted File Methods ### lookup_file_hash() ###
|
||||
# Updated 2023-09-19
|
||||
@logger_reset
|
||||
def check_for_hosted_file_hash_file(
|
||||
file_hash: str,
|
||||
sub_dir: str,
|
||||
) -> dict|bool:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
file_size = None
|
||||
|
||||
hosted_files_path = settings.FILES_PATH['hosted_files_root']
|
||||
log.info(f'Hosted Files Path: {hosted_files_path}')
|
||||
log.debug(shutil.disk_usage(hosted_files_path))
|
||||
|
||||
hosted_files_dir_w_subdir = os.path.join(hosted_files_path, sub_dir)
|
||||
path_hosted_files_dir_w_subdir = pathlib.Path(hosted_files_dir_w_subdir)
|
||||
|
||||
if path_hosted_files_dir_w_subdir.exists(): pass
|
||||
else:
|
||||
log.warning('Hashed hosted file subdirectory was not found in the hosted files root.')
|
||||
return False
|
||||
|
||||
hosted_files_dir_w_subdir_filename = os.path.join(hosted_files_path, sub_dir, f'{file_hash}.file')
|
||||
path_hosted_files_dir_w_subdir_filename = pathlib.Path(hosted_files_dir_w_subdir_filename)
|
||||
if path_hosted_files_dir_w_subdir_filename.exists():
|
||||
file_size = os.path.getsize(path_hosted_files_dir_w_subdir_filename)
|
||||
else:
|
||||
log.warning('Hashed hosted file not found in the expected hosted files subdirectory.')
|
||||
return False
|
||||
|
||||
return {'found': True, 'file_size': file_size}
|
||||
|
||||
|
||||
# ### BEGIN ### API Hosted File Methods ### save_file() ###
|
||||
# Updated 2022-08-09
|
||||
@logger_reset
|
||||
async def save_file(
|
||||
file: UploadFile,
|
||||
account_id: int,
|
||||
link_to_type: str,
|
||||
link_to_id: int,
|
||||
account_id_random: str = None,
|
||||
link_to_id_random: str = None,
|
||||
check_allowed_extension: bool = False,
|
||||
):
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
hosted_files_path = settings.FILES_PATH['hosted_files_root']
|
||||
# hosted_files_path = '/home/scott/tmp/hosted_files_dev/'
|
||||
log.info(f'Hosted Files Path: {hosted_files_path}')
|
||||
log.debug(shutil.disk_usage(hosted_files_path))
|
||||
|
||||
log.debug(dir(file))
|
||||
log.debug(f'{file.filename}')
|
||||
|
||||
if file.filename.endswith('.docwin'):
|
||||
log.warning('Fixing win extension')
|
||||
file.filename = file.filename.replace('.docwin', '.doc')
|
||||
if file.filename.endswith('.docxwin'):
|
||||
log.warning('Fixing win extension')
|
||||
file.filename = file.filename.replace('.docxwin', '.docx')
|
||||
|
||||
if file.filename.endswith('.odpmac'):
|
||||
log.warning('Fixing mac extension')
|
||||
file.filename = file.filename.replace('.odpmac', '.odp')
|
||||
|
||||
if file.filename.endswith('.odpwin'):
|
||||
log.warning('Fixing win extension')
|
||||
file.filename = file.filename.replace('.odpwin', '.odp')
|
||||
|
||||
if file.filename.endswith('.pdfmac'):
|
||||
log.warning('Fixing mac extension')
|
||||
file.filename = file.filename.replace('.pdfmac', '.pdf')
|
||||
|
||||
if file.filename.endswith('.pdfwin'):
|
||||
log.warning('Fixing win extension')
|
||||
file.filename = file.filename.replace('.pdfwin', '.pdf')
|
||||
|
||||
if file.filename.endswith('.pptmac'):
|
||||
log.warning('Fixing mac extension')
|
||||
file.filename = file.filename.replace('.pptmac', '.ppt')
|
||||
if file.filename.endswith('.pptxmac'):
|
||||
log.warning('Fixing mac extension')
|
||||
file.filename = file.filename.replace('.pptxmac', '.pptx')
|
||||
|
||||
if file.filename.endswith('.pptwin'):
|
||||
log.warning('Fixing win extension')
|
||||
file.filename = file.filename.replace('.pptwin', '.ppt')
|
||||
if file.filename.endswith('.pptxwin'):
|
||||
log.warning('Fixing win extension')
|
||||
file.filename = file.filename.replace('.pptxwin', '.pptx')
|
||||
|
||||
if file.filename.endswith('.xlswin'):
|
||||
log.warning('Fixing win extension')
|
||||
file.filename = file.filename.replace('.xlswin', '.xls')
|
||||
if file.filename.endswith('.xlsxwin'):
|
||||
log.warning('Fixing win extension')
|
||||
file.filename = file.filename.replace('.xlsxwin', '.xlsx')
|
||||
|
||||
file_info: dict = {}
|
||||
file_info['saved'] = None
|
||||
file_info['link_to_type'] = link_to_type
|
||||
file_info['link_to_id'] = link_to_id
|
||||
file_info['link_to_id_random'] = link_to_id_random
|
||||
file_info['filename'] = file.filename
|
||||
file_info['extension'] = guess_file_extension(filename=file.filename)
|
||||
|
||||
if check_allowed_extension:
|
||||
if allowed_file_extension(extension=file_info['extension'], extension_list=['jpg','png','webp']):
|
||||
file_info['extension_allowed'] = True
|
||||
else:
|
||||
file_info['extension_allowed'] = False
|
||||
file_info['saved'] = False
|
||||
return file_info
|
||||
else:
|
||||
file_info['extension_allowed'] = None
|
||||
|
||||
# There is a difference between Content-Type and MIME type.
|
||||
# https://stackoverflow.com/questions/3452381/whats-the-difference-of-contenttype-and-mimetype
|
||||
file_info['content_type'] = file.content_type # might also include charset or other parameters
|
||||
# file_info['mimetype'] = file.mimetype # This may need to be filled in a different way?
|
||||
|
||||
file.file.seek(0, os.SEEK_END)
|
||||
file_size = file.file.tell()
|
||||
file.file.seek(0) # The file will not properly save if seek is not reset to 0.
|
||||
log.debug(file_size)
|
||||
file_info['size'] = file_size
|
||||
|
||||
file_hash = await get_file_object_hash(file.file)
|
||||
log.debug(file_hash)
|
||||
file_info['hash_sha256'] = file_hash
|
||||
|
||||
# 16384 bytes is the default
|
||||
# 4096 8192 16384 32768 65536 131072 262144 524288 1048576 bytes
|
||||
buffer_size = 524288
|
||||
|
||||
#f_src = open(file_src, 'rb')
|
||||
f_src = file.file # Don't need to do open(file_src, 'rb') since it is already "open"
|
||||
|
||||
file_hash_subdirectory = file_hash[0:2]
|
||||
subdirectory_dest = os.path.join(hosted_files_path, file_hash_subdirectory)
|
||||
log.debug(subdirectory_dest)
|
||||
pathlib.Path(subdirectory_dest).mkdir(parents=True, exist_ok=True)
|
||||
file_info['subdirectory_path'] = file_hash_subdirectory
|
||||
|
||||
#file_dest = f'{hosted_files_path}{file.filename}'
|
||||
# file_dest = f'{hosted_files_path}{file_hash}.file'
|
||||
|
||||
file_dest = os.path.join(hosted_files_path, f'{file_hash}.file')
|
||||
file_dest_w_subdir = os.path.join(subdirectory_dest, f'{file_hash}.file')
|
||||
|
||||
existing_file_check = pathlib.Path(file_dest)
|
||||
existing_file_check_subdir = pathlib.Path(file_dest_w_subdir)
|
||||
|
||||
|
||||
if existing_file_check.exists():
|
||||
log.warning('This file already exists at the destination without the subdirectory. Not re-saving. Going to move the current file and update the database later.')
|
||||
file_info['already_exists'] = True
|
||||
file_info['already_exists_subdir'] = False
|
||||
try:
|
||||
log.info('Moving file to sub directory destination...')
|
||||
timer_start = time.process_time()
|
||||
shutil.move(existing_file_check, existing_file_check_subdir)
|
||||
timer_end = time.process_time()
|
||||
elapsed_time = timer_end - timer_start
|
||||
log.debug(f'Elapsed time: {elapsed_time}')
|
||||
file_info['copy_timer'] = elapsed_time
|
||||
file_info['saved'] = True
|
||||
|
||||
log.info(f'File moved to: {hosted_files_path}')
|
||||
except Exception as e:
|
||||
log.exception('*** An exception happened. ***')
|
||||
log.exception(repr(e))
|
||||
log.exception('***')
|
||||
log.exception(str(e))
|
||||
log.exception('^^^ exception ^^^')
|
||||
|
||||
file_info['copy_timer'] = 0
|
||||
file_info['saved'] = False
|
||||
elif existing_file_check_subdir.exists():
|
||||
log.warning('This file already exists at the destination with the subdirectory. Not re-saving.')
|
||||
file_info['already_exists'] = True
|
||||
file_info['already_exists_subdir'] = True
|
||||
file_info['copy_timer'] = 0
|
||||
file_info['saved'] = True
|
||||
else:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.warning('This file does not already exist at the destination with or without the subdirectory.')
|
||||
file_info['already_exists'] = False
|
||||
file_info['already_exists_subdir'] = False
|
||||
try:
|
||||
log.info('Saving file to destination...')
|
||||
f_dest = open(file_dest_w_subdir, 'wb')
|
||||
timer_start = time.process_time()
|
||||
shutil.copyfileobj(f_src, f_dest, buffer_size)
|
||||
timer_end = time.process_time()
|
||||
elapsed_time = timer_end - timer_start
|
||||
log.debug(f'Elapsed time: {elapsed_time}')
|
||||
file_info['copy_timer'] = elapsed_time
|
||||
file_info['saved'] = True
|
||||
|
||||
log.info(f'File saved to: {hosted_files_path}')
|
||||
except Exception as e:
|
||||
log.exception('*** An exception happened. ***')
|
||||
log.exception(repr(e))
|
||||
log.exception('***')
|
||||
log.exception(str(e))
|
||||
log.exception('^^^ exception ^^^')
|
||||
|
||||
file_info['copy_timer'] = 0
|
||||
file_info['saved'] = False
|
||||
return False
|
||||
log.info(f'Disk usage: {shutil.disk_usage(hosted_files_path)}')
|
||||
log.info(f"Filename: {file_info['filename']}")
|
||||
log.info(f"Subdirectory Path: {file_info['subdirectory_path']}")
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(file_info)
|
||||
|
||||
|
||||
# if existing_file_check.exists():
|
||||
# file_info['already_exists'] = True
|
||||
# file_info['copy_timer'] = 0
|
||||
# file_info['saved'] = True
|
||||
# else:
|
||||
# file_info['already_exists'] = False
|
||||
# try:
|
||||
# f_dest = open(file_dest, 'wb')
|
||||
# timer_start = time.process_time()
|
||||
# shutil.copyfileobj(f_src, f_dest, buffer_size)
|
||||
# timer_end = time.process_time()
|
||||
# elapsed_time = timer_end - timer_start
|
||||
# log.debug(f'Elapsed time: {elapsed_time}')
|
||||
# file_info['copy_timer'] = elapsed_time
|
||||
# file_info['saved'] = True
|
||||
# except Exception as e:
|
||||
# log.exception('*** An exception happened. ***')
|
||||
# log.exception(repr(e))
|
||||
# log.exception('***')
|
||||
# log.exception(str(e))
|
||||
# log.exception('^^^ exception ^^^')
|
||||
|
||||
# file_info['copy_timer'] = 0
|
||||
# file_info['saved'] = False
|
||||
|
||||
|
||||
log.debug(shutil.disk_usage(hosted_files_path))
|
||||
|
||||
return file_info
|
||||
# ### END ### API Hosted File Methods ### save_file() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Hosted File Methods ### save_file_to_hosted_file() ###
|
||||
# Updated 2022-08-09
|
||||
@logger_reset
|
||||
async def save_file_to_hosted_file(
|
||||
file_path: str,
|
||||
filename: str,
|
||||
extension: str,
|
||||
account_id: int,
|
||||
link_to_type: str,
|
||||
link_to_id: int,
|
||||
):
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
hosted_files_path = settings.FILES_PATH['hosted_files_root']
|
||||
log.info(f'Hosted Files Path: {hosted_files_path}')
|
||||
log.debug(shutil.disk_usage(hosted_files_path))
|
||||
|
||||
log.debug(file_path)
|
||||
log.debug(f'Filename: {filename} Extension: {extension}')
|
||||
|
||||
file_obj = open(file_path, 'rb')
|
||||
|
||||
|
||||
file_info: dict = {}
|
||||
file_info['saved'] = None
|
||||
file_info['link_to_type'] = link_to_type
|
||||
file_info['link_to_id'] = link_to_id
|
||||
file_info['filename'] = filename
|
||||
file_info['extension'] = extension # guess_file_extension(filename=filename)
|
||||
|
||||
# if check_allowed_extension:
|
||||
# if allowed_file_extension(extension=file_info['extension'], extension_list=['jpg','png','webp']):
|
||||
# file_info['extension_allowed'] = True
|
||||
# else:
|
||||
# file_info['extension_allowed'] = False
|
||||
# file_info['saved'] = False
|
||||
# return file_info
|
||||
# else:
|
||||
# file_info['extension_allowed'] = None
|
||||
|
||||
# There is a difference between Content-Type and MIME type.
|
||||
# https://stackoverflow.com/questions/3452381/whats-the-difference-of-contenttype-and-mimetype
|
||||
file_info['content_type'] = mimetypes.guess_type(filename)[0]
|
||||
|
||||
file_obj.seek(0, os.SEEK_END)
|
||||
file_size = file_obj.tell()
|
||||
file_obj.seek(0) # The file will not properly save if seek is not reset to 0.
|
||||
log.debug(file_size)
|
||||
file_info['size'] = file_size
|
||||
|
||||
file_hash = await get_file_object_hash(file_obj)
|
||||
log.debug(file_hash)
|
||||
file_info['hash_sha256'] = file_hash
|
||||
|
||||
# 16384 bytes is the default
|
||||
# 4096 8192 16384 32768 65536 131072 262144 524288 1048576 bytes
|
||||
buffer_size = 524288
|
||||
|
||||
#f_src = open(file_src, 'rb')
|
||||
f_src = file_obj # Don't need to do open(file_src, 'rb') since it is already "open"
|
||||
|
||||
file_hash_subdirectory = file_hash[0:2]
|
||||
subdirectory_dest = os.path.join(hosted_files_path, file_hash_subdirectory)
|
||||
log.debug(subdirectory_dest)
|
||||
pathlib.Path(subdirectory_dest).mkdir(parents=True, exist_ok=True)
|
||||
file_info['subdirectory_path'] = file_hash_subdirectory
|
||||
|
||||
#file_dest = f'{hosted_files_path}{file.filename}'
|
||||
# file_dest = f'{hosted_files_path}{file_hash}.file'
|
||||
|
||||
file_dest = os.path.join(hosted_files_path, f'{file_hash}.file')
|
||||
file_dest_w_subdir = os.path.join(subdirectory_dest, f'{file_hash}.file')
|
||||
|
||||
existing_file_check = pathlib.Path(file_dest)
|
||||
existing_file_check_subdir = pathlib.Path(file_dest_w_subdir)
|
||||
|
||||
log.debug(existing_file_check_subdir)
|
||||
# return file_info
|
||||
|
||||
|
||||
if existing_file_check_subdir.exists():
|
||||
log.warning('This file already exists at the destination with the subdirectory. Not re-saving.')
|
||||
file_info['already_exists'] = True
|
||||
file_info['already_exists_subdir'] = True
|
||||
file_info['copy_timer'] = 0
|
||||
file_info['saved'] = True
|
||||
else:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.warning('This file does not already exist at the destination subdirectory.')
|
||||
file_info['already_exists'] = False
|
||||
file_info['already_exists_subdir'] = False
|
||||
try:
|
||||
log.info('Saving file to destination...')
|
||||
f_dest = open(file_dest_w_subdir, 'wb')
|
||||
timer_start = time.process_time()
|
||||
shutil.copyfileobj(f_src, f_dest, buffer_size)
|
||||
timer_end = time.process_time()
|
||||
elapsed_time = timer_end - timer_start
|
||||
log.debug(f'Elapsed time: {elapsed_time}')
|
||||
file_info['copy_timer'] = elapsed_time
|
||||
file_info['saved'] = True
|
||||
|
||||
log.info(f'File saved to: {hosted_files_path}')
|
||||
except Exception as e:
|
||||
log.exception('*** An exception happened. ***')
|
||||
log.exception(repr(e))
|
||||
log.exception('***')
|
||||
log.exception(str(e))
|
||||
log.exception('^^^ exception ^^^')
|
||||
|
||||
file_info['copy_timer'] = 0
|
||||
file_info['saved'] = False
|
||||
return False
|
||||
log.info(f'Disk usage: {shutil.disk_usage(hosted_files_path)}')
|
||||
log.info(f"Filename: {file_info['filename']}")
|
||||
log.info(f"Subdirectory Path: {file_info['subdirectory_path']}")
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(file_info)
|
||||
|
||||
log.debug(shutil.disk_usage(hosted_files_path))
|
||||
|
||||
return file_info
|
||||
# ### END ### API Hosted File Methods ### save_file_to_hosted_file() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Hosted File Methods ### create_hosted_file_link() ###
|
||||
# Updated 2022-08-09
|
||||
@logger_reset
|
||||
def create_hosted_file_link(
|
||||
account_id: int|str,
|
||||
hosted_file_id: int|str,
|
||||
link_to_type: str,
|
||||
link_to_id: int|str,
|
||||
):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
if hosted_file_id := redis_lookup_id_random(record_id_random=hosted_file_id, table_name='hosted_file'): pass
|
||||
else: return False
|
||||
if link_to_id := redis_lookup_id_random(record_id_random=link_to_id, table_name=link_to_type): pass
|
||||
else: return False
|
||||
|
||||
hosted_file_link_data: dict = {}
|
||||
hosted_file_link_data['account_id'] = account_id
|
||||
hosted_file_link_data['hosted_file_id'] = hosted_file_id
|
||||
hosted_file_link_data['link_to_type'] = link_to_type # Should this be renamed to "link_to_type" for clarity?
|
||||
hosted_file_link_data['link_to_id'] = link_to_id # Should this be renamed to "link_to_id" for clarity?
|
||||
|
||||
# hosted_file_link_data['test'] = 'test'
|
||||
|
||||
# NOTE: Currently sql_insert does not handle all successful inserts correctly. If there is not an autonum ID then it will return 0 as the ID.
|
||||
if hosted_file_link_data_in_result := sql_insert(data=hosted_file_link_data, table_name='hosted_file_link', id_random_length=0):
|
||||
log.info('The hosted_file_link was created.')
|
||||
pass # This should be improved
|
||||
elif hosted_file_link_data_in_result is None:
|
||||
log.info('The hosted_file_link probably already exists.')
|
||||
return None
|
||||
else:
|
||||
# This should be improved
|
||||
log.warning('Because the hosted_file_link table does not have a primary autonum this check is incorrect even when successful.')
|
||||
log.warning('Something may have gone wrong while trying to create the hosted_file_link record.')
|
||||
log.warning('The hosted_file_link was probably created fine though.')
|
||||
return False
|
||||
|
||||
log.debug(hosted_file_link_data_in_result)
|
||||
return True
|
||||
# ### END ### API Hosted File Methods ### create_hosted_file_link() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Hosted File Methods ### handle_delete_hosted_file() ###
|
||||
# Updated 2022-08-09
|
||||
@logger_reset
|
||||
def handle_delete_hosted_file(
|
||||
account_id: int|str,
|
||||
hosted_file_id: int|str,
|
||||
|
||||
link_to_type: str = None,
|
||||
link_to_id: int|str = None,
|
||||
|
||||
rm_all_links: bool = False,
|
||||
rm_orphan: bool = False,
|
||||
):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
|
||||
if hosted_file_id := redis_lookup_id_random(record_id_random=hosted_file_id, table_name='hosted_file'): pass
|
||||
else: return False
|
||||
|
||||
# ### SECTION ### Handle links NOTE NOTE NOTE NOTE NOTE NOTE
|
||||
# NOTE: If link_to_type and link_to_id passed then try and remove that link record first.
|
||||
|
||||
if link_to_type and link_to_id:
|
||||
if hosted_file_link_result := delete_hosted_file_link(
|
||||
account_id = account_id,
|
||||
hosted_file_id = hosted_file_id,
|
||||
|
||||
link_to_type = link_to_type,
|
||||
link_to_id = link_to_id,
|
||||
|
||||
# rm_orphan = rm_orphan,
|
||||
):
|
||||
log.info('The hosted file link record was deleted.')
|
||||
elif hosted_file_link_result is None:
|
||||
log.warning('The hosted file link record was not found and may have already been deleted. Odd, but this can happen. event_file has a trigger to delete hosted_file_link when being deleted.')
|
||||
# return None
|
||||
else:
|
||||
log.error('Something went wrong while trying to delete the hosted file link record.')
|
||||
return False
|
||||
|
||||
# ### SECTION ### Handle orphan check and deletion of hosted_file record and file on server NOTE NOTE NOTE NOTE NOTE NOTE
|
||||
# NOTE: If not rm_orphan then do nothing else.
|
||||
# NOTE: If rm_orphan then get list of links for file.
|
||||
# NOTE: If 0 links result then delete the hosted_file record and file on the server.
|
||||
# NOTE: If >0 links result then do nothing else.
|
||||
|
||||
# NOTE: Don't check or remove orphan
|
||||
if not rm_orphan:
|
||||
log.info('Removed hosted file link. No orphan check.')
|
||||
return True
|
||||
|
||||
if hosted_file_obj := load_hosted_file_obj(
|
||||
hosted_file_id = hosted_file_id,
|
||||
# inc_hosted_file = True,
|
||||
inc_hosted_file_link_list = True, # if rm_orphan (True) then need to include hosted_file_link_list (True)
|
||||
):
|
||||
log.info('Hosted File object loaded.')
|
||||
pass
|
||||
elif hosted_file_obj is None:
|
||||
log.warning('Hosted File object not found. Can not attempt to delete file from the server if there is one.')
|
||||
# pass
|
||||
return None
|
||||
else:
|
||||
log.error('Something went wrong while trying to load the Hosted File object.')
|
||||
return False
|
||||
log.debug(hosted_file_obj)
|
||||
|
||||
# NOTE: Check and remove orphan
|
||||
if hosted_file_link_rec_list_result := get_hosted_file_link_rec_list(hosted_file_id=hosted_file_id):
|
||||
log.info('This hosted file has linked records to it.')
|
||||
hosted_file_link_result_list = []
|
||||
for hosted_file_link_rec in hosted_file_link_rec_list_result:
|
||||
hosted_file_link_result_list.append(hosted_file_link_rec)
|
||||
# log.debug( )
|
||||
hosted_file_list = hosted_file_link_result_list
|
||||
# NOT safe to delete the hosted_file record and file from server!!!
|
||||
# STOP!
|
||||
log.info('Removed hosted file link (above). Still not an orphan file.')
|
||||
return True
|
||||
elif isinstance(hosted_file_link_rec_list_result, list) or hosted_file_link_rec_list_result is None:
|
||||
log.info('This hosted file has no link records to it.')
|
||||
hosted_file_list = []
|
||||
# Safe to delete the hosted_file record and file from server???
|
||||
# CONTINUE
|
||||
else:
|
||||
hosted_file_list = False
|
||||
# Safe to delete the hosted_file record and file from server???
|
||||
# CONTINUE???
|
||||
log.error('Something went wrong while trying to get a list of the hosted file link records.')
|
||||
return False
|
||||
|
||||
# ### Orphan file: ### Delete file from server
|
||||
hosted_files_path = settings.FILES_PATH['hosted_files_root']
|
||||
# hosted_files_path = '/home/scott/tmp/hosted_files_dev/'
|
||||
log.info(f'Hosted Files Path: {hosted_files_path}')
|
||||
|
||||
# dir_path = hosted_file_obj.directory_path
|
||||
subdir_path = hosted_file_obj.subdirectory_path
|
||||
hash_sha256 = hosted_file_obj.hash_sha256
|
||||
hash_filename = hash_sha256+'.file'
|
||||
|
||||
if subdir_path:
|
||||
full_subdirectory_path = os.path.join(hosted_files_path, subdir_path)
|
||||
else:
|
||||
full_subdirectory_path = hosted_files_path
|
||||
log.debug(full_subdirectory_path)
|
||||
file_path_w_subdir = os.path.join(full_subdirectory_path, hash_filename)
|
||||
log.info(f'Full file path with subdirectory: {file_path_w_subdir}')
|
||||
|
||||
if os.path.exists(file_path_w_subdir):
|
||||
log.info('File exists!')
|
||||
log.info('Going remove the file if it is an orphan...')
|
||||
try:
|
||||
pathlib.Path(file_path_w_subdir).unlink()
|
||||
except OSError as e:
|
||||
log.error("Error: %s : %s" % (file_path, e.strerror))
|
||||
return False
|
||||
pass
|
||||
# return True
|
||||
else:
|
||||
log.warning(f'The hosted file was not found on the server. Hash: {hash_sha256}')
|
||||
pass
|
||||
# return None
|
||||
|
||||
# ### Orphan file: ### Delete hosted_file record
|
||||
sql = f"""
|
||||
DELETE FROM hosted_file
|
||||
WHERE hosted_file.id = :hosted_file_id
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
hosted_file_data = {}
|
||||
hosted_file_data['hosted_file_id'] = hosted_file_id
|
||||
log.debug(hosted_file_data)
|
||||
|
||||
if hosted_file_delete_result := sql_delete(sql=sql, data=hosted_file_data):
|
||||
log.info(f'Deleted Hosted File record. Hosted File ID: {hosted_file_id}')
|
||||
return True
|
||||
elif hosted_file_delete_result is None:
|
||||
log.warning(f'Hosted File record was not found and may have already been removed. Hosted File ID: {hosted_file_id}')
|
||||
return None
|
||||
# pass
|
||||
else:
|
||||
log.error('Something went wrong while trying to delete the hosted file record.')
|
||||
return False
|
||||
# ### END ### API Hosted File Methods ### handle_delete_hosted_file() ###
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Hosted File Methods ### delete_hosted_file_link() ###
|
||||
# Updated 2022-08-09
|
||||
@logger_reset
|
||||
def delete_hosted_file_link(
|
||||
account_id: int|str,
|
||||
hosted_file_id: int|str,
|
||||
|
||||
link_to_type: str,
|
||||
link_to_id: int|str,
|
||||
|
||||
# rm_orphan: bool = False,
|
||||
):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
# else: return False
|
||||
|
||||
if hosted_file_id := redis_lookup_id_random(record_id_random=hosted_file_id, table_name='hosted_file'): pass
|
||||
else: return False
|
||||
|
||||
if link_to_id := redis_lookup_id_random(record_id_random=link_to_id, table_name=link_to_type): pass
|
||||
else: return False
|
||||
|
||||
sql = f"""
|
||||
DELETE FROM hosted_file_link
|
||||
WHERE hosted_file_id = :hosted_file_id
|
||||
AND link_to_type = :link_to_type
|
||||
AND link_to_id = :link_to_id
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
hosted_file_link_data = {}
|
||||
hosted_file_link_data['hosted_file_id'] = hosted_file_id
|
||||
hosted_file_link_data['link_to_type'] = link_to_type
|
||||
hosted_file_link_data['link_to_id'] = link_to_id
|
||||
log.debug(hosted_file_link_data)
|
||||
|
||||
if hosted_file_delete_result := sql_delete(sql=sql, data=hosted_file_link_data):
|
||||
log.info(f'Deleted Hosted File Link. Hosted File ID: {hosted_file_id}, Link To Type: {link_to_type}, Link To ID: {link_to_id}')
|
||||
elif hosted_file_delete_result is None:
|
||||
return None
|
||||
else:
|
||||
return False
|
||||
|
||||
return True
|
||||
# ### END ### API Hosted File Methods ### delete_hosted_file_link() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Hosted File Methods ### get_hosted_file_rec_list() ###
|
||||
# This needs to be improved. Currently it does not really do anything.
|
||||
# Need to allow for list by account? Probably have the same actual hosted file have two hosted_file entries if it was uploaded for two separate accounts.
|
||||
# Updated 2022-09-22
|
||||
@logger_reset
|
||||
def get_hosted_file_rec_list(
|
||||
for_obj_type: str,
|
||||
for_obj_id: str,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
else: return False
|
||||
data = {}
|
||||
data[f'{for_obj_type}_id'] = for_obj_id
|
||||
# data['for_obj_type'] = for_obj_type
|
||||
sql_obj_type_id = f'`tbl`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `hosted_file`.id AS 'hosted_file_id', `hosted_file`.id_random AS 'hosted_file_id_random'
|
||||
FROM `hosted_file` AS `hosted_file`
|
||||
WHERE
|
||||
{sql_obj_type_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `hosted_file`.created_on DESC, `hosted_file`.updated_on DESC, `hosted_file`.filename ASC, `hosted_file`.extension ASC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
# NOTE: Use the ORDER BY below if priority and sort fields are added to the hosted_file table.
|
||||
# /* ORDER BY `hosted_file`.priority DESC, -`hosted_file`.sort DESC, `hosted_file`.created_on DESC, `hosted_file`.updated_on DESC, `hosted_file`.filename ASC, `hosted_file`.extension ASC */
|
||||
|
||||
if hosted_file_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
hosted_file_rec_li = hosted_file_rec_li_result
|
||||
else:
|
||||
hosted_file_rec_li = []
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(hosted_file_rec_li_result)
|
||||
|
||||
return hosted_file_rec_li
|
||||
# ### END ### API Hosted File Methods ### get_hosted_file_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Hosted File Methods ### get_hosted_file_link_rec_list() ###
|
||||
# Updated 2022-08-09
|
||||
@logger_reset
|
||||
def get_hosted_file_link_rec_list(
|
||||
hosted_file_id: int|str,
|
||||
|
||||
link_to_type: str = None,
|
||||
link_to_id: int|str = None,
|
||||
|
||||
limit: int = 10,
|
||||
offset: int = 0,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
data = {'hosted_file_id': hosted_file_id}
|
||||
|
||||
# sql_enabled, data['enable'] = sql_enable_part(table_name='hosted_file', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
sql = f"""
|
||||
SELECT *
|
||||
FROM `hosted_file_link` AS `hosted_file_link`
|
||||
WHERE
|
||||
`hosted_file_link`.hosted_file_id = :hosted_file_id
|
||||
ORDER BY `hosted_file_link`.created_on DESC, `hosted_file_link`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if hosted_file_link_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
hosted_file_link_rec_li = hosted_file_link_rec_li_result
|
||||
else:
|
||||
hosted_file_link_rec_li = []
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(hosted_file_link_rec_li_result)
|
||||
|
||||
return hosted_file_link_rec_li
|
||||
# ### END ### API Hosted File Methods ### get_hosted_file_link_rec_list() ###
|
||||
151
app/methods/journal_entry_methods.py
Normal file
151
app/methods/journal_entry_methods.py
Normal file
@@ -0,0 +1,151 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging
|
||||
|
||||
from app.models.journal_entry_models import Journal_Entry_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Journal Entry Methods ### create_journal_entry_obj() ###
|
||||
def create_journal_entry_obj(journal_entry_obj_new:Journal_Entry_Base) -> bool|int:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
journal_entry_obj_data = journal_entry_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'created_on', 'updated_on'})
|
||||
|
||||
if journal_entry_obj_in_result := sql_insert(
|
||||
data=journal_entry_obj_data,
|
||||
table_name='journal_entry',
|
||||
rm_id_random=True,
|
||||
id_random_length=8
|
||||
): pass
|
||||
else: return False
|
||||
|
||||
log.debug(journal_entry_obj_in_result)
|
||||
|
||||
journal_entry_id = journal_entry_obj_in_result
|
||||
|
||||
log.debug(f'New journal_entry_id: {journal_entry_id}')
|
||||
return journal_entry_id
|
||||
# ### END ### API Journal Entry Methods ### create_journal_entry_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Journal Entry Methods ### load_journal_entry_obj() ###
|
||||
def load_journal_entry_obj(
|
||||
journal_entry_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
# enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> Journal_Entry_Base|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if journal_entry_id := redis_lookup_id_random(record_id_random=journal_entry_id, table_name='journal_entry'): pass
|
||||
else: return False
|
||||
log.debug(journal_entry_id)
|
||||
|
||||
if journal_entry_rec := sql_select(table_name='v_journal_entry', record_id=journal_entry_id):
|
||||
log.debug(journal_entry_rec)
|
||||
else: return False
|
||||
log.debug(journal_entry_rec)
|
||||
|
||||
try:
|
||||
journal_entry_obj = Journal_Entry_Base(**journal_entry_rec)
|
||||
log.debug(journal_entry_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
if model_as_dict:
|
||||
return journal_entry_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return journal_entry_obj
|
||||
# ### END ### API Journal Entry Methods ### load_journal_entry_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Journal Entry Methods ### update_journal_entry_obj() ###
|
||||
def update_journal_entry_obj(
|
||||
journal_entry_id: int|str, # This allows for updating of the id_random value.
|
||||
journal_entry_obj_up: Journal_Entry_Base,
|
||||
create_sub_obj: bool = False,
|
||||
) -> bool:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if journal_entry_id := redis_lookup_id_random(record_id_random=journal_entry_id, table_name='journal_entry'): pass
|
||||
else: return False
|
||||
|
||||
journal_entry_obj_up.id = journal_entry_id
|
||||
|
||||
log.debug(journal_entry_obj_up)
|
||||
log.debug(journal_entry_obj_up.dict(by_alias=False, exclude_unset=True))
|
||||
# log.debug(journal_entry_obj_up.dict(by_alias=False, exclude_unset=False))
|
||||
|
||||
journal_dict_up = journal_entry_obj_up.dict(by_alias=False, exclude_unset=True)
|
||||
log.debug(journal_dict_up)
|
||||
|
||||
if journal_entry_obj_up_result := sql_update(data=journal_dict_up, table_name='journal_entry', rm_id_random=True):
|
||||
log.debug(journal_entry_obj_up_result)
|
||||
return True
|
||||
else:
|
||||
log.debug(journal_entry_obj_up_result)
|
||||
return False
|
||||
# ### END ### API Journal Entry Methods ### update_journal_entry_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Journal Entry Methods ### get_journal_entry_rec_list() ###
|
||||
def get_journal_entry_rec_list(
|
||||
journal_id: str,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if journal_id := redis_lookup_id_random(record_id_random=journal_id, table_name='journal'): pass
|
||||
else: return False
|
||||
data = {}
|
||||
data['journal_id'] = journal_id
|
||||
|
||||
sql_journal_id = f'`tbl`.journal_id = :journal_id'
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `tbl`.id AS 'journal_entry_id', `tbl`.id_random AS 'journal_entry_id_random'
|
||||
FROM `journal_entry` AS `tbl`
|
||||
WHERE
|
||||
{sql_journal_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if journal_entry_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
journal_entry_rec_li = journal_entry_rec_li_result
|
||||
else:
|
||||
journal_entry_rec_li = []
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(journal_entry_rec_li_result)
|
||||
|
||||
return journal_entry_rec_li
|
||||
# ### END ### API Journal Entry Methods ### get_journal_entry_rec_list() ###
|
||||
184
app/methods/journal_methods.py
Normal file
184
app/methods/journal_methods.py
Normal file
@@ -0,0 +1,184 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging
|
||||
|
||||
# from app.methods.person_methods import load_person_obj
|
||||
from app.methods.journal_entry_methods import get_journal_entry_rec_list, load_journal_entry_obj
|
||||
# from app.methods.user_methods import load_user_obj
|
||||
|
||||
from app.models.journal_models import Journal_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Journal Methods ### create_journal_obj() ###
|
||||
def create_journal_obj(journal_obj_new:Journal_Base):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if not journal_obj_new:
|
||||
return False
|
||||
|
||||
journal_obj_data = journal_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'user', 'created_on', 'updated_on'})
|
||||
|
||||
if journal_obj_in_result := sql_insert(
|
||||
data=journal_obj_data,
|
||||
table_name='journal',
|
||||
rm_id_random=True,
|
||||
id_random_length=8
|
||||
): pass
|
||||
else: return False
|
||||
|
||||
log.debug(journal_obj_in_result)
|
||||
|
||||
journal_id = journal_obj_in_result
|
||||
|
||||
log.debug(f'New journal_id: {journal_entry_id}')
|
||||
return journal_id
|
||||
# ### END ### API Journal Methods ### create_journal_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Journal Methods ### load_journal_obj() ###
|
||||
def load_journal_obj(
|
||||
journal_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_journal_entry_list: bool = False,
|
||||
inc_person: bool = False,
|
||||
inc_user: bool = False,
|
||||
) -> Journal_Base|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if journal_id := redis_lookup_id_random(record_id_random=journal_id, table_name='journal'): pass
|
||||
else: return False
|
||||
|
||||
if journal_rec := sql_select(table_name='v_journal', record_id=journal_id):
|
||||
log.debug(journal_rec)
|
||||
else: return False
|
||||
|
||||
log.debug(journal_rec)
|
||||
|
||||
try:
|
||||
journal_obj = Journal_Base(**journal_rec)
|
||||
log.debug(journal_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
# Updated 2021-06-18
|
||||
if inc_journal_entry_list:
|
||||
if journal_entry_rec_list_result := get_journal_entry_rec_list(
|
||||
journal_id = journal_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
journal_entry_result_list = []
|
||||
for journal_entry_rec in journal_entry_rec_list_result:
|
||||
journal_entry_result_list.append(
|
||||
load_journal_entry_obj(
|
||||
journal_entry_id = journal_entry_rec.get('journal_entry_id', None),
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
)
|
||||
)
|
||||
journal_obj.journal_entry_list = journal_entry_result_list
|
||||
else: journal_obj.journal_entry_list = []
|
||||
|
||||
if model_as_dict:
|
||||
return journal_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return journal_obj
|
||||
# ### END ### API Journal Methods ### load_journal_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Journal Methods ### update_journal_obj() ###
|
||||
def update_journal_obj(
|
||||
journal_id: int|str, # This allows for updating of the id_random value.
|
||||
journal_obj_up: Journal_Base,
|
||||
create_sub_obj: bool = False,
|
||||
) -> bool:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if journal_id := redis_lookup_id_random(record_id_random=journal_id, table_name='journal'): pass
|
||||
else: return False
|
||||
|
||||
journal_obj_up.id = journal_id
|
||||
|
||||
log.debug(journal_obj_up)
|
||||
log.debug(journal_obj_up.dict(by_alias=False, exclude_unset=True))
|
||||
# log.debug(journal_obj_up.dict(by_alias=False, exclude_unset=False))
|
||||
|
||||
journal_dict_up = journal_obj_up.dict(by_alias=False, exclude_unset=True, exclude={'user'})
|
||||
log.debug(journal_dict_up)
|
||||
|
||||
if journal_obj_up_result := sql_update(data=journal_dict_up, table_name='journal', rm_id_random=True):
|
||||
log.debug(journal_obj_up_result)
|
||||
return True
|
||||
else:
|
||||
log.debug(journal_obj_up_result)
|
||||
return False
|
||||
# ### END ### API Journal Methods ### update_journal_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Journal Methods ### get_journal_rec_list() ###
|
||||
def get_journal_rec_list(
|
||||
for_obj_type: str,
|
||||
for_obj_id: str,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
else: return False
|
||||
data = {}
|
||||
data[f'{for_obj_type}_id'] = for_obj_id
|
||||
# data['for_obj_type'] = for_obj_type
|
||||
sql_obj_type_id = f'`tbl`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `tbl`.id AS 'journal_id', `tbl`.id_random AS 'journal_id_random'
|
||||
FROM `journal` AS `tbl`
|
||||
WHERE
|
||||
{sql_obj_type_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if journal_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
journal_rec_li = journal_rec_li_result
|
||||
else:
|
||||
journal_rec_li = []
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(journal_rec_li_result)
|
||||
|
||||
return journal_rec_li
|
||||
# ### END ### API Journal Methods ### get_journal_rec_list() ###
|
||||
97
app/methods/log_client_viewing_methods.py
Normal file
97
app/methods/log_client_viewing_methods.py
Normal file
@@ -0,0 +1,97 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_insert_or_update, sql_select, sql_update
|
||||
from app.lib_general import log, logging
|
||||
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
from app.models.log_client_viewing_models import Log_Client_Viewing_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Log Client Viewing Methods ### load_log_client_viewing_obj() ###
|
||||
def load_log_client_viewing_obj(
|
||||
log_client_viewing_id: int|str,
|
||||
limit: int = 10000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
) -> Log_Client_Viewing_Base|bool:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if log_client_viewing_id := redis_lookup_id_random(record_id_random=log_client_viewing_id, table_name='log_client_viewing'): pass
|
||||
else: return False
|
||||
|
||||
if log_client_viewing_rec := sql_select(table_name='v_log_client_viewing', record_id=log_client_viewing_id): pass
|
||||
else: return False
|
||||
|
||||
try:
|
||||
log_client_viewing_obj = Log_Client_Viewing_Base(**log_client_viewing_rec)
|
||||
log.debug(log_client_viewing_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
if model_as_dict:
|
||||
return log_client_viewing_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return log_client_viewing_obj
|
||||
# ### END ### API Log Client Viewing Methods ### load_log_client_viewing_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Log Client Viewing Methods ### get_log_client_viewing_rec_list() ###
|
||||
def get_log_client_viewing_rec_list(
|
||||
account_id: str,
|
||||
from_datetime: datetime.datetime = None,
|
||||
to_datetime: datetime.datetime = None,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
data = {}
|
||||
data['account_id'] = account_id
|
||||
sql_account_id = f'`tbl`.account_id = :account_id'
|
||||
|
||||
# if enabled in ['enabled', 'disabled', 'all']:
|
||||
# if enabled == 'enabled':
|
||||
# data['enable'] = True
|
||||
# sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
# elif enabled == 'disabled':
|
||||
# data['enable'] = False
|
||||
# sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
# elif enabled == 'all':
|
||||
# sql_enabled = ''
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `tbl`.id AS 'log_client_viewing_id', `tbl`.id_random AS 'log_client_viewing_id_random'
|
||||
FROM `log_client_viewing` AS `tbl`
|
||||
WHERE
|
||||
{sql_account_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if log_client_viewing_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
log_client_viewing_rec_li = log_client_viewing_rec_li_result
|
||||
else:
|
||||
log_client_viewing_rec_li = []
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(log_client_viewing_rec_li_result)
|
||||
|
||||
return log_client_viewing_rec_li
|
||||
# ### END ### API Log Client Viewing Methods ### get_log_client_viewing_rec_list() ###
|
||||
92
app/methods/lu_post_topic_methods.py
Normal file
92
app/methods/lu_post_topic_methods.py
Normal file
@@ -0,0 +1,92 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging
|
||||
|
||||
|
||||
# ### BEGIN ### API Lookup Post Topic Methods ### load_post_topic() ###
|
||||
# def load_lu_post_topic_obj(
|
||||
# lu_post_topic_id: int|str,
|
||||
# limit: int = 1000,
|
||||
# by_alias: bool = True,
|
||||
# exclude_unset: bool = True,
|
||||
# model_as_dict: bool = False,
|
||||
# enabled: str = 'enabled', # enabled, disabled, all
|
||||
# ) -> Post_Base|bool:
|
||||
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(locals())
|
||||
|
||||
# if post_id := redis_lookup_id_random(record_id_random=post_id, table_name='post'): pass
|
||||
# else: return False
|
||||
|
||||
# if model_as_dict:
|
||||
# return post_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
# else:
|
||||
# return post_obj
|
||||
# ### END ### API Post Methods ### load_post_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Lookup Post Topic Methods ### get_lu_post_topic_rec_list() ###
|
||||
def get_lu_post_topic_rec_list(
|
||||
account_id: str,
|
||||
for_type: str,
|
||||
inc_admin_options: bool = False,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
data = {}
|
||||
|
||||
if account_id:
|
||||
data['account_id'] = account_id
|
||||
sql_account_id = f'`lu_post_topic`.account_id = :account_id'
|
||||
else:
|
||||
sql_account_id = ''
|
||||
|
||||
if for_type:
|
||||
data['for_type'] = for_type
|
||||
sql_for_type = f'AND `lu_post_topic`.for_type = :for_type'
|
||||
else:
|
||||
sql_for_type = ''
|
||||
|
||||
if inc_admin_options:
|
||||
data['admin_option'] = [0, 1]
|
||||
sql_admin_option = f'AND `lu_post_topic`.admin_option IN :admin_option'
|
||||
else:
|
||||
data['admin_option'] = [0]
|
||||
sql_admin_option = f'AND `lu_post_topic`.admin_option IN :admin_option'
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT * /*`lu_post_topic`.id AS 'lu_post_topic_id'*/
|
||||
FROM `lu_post_topic` AS `lu_post_topic`
|
||||
WHERE
|
||||
{sql_account_id}
|
||||
{sql_for_type}
|
||||
{sql_admin_option}
|
||||
ORDER BY -`lu_post_topic`.sort DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if lu_post_topic_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
lu_post_topic_rec_li = lu_post_topic_rec_li_result
|
||||
else:
|
||||
lu_post_topic_rec_li = []
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(lu_post_topic_rec_li_result)
|
||||
|
||||
return lu_post_topic_rec_li
|
||||
# ### END ### API Lookup Post Topic Methods ### get_lu_post_topic_rec_list() ###
|
||||
49
app/methods/membership_cfg_methods.py
Normal file
49
app/methods/membership_cfg_methods.py
Normal file
@@ -0,0 +1,49 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_select
|
||||
from app.lib_general import log, logging
|
||||
|
||||
from app.models.membership_cfg_models import Membership_Cfg_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Cfg Methods ### load_membership_cfg_obj() ###
|
||||
# Updated 2021-06-23
|
||||
def load_membership_cfg_obj(
|
||||
account_id: int|str,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
) -> Membership_Cfg_Base|dict|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
|
||||
if membership_cfg_rec := sql_select(
|
||||
table_name = 'v_membership_cfg',
|
||||
field_name = 'account_id',
|
||||
field_value = account_id,
|
||||
): pass
|
||||
else: return False
|
||||
# log.debug(membership_cfg_rec)
|
||||
log.debug(type(membership_cfg_rec['extended_membership_person_profile']))
|
||||
log.debug(membership_cfg_rec['extended_membership_person_profile'])
|
||||
membership_cfg_rec['extended_membership_person_profile'] = str(membership_cfg_rec['extended_membership_person_profile'], )
|
||||
|
||||
try:
|
||||
membership_cfg_obj = Membership_Cfg_Base(**membership_cfg_rec)
|
||||
log.debug(membership_cfg_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
if model_as_dict:
|
||||
return membership_cfg_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return membership_cfg_obj
|
||||
# ### END ### API Membership Cfg Methods ### load_membership_cfg_obj() ###
|
||||
289
app/methods/membership_group_methods.py
Normal file
289
app/methods/membership_group_methods.py
Normal file
@@ -0,0 +1,289 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging
|
||||
|
||||
from app.methods.membership_cfg_methods import load_membership_cfg_obj
|
||||
from app.methods.membership_person_group_methods import get_membership_person_group_rec_list, load_membership_person_group_obj
|
||||
from app.methods.product_methods import get_product_rec_list, load_product_obj
|
||||
|
||||
from app.models.membership_group_models import Membership_Group_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Group Methods ### load_membership_group_obj() ###
|
||||
# Updated 2021-07-01
|
||||
def load_membership_group_obj(
|
||||
membership_group_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_address: bool = False,
|
||||
inc_contact: bool = False,
|
||||
inc_membership_cfg: bool = False,
|
||||
inc_membership_person_group_list: bool = False, # List of members that are a part of this group
|
||||
inc_membership_person: bool = False,
|
||||
inc_membership_person_profile: bool = False, # under membership_person
|
||||
# inc_membership_type_list: bool = False, # ???
|
||||
inc_organization: bool = False,
|
||||
inc_parent_membership_group: bool = False,
|
||||
inc_person: bool = False,
|
||||
inc_product: bool = False, # Per membership member
|
||||
inc_product_list: bool = False, # List of products that give access to this group
|
||||
inc_user: bool = False,
|
||||
) -> Membership_Group_Base|bool:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if membership_group_id := redis_lookup_id_random(record_id_random=membership_group_id, table_name='membership_group'): pass
|
||||
else: return False
|
||||
log.debug(membership_group_id)
|
||||
|
||||
if membership_group_rec := sql_select(table_name='v_membership_group', record_id=membership_group_id):
|
||||
log.debug(membership_group_rec)
|
||||
else: return False
|
||||
log.debug(membership_group_rec)
|
||||
|
||||
try:
|
||||
membership_group_obj = Membership_Group_Base(**membership_group_rec)
|
||||
log.debug(membership_group_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
# Updated 2021-06-24
|
||||
if inc_membership_cfg:
|
||||
if membership_cfg_obj_result := load_membership_cfg_obj(
|
||||
account_id = membership_group_rec.get('account_id', None),
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
membership_group_obj.cfg = membership_cfg_obj_result
|
||||
else: membership_group_obj.cfg = None
|
||||
|
||||
# Updated 2021-06-23
|
||||
if inc_membership_person_list:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
if membership_person_group_rec_list_result := get_membership_person_group_rec_list(
|
||||
for_obj_type = 'membership_group',
|
||||
for_obj_id = membership_group_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
membership_person_group_result_list = []
|
||||
for membership_person_group_rec in membership_person_group_rec_list_result:
|
||||
if load_membership_person_group_result := load_membership_person_group_obj(
|
||||
membership_person_group_id = membership_person_group_rec.get('membership_person_group_id', None),
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
inc_membership_person_profile = inc_membership_person_profile,
|
||||
inc_membership_person_type = inc_membership_person_type,
|
||||
# inc_organization = inc_organization,
|
||||
inc_person = inc_person,
|
||||
# inc_product = inc_product,
|
||||
):
|
||||
membership_person_group_result_list.append(load_membership_person_group_result)
|
||||
else: membership_person_group_result_list.append(None)
|
||||
membership_group_obj.membership_person_group_list = membership_person_group_result_list
|
||||
else: membership_group_obj.membership_person_group_list = []
|
||||
|
||||
# Updated 2021-06-18
|
||||
# if inc_parent_membership_group:
|
||||
# parent_membership_group_id = membership_group_rec.get('parent_membership_group_id', None)
|
||||
# log.debug(parent_membership_group_id)
|
||||
# if parent_membership_group_result := load_membership_group_obj(
|
||||
# membership_group_id = parent_membership_group_id,
|
||||
# by_alias = by_alias,
|
||||
# exclude_unset = exclude_unset,
|
||||
# model_as_dict = model_as_dict,
|
||||
# ):
|
||||
# membership_group_obj.parent_membership_group = parent_membership_group_result
|
||||
# else: membership_group_obj.parent_membership_group = None
|
||||
# log.debug(parent_membership_group_result)
|
||||
|
||||
# Updated 2021-06-23
|
||||
if inc_product_list:
|
||||
if product_rec_list_result := get_product_rec_list(
|
||||
for_obj_type = 'membership_group',
|
||||
for_obj_id = membership_group_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
product_result_list = []
|
||||
for product_rec in product_rec_list_result:
|
||||
product_result_list.append(
|
||||
load_product_obj(
|
||||
product_id = product_rec.get('product_id', None),
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
)
|
||||
)
|
||||
membership_group_obj.product_list = product_result_list
|
||||
else: membership_group_obj.product_list = []
|
||||
|
||||
if model_as_dict:
|
||||
return membership_group_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return membership_group_obj
|
||||
# ### END ### API Membership Group Methods ### load_membership_group_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Group Methods ### get_membership_group_rec_list() ###
|
||||
def get_membership_group_rec_list(
|
||||
account_id: str = None,
|
||||
membership_person_id: str = None,
|
||||
# product_id: str = None,
|
||||
# type_level: int = None,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
# if product_id := redis_lookup_id_random(record_id_random=product_id, table_name='product'): pass
|
||||
|
||||
data = {}
|
||||
data['account_id'] = account_id
|
||||
data['membership_person_id'] = membership_person_id
|
||||
# data['product_id'] = product_id
|
||||
# data['level'] = type_level
|
||||
|
||||
if account_id:
|
||||
sql_account_id = f'`membership_group`.account_id = :account_id'
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `membership_group`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `membership_group`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
else: sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `membership_group`.id AS 'membership_group_id', `membership_group`.id_random AS 'membership_group_id_random'
|
||||
FROM `v_membership_group` AS `membership_group`
|
||||
WHERE
|
||||
{sql_account_id}
|
||||
{sql_enabled}
|
||||
ORDER BY -`membership_group`.sort DESC, `membership_group`.created_on DESC, `membership_group`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
elif membership_person_id:
|
||||
sql_membership_person_id = f'`membership_person_group`.membership_person_id = :membership_person_id'
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `membership_person_group`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `membership_person_group`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
else: sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `membership_person_group`.membership_group_id AS 'membership_group_id', `membership_person_group`.membership_group_id_random AS 'membership_group_id_random'
|
||||
FROM `v_membership_person_group` AS `membership_person_group`
|
||||
WHERE
|
||||
{sql_membership_person_id}
|
||||
{sql_enabled}
|
||||
ORDER BY -`membership_person_group`.sort DESC, `membership_person_group`.created_on DESC, `membership_person_group`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
else: return False
|
||||
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(sql)
|
||||
|
||||
if membership_group_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
membership_group_rec_li = membership_group_rec_li_result
|
||||
else:
|
||||
membership_group_rec_li = []
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(membership_group_rec_li_result)
|
||||
|
||||
return membership_group_rec_li
|
||||
# ### END ### API Membership Group Methods ### get_membership_group_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Group Methods ### create_membership_group_obj() ###
|
||||
def create_membership_group_obj(
|
||||
membership_group_dict_obj: Membership_Group_Base
|
||||
) -> bool|dict|int:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
membership_group_obj_data = membership_group_dict_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'created_on', 'updated_on'})
|
||||
|
||||
if membership_group_obj_in_result := sql_insert(
|
||||
data=membership_group_obj_data,
|
||||
table_name='membership_group',
|
||||
rm_id_random=True,
|
||||
id_random_length=8
|
||||
): pass
|
||||
else: return False
|
||||
|
||||
log.debug(membership_group_obj_in_result)
|
||||
|
||||
membership_group_id = membership_group_obj_in_result
|
||||
|
||||
log.debug(f'New membership_group_id: {membership_group_id}')
|
||||
return membership_group_id
|
||||
# ### END ### API Membership Group Methods ### create_membership_group_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Group Methods ### update_membership_group_obj() ###
|
||||
def update_membership_group_obj(
|
||||
membership_group_id: int|str, # This allows for updating of the id_random value.
|
||||
membership_group_dict_obj: Membership_Group_Base,
|
||||
create_sub_obj: bool = False,
|
||||
) -> bool:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if membership_group_id := redis_lookup_id_random(record_id_random=membership_group_id, table_name='membership_group'): pass
|
||||
else: return False
|
||||
|
||||
membership_group_dict_obj.id = membership_group_id
|
||||
|
||||
log.debug(membership_group_dict_obj)
|
||||
log.debug(membership_group_dict_obj.dict(by_alias=False, exclude_unset=True))
|
||||
# log.debug(membership_group_dict_obj.dict(by_alias=False, exclude_unset=False))
|
||||
|
||||
membership_group_dict_up = membership_group_dict_obj.dict(by_alias=False, exclude_unset=True)
|
||||
log.debug(membership_group_dict_up)
|
||||
|
||||
if membership_group_dict_obj_result := sql_update(data=membership_group_dict_up, table_name='membership_group', rm_id_random=True):
|
||||
log.debug(membership_group_dict_obj_result)
|
||||
return True
|
||||
else:
|
||||
log.debug(membership_group_dict_obj_result)
|
||||
return False
|
||||
# ### END ### API Membership Group Methods ### update_membership_group_obj() ###
|
||||
195
app/methods/membership_person_group_methods.py
Normal file
195
app/methods/membership_person_group_methods.py
Normal file
@@ -0,0 +1,195 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging
|
||||
# from app.methods.membership_person_methods import get_membership_person_rec_list, load_membership_person_obj
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
from app.models.membership_person_group_models import Membership_Person_Group_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Group Person Methods ### load_membership_person_group_obj() ###
|
||||
def load_membership_person_group_obj(
|
||||
membership_person_group_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_address: bool = False,
|
||||
inc_contact: bool = False,
|
||||
inc_membership_cfg: bool = False,
|
||||
inc_membership_group: bool = False,
|
||||
inc_membership_person: bool = False,
|
||||
inc_membership_person_profile: bool = False,
|
||||
inc_membership_person_type: bool = False,
|
||||
inc_membership_type: bool = False,
|
||||
inc_organization: bool = False,
|
||||
inc_person: bool = False,
|
||||
inc_product: bool = False,
|
||||
# inc_product_list: bool = False,
|
||||
) -> Membership_Person_Group_Base|bool:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if membership_person_group_id := redis_lookup_id_random(record_id_random=membership_person_group_id, table_name='membership_person_group'): pass
|
||||
else: return False
|
||||
log.debug(membership_person_group_id)
|
||||
|
||||
if membership_person_group_rec := sql_select(table_name='v_membership_person_group', record_id=membership_person_group_id):
|
||||
log.debug(membership_person_group_rec)
|
||||
else: return False
|
||||
log.debug(membership_person_group_rec)
|
||||
|
||||
try:
|
||||
membership_person_group_obj = Membership_Person_Group_Base(**membership_person_group_rec)
|
||||
log.debug(membership_person_group_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
# Updated 2021-06-21
|
||||
if inc_membership_person:
|
||||
from app.methods.membership_person_methods import load_membership_person_obj
|
||||
membership_person_id = membership_person_group_rec.get('membership_person_id', None)
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(membership_person_id)
|
||||
if membership_person_result := load_membership_person_obj(
|
||||
membership_person_id = membership_person_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
inc_address = inc_address,
|
||||
inc_contact = inc_contact,
|
||||
inc_membership_person_profile = inc_membership_person_profile,
|
||||
inc_membership_type = inc_membership_type,
|
||||
inc_organization = inc_organization,
|
||||
inc_person = inc_person,
|
||||
inc_user = inc_user,
|
||||
):
|
||||
membership_person_group_obj.membership_person = membership_person_result
|
||||
else: membership_person_group_obj.membership_person = None
|
||||
log.debug(membership_person_result)
|
||||
|
||||
if model_as_dict:
|
||||
return membership_person_group_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return membership_person_group_obj
|
||||
# ### END ### API Membership Group Person Methods ### load_membership_person_group_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Group Person Methods ### get_membership_person_group_rec_list() ###
|
||||
def get_membership_person_group_rec_list(
|
||||
for_obj_type: str,
|
||||
for_obj_id: str,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
else: return False
|
||||
data = {}
|
||||
data[f'{for_obj_type}_id'] = for_obj_id
|
||||
# data['for_obj_type'] = for_obj_type
|
||||
sql_obj_type_id = f'`tbl`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `tbl`.id AS 'membership_person_group_id', `tbl`.id_random AS 'membership_person_group_id_random'
|
||||
FROM `membership_person_group` AS `tbl`
|
||||
WHERE
|
||||
{sql_obj_type_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(sql)
|
||||
|
||||
if membership_person_group_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
membership_person_group_rec_li = membership_person_group_rec_li_result
|
||||
else:
|
||||
membership_person_group_rec_li = []
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(membership_person_group_rec_li_result)
|
||||
|
||||
return membership_person_group_rec_li
|
||||
# ### END ### API Membership Group Person Methods ### get_membership_person_group_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Group Person Methods ### create_membership_person_group_obj() ###
|
||||
def create_membership_person_group_obj(
|
||||
membership_person_group_obj_new: Membership_Person_Group_Base
|
||||
) -> bool|dict|int:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
membership_person_group_obj_data = membership_person_group_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'created_on', 'updated_on'})
|
||||
|
||||
if membership_person_group_obj_in_result := sql_insert(
|
||||
data=membership_person_group_obj_data,
|
||||
table_name='membership_person_group',
|
||||
rm_id_random=True,
|
||||
id_random_length=8
|
||||
): pass
|
||||
else: return False
|
||||
|
||||
log.debug(membership_person_group_obj_in_result)
|
||||
|
||||
membership_person_group_id = membership_person_group_obj_in_result
|
||||
|
||||
log.debug(f'New membership_person_group_id: {membership_person_group_id}')
|
||||
return membership_person_group_id
|
||||
# ### END ### API Membership Group Person Methods ### create_membership_person_group_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Group Person Methods ### update_membership_person_group_obj() ###
|
||||
def update_membership_person_group_obj(
|
||||
membership_person_group_id: int|str, # This allows for updating of the id_random value.
|
||||
membership_person_group_obj_up: Membership_Person_Group_Base,
|
||||
create_sub_obj: bool = False,
|
||||
) -> bool|dict:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if membership_person_group_id := redis_lookup_id_random(record_id_random=membership_person_group_id, table_name='membership_person_group'): pass
|
||||
else: return False
|
||||
|
||||
membership_person_group_obj_up.id = membership_person_group_id
|
||||
|
||||
log.debug(membership_person_group_obj_up)
|
||||
log.debug(membership_person_group_obj_up.dict(by_alias=False, exclude_unset=True))
|
||||
# log.debug(membership_person_group_obj_up.dict(by_alias=False, exclude_unset=False))
|
||||
|
||||
membership_person_group_dict_up = membership_person_group_obj_up.dict(by_alias=False, exclude_unset=True)
|
||||
log.debug(membership_person_group_dict_up)
|
||||
|
||||
if membership_person_group_obj_up_result := sql_update(data=membership_person_group_dict_up, table_name='membership_person_group', rm_id_random=True):
|
||||
log.debug(membership_person_group_obj_up_result)
|
||||
return True
|
||||
else:
|
||||
log.debug(membership_person_group_obj_up_result)
|
||||
return False
|
||||
# ### END ### API Membership Group Person Methods ### update_membership_person_group_obj() ###
|
||||
694
app/methods/membership_person_methods.py
Normal file
694
app/methods/membership_person_methods.py
Normal file
@@ -0,0 +1,694 @@
|
||||
from __future__ import annotations
|
||||
import datetime, json
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_insert_or_update, sql_select, sql_update
|
||||
|
||||
from app.methods.membership_cfg_methods import load_membership_cfg_obj
|
||||
from app.methods.membership_group_methods import get_membership_group_rec_list, load_membership_group_obj
|
||||
from app.methods.membership_person_group_methods import get_membership_person_group_rec_list, load_membership_person_group_obj
|
||||
from app.methods.membership_person_profile_methods import get_membership_person_profile_rec_list, load_membership_person_profile_obj
|
||||
from app.methods.membership_person_type_methods import create_membership_person_type_obj, update_membership_person_type_obj
|
||||
from app.methods.person_methods import load_person_obj
|
||||
from app.methods.product_methods import load_product_obj
|
||||
from app.methods.user_methods import load_user_obj
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
from app.models.membership_person_models import Membership_Person_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Person Methods ### load_membership_person_obj() ###
|
||||
# Updated 2022-01-11
|
||||
@logger_reset
|
||||
def load_membership_person_obj(
|
||||
membership_person_id: int|str,
|
||||
limit: int = 100,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_address: bool = False,
|
||||
inc_contact: bool = False,
|
||||
inc_membership_cfg: bool = False,
|
||||
# inc_membership_group: bool = False, # Their primary membership group
|
||||
inc_membership_person_group_list: bool = False, # List of membership group for a person - 2022-01-11
|
||||
# inc_membership_person_group: bool = False, # The person information for their primary membership group
|
||||
# inc_membership_person_group_list: bool = False, # The person information for all of their membership groups
|
||||
# inc_membership_person_profile: bool = False,
|
||||
# inc_membership_person_profile_cust: bool = False, # Extended profile?
|
||||
inc_membership_person_profile: bool = False, # Membership profile for a person - 2022-01-11
|
||||
inc_membership_person_type: bool = False, # Primary membership type for a person - 2022-01-11
|
||||
# inc_membership_type_list: bool = False, # The list of membership types the person is a part of
|
||||
# inc_membership_person_type: bool = False, # The person information for their primary membership type
|
||||
# inc_membership_person_type_list: bool = False, # The person information for all of their membership types
|
||||
inc_order: bool = False,
|
||||
# inc_organization: bool = False,
|
||||
inc_person: bool = False,
|
||||
inc_product: bool = False, # The product the person actually purchased for a member_type or member_group
|
||||
inc_product_list: bool = False, # The list of products that give access to a member_type or member_group
|
||||
# inc_user: bool = False,
|
||||
) -> Membership_Person_Base:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if membership_person_id := redis_lookup_id_random(record_id_random=membership_person_id, table_name='membership_person'): pass
|
||||
else: return False
|
||||
|
||||
if membership_person_rec := sql_select(table_name='v_membership_person', record_id=membership_person_id):
|
||||
log.debug(membership_person_rec)
|
||||
else: return False
|
||||
|
||||
log.debug(membership_person_rec)
|
||||
|
||||
try:
|
||||
membership_person_obj = Membership_Person_Base(**membership_person_rec)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
log.debug(membership_person_obj)
|
||||
|
||||
# Updated 2021-06-24
|
||||
if inc_membership_cfg:
|
||||
if membership_cfg_obj_result := load_membership_cfg_obj(
|
||||
account_id = membership_person_rec.get('account_id', None),
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
membership_person_obj.membership_cfg = membership_cfg_obj_result
|
||||
else: membership_person_obj.membership_cfg = {} # None
|
||||
|
||||
# if inc_membership_group: pass # The primary membership group the person is a part of. Not used at this time. 2021-12-16
|
||||
|
||||
# Updated 2021-01-12
|
||||
if inc_membership_person_group_list: # List of membership group for a person - 2022-01-11
|
||||
if membership_person_group_rec_list_result := get_membership_person_group_rec_list(
|
||||
membership_person_id = membership_person_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
membership_person_group_result_list = []
|
||||
for membership_person_group_rec in membership_person_group_rec_list_result:
|
||||
if load_membership_person_group_result := load_membership_person_group_obj(
|
||||
membership_person_group_id = membership_person_group_rec.get('membership_person_group_id', None),
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
# inc_membership_group_list = inc_membership_group_list,
|
||||
# inc_membership_person_profile = inc_membership_person_profile,
|
||||
# inc_organization = inc_organization,
|
||||
# inc_person = inc_person,
|
||||
# inc_product = inc_product,
|
||||
# inc_product_list = inc_product_list,
|
||||
# inc_user = inc_user,
|
||||
):
|
||||
membership_person_group_result_list.append(load_membership_person_group_result)
|
||||
else: membership_person_group_result_list.append(None)
|
||||
membership_person_obj.membership_group_list = membership_person_group_result_list
|
||||
else: membership_person_obj.membership_person_group_list = []
|
||||
|
||||
# Updated 2021-07-09
|
||||
# if inc_membership_person_group_list: # The person information for the list of groups the member is a part of
|
||||
# if membership_person_group_rec_list_result := get_membership_person_group_rec_list(
|
||||
# for_obj_type = 'membership_person',
|
||||
# for_obj_id = membership_person_id,
|
||||
# # membership_person_id = membership_person_id,
|
||||
# limit = limit,
|
||||
# enabled = enabled,
|
||||
# ):
|
||||
# membership_person_group_result_list = []
|
||||
# for membership_person_group_rec in membership_person_group_rec_list_result:
|
||||
# if load_membership_person_group_result := load_membership_person_group_obj(
|
||||
# membership_person_group_id = membership_person_group_rec.get('membership_person_group_id', None),
|
||||
# limit = limit,
|
||||
# by_alias = by_alias,
|
||||
# exclude_unset = exclude_unset,
|
||||
# model_as_dict = model_as_dict,
|
||||
# enabled = enabled,
|
||||
# # inc_membership_person_group_list = inc_membership_person_group_list,
|
||||
# # inc_membership_person_profile = inc_membership_person_profile,
|
||||
# # inc_organization = inc_organization,
|
||||
# # inc_person = inc_person,
|
||||
# inc_product = inc_product,
|
||||
# # inc_product_list = inc_product_list,
|
||||
# # inc_user = inc_user,
|
||||
# ):
|
||||
# membership_person_group_result_list.append(load_membership_person_group_result)
|
||||
# else: membership_person_group_result_list.append(None)
|
||||
# membership_person_obj.membership_person_group_list = membership_person_group_result_list
|
||||
# else: membership_person_obj.membership_person_group_list = []
|
||||
|
||||
# Updated 2021-06-21
|
||||
if inc_membership_person_profile: # Membership profile for a person - 2022-01-11
|
||||
membership_person_profile_id = membership_person_rec.get('membership_person_profile_id', None)
|
||||
log.debug(membership_person_profile_id)
|
||||
if membership_person_profile_result := load_membership_person_profile_obj(
|
||||
membership_person_profile_id = membership_person_profile_id,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
inc_address = inc_address,
|
||||
inc_contact = inc_contact,
|
||||
# inc_membership = inc_membership,
|
||||
# inc_membership_cfg = inc_membership_cfg,
|
||||
inc_organization = inc_organization,
|
||||
):
|
||||
membership_person_obj.membership_person_profile = membership_person_profile_result
|
||||
else: membership_person_obj.membership_person_profile = {} # None
|
||||
log.debug(membership_person_profile_result)
|
||||
|
||||
# Updated 2021-01-12
|
||||
if inc_membership_person_type: # Primary membership type for a person - 2022-01-11
|
||||
from app.methods.membership_person_type_methods import load_membership_person_type_obj
|
||||
membership_person_type_id = membership_person_rec.get('membership_person_type_id', None)
|
||||
log.debug(membership_person_type_id)
|
||||
if membership_person_type_result := load_membership_person_type_obj(
|
||||
membership_person_type_id = membership_person_type_id,
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
# inc_address = inc_address,
|
||||
# inc_contact = inc_contact,
|
||||
# inc_membership = inc_membership,
|
||||
# inc_membership_cfg = inc_membership_cfg,
|
||||
# inc_organization = inc_organization,
|
||||
inc_product_list = inc_product_list,
|
||||
):
|
||||
membership_person_obj.membership_person_type = membership_person_type_result
|
||||
else: membership_person_obj.membership_person_type = {} # None
|
||||
log.debug(membership_person_type_result)
|
||||
|
||||
# if inc_membership_person_type_list: pass # All of the membership types the person is a part of
|
||||
|
||||
# Updated 2021-07-09
|
||||
# if inc_membership_person_type: # The primary membership type person information for the person
|
||||
# from app.methods.membership_person_type_methods import load_membership_person_type_obj
|
||||
# membership_person_type_id = membership_person_rec.get('membership_person_type_id', None)
|
||||
# log.debug(membership_person_type_id)
|
||||
# if membership_person_type_result := load_membership_person_type_obj(
|
||||
# membership_person_type_id = membership_person_type_id,
|
||||
# limit = limit,
|
||||
# by_alias = by_alias,
|
||||
# exclude_unset = exclude_unset,
|
||||
# model_as_dict = model_as_dict,
|
||||
# enabled = enabled,
|
||||
# inc_membership_cfg = inc_membership_cfg,
|
||||
# inc_membership_type = inc_membership_type,
|
||||
# inc_product = inc_product,
|
||||
# ):
|
||||
# membership_person_obj.membership_person_type = membership_person_type_result
|
||||
# else: membership_person_obj.membership_person_type = {} # None
|
||||
# log.debug(membership_person_type_result)
|
||||
|
||||
# if inc_membership_person_type_list: pass # All of the membership type person records for a person
|
||||
|
||||
# Updated 2021-06-18
|
||||
if inc_person:
|
||||
person_id = membership_person_rec.get('person_id', None)
|
||||
log.debug(person_id)
|
||||
if person_result := load_person_obj(
|
||||
person_id = person_id,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
inc_address = inc_address,
|
||||
inc_contact = inc_contact,
|
||||
# inc_organization = inc_organization,
|
||||
# inc_user = inc_user,
|
||||
):
|
||||
membership_person_obj.person = person_result
|
||||
else: membership_person_obj.person = {} # None
|
||||
log.debug(person_result)
|
||||
|
||||
# Updated 2021-06-24
|
||||
if inc_product:
|
||||
product_id = membership_person_rec.get('product_id', None)
|
||||
log.debug(product_id)
|
||||
if product_result := load_product_obj(
|
||||
product_id = product_id,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
membership_person_obj.product = product_result
|
||||
else: membership_person_obj.product = {} # None
|
||||
log.debug(product_result)
|
||||
|
||||
# Updated 2021-06-18
|
||||
# if inc_user:
|
||||
# log.warning(f'This is being deprecated? load_membership_person_obj() inc_user')
|
||||
# user_id = membership_person_rec.get('user_id', None)
|
||||
# if user_result := load_user_obj(
|
||||
# user_id = user_id,
|
||||
# by_alias = by_alias,
|
||||
# exclude_unset = exclude_unset,
|
||||
# model_as_dict = model_as_dict,
|
||||
# # inc_address = inc_address,
|
||||
# # inc_contact = inc_contact,
|
||||
# # inc_organization = inc_organization,
|
||||
# # inc_person = inc_person,
|
||||
# ):
|
||||
# membership_person_obj.user = user_result
|
||||
# else: membership_person_obj.user = {} # None
|
||||
# log.debug(user_result)
|
||||
|
||||
if model_as_dict:
|
||||
return membership_person_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return membership_person_obj
|
||||
# ### END ### API Membership Person Methods ### load_membership_person_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Person Methods ### get_membership_person_rec_list() ###
|
||||
@logger_reset
|
||||
def get_membership_person_rec_list(
|
||||
for_obj_type: str,
|
||||
for_obj_id: str,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
else: return False
|
||||
data = {}
|
||||
data[f'{for_obj_type}_id'] = for_obj_id
|
||||
|
||||
allowed_forign_key_li = ['account', 'membership_type', 'person', 'user']
|
||||
if for_obj_type in allowed_forign_key_li:
|
||||
log.info(f'Query using forign key: {for_obj_type} {for_obj_id}')
|
||||
sql_obj_type_id = f'`tbl`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `tbl`.id AS 'membership_person_id', `tbl`.id_random AS 'membership_person_id_random'
|
||||
FROM `membership_person` AS `tbl`
|
||||
WHERE
|
||||
{sql_obj_type_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
elif for_obj_type == 'unknown':
|
||||
log.info(f'Query using joined table: {for_obj_type} {for_obj_id}')
|
||||
# sql_obj_type_id = f'`membership_person`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
# if enabled in ['enabled', 'disabled', 'all']:
|
||||
# if enabled == 'enabled':
|
||||
# data['enable'] = True
|
||||
# sql_enabled = f'AND `membership_person`.enable = :enable'
|
||||
# elif enabled == 'disabled':
|
||||
# data['enable'] = False
|
||||
# sql_enabled = f'AND `membership_person`.enable = :enable'
|
||||
# elif enabled == 'all':
|
||||
# sql_enabled = ''
|
||||
|
||||
# if limit:
|
||||
# data['limit'] = limit
|
||||
# sql_limit = f'LIMIT :limit'
|
||||
# else:
|
||||
# sql_limit = ''
|
||||
|
||||
# sql = f"""
|
||||
# SELECT `membership_person`.id AS 'membership_type_id', `membership_person`.id_random AS 'membership_type_id_random'
|
||||
# FROM `membership_person`
|
||||
# INNER JOIN membership_type ON membership_person.membership_type_id = membership_type.id
|
||||
# WHERE
|
||||
# {sql_obj_type_id}
|
||||
# {sql_enabled}
|
||||
|
||||
# ORDER BY `membership_person`.created_on DESC, `membership_person`.updated_on DESC
|
||||
# {sql_limit};
|
||||
# """
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(sql)
|
||||
|
||||
# sql_obj_type_id = f'`tbl`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
# if enabled in ['enabled', 'disabled', 'all']:
|
||||
# if enabled == 'enabled':
|
||||
# data['enable'] = True
|
||||
# sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
# elif enabled == 'disabled':
|
||||
# data['enable'] = False
|
||||
# sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
# elif enabled == 'all':
|
||||
# sql_enabled = ''
|
||||
|
||||
# if limit:
|
||||
# data['limit'] = limit
|
||||
# sql_limit = f'LIMIT :limit'
|
||||
# else:
|
||||
# sql_limit = ''
|
||||
|
||||
# sql = f"""
|
||||
# SELECT `tbl`.id AS 'membership_person_id', `tbl`.id_random AS 'membership_person_id_random'
|
||||
# FROM `membership_person` AS `tbl`
|
||||
# WHERE
|
||||
# {sql_obj_type_id}
|
||||
# {sql_enabled}
|
||||
# ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
|
||||
# {sql_limit};
|
||||
# """
|
||||
|
||||
if membership_person_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
membership_person_rec_li = membership_person_rec_li_result
|
||||
else:
|
||||
membership_person_rec_li = []
|
||||
|
||||
log.debug(membership_person_rec_li_result)
|
||||
|
||||
return membership_person_rec_li
|
||||
# ### END ### API Membership Person Methods ### get_membership_person_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Person Methods ### create_membership_person_obj() ###
|
||||
# Updated 2022-01-04
|
||||
@logger_reset
|
||||
def create_membership_person_obj(
|
||||
account_id: int,
|
||||
person_id: int,
|
||||
membership_person_dict_obj: Membership_Person_Base,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_outline: bool = False,
|
||||
) -> bool|dict|int:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
log.info('Checking requirements...')
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Account ID passed. Failed requirement.')
|
||||
log.info(f'Account ID: {account_id}')
|
||||
if person_id := redis_lookup_id_random(record_id_random=person_id, table_name='person'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Person ID passed. Failed requirement.')
|
||||
log.info(f'Person ID: {person_id}')
|
||||
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(membership_person_dict_obj))
|
||||
if isinstance(membership_person_dict_obj, dict):
|
||||
membership_person_dict = membership_person_dict_obj
|
||||
membership_person_dict['account_id'] = account_id
|
||||
membership_person_dict['person_id'] = person_id
|
||||
try:
|
||||
membership_person_obj = Membership_Person_Base(**membership_person_dict)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
membership_person_obj = membership_person_dict_obj
|
||||
membership_person_obj.account_id = account_id
|
||||
membership_person_obj.person_id = person_id
|
||||
log.debug(membership_person_obj)
|
||||
|
||||
membership_person_dict = membership_person_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'membership_cfg', 'membership_person_group_list', 'membership_person_profile', 'membership_person_type', 'membership_group', 'membership_group_list', 'membership_type', 'membership_type_list', 'person', 'product', 'created_on', 'updated_on'})
|
||||
|
||||
# ### SECTION ### Process data
|
||||
membership_person_obj.account_id = account_id # Is this needed?
|
||||
membership_person_dict['account_id'] = account_id
|
||||
|
||||
if membership_person_dict_in_result := sql_insert(
|
||||
data = membership_person_dict,
|
||||
table_name = 'membership_person',
|
||||
rm_id_random = True,
|
||||
id_random_length = default_num_bytes
|
||||
): pass
|
||||
else:
|
||||
log.warning(f'Membership Person not created.')
|
||||
log.debug(membership_person_dict_in_result)
|
||||
return False
|
||||
|
||||
log.debug(membership_person_dict_in_result)
|
||||
membership_person_id = membership_person_dict_in_result
|
||||
|
||||
membership_person_outline = {}
|
||||
membership_person_outline['membership_person_id'] = membership_person_id
|
||||
membership_person_outline['account_id'] = account_id
|
||||
membership_person_outline['person_id'] = person_id
|
||||
|
||||
membership_person_outline['membership_person_group_list'] = []
|
||||
membership_person_outline['membership_person_profile'] = {}
|
||||
membership_person_outline['membership_person_profile_id'] = None
|
||||
membership_person_outline['membership_person_type'] = {}
|
||||
membership_person_outline['membership_person_type_id'] = None
|
||||
|
||||
if membership_person_obj.membership_person_group_list:
|
||||
log.info('Looping through Membership Person Group object list')
|
||||
for membership_person_group_obj in membership_person_obj.membership_person_group_list:
|
||||
if membership_person_group_id := membership_person_group_obj.id:
|
||||
log.info('Updating Membership Person Group object')
|
||||
if membership_person_group_update_result := update_membership_person_group_obj(
|
||||
membership_person_group_id = membership_person_group_id,
|
||||
membership_person_group_dict_obj = membership_person_group_obj,
|
||||
): pass
|
||||
else: return False
|
||||
else:
|
||||
log.info('Creating Membership Person Group object')
|
||||
if membership_person_group_create_result := create_membership_person_group_obj(
|
||||
membership_person_id = membership_person_id,
|
||||
membership_person_group_dict_obj = membership_person_group_obj,
|
||||
): pass
|
||||
else: pass
|
||||
|
||||
if membership_person_obj.membership_person_type and membership_person_obj.membership_person_type.id:
|
||||
log.info('Updating Membership Person Type object')
|
||||
membership_person_type_id = membership_person_obj.membership_person_type.id
|
||||
if membership_person_type_update_result := update_membership_person_type_obj(
|
||||
membership_person_type_id = membership_person_type_id,
|
||||
membership_person_type_dict_obj = membership_person_obj.membership_person_type,
|
||||
): pass
|
||||
else: return False
|
||||
elif membership_person_obj.membership_person_type:
|
||||
log.info('Creating Membership Type object')
|
||||
if membership_person_type_create_result := create_membership_person_type_obj(
|
||||
membership_person_id = membership_person_id,
|
||||
membership_person_type_dict_obj = membership_person_obj.membership_person_type,
|
||||
): pass
|
||||
else: return False
|
||||
else: pass
|
||||
|
||||
if return_outline:
|
||||
log.debug(f'Returning the Membership Person Outline: {membership_person_outline}')
|
||||
return membership_person_outline
|
||||
else:
|
||||
log.debug(f'Returning the Membership Person ID: {membership_person_id}')
|
||||
return membership_person_id
|
||||
# ### END ### API Membership Person Methods ### create_membership_person_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Person Methods ### update_membership_person_obj() ###
|
||||
# Updated 2022-01-04
|
||||
@logger_reset
|
||||
def update_membership_person_obj(
|
||||
membership_person_id: int,
|
||||
membership_person_dict_obj: Membership_Person_Base,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_outline: bool = False,
|
||||
) -> bool|dict:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
log.info('Checking requirements...')
|
||||
if membership_person_id := redis_lookup_id_random(record_id_random=membership_person_id, table_name='membership_person'): pass
|
||||
else:
|
||||
log.error('Membership Person ID passed but is invalid. Failed requirement.')
|
||||
return False
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(membership_person_dict_obj))
|
||||
if isinstance(membership_person_dict_obj, dict):
|
||||
membership_person_dict = membership_person_dict_obj
|
||||
membership_person_dict['membership_person_id'] = membership_person_id
|
||||
try:
|
||||
membership_person_obj = Membership_Person_Base(**membership_person_dict)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
membership_person_obj = membership_person_dict_obj
|
||||
membership_person_obj.id = membership_person_id
|
||||
log.debug(json.dumps(membership_person_obj, indent=2, default=str))
|
||||
|
||||
membership_person_dict = membership_person_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'membership_cfg', 'membership_person_group_list', 'membership_person_profile', 'membership_person_type', 'membership_group', 'membership_group_list', 'membership_type', 'membership_type_list', 'person', 'product', 'created_on', 'updated_on'})
|
||||
log.debug(membership_person_dict)
|
||||
|
||||
# ### SECTION ### Process data
|
||||
|
||||
if membership_person_dict_up_result := sql_update(
|
||||
data = membership_person_dict,
|
||||
table_name = 'membership_person',
|
||||
rm_id_random = True,
|
||||
): pass
|
||||
elif membership_person_dict_up_result is None: pass
|
||||
else:
|
||||
log.warning(f'Membership Person not updated.')
|
||||
log.debug(membership_person_dict_up_result)
|
||||
return False
|
||||
|
||||
membership_person_outline = {}
|
||||
membership_person_outline['membership_person_id'] = membership_person_id
|
||||
# membership_person_outline['account_id'] = account_id
|
||||
# membership_person_outline['person_id'] = person_id
|
||||
|
||||
membership_person_outline['membership_person_group_list'] = []
|
||||
membership_person_outline['membership_person_profile'] = {}
|
||||
membership_person_outline['membership_person_profile_id'] = None
|
||||
membership_person_outline['membership_person_type'] = {}
|
||||
membership_person_outline['membership_person_type_id'] = None
|
||||
|
||||
if membership_person_obj.membership_person_group_list:
|
||||
log.info('Looping through Membership Person Group object list')
|
||||
for membership_person_group_obj in membership_person_obj.membership_person_group_list:
|
||||
if membership_person_group_id := membership_person_group_obj.id:
|
||||
log.info('Updating Membership Person Group object')
|
||||
if membership_person_group_update_result := update_membership_person_group_obj(
|
||||
membership_person_group_id = membership_person_group_id,
|
||||
membership_person_group_dict_obj = membership_person_group_obj,
|
||||
): pass
|
||||
else: return False
|
||||
else:
|
||||
log.info('Creating Membership Person Group object')
|
||||
if membership_person_group_create_result := create_membership_person_group_obj(
|
||||
membership_person_id = membership_person_id,
|
||||
membership_person_group_dict_obj = membership_person_group_obj,
|
||||
): pass
|
||||
else: pass
|
||||
|
||||
if membership_person_obj.membership_person_type and membership_person_obj.membership_person_type.id:
|
||||
log.info('Updating Membership Person Type object')
|
||||
membership_person_type_id = membership_person_obj.membership_person_type.id
|
||||
if membership_person_type_update_result := update_membership_person_type_obj(
|
||||
membership_person_type_id = membership_person_type_id,
|
||||
membership_person_type_dict_obj = membership_person_obj.membership_person_type,
|
||||
): pass
|
||||
else: return False
|
||||
elif membership_person_obj.membership_person_type:
|
||||
log.info('Creating Membership Person Type object')
|
||||
if membership_person_type_create_result := create_membership_person_type_obj(
|
||||
membership_person_id = membership_person_id,
|
||||
membership_person_type_dict_obj = membership_person_obj.membership_person_type,
|
||||
): pass
|
||||
else: return False
|
||||
else: pass
|
||||
|
||||
# # NOTE: Use object model version because of better type checking and validations
|
||||
# if membership_person_obj.membership_person_type:
|
||||
# membership_person_outline['membership_person_type_id'] = None
|
||||
# membership_person_type_obj = membership_person_obj.membership_person_type
|
||||
# if membership_person_type_id := membership_person_obj.membership_person_type_id: pass
|
||||
# elif membership_person_type_id := membership_person_type_obj.id: pass
|
||||
# else: membership_person_type_id = None
|
||||
|
||||
# membership_person_type_obj.membership_type_id = 6
|
||||
|
||||
# if membership_person_type_id:
|
||||
# update_membership_person_type_obj_result = update_membership_person_type_obj(
|
||||
# membership_person_type_dict_obj = membership_person_type_obj,
|
||||
# membership_person_type_id = memberssql_update
|
||||
# else:
|
||||
# pass
|
||||
# else:
|
||||
# create_membership_person_type_obj_result = create_membership_person_type_obj(
|
||||
# membership_person_type_dict_obj = membership_person_type_obj,
|
||||
# membership_person_id = membership_person_id,
|
||||
# fail_any = fail_any,
|
||||
# return_outline = return_outline,
|
||||
# )
|
||||
# if isinstance(create_membership_person_type_obj_result, int):
|
||||
# membership_person_type_id = create_membership_person_type_obj_result
|
||||
# membership_person_outline['membership_person_type_id'] = membership_person_type_id
|
||||
# else:
|
||||
# pass
|
||||
|
||||
if return_outline:
|
||||
log.debug(f'Returning the Membership Person Outline: {membership_person_outline}')
|
||||
return membership_person_outline
|
||||
else:
|
||||
log.debug(f'Returning True')
|
||||
return True
|
||||
# ### END ### API Membership Person Methods ### create_update_membership_person_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Person Methods ### create_update_membership_person_obj() ###
|
||||
# Updated 2021-08-25
|
||||
@logger_reset
|
||||
def create_update_membership_person_obj(
|
||||
membership_person_dict_obj: Membership_Person_Base|dict,
|
||||
person_id: int|str,
|
||||
account_id: int|str = None,
|
||||
membership_person_id: int|str = None,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_outline: bool = False,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
log.info('Checking requirements...')
|
||||
if membership_person_id:
|
||||
log.info(f'Membership Person ID passed. Update existing Membership Person. Membership Person ID: {membership_person_id}')
|
||||
|
||||
if membership_person_id := redis_lookup_id_random(record_id_random=membership_person_id, table_name='membership_person'): pass
|
||||
else:
|
||||
log.error('Membership Person ID passed but is invalid. Failed requirement.')
|
||||
return False
|
||||
|
||||
if person_id := redis_lookup_id_random(record_id_random=person_id, table_name='person'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Person ID passed. Not required. Ignoring.')
|
||||
log.info(f'Person ID: {person_id}')
|
||||
|
||||
# log.info('Attempting to get Person ID from related object.')
|
||||
# from app.methods.person_methods import get_person_id_w_for_type_id
|
||||
# if person_id := get_person_id_w_for_type_id(for_type='person_session', for_id=person_session_id): pass
|
||||
# elif person_id := get_person_id_w_for_type_id(for_type='person_presentation', for_id=person_presentation_id): pass
|
||||
# elif person_id := get_person_id_w_for_type_id(for_type='membership_person', for_id=membership_person_id): pass
|
||||
# else:
|
||||
# log.error('Unable to get Person ID from related object.')
|
||||
# False
|
||||
else:
|
||||
log.info('No Membership Person ID passed. Create new Membership Person. Required: Account ID, Person ID')
|
||||
|
||||
if person_id := redis_lookup_id_random(record_id_random=person_id, table_name='person'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Person ID passed. Failed requirement.')
|
||||
log.info(f'Person ID: {person_id}')
|
||||
|
||||
log.info('Attempting to get Person ID from related object.')
|
||||
from app.methods.person_methods import get_person_id_w_for_type_id
|
||||
if person_id := get_person_id_w_for_type_id(for_type='person_session', for_id=person_session_id): pass
|
||||
elif person_id := get_person_id_w_for_type_id(for_type='person_presentation', for_id=person_presentation_id): pass
|
||||
else:
|
||||
log.error('Unable to get Person ID from related object.')
|
||||
False
|
||||
# ### END ### API Membership Person Methods ### create_update_membership_person_obj() ###
|
||||
124
app/methods/membership_person_profile_methods.py
Normal file
124
app/methods/membership_person_profile_methods.py
Normal file
@@ -0,0 +1,124 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_select
|
||||
from app.lib_general import log, logging
|
||||
from app.methods.membership_cfg_methods import load_membership_cfg_obj
|
||||
|
||||
from app.models.membership_person_profile_models import Membership_Person_Profile_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Person Profile Methods ### load_membership_person_profile_obj() ###
|
||||
# Updated 2021-07-13
|
||||
def load_membership_person_profile_obj(
|
||||
membership_person_profile_id: int|str|None = None,
|
||||
membership_person_id: int|str|None = None,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
inc_address: bool = False,
|
||||
inc_contact: bool = False,
|
||||
inc_membership_cfg: bool = False,
|
||||
inc_organization: bool = False,
|
||||
) -> Membership_Person_Profile_Base|dict|bool:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if membership_person_profile_id := redis_lookup_id_random(record_id_random=membership_person_profile_id, table_name='membership_person_profile'): pass
|
||||
if membership_person_id := redis_lookup_id_random(record_id_random=membership_person_id, table_name='membership_person'): pass
|
||||
|
||||
if membership_person_profile_id:
|
||||
if membership_person_profile_rec := sql_select(
|
||||
table_name = 'v_membership_person_profile',
|
||||
record_id = membership_person_profile_id,
|
||||
): pass
|
||||
else: return None
|
||||
elif membership_person_id:
|
||||
if membership_person_profile_rec := sql_select(
|
||||
table_name = 'v_membership_person_profile',
|
||||
field_name = 'membership_person_id',
|
||||
field_value = membership_person_id,
|
||||
): pass
|
||||
else: return None
|
||||
else:
|
||||
return None
|
||||
log.debug(membership_person_profile_rec)
|
||||
try:
|
||||
membership_person_profile_obj = Membership_Person_Profile_Base(**membership_person_profile_rec)
|
||||
log.debug(membership_person_profile_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
# Updated 2021-07-13
|
||||
if inc_membership_cfg:
|
||||
if membership_cfg_obj_result := load_membership_cfg_obj(
|
||||
account_id = membership_person_profile_rec.get('account_id', None),
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
membership_person_profile_obj.membership_cfg = membership_cfg_obj_result
|
||||
else: membership_person_profile_obj.membership_cfg = None
|
||||
|
||||
if model_as_dict:
|
||||
return membership_person_profile_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return membership_person_profile_obj
|
||||
# ### END ### API Membership Person Profile Methods ### load_membership_person_profile_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Person Profile Methods ### get_membership_person_profile_rec_list() ###
|
||||
def get_membership_person_profile_rec_list(
|
||||
for_obj_type: str,
|
||||
for_obj_id: str,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
else: return False
|
||||
data = {}
|
||||
data[f'{for_obj_type}_id'] = for_obj_id
|
||||
# data['for_obj_type'] = for_obj_type
|
||||
sql_obj_type_id = f'`tbl`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `tbl`.id AS 'membership_person_profile_id', `tbl`.id_random AS 'membership_person_profile_id_random'
|
||||
FROM `membership_person_profile` AS `tbl`
|
||||
WHERE
|
||||
{sql_obj_type_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if membership_person_profile_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
membership_person_profile_rec_li = membership_person_profile_rec_li_result
|
||||
else:
|
||||
membership_person_profile_rec_li = []
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(membership_person_profile_rec_li_result)
|
||||
|
||||
return membership_person_profile_rec_li
|
||||
# ### END ### API Membership Person Profile Methods ### get_membership_person_profile_rec_list() ###
|
||||
325
app/methods/membership_person_type_methods.py
Normal file
325
app/methods/membership_person_type_methods.py
Normal file
@@ -0,0 +1,325 @@
|
||||
from __future__ import annotations
|
||||
import datetime, json
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
# from app.methods.membership_person_methods import get_membership_person_rec_list, load_membership_person_obj
|
||||
from app.methods.membership_cfg_methods import load_membership_cfg_obj
|
||||
from app.methods.product_methods import get_product_rec_list, load_product_obj
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
from app.models.membership_person_type_models import Membership_Person_Type_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Type Person Methods ### load_membership_person_type_obj() ###
|
||||
# Updated 2021-07-09
|
||||
@logger_reset
|
||||
def load_membership_person_type_obj(
|
||||
membership_person_type_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_address: bool = False,
|
||||
inc_contact: bool = False,
|
||||
inc_membership_cfg: bool = False,
|
||||
inc_membership_group: bool = False,
|
||||
inc_membership_group_list: bool = False,
|
||||
inc_membership_person: bool = False,
|
||||
inc_membership_person_profile: bool = False,
|
||||
inc_membership_type: bool = False,
|
||||
inc_organization: bool = False,
|
||||
inc_product: bool = False,
|
||||
inc_product_list: bool = False,
|
||||
inc_person: bool = False,
|
||||
) -> Membership_Person_Type_Base|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if membership_person_type_id := redis_lookup_id_random(record_id_random=membership_person_type_id, table_name='membership_person_type'): pass
|
||||
else: return False
|
||||
log.debug(membership_person_type_id)
|
||||
|
||||
if membership_person_type_rec := sql_select(table_name='v_membership_person_type', record_id=membership_person_type_id):
|
||||
log.debug(membership_person_type_rec)
|
||||
else: return False
|
||||
log.debug(membership_person_type_rec)
|
||||
|
||||
try:
|
||||
membership_person_type_obj = Membership_Person_Type_Base(**membership_person_type_rec)
|
||||
log.debug(membership_person_type_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
# Updated 2021-06-24
|
||||
if inc_membership_cfg:
|
||||
if membership_cfg_obj_result := load_membership_cfg_obj(
|
||||
account_id = membership_person_type_rec.get('account_id', None),
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
membership_person_type_obj.membership_cfg = membership_cfg_obj_result
|
||||
else: membership_person_type_obj.membership_cfg = None
|
||||
|
||||
# Updated 2021-06-21
|
||||
if inc_membership_person:
|
||||
from app.methods.membership_person_methods import load_membership_person_obj
|
||||
membership_person_id = membership_person_type_rec.get('membership_person_id', None)
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(membership_person_id)
|
||||
if membership_person_result := load_membership_person_obj(
|
||||
membership_person_id = membership_person_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
inc_address = inc_address,
|
||||
inc_contact = inc_contact,
|
||||
inc_membership_person_profile = inc_membership_person_profile,
|
||||
inc_membership_type = inc_membership_type,
|
||||
inc_organization = inc_organization,
|
||||
inc_person = inc_person,
|
||||
inc_user = inc_user,
|
||||
):
|
||||
membership_person_type_obj.membership_person = membership_person_result
|
||||
else: membership_person_type_obj.membership_person = None
|
||||
log.debug(membership_person_result)
|
||||
|
||||
# Updated 2021-07-09
|
||||
if inc_membership_type: # The primary membership type for the person
|
||||
from app.methods.membership_type_methods import load_membership_type_obj
|
||||
membership_type_id = membership_person_type_rec.get('membership_type_id', None)
|
||||
log.debug(membership_type_id)
|
||||
if membership_type_result := load_membership_type_obj(
|
||||
membership_type_id = membership_type_id,
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
# inc_membership_cfg = inc_membership_cfg,
|
||||
inc_product_list = inc_product_list,
|
||||
):
|
||||
membership_person_type_obj.membership_type = membership_type_result
|
||||
else: membership_person_type_obj.membership_type = None
|
||||
log.debug(membership_type_result)
|
||||
|
||||
# Updated 2021-07-09
|
||||
if inc_product:
|
||||
product_id = membership_person_type_rec.get('product_id', None)
|
||||
log.debug(product_id)
|
||||
if product_result := load_product_obj(
|
||||
product_id = product_id,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
membership_person_type_obj.product = product_result
|
||||
else: membership_person_type_obj.product = None
|
||||
log.debug(product_result)
|
||||
|
||||
if model_as_dict:
|
||||
return membership_person_type_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return membership_person_type_obj
|
||||
# ### END ### API Membership Type Person Methods ### load_membership_person_type_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Type Person Methods ### get_membership_person_type_rec_list() ###
|
||||
def get_membership_person_type_rec_list(
|
||||
for_obj_type: str,
|
||||
for_obj_id: str,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
else: return False
|
||||
data = {}
|
||||
data[f'{for_obj_type}_id'] = for_obj_id
|
||||
# data['for_obj_type'] = for_obj_type
|
||||
sql_obj_type_id = f'`tbl`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `tbl`.id AS 'membership_person_type_id', `tbl`.id_random AS 'membership_person_type_id_random'
|
||||
FROM `membership_person_type` AS `tbl`
|
||||
WHERE
|
||||
{sql_obj_type_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(sql)
|
||||
|
||||
if membership_person_type_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
membership_person_type_rec_li = membership_person_type_rec_li_result
|
||||
else:
|
||||
membership_person_type_rec_li = []
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(membership_person_type_rec_li_result)
|
||||
|
||||
return membership_person_type_rec_li
|
||||
# ### END ### API Membership Type Person Methods ### get_membership_person_type_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Type Person Methods ### create_membership_person_type_obj() ###
|
||||
def create_membership_person_type_obj(
|
||||
membership_person_id: int|str,
|
||||
membership_person_type_dict_obj: Membership_Person_Type_Base,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_outline: bool = False,
|
||||
) -> bool|dict|int:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
log.info('Checking requirements...')
|
||||
if membership_person_id := redis_lookup_id_random(record_id_random=membership_person_id, table_name='membership_person'): pass
|
||||
else:
|
||||
log.error('Missing or invalid Membership Person ID passed. Failed requirement.')
|
||||
log.info(f'Membership Person ID: {membership_person_id}')
|
||||
return False
|
||||
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(membership_person_type_dict_obj))
|
||||
if isinstance(membership_person_type_dict_obj, dict):
|
||||
membership_person_type_dict = membership_person_type_dict_obj
|
||||
try:
|
||||
membership_person_type_obj = Membership_Person_Type_Base(**membership_person_type_dict)
|
||||
log.debug(membership_person_type_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
membership_person_type_obj = membership_person_type_dict_obj
|
||||
membership_person_type_obj.membership_person_id = membership_person_id
|
||||
|
||||
membership_person_type_dict = membership_person_type_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'membership_cfg', 'membership_type', 'membership_type_list', 'product', 'created_on', 'updated_on'})
|
||||
|
||||
# ### SECTION ### Process data
|
||||
membership_person_type_obj.membership_person_id = membership_person_id # Is this needed?
|
||||
membership_person_type_dict['membership_person_id'] = membership_person_id
|
||||
|
||||
if membership_person_type_dict_in_result := sql_insert(
|
||||
data = membership_person_type_dict,
|
||||
table_name = 'membership_person_type',
|
||||
rm_id_random = True,
|
||||
id_random_length = default_num_bytes
|
||||
): pass
|
||||
else:
|
||||
log.warning(f'Membership Person Type not created.')
|
||||
log.debug(membership_person_type_dict_in_result)
|
||||
return False
|
||||
|
||||
log.debug(membership_person_type_dict_in_result)
|
||||
membership_person_type_id = membership_person_type_dict_in_result
|
||||
|
||||
membership_person_data = {}
|
||||
membership_person_data['id'] = membership_person_id
|
||||
membership_person_data['membership_person_type_id'] = membership_person_type_id
|
||||
|
||||
# NOTE: Need to update the membership_person record with the new primary membership person type record.
|
||||
# NOTE: This makes it so that there is only one primary type.
|
||||
if membership_person_dict_up_result := sql_update(
|
||||
data = membership_person_data,
|
||||
table_name = 'membership_person',
|
||||
rm_id_random = True
|
||||
):
|
||||
log.debug(f'Returning True')
|
||||
log.debug(membership_person_dict_up_result)
|
||||
else:
|
||||
log.warning(f'Membership Person not updated with the new Membership Person Type ID. Membership Person ID: {membership_person_id}; Membership Person Type ID: {membership_person_type_id}')
|
||||
log.debug(membership_person_type_dict_up_result)
|
||||
return False
|
||||
|
||||
log.info(f'Returning the Membership Person Type ID: {membership_person_type_id}')
|
||||
|
||||
return membership_person_type_id
|
||||
# ### END ### API Membership Type Person Methods ### create_membership_person_type_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Type Person Methods ### update_membership_person_type_obj() ###
|
||||
def update_membership_person_type_obj(
|
||||
membership_person_type_id: int|str, # This allows for updating of the id_random value.
|
||||
membership_person_type_dict_obj: Membership_Person_Type_Base,
|
||||
fail_any: bool = False, # Fail if any thing goes wrong for sub objects
|
||||
return_outline: bool = False,
|
||||
) -> bool|dict:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
log.info('Checking requirements...')
|
||||
if membership_person_type_id := redis_lookup_id_random(record_id_random=membership_person_type_id, table_name='membership_person_type'): pass
|
||||
else:
|
||||
log.error('Membership Person Type ID passed but is invalid. Failed requirement.')
|
||||
return False
|
||||
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(membership_person_type_dict_obj))
|
||||
if isinstance(membership_person_type_dict_obj, dict):
|
||||
membership_person_type_dict = membership_person_type_dict_obj
|
||||
try:
|
||||
membership_person_type_obj = Membership_Person_Type_Base(**membership_person_type_dict)
|
||||
log.debug(membership_person_type_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
membership_person_type_obj = membership_person_type_dict_obj
|
||||
|
||||
membership_person_type_dict = membership_person_type_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'membership_cfg', 'membership_type', 'membership_type_list', 'product', 'created_on', 'updated_on'})
|
||||
|
||||
# ### SECTION ### Process data
|
||||
membership_person_type_obj.id = membership_person_type_id # Is this needed?
|
||||
membership_person_type_dict['id'] = membership_person_type_id
|
||||
|
||||
log.debug(membership_person_type_obj)
|
||||
log.debug(membership_person_type_obj.dict(by_alias=False, exclude_unset=True))
|
||||
# log.debug(membership_person_type_obj.dict(by_alias=False, exclude_unset=False))
|
||||
|
||||
membership_person_type_dict = membership_person_type_obj.dict(by_alias=False, exclude_unset=True)
|
||||
log.debug(membership_person_type_dict)
|
||||
|
||||
if membership_person_type_dict_up_result := sql_update(
|
||||
data = membership_person_type_dict,
|
||||
table_name = 'membership_person_type',
|
||||
rm_id_random = True
|
||||
):
|
||||
log.debug(f'Returning True')
|
||||
log.debug(membership_person_type_dict_up_result)
|
||||
return True
|
||||
elif membership_person_type_dict_up_result is None:
|
||||
log.debug(f'Returning True')
|
||||
log.debug(membership_person_type_dict_up_result)
|
||||
return None
|
||||
else:
|
||||
log.warning(f'Membership Person Type not updated.')
|
||||
log.debug(membership_person_type_dict_up_result)
|
||||
return False
|
||||
# ### END ### API Membership Type Person Methods ### update_membership_person_type_obj() ###
|
||||
259
app/methods/membership_type_methods.py
Normal file
259
app/methods/membership_type_methods.py
Normal file
@@ -0,0 +1,259 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.lib_general import log, logging
|
||||
from app.db_sql import redis_lookup_id_random, sql_select
|
||||
|
||||
from app.methods.membership_cfg_methods import load_membership_cfg_obj
|
||||
from app.methods.membership_person_methods import get_membership_person_rec_list, load_membership_person_obj
|
||||
from app.methods.product_methods import get_product_rec_list, load_product_obj
|
||||
|
||||
from app.models.membership_type_models import Membership_Type_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Type Methods ### load_membership_type_obj() ###
|
||||
def load_membership_type_obj(
|
||||
membership_type_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_address: bool = False,
|
||||
inc_contact: bool = False,
|
||||
inc_membership_cfg: bool = False,
|
||||
inc_membership_group_list: bool = False, # under membership_person
|
||||
inc_membership_person_group_list: bool = False,
|
||||
inc_membership_person_list: bool = False,
|
||||
inc_membership_person_profile: bool = False, # under membership_person
|
||||
inc_organization: bool = False,
|
||||
inc_person: bool = False,
|
||||
inc_product: bool = False, # Per membership member
|
||||
inc_product_list: bool = False, # One or more er membership type
|
||||
inc_user: bool = False,
|
||||
) -> Membership_Type_Base:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if membership_type_id := redis_lookup_id_random(record_id_random=membership_type_id, table_name='membership_type'): pass
|
||||
else: return False
|
||||
|
||||
if membership_type_rec := sql_select(table_name='v_membership_type', record_id=membership_type_id): pass
|
||||
else: return False
|
||||
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(membership_type_rec)
|
||||
|
||||
try:
|
||||
membership_type_obj = Membership_Type_Base(**membership_type_rec)
|
||||
log.debug(membership_type_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
# Updated 2021-06-23
|
||||
if inc_membership_cfg:
|
||||
if membership_cfg_result := load_membership_cfg_obj(
|
||||
account_id = membership_type_rec.get('account_id', None),
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
membership_type_obj.cfg = membership_cfg_result
|
||||
else: membership_type_obj.cfg = None
|
||||
|
||||
# Updated 2021-06-23
|
||||
if inc_membership_person_list:
|
||||
if membership_person_rec_list_result := get_membership_person_rec_list(
|
||||
for_obj_type = 'membership_type',
|
||||
for_obj_id = membership_type_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
membership_person_result_list = []
|
||||
for membership_person_rec in membership_person_rec_list_result:
|
||||
if load_membership_person_result := load_membership_person_obj(
|
||||
membership_person_id = membership_person_rec.get('membership_person_id', None),
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
inc_membership_person_group_list = inc_membership_person_group_list,
|
||||
inc_membership_person_profile = inc_membership_person_profile,
|
||||
# inc_organization = inc_organization,
|
||||
inc_person = inc_person,
|
||||
# inc_product = inc_product,
|
||||
):
|
||||
membership_person_result_list.append(load_membership_person_result)
|
||||
else: membership_person_result_list.append(None)
|
||||
membership_type_obj.membership_person_list = membership_person_result_list
|
||||
else: membership_type_obj.membership_person_list = []
|
||||
|
||||
# Updated 2021-06-23
|
||||
if inc_product_list:
|
||||
if product_rec_list_result := get_product_rec_list(
|
||||
for_obj_type = 'membership_type',
|
||||
for_obj_id = membership_type_id,
|
||||
# prod_type = prod_type,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
product_result_list = []
|
||||
for product_rec in product_rec_list_result:
|
||||
product_result_list.append(
|
||||
load_product_obj(
|
||||
product_id = product_rec.get('product_id', None),
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
)
|
||||
)
|
||||
membership_type_obj.product_list = product_result_list
|
||||
else: membership_type_obj.product_list = []
|
||||
|
||||
if model_as_dict:
|
||||
return membership_type_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return membership_type_obj
|
||||
# ### END ### API Membership Type Methods ### load_membership_type_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Type Methods ### get_membership_type_rec_list() ###
|
||||
def get_membership_type_rec_list(
|
||||
account_id: str = None,
|
||||
# product_id: str = None,
|
||||
type_level: int = None,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
# if product_id := redis_lookup_id_random(record_id_random=product_id, table_name='product'): pass
|
||||
|
||||
data = {}
|
||||
data['account_id'] = account_id
|
||||
# data['product_id'] = product_id
|
||||
data['level'] = type_level
|
||||
|
||||
if account_id:
|
||||
sql_account_id = f'`membership_type`.account_id = :account_id'
|
||||
else: sql_account_id = ''
|
||||
|
||||
# if product_id:
|
||||
# sql_product_id = f'`membership_type`.product_id = :product_id'
|
||||
# else: sql_product_id = ''
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `membership_type`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `membership_type`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
else: sql_enabled = ''
|
||||
|
||||
if type_level:
|
||||
sql_type_level = f"""AND membership_type.level = :level"""
|
||||
else: sql_type_level = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `membership_type`.id AS 'membership_type_id', `membership_type`.id_random AS 'membership_type_id_random'
|
||||
FROM `v_membership_type` AS `membership_type`
|
||||
WHERE
|
||||
{sql_account_id}
|
||||
{sql_type_level}
|
||||
{sql_enabled}
|
||||
ORDER BY -`membership_type`.sort DESC, `membership_type`.created_on DESC, `membership_type`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(sql)
|
||||
|
||||
if membership_type_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
membership_type_rec_li = membership_type_rec_li_result
|
||||
else:
|
||||
membership_type_rec_li = []
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(membership_type_rec_li_result)
|
||||
|
||||
return membership_type_rec_li
|
||||
# ### END ### API Membership Type Methods ### get_membership_type_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Type Methods ### create_membership_type_obj() ###
|
||||
def create_membership_type_obj(
|
||||
membership_type_dict_obj: Membership_Type_Base
|
||||
) -> bool|dict|int:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
return membership_type_id
|
||||
# ### END ### API Membership Type Methods ### create_membership_type_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Membership Type Methods ### get_membership_type_rec_list() ###
|
||||
# def get_membership_type_rec_list(
|
||||
# for_obj_type: str,
|
||||
# for_obj_id: str,
|
||||
# limit: int = 1000,
|
||||
# enabled: str = 'enabled', # enabled, disabled, all
|
||||
# ) -> list|bool:
|
||||
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(locals())
|
||||
|
||||
# if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
# else: return False
|
||||
# data = {}
|
||||
# data[f'{for_obj_type}_id'] = for_obj_id
|
||||
# # data['for_obj_type'] = for_obj_type
|
||||
# sql_obj_type_id = f'`tbl`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
# if enabled in ['enabled', 'disabled', 'all']:
|
||||
# if enabled == 'enabled':
|
||||
# data['enable'] = True
|
||||
# sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
# elif enabled == 'disabled':
|
||||
# data['enable'] = False
|
||||
# sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
# elif enabled == 'all':
|
||||
# sql_enabled = ''
|
||||
|
||||
# if limit:
|
||||
# data['limit'] = limit
|
||||
# sql_limit = f'LIMIT :limit'
|
||||
# else:
|
||||
# sql_limit = ''
|
||||
|
||||
# sql = f"""
|
||||
# SELECT `tbl`.id AS 'membership_type_id', `tbl`.id_random AS 'membership_type_id_random'
|
||||
# FROM `membership_type` AS `tbl`
|
||||
# WHERE
|
||||
# {sql_obj_type_id}
|
||||
# {sql_enabled}
|
||||
# ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
|
||||
# {sql_limit};
|
||||
# """
|
||||
|
||||
# if membership_type_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
# membership_type_rec_li = membership_type_rec_li_result
|
||||
# else:
|
||||
# membership_type_rec_li = []
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(membership_type_rec_li_result)
|
||||
|
||||
# return membership_type_rec_li
|
||||
# ### END ### API Membership Type Methods ### get_membership_type_rec_list() ###
|
||||
187
app/methods/order_cart_line_methods.py
Normal file
187
app/methods/order_cart_line_methods.py
Normal file
@@ -0,0 +1,187 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging
|
||||
|
||||
|
||||
from app.models.order_cart_line_models import Order_Cart_Line_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Cart Line Methods ### create_order_cart_line_obj() ###
|
||||
def create_order_cart_line_obj(order_cart_line_obj_new:Order_Cart_Line_Base):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if not order_cart_line_obj_new:
|
||||
return False
|
||||
|
||||
# Something needs to be added to lookup the current product information and copy that into the order_cart_line. Also knowing this will eventually be order_line.
|
||||
|
||||
order_cart_line_obj_data = order_cart_line_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'user', 'created_on', 'updated_on'})
|
||||
|
||||
if order_cart_line_obj_in_result := sql_insert(data=order_cart_line_obj_data, table_name='order_cart_line', rm_id_random=True, id_random_length=8): pass
|
||||
else:
|
||||
return False
|
||||
|
||||
log.debug(order_cart_line_obj_in_result)
|
||||
|
||||
order_cart_line_id = order_cart_line_obj_in_result
|
||||
|
||||
log.debug(f'Returning the new order_cart_line_id: {order_cart_line_id}')
|
||||
return order_cart_line_id
|
||||
# ### END ### API Order Cart Line Methods ### create_order_cart_line_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Cart Line Methods ### load_order_cart_line_obj() ###
|
||||
def load_order_cart_line_obj(
|
||||
order_cart_line_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
) -> Order_Cart_Line_Base|dict|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if order_cart_line_id := redis_lookup_id_random(record_id_random=order_cart_line_id, table_name='order_cart_line'): pass
|
||||
else: return False
|
||||
|
||||
if order_cart_line_rec := sql_select(table_name='v_order_cart_line', record_id=order_cart_line_id): pass
|
||||
else: return False
|
||||
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(order_cart_line_rec)
|
||||
|
||||
try:
|
||||
order_cart_line_obj = Order_Cart_Line_Base(**order_cart_line_rec)
|
||||
log.debug(order_cart_line_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
if model_as_dict:
|
||||
return order_cart_line_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return order_cart_line_obj
|
||||
# ### END ### API Order Cart Line Methods ### load_order_cart_line_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Cart Line Methods ### update_order_cart_line_obj() ###
|
||||
def update_order_cart_line_obj(
|
||||
order_cart_line_id: int|str, # Ideally the int ID should be passed. This allows for updating of the id_random value.
|
||||
order_cart_line_obj_up: Order_Cart_Line_Base,
|
||||
create_sub_obj: bool = False,
|
||||
) -> bool:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if order_cart_line_id := redis_lookup_id_random(record_id_random=order_cart_line_id, table_name='order_cart_line'): pass
|
||||
else: return False
|
||||
|
||||
order_cart_line_obj_up.id = order_cart_line_id
|
||||
|
||||
log.debug(order_cart_line_obj_up)
|
||||
# log.debug(order_cart_line_obj_up.dict(by_alias=True, exclude_unset=True))
|
||||
log.debug(order_cart_line_obj_up.dict(by_alias=False, exclude_unset=True))
|
||||
# log.debug(order_cart_line_obj_up.dict(by_alias=False, exclude_unset=False))
|
||||
|
||||
#order_cart_line_dict_up = order_cart_line_obj_up.dict(by_alias=False, exclude_unset=True)
|
||||
|
||||
# if order_cart_line_obj_up.person_id and order_cart_line_obj_up.person:
|
||||
# person_id = order_cart_line_obj_up.person_id
|
||||
# person_obj_up = order_cart_line_obj_up.person
|
||||
# log.debug(person_id)
|
||||
# log.debug(person_obj_up)
|
||||
# if person_obj_up_result := update_person_obj(
|
||||
# person_id = person_id,
|
||||
# person_obj_up = person_obj_up,
|
||||
# create_sub_obj = create_sub_obj,
|
||||
# ):
|
||||
# log.debug(person_obj_up_result)
|
||||
# else:
|
||||
# log.debug(person_obj_up_result)
|
||||
# return False
|
||||
|
||||
# if order_cart_line_obj_up.user_id and order_cart_line_obj_up.user:
|
||||
# user_id = order_cart_line_obj_up.user_id
|
||||
# user_obj_up = order_cart_line_obj_up.user
|
||||
# log.debug(user_id)
|
||||
# log.debug(user_obj_up)
|
||||
# if user_obj_up_result := update_user_obj(
|
||||
# user_id = user_id,
|
||||
# user_dict_obj = user_obj_up,
|
||||
# create_sub_obj = create_sub_obj,
|
||||
# ):
|
||||
# log.debug(user_obj_up_result)
|
||||
# else:
|
||||
# log.debug(user_obj_up_result)
|
||||
# return False
|
||||
|
||||
order_cart_line_dict_up = order_cart_line_obj_up.dict(by_alias=False, exclude_unset=True, exclude={'user'})
|
||||
log.debug(order_cart_line_dict_up)
|
||||
|
||||
if order_cart_line_obj_up_result := sql_update(data=order_cart_line_dict_up, table_name='order_cart_line', rm_id_random=True):
|
||||
log.debug(order_cart_line_obj_up_result)
|
||||
return True
|
||||
else:
|
||||
log.debug(order_cart_line_obj_up_result)
|
||||
return False
|
||||
# ### END ### API Order Cart Line Methods ### update_order_cart_line_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Cart Line Methods ### get_order_cart_line_rec_list() ###
|
||||
def get_order_cart_line_rec_list(
|
||||
for_obj_type: str,
|
||||
for_obj_id: str,
|
||||
limit: int = 1000,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
else: return False
|
||||
data = {}
|
||||
data[f'{for_obj_type}_id'] = for_obj_id
|
||||
# data['for_obj_type'] = for_obj_type
|
||||
sql_obj_type_id = f'`tbl`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
# if enabled in ['enabled', 'disabled', 'all']:
|
||||
# if enabled == 'enabled':
|
||||
# data['enable'] = True
|
||||
# sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
# elif enabled == 'disabled':
|
||||
# data['enable'] = False
|
||||
# sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
# elif enabled == 'all':
|
||||
# sql_enabled = ''
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `tbl`.id AS 'order_cart_line_id', `tbl`.id_random AS 'order_cart_line_id_random'
|
||||
FROM `order_cart_line` AS `tbl`
|
||||
WHERE
|
||||
{sql_obj_type_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if order_cart_line_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
order_cart_line_rec_li = order_cart_line_rec_li_result
|
||||
else:
|
||||
order_cart_line_rec_li = []
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(order_cart_line_rec_li_result)
|
||||
|
||||
return order_cart_line_rec_li
|
||||
# ### END ### API Order Cart Line Methods ### get_order_cart_line_rec_list() ###
|
||||
427
app/methods/order_cart_methods.py
Normal file
427
app/methods/order_cart_methods.py
Normal file
@@ -0,0 +1,427 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.lib_general import log, logging
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert_or_update, sql_insert, sql_update, sql_select
|
||||
|
||||
from app.methods.order_cart_line_methods import get_order_cart_line_rec_list, load_order_cart_line_obj
|
||||
from app.methods.order_cfg_methods import load_order_cfg_obj
|
||||
|
||||
from app.models.order_cart_models import Order_Cart_Base
|
||||
from app.models.order_cart_line_models import Order_Cart_Line_Base
|
||||
|
||||
|
||||
def update_order_cart_obj(
|
||||
order_cart_obj: Order_Cart_Base,
|
||||
repl_order_cart_line_list: bool = False,
|
||||
) -> bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if order_cart_obj.account_id_random and (order_cart_obj.person_id_random or order_cart_obj.user_id_random):
|
||||
log.info(f'An account.id_random {order_cart_obj.account_id_random} was passed. And either a person.id_random {order_cart_obj.person_id_random} or user.id_random {order_cart_obj.user_id_random} was passed. We can update the order cart.')
|
||||
elif order_cart_obj.account_id_random and not (order_cart_obj.person_id_random or order_cart_obj.user_id_random):
|
||||
log.info(f'An account.id_random {order_cart_obj.account_id_random} was passed. A person.id_random {order_cart_obj.person_id_random} or user.id_random {order_cart_obj.user_id_random} was not passed. We can update the order cart without one of those.')
|
||||
else:
|
||||
log.error('An account ID. A person ID or user ID is not required until starting to process an order.')
|
||||
return False
|
||||
|
||||
#if order_cart_id := redis_lookup_id_random(record_id_random=order_cart_id_random, table_name='order_cart'): pass
|
||||
#else: return False
|
||||
|
||||
order_cart_id_random = order_cart_obj.id_random # id_random because can't ref the alias
|
||||
#log.setLevel(logging.DEBUG)
|
||||
log.debug(order_cart_obj.id)
|
||||
log.debug(order_cart_id_random)
|
||||
if order_cart_id := redis_lookup_id_random(record_id_random=order_cart_id_random, table_name='order_cart'): pass
|
||||
else: return False
|
||||
|
||||
# log.setLevel(logging.DEBUG)
|
||||
log.info('Loop through lines to update and calculate totals')
|
||||
|
||||
# Calculate totals
|
||||
order_cart_total_amount: int = 0
|
||||
order_cart_total_quantity: int = 0
|
||||
for order_cart_line_obj in order_cart_obj.order_cart_line_list:
|
||||
log.debug(order_cart_line_obj)
|
||||
|
||||
order_cart_line_obj.order_cart_id = order_cart_id
|
||||
order_cart_line_obj.order_cart_id_random = order_cart_id_random
|
||||
|
||||
log.setLevel(logging.DEBUG)
|
||||
if product_sql_select_result := sql_select(table_name='product', record_id=order_cart_line_obj.product_id):
|
||||
product_obj = product_sql_select_result
|
||||
log.debug(product_sql_select_result)
|
||||
|
||||
order_cart_line_obj_data = order_cart_line_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'product_type_id', 'product_type', 'created_on', 'updated_on'})
|
||||
|
||||
# log.setLevel(logging.DEBUG)
|
||||
log.debug(order_cart_line_obj_data)
|
||||
|
||||
data = {}
|
||||
data['order_cart_id'] = order_cart_id
|
||||
data['product_id'] = order_cart_line_obj.product_id
|
||||
|
||||
order_cart_line_obj_data['product_for_type'] = product_obj.get('for_type', None)
|
||||
order_cart_line_obj_data['product_for_id'] = product_obj.get('for_id', None)
|
||||
order_cart_line_obj_data['product_type_id'] = product_obj.get('type_id', None)
|
||||
order_cart_line_obj_data['product_name'] = product_obj.get('name', None)
|
||||
order_cart_line_obj_data['product_unit_price'] = product_obj.get('unit_price', None)
|
||||
order_cart_line_obj_data['product_recurring'] = product_obj.get('recurring', None)
|
||||
|
||||
sql_select_result = sql_select(table_name='order_cart_line', data=data, rm_id_random=True)
|
||||
# log.setLevel(logging.DEBUG)
|
||||
log.debug(sql_select_result)
|
||||
|
||||
if sql_select_result:
|
||||
# log.setLevel(logging.DEBUG)
|
||||
log.info('A matching order cart line was found. Update...')
|
||||
if order_cart_line_obj_up_result := sql_update(
|
||||
data = order_cart_line_obj_data,
|
||||
table_name = 'order_cart_line',
|
||||
record_id = sql_select_result.get('id'),
|
||||
rm_id_random = True,
|
||||
id_random_length = 8,
|
||||
): pass
|
||||
else:
|
||||
log.error('Something went wrong while trying to update an order cart line record.')
|
||||
return False
|
||||
else:
|
||||
# log.setLevel(logging.DEBUG)
|
||||
log.info('A matching order cart line was not found. Insert...')
|
||||
if order_cart_line_obj_in_result := sql_insert(data=order_cart_line_obj_data, table_name='order_cart_line', rm_id_random=True, id_random_length=8): pass
|
||||
else:
|
||||
log.error('Something went wrong while trying to insert an order cart line record.')
|
||||
return False
|
||||
|
||||
# order_cart_total_amount += order_cart_line_obj.quantity * order_cart_line_obj.amount
|
||||
# order_cart_total_quantity += order_cart_line_obj.quantity
|
||||
|
||||
order_cart_line_data = {}
|
||||
order_cart_line_data['order_cart_id'] = order_cart_id
|
||||
|
||||
if order_cart_line_sql_select_result := sql_select(table_name='order_cart_line', data=order_cart_line_data, rm_id_random=True, as_list=True):
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.debug(sql_select_result)
|
||||
|
||||
for order_cart_line_rec in order_cart_line_sql_select_result:
|
||||
log.debug(order_cart_line_rec)
|
||||
|
||||
quantity = order_cart_line_rec.get('quantity', 0)
|
||||
amount = order_cart_line_rec.get('amount', 0)
|
||||
|
||||
order_cart_total_amount += quantity * amount
|
||||
order_cart_total_quantity += quantity
|
||||
|
||||
order_cart_obj_new = {}
|
||||
order_cart_obj_new['id'] = order_cart_id
|
||||
order_cart_obj_new['account_id_random'] = order_cart_obj.account_id_random
|
||||
order_cart_obj_new['person_id_random'] = order_cart_obj.person_id_random
|
||||
# order_cart_obj_new['user_id_random'] = order_cart_obj.user_id_random
|
||||
|
||||
order_cart_obj_new['order_id_random'] = order_cart_obj.order_id_random
|
||||
|
||||
order_cart_obj_new['total_amount'] = order_cart_total_amount
|
||||
order_cart_obj_new['total_quantity'] = order_cart_total_quantity
|
||||
|
||||
order_cart_obj_new['notes'] = order_cart_obj.notes
|
||||
|
||||
if order_cart_obj_resp := sql_update(data=order_cart_obj_new, table_name='order_cart', rm_id_random=True): pass
|
||||
else:
|
||||
log.error('Something went wrong while trying to update an order cart record.')
|
||||
return False
|
||||
|
||||
return False
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Cart Methods ### load_order_cart_obj() ###
|
||||
# Updated 2021-08-07
|
||||
def load_order_cart_obj(
|
||||
order_cart_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_order_cart_line_list: bool = False,
|
||||
inc_order_cfg: bool = False,
|
||||
) -> Order_Cart_Base|dict|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if order_cart_id := redis_lookup_id_random(record_id_random=order_cart_id, table_name='order_cart'): pass
|
||||
else: return False
|
||||
|
||||
if order_cart_rec := sql_select(table_name='v_order_cart', record_id=order_cart_id): pass
|
||||
else: return False
|
||||
|
||||
#log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(order_cart_rec)
|
||||
|
||||
try:
|
||||
order_cart_obj = Order_Cart_Base(**order_cart_rec)
|
||||
log.debug(order_cart_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
# Updated 2021-08-07
|
||||
if inc_order_cart_line_list:
|
||||
if order_cart_line_rec_list_result := get_order_cart_line_rec_list(
|
||||
for_obj_type = 'order_cart',
|
||||
for_obj_id = order_cart_id,
|
||||
limit = limit,
|
||||
):
|
||||
order_cart_line_result_list = []
|
||||
for order_cart_line_rec in order_cart_line_rec_list_result:
|
||||
order_cart_line_result_list.append(
|
||||
load_order_cart_line_obj(
|
||||
order_cart_line_id = order_cart_line_rec.get('order_cart_line_id', None),
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
)
|
||||
)
|
||||
order_cart_obj.order_cart_line_list = order_cart_line_result_list
|
||||
else: order_cart_obj.order_cart_line_list = []
|
||||
|
||||
if inc_order_cfg:
|
||||
if order_cfg_result := load_order_cfg_obj(
|
||||
account_id = order_cart_rec.get('account_id', None),
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
order_cart_obj.cfg = order_cfg_result
|
||||
else: order_cart_obj.cfg = None
|
||||
|
||||
if model_as_dict:
|
||||
return order_cart_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return order_cart_obj
|
||||
# ### END ### API Order Cart Methods ### load_order_cart_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Cart Methods ### get_order_cart_rec_list() ###
|
||||
# Updated 2021-08-07
|
||||
def get_order_cart_rec_list(
|
||||
for_obj_type: str,
|
||||
for_obj_id: str,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
from_datetime: datetime.datetime = None,
|
||||
to_datetime: datetime.datetime = None,
|
||||
# status: str = 'complete', # started, in progress, complete, all
|
||||
balance_gt: int = 0, # $0 to $99999
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
else: return False
|
||||
data = {}
|
||||
data[f'{for_obj_type}_id'] = for_obj_id
|
||||
# data['for_obj_type'] = for_obj_type
|
||||
sql_obj_type_id = f'`tbl`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `tbl`.id AS 'order_cart_id', `tbl`.id_random AS 'order_cart_id_random'
|
||||
FROM `order` AS `tbl`
|
||||
WHERE
|
||||
{sql_obj_type_id}
|
||||
ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if order_cart_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
order_cart_rec_li = order_cart_rec_li_result
|
||||
else:
|
||||
order_cart_rec_li = []
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(order_cart_rec_li_result)
|
||||
|
||||
return order_cart_rec_li
|
||||
# ### END ### API Order Cart Methods ### get_order_cart_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Cart Methods ### get_order_cart_id_for_person_id() ###
|
||||
# Updated 2021-11-16
|
||||
def get_order_cart_id_for_person_id(
|
||||
person_id: int|str,
|
||||
) -> bool|int|None:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if person_id := redis_lookup_id_random(record_id_random=person_id, table_name='person'): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['person_id'] = person_id
|
||||
|
||||
sql = f"""
|
||||
SELECT `order_cart`.id AS 'order_cart_id', `order_cart`.id_random AS 'order_cart_id_random', `order_cart`.person_id AS person_id
|
||||
FROM `order_cart` AS `order_cart`
|
||||
WHERE `order_cart`.person_id = :person_id
|
||||
LIMIT 1;
|
||||
"""
|
||||
|
||||
if order_cart_data_result := sql_select(data=data, sql=sql):
|
||||
log.debug(order_cart_data_result)
|
||||
if order_cart_id := order_cart_data_result.get('order_cart_id', None): return order_cart_id
|
||||
else: return False
|
||||
else: return None
|
||||
# ### END ### API Order Cart Methods ### get_order_cart_id_for_person_id() ###
|
||||
|
||||
|
||||
|
||||
|
||||
# IS THIS STILL NEEDED?
|
||||
# ### BEGIN ### API Order Cart Model ### save_order_cart_obj() ###
|
||||
def old_save_order_cart_obj(order_cart_obj_new=None):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if not order_cart_obj_new:
|
||||
return False
|
||||
|
||||
#log.debug(order_cart_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True))
|
||||
|
||||
# Get the current order_cart_line li to compare with what was sent
|
||||
data = {}
|
||||
data['order_cart_id_random'] = order_cart_obj_new.id_random
|
||||
if order_cart_line_rec_li_curr := sql_select(table_name='v_order_cart_line', data=data, rm_id_random=True, as_list=True):
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
#log.debug(order_cart_line_rec_li_curr)
|
||||
order_cart_line_obj_li_curr = []
|
||||
for order_cart_line_rec in order_cart_line_rec_li_curr:
|
||||
|
||||
try:
|
||||
order_cart_line_obj = Order_Cart_Line_Base(**order_cart_line_rec)
|
||||
log.debug(order_cart_line_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
order_cart_line_obj_li_curr.append(order_cart_line_obj)
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(order_cart_line_obj_li_curr)
|
||||
else:
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(order_cart_line_rec_li_curr)
|
||||
order_cart_line_obj_li_curr = []
|
||||
|
||||
# Loop through the line list that was sent and compare with what was pulled from the DB
|
||||
# Only insert if a product ID does not match
|
||||
# Only update if a product ID does match
|
||||
for order_cart_line_obj_new in order_cart_obj_new.order_cart_line_list:
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
if not any(order_cart_line_obj_curr.product_id_random == order_cart_line_obj_new.product_id_random for order_cart_line_obj_curr in order_cart_line_obj_li_curr):
|
||||
# Need to append to current list
|
||||
log.info('Need to append to current list')
|
||||
order_cart_line_obj_li_curr.append(order_cart_line_obj_new)
|
||||
else:
|
||||
# Need to update a current list item ... loop through to find
|
||||
log.info('Need to update a current list item ... loop through to find')
|
||||
for index, order_cart_line_obj_curr in enumerate(order_cart_line_obj_li_curr):
|
||||
log.info(index)
|
||||
if order_cart_line_obj_new.product_id_random == order_cart_line_obj_curr.product_id_random:
|
||||
log.info(f'Match: {order_cart_line_obj_curr.product_id_random}')
|
||||
order_cart_line_obj_new.id_random = order_cart_line_obj_curr.id_random
|
||||
order_cart_line_obj_li_curr[index] = order_cart_line_obj_new
|
||||
else:
|
||||
log.info(f'Not a match: {order_cart_line_obj_curr.product_id_random}')
|
||||
|
||||
# Save merged current and new list to the new order cart object
|
||||
order_cart_obj_new.order_cart_line_list = order_cart_line_obj_li_curr
|
||||
log.debug(order_cart_obj_new)
|
||||
|
||||
# Final loop through to get the new order totals
|
||||
# Calculate totals
|
||||
order_cart_total_amount = 0
|
||||
order_cart_total_quantity = 0
|
||||
for order_cart_line_obj_curr in order_cart_line_obj_li_curr:
|
||||
order_cart_total_amount += order_cart_line_obj_curr.quantity * order_cart_line_obj_curr.amount
|
||||
order_cart_total_quantity += order_cart_line_obj_curr.quantity
|
||||
|
||||
order_cart_obj_new.total_amount = order_cart_total_amount
|
||||
order_cart_obj_new.total_quantity = order_cart_total_quantity
|
||||
|
||||
log.debug(order_cart_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'order_cart_id_random', 'order_cart_line_list', 'cfg', 'created_on', 'updated_on'}))
|
||||
order_cart_obj_data = order_cart_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'order_cart_id_random', 'order_cart_line_list', 'cfg', 'created_on', 'updated_on'})
|
||||
|
||||
# SQL INSERT or UPDATE the order_cart record
|
||||
log.info('SQL INSERT or UPDATE the order_cart record')
|
||||
if order_cart_obj_resp := sql_insert_or_update(sql=None, data=order_cart_obj_data, table_name='order_cart', rm_id_random=True, id_random_length=8): pass
|
||||
else: return False
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(order_cart_obj_resp)
|
||||
|
||||
if isinstance(order_cart_obj_resp, bool) and order_cart_obj_resp:
|
||||
if order_cart_id := order_cart_obj_new.id: pass
|
||||
elif order_cart_id := order_cart_obj_new.id_random: pass
|
||||
elif isinstance(order_cart_obj_resp, int):
|
||||
order_cart_id = order_cart_obj_resp
|
||||
else:
|
||||
return False
|
||||
|
||||
# Loop through the order_cart_line list to SQL INSERT or UPDATE the records
|
||||
log.info('Loop through the order_cart_line list to SQL INSERT or UPDATE the records')
|
||||
for order_cart_line_obj in order_cart_obj_new.order_cart_line_list:
|
||||
log.debug(f"--- {order_cart_line_obj}")
|
||||
log.debug(order_cart_line_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=False, exclude={}))
|
||||
|
||||
order_cart_line_obj_data = order_cart_line_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'product_type_id', 'product_type', 'product_name', 'product_description', 'product_unit_price', 'product_max_quantity', 'order_cart_line_id_random', 'created_on', 'updated_on'})
|
||||
|
||||
order_cart_line_obj_data['order_cart_id'] = order_cart_id
|
||||
|
||||
if order_cart_line_obj_resp := sql_insert_or_update(sql=None, data=order_cart_line_obj_data, table_name='order_cart_line', rm_id_random=True, id_random_length=8): pass
|
||||
else: return False
|
||||
log.debug(order_cart_line_obj_resp)
|
||||
return order_cart_id
|
||||
# ### END ### API Order Cart Model ### save_order_cart_obj() ###
|
||||
|
||||
|
||||
# IS THIS STILL NEEDED?
|
||||
# ### BEGIN ### API Order Cart Model ### get_order_cart_obj() ###
|
||||
def old_get_order_cart_obj(order_cart_id=None, inc_order_cart_line_list=None, inc_order_cfg=None):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if order_cart_id := redis_lookup_id_random(record_id_random=order_cart_id, table_name='order_cart'): pass
|
||||
else:
|
||||
return False
|
||||
|
||||
if order_cart_rec := sql_select(table_name='v_order_cart', record_id=order_cart_id):
|
||||
#log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(order_cart_rec)
|
||||
|
||||
if inc_order_cart_line_list:
|
||||
order_cart_line_data = {}
|
||||
order_cart_line_data['order_cart_id'] = order_cart_id
|
||||
if order_cart_line_rec_li := sql_select(table_name='v_order_cart_line', data=order_cart_line_data, as_list=True):
|
||||
order_cart_rec['order_cart_line_list'] = order_cart_line_rec_li
|
||||
|
||||
if inc_order_cfg:
|
||||
if order_cfg_rec := sql_select(table_name='v_account_cfg', field_name='account_id', field_value=order_cart_rec.get('account_id', None)):
|
||||
order_cart_rec['cfg'] = order_cfg_rec
|
||||
|
||||
log.debug(order_cart_rec)
|
||||
else:
|
||||
return False
|
||||
|
||||
try:
|
||||
order_cart_obj = Order_Cart_Base(**order_cart_rec)
|
||||
log.debug(order_cart_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
return order_cart_obj
|
||||
# ### END ### API Order Cart Model ### get_order_cart_obj() ###
|
||||
46
app/methods/order_cfg_methods.py
Normal file
46
app/methods/order_cfg_methods.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_select
|
||||
from app.lib_general import log, logging
|
||||
|
||||
from app.models.order_cfg_models import Order_Cfg_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Cfg Methods ### load_order_cfg_obj() ###
|
||||
def load_order_cfg_obj(
|
||||
account_id: int|str,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = True,
|
||||
) -> Order_Cfg_Base|dict|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
|
||||
if order_cfg_rec := sql_select(
|
||||
table_name = 'v_account_cfg',
|
||||
field_name = 'account_id',
|
||||
field_value = account_id,
|
||||
): pass
|
||||
else: return False
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(order_cfg_rec)
|
||||
|
||||
try:
|
||||
order_cfg_obj = Order_Cfg_Base(**order_cfg_rec)
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(order_cfg_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
if model_as_dict:
|
||||
return order_cfg_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return order_cfg_obj
|
||||
# ### END ### API Order Cfg Methods ### load_order_cfg_obj() ###
|
||||
512
app/methods/order_line_methods.py
Normal file
512
app/methods/order_line_methods.py
Normal file
@@ -0,0 +1,512 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_delete, sql_enable_part, sql_insert, sql_limit_offset_part, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
# from app.models.order_line_models import Order_Line_Base, Order_Line_Full_Detail_Base
|
||||
from app.models.order_line_models_v3 import Order_Line_Base, Order_Line_Full_Detail_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Line Methods ### create_order_obj_line() ###
|
||||
# Updated 2022-01-18
|
||||
def create_order_obj_line(
|
||||
order_id: int,
|
||||
order_line_dict_obj: Order_Line_Base,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(order_line_dict_obj))
|
||||
if isinstance(order_line_dict_obj, dict):
|
||||
order_line_dict = order_line_dict_obj
|
||||
try:
|
||||
order_obj = Order_Line_Base(**order_line_dict)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
order_obj = order_line_dict_obj
|
||||
# order_obj.order_id = order_id
|
||||
|
||||
order_line_dict = order_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'product', 'remove_line', 'created_on', 'updated_on'})
|
||||
log.debug(order_obj)
|
||||
|
||||
# ### SECTION ### Process data
|
||||
order_obj.order_id = order_id # Is this needed?
|
||||
order_line_dict['order_id'] = order_id
|
||||
|
||||
if order_line_dict_in_result := sql_insert(
|
||||
data = order_line_dict,
|
||||
table_name = 'order_line',
|
||||
rm_id_random = True,
|
||||
id_random_length = default_num_bytes
|
||||
): pass
|
||||
else:
|
||||
log.warning(f'Order Line not created.')
|
||||
log.debug(order_line_dict_in_result)
|
||||
return False
|
||||
|
||||
log.debug(order_line_dict_in_result)
|
||||
order_line_id = order_line_dict_in_result
|
||||
|
||||
log.info(f'Returning the Order Line ID: {order_line_id}')
|
||||
|
||||
return order_line_id
|
||||
# ### END ### API Order Methods ### create_order_obj_line() ###
|
||||
|
||||
|
||||
# # ### BEGIN ### API Order Line Methods ### create_order_obj_line() ###
|
||||
# @logger_reset
|
||||
# def create_order_obj_line(order_line_dict_obj:Order_Line_Base):
|
||||
# log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(locals())
|
||||
|
||||
# if not order_line_dict_obj:
|
||||
# return False
|
||||
|
||||
# order_line_obj_data = order_line_dict_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'user', 'created_on', 'updated_on'})
|
||||
|
||||
# if order_line_obj_in_result := sql_insert(data=order_line_obj_data, table_name='order_line', rm_id_random=True, id_random_length=8): pass
|
||||
# else:
|
||||
# return False
|
||||
|
||||
# log.debug(order_line_obj_in_result)
|
||||
|
||||
# order_line_id = order_line_obj_in_result
|
||||
|
||||
# log.debug(f'Returning the new order_line_id: {order_line_id}')
|
||||
# return order_line_id
|
||||
# # ### END ### API Order Line Methods ### create_order_obj_line() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Line Methods ### update_order_obj_line() ###
|
||||
# Updated 2022-01-18
|
||||
def update_order_obj_line(
|
||||
order_line_id: int,
|
||||
order_line_dict_obj: Order_Line_Base,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
if order_line_id := redis_lookup_id_random(record_id_random=order_line_id, table_name='order_line'): pass
|
||||
else: return False
|
||||
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(order_line_dict_obj))
|
||||
if isinstance(order_line_dict_obj, dict):
|
||||
order_line_dict = order_line_dict_obj
|
||||
try:
|
||||
order_line_obj = Order_Line_Base(**order_line_dict)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
order_line_obj = order_line_dict_obj
|
||||
# order_line_obj.order_line_id = order_line_id
|
||||
|
||||
order_line_dict = order_line_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'product', 'remove_line', 'updated_on', 'updated_on'})
|
||||
log.debug(order_line_obj)
|
||||
|
||||
# ### SECTION ### Process data
|
||||
order_line_obj.id = order_line_id # Is this needed?
|
||||
order_line_dict['id'] = order_line_id
|
||||
|
||||
if order_line_dict_up_result := sql_update(
|
||||
data = order_line_dict,
|
||||
table_name = 'order_line',
|
||||
rm_id_random = True,
|
||||
): pass
|
||||
else:
|
||||
log.warning(f'Order Line not updated.')
|
||||
log.debug(order_line_dict_up_result)
|
||||
return False
|
||||
|
||||
log.debug(order_line_dict_up_result)
|
||||
|
||||
return True
|
||||
# ### END ### API Order Methods ### update_order_obj_line() ###
|
||||
|
||||
|
||||
# # ### BEGIN ### API Order Line Methods ### update_order_obj_line() ###
|
||||
# @logger_reset
|
||||
# def update_order_obj_line(
|
||||
# order_line_id: int|str, # Ideally the int ID should be passed. This allows for updating of the id_random value.
|
||||
# order_obj_line_obj_up: Order_Line_Base,
|
||||
# create_sub_obj: bool = False,
|
||||
# ) -> bool:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(locals())
|
||||
|
||||
# if order_line_id := redis_lookup_id_random(record_id_random=order_line_id, table_name='order_line'): pass
|
||||
# else: return False
|
||||
|
||||
# order_obj_line_obj_up.id = order_line_id
|
||||
|
||||
# log.debug(order_obj_line_obj_up)
|
||||
# # log.debug(order_obj_line_obj_up.dict(by_alias=True, exclude_unset=True))
|
||||
# log.debug(order_obj_line_obj_up.dict(by_alias=False, exclude_unset=True))
|
||||
# # log.debug(order_obj_line_obj_up.dict(by_alias=False, exclude_unset=False))
|
||||
|
||||
# #order_line_dict_up = order_obj_line_obj_up.dict(by_alias=False, exclude_unset=True)
|
||||
|
||||
# # if order_obj_line_obj_up.person_id and order_obj_line_obj_up.person:
|
||||
# # person_id = order_obj_line_obj_up.person_id
|
||||
# # person_obj_up = order_obj_line_obj_up.person
|
||||
# # log.debug(person_id)
|
||||
# # log.debug(person_obj_up)
|
||||
# # if person_obj_up_result := update_person_obj(
|
||||
# # person_id = person_id,
|
||||
# # person_obj_up = person_obj_up,
|
||||
# # create_sub_obj = create_sub_obj,
|
||||
# # ):
|
||||
# # log.debug(person_obj_up_result)
|
||||
# # else:
|
||||
# # log.debug(person_obj_up_result)
|
||||
# # return False
|
||||
|
||||
# # if order_obj_line_obj_up.user_id and order_obj_line_obj_up.user:
|
||||
# # user_id = order_obj_line_obj_up.user_id
|
||||
# # user_obj_up = order_obj_line_obj_up.user
|
||||
# # log.debug(user_id)
|
||||
# # log.debug(user_obj_up)
|
||||
# # if user_obj_up_result := update_user_obj(
|
||||
# # user_id = user_id,
|
||||
# # user_dict_obj = user_obj_up,
|
||||
# # create_sub_obj = create_sub_obj,
|
||||
# # ):
|
||||
# # log.debug(user_obj_up_result)
|
||||
# # else:
|
||||
# # log.debug(user_obj_up_result)
|
||||
# # return False
|
||||
|
||||
# order_line_dict_up = order_obj_line_obj_up.dict(by_alias=False, exclude_unset=True, exclude={'user'})
|
||||
# log.debug(order_line_dict_up)
|
||||
|
||||
# if order_obj_line_obj_up_result := sql_update(data=order_line_dict_up, table_name='order_line', rm_id_random=True):
|
||||
# log.debug(order_obj_line_obj_up_result)
|
||||
# return True
|
||||
# else:
|
||||
# log.debug(order_obj_line_obj_up_result)
|
||||
# return False
|
||||
# # ### END ### API Order Line Methods ### update_order_obj_line() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Line Methods ### load_order_obj_line() ###
|
||||
# Updated 2021-11-19
|
||||
@logger_reset
|
||||
def load_order_obj_line(
|
||||
order_line_id: int|str,
|
||||
# limit: int = 500,
|
||||
# offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True, # NOTE: Normally this is True
|
||||
model_as_dict: bool = False, # NOTE: Normally this is False
|
||||
) -> Order_Line_Base|dict|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if order_line_id := redis_lookup_id_random(record_id_random=order_line_id, table_name='order_line'): pass
|
||||
else: return False
|
||||
|
||||
if order_line_rec := sql_select(table_name='v_order_line', record_id=order_line_id): pass
|
||||
else: return False
|
||||
log.debug(order_line_rec)
|
||||
|
||||
try:
|
||||
order_line_obj = Order_Line_Base(**order_line_rec)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
log.debug(order_line_obj)
|
||||
|
||||
if model_as_dict:
|
||||
return order_line_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return order_line_obj
|
||||
# ### END ### API Order Line Methods ### load_order_obj_line() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Line Methods ### load_order_obj_line_full_detail() ###
|
||||
# Updated 2021-11-22
|
||||
@logger_reset
|
||||
def load_order_obj_line_full_detail(
|
||||
order_line_rec: dict,
|
||||
# limit: int = 500,
|
||||
# offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True, # NOTE: Normally this is True
|
||||
model_as_dict: bool = False, # NOTE: Normally this is False
|
||||
) -> Order_Line_Full_Detail_Base|dict|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
try:
|
||||
order_line_obj_full_detail = Order_Line_Full_Detail_Base(**order_line_rec)
|
||||
log.debug(order_line_obj_full_detail)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
if model_as_dict:
|
||||
return order_line_obj_full_detail.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return order_line_obj_full_detail
|
||||
# ### END ### API Order Line Methods ### load_order_obj_line_full_detail() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Line Methods ### get_order_line_rec_list() ###
|
||||
@logger_reset
|
||||
def get_order_line_rec_list(
|
||||
for_obj_type: str,
|
||||
for_obj_id: str,
|
||||
from_datetime: datetime.datetime = None, # For the order, not order_line
|
||||
to_datetime: datetime.datetime = None, # For the order, not order_line
|
||||
product_for_type: str = 'all', # all, cont_edu_cert, event, fundraising, membership, etc
|
||||
status: str = 'all', # started, in progress, complete, all
|
||||
full_detail: bool = False,
|
||||
# enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 500,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data[f'{for_obj_type}_id'] = for_obj_id
|
||||
# data['for_obj_type'] = for_obj_type
|
||||
sql_obj_type_id = f'`order_line`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
allowed_prod_type_li = ['cont_edu_cert', 'event', 'fundraising', 'membership', 'other'] # TEMPORARY list...
|
||||
sql_product_for_type = ''
|
||||
if product_for_type in allowed_prod_type_li:
|
||||
if product_for_type == 'closed' or product_for_type == 'complete':
|
||||
data['product_for_type'] = ['closed', 'complete']
|
||||
sql_product_for_type = f'AND `order_line`.product_for_type IN :product_for_type'
|
||||
elif product_for_type == 'locked' or product_for_type == 'in progress':
|
||||
data['product_for_type'] = ['locked', 'in progress']
|
||||
sql_product_for_type = f'AND `order_line`.product_for_type IN :product_for_type'
|
||||
else:
|
||||
data['product_for_type'] = product_for_type
|
||||
sql_product_for_type = f'AND `order_line`.product_for_type = :product_for_type'
|
||||
elif product_for_type == 'all':
|
||||
sql_product_for_type = f'AND (`order_line`.product_for_type IS NULL OR `order_line`.product_for_type IS NOT NULL)'
|
||||
else:
|
||||
log.warning('The product_for_type value passed is not allowed. Returning None')
|
||||
return False
|
||||
|
||||
allowed_status_li = ['open', 'locked', 'in progress', 'reopened', 'closed', 'complete', 'canceled', 'other'] # TEMPORARY list...
|
||||
sql_status = ''
|
||||
if status in allowed_status_li:
|
||||
if status == 'closed' or status == 'complete':
|
||||
data['status'] = ['closed', 'complete']
|
||||
sql_status = f'AND `order_line`.order_status IN :status'
|
||||
elif status == 'locked' or status == 'in progress':
|
||||
data['status'] = ['locked', 'in progress']
|
||||
sql_status = f'AND `order_line`.order_status IN :status'
|
||||
else:
|
||||
data['status'] = status
|
||||
sql_status = f'AND `order_line`.order_status = :status'
|
||||
elif status == 'all':
|
||||
sql_status = f'AND `order_line`.order_status IS NOT NULL'
|
||||
else:
|
||||
log.warning('The status value passed is not allowed. Returning None')
|
||||
return False
|
||||
|
||||
if from_datetime and to_datetime:
|
||||
data['from_datetime'] = from_datetime
|
||||
data['to_datetime'] = to_datetime
|
||||
# sql_from_to_datetime = f'AND `order_line`.order_created_on >= :from_datetime AND `order_line`.order_created_on <= :to_datetime'
|
||||
sql_from_to_datetime = f'AND `order_line`.order_updated_on >= :from_datetime AND `order_line`.order_updated_on <= :to_datetime'
|
||||
elif from_datetime:
|
||||
data['from_datetime'] = from_datetime
|
||||
# sql_from_to_datetime = f'AND `order_line`.order_created_on >= :from_datetime'
|
||||
sql_from_to_datetime = f'AND `order_line`.order_updated_on >= :from_datetime'
|
||||
elif to_datetime:
|
||||
data['to_datetime'] = to_datetime
|
||||
# sql_from_to_datetime = f'AND `order_line`.order_created_on <= :to_datetime'
|
||||
sql_from_to_datetime = f'AND `order_line`.order_updated_on <= :to_datetime'
|
||||
else:
|
||||
sql_from_to_datetime = ''
|
||||
|
||||
# sql_enabled, data['enable'] = sql_enable_part(table_name='order', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
log.debug(data)
|
||||
|
||||
if not full_detail:
|
||||
sql = f"""
|
||||
SELECT `order_line`.id AS 'order_line_id', `order_line`.id_random AS 'order_line_id_random'
|
||||
FROM `v_order_line` AS `order_line`
|
||||
WHERE
|
||||
{sql_obj_type_id}
|
||||
{sql_product_for_type}
|
||||
{sql_status}
|
||||
{sql_from_to_datetime}
|
||||
ORDER BY order_line.name, `order_line`.created_on DESC, `order_line`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
else:
|
||||
sql = f"""
|
||||
SELECT *
|
||||
FROM `v_order_line_full_detail` AS `order_line`
|
||||
WHERE
|
||||
{sql_obj_type_id}
|
||||
{sql_product_for_type}
|
||||
{sql_status}
|
||||
{sql_from_to_datetime}
|
||||
ORDER BY `order_line`.created_on DESC, `order_line`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if order_line_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
order_line_rec_li = order_line_rec_li_result
|
||||
else: # [] or False
|
||||
order_line_rec_li = order_line_rec_li_result
|
||||
|
||||
log.debug(order_line_rec_li_result)
|
||||
|
||||
return order_line_rec_li
|
||||
# ### END ### API Order Line Methods ### get_order_line_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Line Methods ### check_order_obj_line_list() ###
|
||||
@logger_reset
|
||||
def check_order_obj_line_list(
|
||||
order_id: int|str,
|
||||
product_id: int|str = None,
|
||||
# product_for_id: int|str = 'all',
|
||||
product_for_type: str = 'all', # all, cont_edu_cert, event, fundraising, membership, etc
|
||||
for_person_id: int|str = None,
|
||||
limit: int = 50,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if order_id := redis_lookup_id_random(record_id_random=order_id, table_name='order'): pass
|
||||
else: return False
|
||||
|
||||
if product_id := redis_lookup_id_random(record_id_random=product_id, table_name='product'): pass
|
||||
elif product_id is None: pass
|
||||
else: return False
|
||||
|
||||
if for_person_id := redis_lookup_id_random(record_id_random=for_person_id, table_name='person'): pass
|
||||
elif for_person_id is None: pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['order_id'] = order_id
|
||||
sql_order_id = f'`order_line`.order_id = :order_id'
|
||||
|
||||
if product_id:
|
||||
data['product_id'] = product_id
|
||||
sql_product_id = f'AND `order_line`.product_id = :product_id'
|
||||
|
||||
allowed_prod_type_li = ['cont_edu_cert', 'event', 'fundraising', 'membership', 'other'] # TEMPORARY list...
|
||||
sql_product_for_type = ''
|
||||
if product_for_type in allowed_prod_type_li:
|
||||
if product_for_type == 'closed' or product_for_type == 'complete':
|
||||
data['product_for_type'] = ['closed', 'complete']
|
||||
sql_product_for_type = f'AND `order_line`.product_for_type IN :prod_type'
|
||||
elif product_for_type == 'locked' or product_for_type == 'in progress':
|
||||
data['product_for_type'] = ['locked', 'in progress']
|
||||
sql_product_for_type = f'AND `order_line`.product_for_type IN :prod_type'
|
||||
else:
|
||||
data['product_for_type'] = prod_type
|
||||
sql_product_for_type = f'AND `order_line`.product_for_type = :prod_type'
|
||||
elif product_for_type == 'all':
|
||||
sql_product_for_type = f'AND (`order_line`.product_for_type IS NULL OR `order_line`.product_for_type IS NOT NULL)'
|
||||
else:
|
||||
log.warning('The product_for_type value passed is not allowed. Returning None')
|
||||
return False
|
||||
|
||||
sql_for_person_id = ''
|
||||
if for_person_id:
|
||||
data['for_person_id'] = for_person_id
|
||||
sql_for_person_id = f'AND `order_line`.for_person_id = :for_person_id'
|
||||
|
||||
# sql_enabled, data['enable'] = sql_enable_part(table_name='order', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
log.debug(data)
|
||||
|
||||
sql = f"""
|
||||
SELECT `order_line`.id AS 'order_line_id', `order_line`.id_random AS 'order_line_id_random'
|
||||
FROM `order_line` AS `order_line`
|
||||
WHERE
|
||||
{sql_order_id}
|
||||
{sql_product_id}
|
||||
{sql_product_for_type}
|
||||
{sql_for_person_id}
|
||||
ORDER BY order_line.name, `order_line`.created_on DESC, `order_line`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if order_line_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
order_line_rec_li = order_line_rec_li_result
|
||||
else: # [] or False
|
||||
order_line_rec_li = order_line_rec_li_result
|
||||
|
||||
log.debug(order_line_rec_li_result)
|
||||
|
||||
return order_line_rec_li
|
||||
# ### END ### API Order Line Methods ### check_order_obj_line_list() ###
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Line Methods ### remove_order_obj_line() ###
|
||||
# Updated 2022-01-19
|
||||
def remove_order_obj_line(
|
||||
order_id: int,
|
||||
order_line_id: int,
|
||||
product_id: int,
|
||||
) -> bool|None:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
if order_id := redis_lookup_id_random(record_id_random=order_id, table_name='order'): pass
|
||||
elif order_id is None: pass
|
||||
else: return False
|
||||
|
||||
if order_line_id := redis_lookup_id_random(record_id_random=order_line_id, table_name='order_line'): pass
|
||||
elif order_line_id is None: pass
|
||||
else: return False
|
||||
|
||||
if product_id := redis_lookup_id_random(record_id_random=product_id, table_name='product'): pass
|
||||
elif product_id is None: pass
|
||||
else: return False
|
||||
|
||||
if order_line_id:
|
||||
log.info(f'Deleting Order Line ID: {order_line_id}')
|
||||
if order_line_del_result := sql_delete(
|
||||
table_name = 'order_line',
|
||||
record_id = order_line_id
|
||||
):
|
||||
log.debug(order_line_del_result)
|
||||
return True
|
||||
else: return False
|
||||
elif order_id and product_id:
|
||||
log.info(f'Deleting Order Line with Order ID: {order_id} and Product ID {product_id}')
|
||||
data = { 'order_id': order_id, 'product_id': product_id}
|
||||
if order_line_del_result := sql_delete(
|
||||
table_name = 'order_line',
|
||||
data = data,
|
||||
):
|
||||
log.debug(order_line_del_result)
|
||||
return True
|
||||
else: return False
|
||||
# ### END ### API Order Line Methods ### remove_order_obj_line() ###
|
||||
623
app/methods/order_methods.py
Normal file
623
app/methods/order_methods.py
Normal file
@@ -0,0 +1,623 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_delete, sql_enable_part, sql_insert, sql_insert_or_update, sql_limit_offset_part, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.methods.order_cfg_methods import load_order_cfg_obj
|
||||
from app.methods.order_line_methods import check_order_obj_line_list, create_order_obj_line, get_order_line_rec_list, load_order_obj_line, remove_order_obj_line, update_order_obj_line
|
||||
# from app.methods.person_methods import load_person_obj
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
# from app.models.order_models import Order_Base
|
||||
# from app.models.order_line_models import Order_Line_Base, Order_Line_DB_Base # This should go away later.
|
||||
from app.models.order_models_v3 import Order_Base
|
||||
from app.models.order_line_models_v3 import Order_Line_Base, Order_Line_DB_Base # This should go away later.
|
||||
# from app.models.person_models import Person_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Methods ### create_order_obj() ###
|
||||
# Updated 2022-01-18
|
||||
def create_order_obj(
|
||||
account_id: int,
|
||||
order_dict_obj: Order_Base,
|
||||
person_id: int|None = None,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(order_dict_obj))
|
||||
if isinstance(order_dict_obj, dict):
|
||||
order_dict = order_dict_obj
|
||||
try:
|
||||
order_obj = Order_Base(**order_dict)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
order_obj = order_dict_obj
|
||||
# order_obj.account_id = account_id
|
||||
|
||||
order_dict = order_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'cfg', 'order_line_list', 'person', 'user', 'created_on', 'updated_on'})
|
||||
log.debug(order_obj)
|
||||
|
||||
# ### SECTION ### Process data
|
||||
# Look for an account_id in the order_obj
|
||||
# if account_id: pass
|
||||
# elif account_id := order_obj.account_id: pass
|
||||
|
||||
order_obj.account_id = account_id # Is this needed?
|
||||
order_dict['account_id'] = account_id
|
||||
|
||||
# Look for a person_id in the contact_obj
|
||||
if person_id:
|
||||
order_obj.person_id = person_id # Is this needed?
|
||||
order_dict['person_id'] = person_id
|
||||
elif person_id := order_obj.person.id: pass
|
||||
|
||||
if order_dict_in_result := sql_insert(
|
||||
data = order_dict,
|
||||
table_name = 'order',
|
||||
rm_id_random = True,
|
||||
id_random_length = default_num_bytes
|
||||
): pass
|
||||
else:
|
||||
log.warning(f'Order not created.')
|
||||
log.debug(order_dict_in_result)
|
||||
return False
|
||||
|
||||
log.debug(order_dict_in_result)
|
||||
order_id = order_dict_in_result
|
||||
|
||||
if order_obj.order_line_list:
|
||||
log.info('Looping through Order Line list')
|
||||
for order_line in order_obj.order_line_list:
|
||||
# NOTE: Should there be a check here using check_order_obj_line_list()???
|
||||
# In theory there should not already be any order_line records associated with the new order_id.
|
||||
order_line_id = order_line.id
|
||||
|
||||
if order_line_id:
|
||||
log.info('Updating Order Line')
|
||||
if update_order_obj_result := update_order_obj_line(
|
||||
order_line_id = order_line_id,
|
||||
order_line_dict_obj = order_line,
|
||||
): pass
|
||||
else: return False
|
||||
else:
|
||||
log.info('Creating Order Line')
|
||||
if create_order_obj_line_result := create_order_obj_line(
|
||||
order_id = order_id,
|
||||
order_line_dict_obj = order_line,
|
||||
): pass
|
||||
else: pass
|
||||
|
||||
log.info(f'Returning the Order ID: {order_id}')
|
||||
|
||||
return order_id
|
||||
# ### END ### API Order Methods ### create_order_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Methods ### update_order_obj() ###
|
||||
# Updated 2022-01-18
|
||||
def update_order_obj(
|
||||
order_id: int,
|
||||
order_dict_obj: Order_Base,
|
||||
# person_id: int|None = None,
|
||||
) -> int|bool:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(order_dict_obj))
|
||||
if isinstance(order_dict_obj, dict):
|
||||
order_dict = order_dict_obj
|
||||
try:
|
||||
order_obj = Order_Base(**order_dict)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
order_obj = order_dict_obj
|
||||
# order_obj.account_id = account_id
|
||||
|
||||
order_dict = order_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'cfg', 'order_line_list', 'person', 'user', 'created_on', 'updated_on'})
|
||||
log.debug(order_obj)
|
||||
|
||||
# ### SECTION ### Process data
|
||||
order_obj.id = order_id # Is this needed?
|
||||
order_dict['id'] = order_id
|
||||
|
||||
# # Look for a person_id in the order_obj
|
||||
# if person_id:
|
||||
# order_obj.person_id = person_id # Is this needed?
|
||||
# order_dict['person_id'] = person_id
|
||||
# elif person_id := order_obj.person.id: pass
|
||||
|
||||
if order_dict_up_result := sql_update(
|
||||
data = order_dict,
|
||||
table_name = 'order',
|
||||
rm_id_random = True,
|
||||
): pass
|
||||
elif order_dict_up_result is None: pass # More than likely no order specific data was passed. There might be order lines though.
|
||||
else:
|
||||
log.warning(f'Person not updated.')
|
||||
log.debug(order_dict_up_result)
|
||||
return False
|
||||
|
||||
log.debug(order_dict_up_result)
|
||||
|
||||
if order_obj.order_line_list:
|
||||
log.info('Looping through Order Line list')
|
||||
for order_line in order_obj.order_line_list:
|
||||
order_line_id = order_line.id
|
||||
product_id = order_line.product_id
|
||||
|
||||
if order_line.remove_line:
|
||||
remove_order_obj_line(
|
||||
order_id = order_id,
|
||||
order_line_id = order_line_id,
|
||||
product_id = product_id,
|
||||
)
|
||||
continue # Do not need to check for anything else on this loop
|
||||
|
||||
order_line_id = order_line.id
|
||||
product_id = order_line.product_id
|
||||
if for_person_id := order_line.for_person_id: pass
|
||||
log.info(f'Checking for matching order lines. Order ID: {order_id}; Product ID: {product_id}; For Person ID: {for_person_id}')
|
||||
|
||||
order_line_id_found = None
|
||||
if check_order_obj_line_list_result := check_order_obj_line_list(
|
||||
order_id = order_id,
|
||||
product_id = product_id,
|
||||
for_person_id = for_person_id,
|
||||
):
|
||||
for order_line_rec in check_order_obj_line_list_result:
|
||||
order_line_id_found = order_line_rec.get('order_line_id')
|
||||
|
||||
if order_line_id == order_line_id_found: pass
|
||||
elif order_line_id := order_line_id_found: pass
|
||||
|
||||
if order_line_id:
|
||||
log.info('Updating Order Line')
|
||||
if update_order_obj_result := update_order_obj_line(
|
||||
order_line_id = order_line_id,
|
||||
order_line_dict_obj = order_line,
|
||||
): pass
|
||||
else: return False
|
||||
else:
|
||||
log.info('Creating Order Line')
|
||||
if create_order_obj_line_result := create_order_obj_line(
|
||||
order_id = order_id,
|
||||
order_line_dict_obj = order_line,
|
||||
): pass
|
||||
else: pass
|
||||
|
||||
return True
|
||||
# ### END ### API Order Methods ### update_order_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Methods ### load_order_obj() ###
|
||||
# Updated 2021-11-19
|
||||
# @logger_reset
|
||||
def load_order_obj(
|
||||
order_id: int|str,
|
||||
inc_address: bool = False,
|
||||
inc_contact: bool = False,
|
||||
inc_order_cfg: bool = False,
|
||||
inc_order_line_list: bool = False,
|
||||
inc_person: bool = False,
|
||||
inc_user: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 500,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
) -> None|bool|dict|list:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if order_id := redis_lookup_id_random(record_id_random=order_id, table_name='order'): pass
|
||||
else: return False # None, false bool
|
||||
|
||||
if order_rec := sql_select(table_name='v_order', record_id=order_id): pass
|
||||
else: return order_rec # None, empty dict, empty list, false bool
|
||||
log.debug(order_rec)
|
||||
|
||||
try:
|
||||
order_obj = Order_Base(**order_rec)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
log.debug(order_obj)
|
||||
|
||||
# Updated 2022-01-18
|
||||
if inc_order_cfg:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
if order_cfg_result := load_order_cfg_obj(
|
||||
account_id = order_rec.get('account_id'),
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = True,
|
||||
):
|
||||
order_obj.cfg = order_cfg_result
|
||||
else: order_obj.cfg = {} # None
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(order_cfg_result)
|
||||
|
||||
# Updated 2021-06-18
|
||||
if inc_order_line_list:
|
||||
if order_line_rec_list_result := get_order_line_rec_list(
|
||||
for_obj_type = 'order',
|
||||
for_obj_id = order_id,
|
||||
# product_for_type = 'all',
|
||||
# status = 'all',
|
||||
limit = limit,
|
||||
):
|
||||
order_line_result_list = []
|
||||
for order_line_rec in order_line_rec_list_result:
|
||||
order_line_result_list.append(
|
||||
load_order_obj_line(
|
||||
order_line_id = order_line_rec.get('order_line_id'),
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
)
|
||||
)
|
||||
order_obj.order_line_list = order_line_result_list
|
||||
else: order_obj.order_line_list = [] # None
|
||||
|
||||
# Updated 2022-01-18
|
||||
if inc_person:
|
||||
from app.methods.person_methods import load_person_obj
|
||||
if person_result := load_person_obj(
|
||||
person_id = order_rec.get('person_id'),
|
||||
inc_address = inc_address,
|
||||
inc_contact = inc_contact,
|
||||
inc_user = inc_user,
|
||||
enabled = enabled,
|
||||
limit = limit,
|
||||
offset = offset,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
order_obj.person = person_result
|
||||
else: order_obj.person = {} # None
|
||||
pass
|
||||
|
||||
# Updated 2021-06-22
|
||||
# NOTE: Phasing out! Use *inc_user* under load_person_obj() instead.
|
||||
# if inc_user:
|
||||
# log.warning(f'This is being deprecated? load_order_obj() inc_user')
|
||||
# from app.methods.user_methods import load_user_obj
|
||||
# if user_result := load_user_obj(
|
||||
# user_id = order_rec.get('user_id', None),
|
||||
# limit = limit,
|
||||
# by_alias = by_alias,
|
||||
# exclude_unset = exclude_unset,
|
||||
# model_as_dict = model_as_dict,
|
||||
# enabled = enabled,
|
||||
# ):
|
||||
# order_obj.user = user_result
|
||||
# else: order_obj.user = None
|
||||
# pass
|
||||
|
||||
if model_as_dict:
|
||||
return order_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return order_obj
|
||||
# ### END ### API Order Methods ### load_order_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Methods ### get_order_obj_cart_for_person_id_v3() ###
|
||||
# Updated 2022-01-21
|
||||
@logger_reset
|
||||
def get_order_id_cart_for_person_id_v3(
|
||||
person_id: int|str,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 5,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
) -> None|bool|dict|list:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if person_id := redis_lookup_id_random(record_id_random=person_id, table_name='person'): pass
|
||||
else: return False # None, false bool
|
||||
|
||||
data = {}
|
||||
data['person_id'] = person_id
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='order', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
sql = f"""
|
||||
SELECT `order`.id AS 'order_id', `order`.id_random AS 'order_id_random'
|
||||
FROM `order` AS `order`
|
||||
WHERE
|
||||
`order`.person_id = :person_id
|
||||
AND `order`.status IN ('open', 'locked')
|
||||
{sql_enabled}
|
||||
ORDER BY `order`.created_on DESC, `order`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if order_rec_result := sql_select(data=data, sql=sql):
|
||||
log.debug(order_rec_result)
|
||||
if isinstance(order_rec_result, dict):
|
||||
order_id_cart = order_rec_result.get('order_id')
|
||||
log.info(f'Got Order ID {order_id_cart} cart for Person ID {person_id}')
|
||||
return order_id_cart
|
||||
elif isinstance(order_rec_result, list):
|
||||
log.warning(f'Got multiple Orders for a cart for Person ID {person_id}. This should not happen.')
|
||||
return False
|
||||
else: # None or [] or False
|
||||
log.debug(order_rec_result)
|
||||
return order_rec_result
|
||||
# ### END ### API Order Methods ### get_order_obj_cart_for_person_id_v3() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Methods ### save_order_obj() ###
|
||||
# @logger_reset
|
||||
def save_order_obj(order_obj_new:Order_Base, repl_order_line_li: bool=False):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
log.debug(order_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True))
|
||||
|
||||
order_line_obj_li_curr = [] # Initialize to store order_line list
|
||||
if order_obj_new.id_random:
|
||||
log.info(f'An order.id {order_obj_new.id} or order.id_random {order_obj_new.id_random} was included. We can update an existing order.')
|
||||
log.info(f'Get the current order_line list to compare with what was sent...')
|
||||
data = {}
|
||||
data['order_id_random'] = order_obj_new.id_random
|
||||
|
||||
if order_line_rec_li_curr := sql_select(table_name='v_order_line', data=data, rm_id_random=True, as_list=True):
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(order_line_rec_li_curr)
|
||||
|
||||
for order_line_rec in order_line_rec_li_curr:
|
||||
try:
|
||||
order_line_obj = Order_Line_Base(**order_line_rec)
|
||||
log.debug(order_line_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
order_line_obj_li_curr.append(order_line_obj)
|
||||
else:
|
||||
log.info(f'No order_line records were found')
|
||||
|
||||
|
||||
elif order_obj_new.account_id_random and order_obj_new.person_id_random:
|
||||
log.info(f'An account.id_random {order_obj_new.account_id_random} was passed. And a person.id_random {order_obj_new.person_id_random} was passed. We can create a new order.')
|
||||
# Because there was not an order ID, assume there are no order lines yet. So no look up.
|
||||
else:
|
||||
log.info('Either an order ID is required to update an order or an account ID along with a person ID is required to create an order.')
|
||||
return False
|
||||
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(order_line_obj_li_curr)
|
||||
|
||||
if repl_order_line_li: # This will remove any order line list items not sent with the new order information.
|
||||
log.info('Removing any order line list items not sent with the new order information...')
|
||||
for index, order_line_obj_curr in enumerate(order_line_obj_li_curr):
|
||||
log.info(f'Current: order line ID={order_line_obj_curr.id_random} and product ID= {order_line_obj_curr.product_id_random}')
|
||||
matched_product_id = False
|
||||
for order_line_obj_new in order_obj_new.order_line_li:
|
||||
log.debug(f'Checking new: product ID={order_line_obj_new.product_id_random}')
|
||||
|
||||
if order_line_obj_curr.product_id_random == order_line_obj_new.product_id_random:
|
||||
matched_product_id = True
|
||||
log.debug(f'Matched: product ID={order_line_obj_new.product_id_random}')
|
||||
break
|
||||
else:
|
||||
log.debug(f'No match: product ID={order_line_obj_new.product_id_random}')
|
||||
if not matched_product_id: # Was not found in the new order line list sent
|
||||
log.info(f'Current order line product ID did not match any of the new list. DELETE order line ID {order_line_obj_curr.id_random} with product ID {order_line_obj_curr.product_id_random}')
|
||||
|
||||
if order_line_del_result := sql_delete(table_name='order_line', record_id_random=order_line_obj_curr.id_random):
|
||||
log.info(f'Deleted record and now pop the current list item {index}...')
|
||||
order_line_obj_li_curr.pop(index)
|
||||
else:
|
||||
log.info(f'Current order line product ID matched. Keeping order line ID {order_line_obj_curr.id_random} with product ID {order_line_obj_curr.product_id_random}')
|
||||
# NOTE: That this current order line item will be updated below.
|
||||
log.debug(order_line_obj_li_curr)
|
||||
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
|
||||
log.info('Loop through the line list that was sent and compare with what was pulled from the DB')
|
||||
# Loop through the new line list that was sent and compare with the current line list that was pulled from the DB
|
||||
# Only insert if a product ID does not match
|
||||
# Only update if a product ID does match
|
||||
for order_line_obj_new in order_obj_new.order_line_li:
|
||||
log.info(f'New: order line ID={order_line_obj_new.id_random} and product ID= {order_line_obj_new.product_id_random}')
|
||||
matched_product_id = False
|
||||
for index, order_line_obj_curr in enumerate(order_line_obj_li_curr):
|
||||
log.debug(f'Checking current: product ID={order_line_obj_curr.product_id_random}')
|
||||
|
||||
if order_line_obj_new.product_id_random == order_line_obj_curr.product_id_random:
|
||||
matched_product_id = True
|
||||
log.debug(f'Matched: product ID={order_line_obj_curr.product_id_random}')
|
||||
log.info(f'Updating the current line item with the new line item.')
|
||||
order_line_obj_new.id_random = order_line_obj_curr.id_random
|
||||
order_line_obj_new.id = order_line_obj_curr.id
|
||||
order_line_obj_li_curr[index] = order_line_obj_new
|
||||
break
|
||||
else:
|
||||
log.debug(f'No match: product ID={order_line_obj_curr.product_id_random}')
|
||||
|
||||
if not matched_product_id: # Was not found in the current order line list that was pulled from the DB
|
||||
log.info(f'New order line product ID did not match any of the current list. Append order line ID {order_line_obj_new.id_random} with product ID {order_line_obj_new.product_id_random}')
|
||||
log.info('Append to current list...')
|
||||
order_line_obj_li_curr.append(order_line_obj_new) # These will be inserted/updated below
|
||||
|
||||
# Save merged current and new list to the new order object
|
||||
order_obj_new.order_line_li = order_line_obj_li_curr
|
||||
log.debug(order_obj_new)
|
||||
|
||||
# Final loop through to get the new order totals
|
||||
# Calculate totals
|
||||
order_total_amount: int = 0
|
||||
order_total_quantity: int = 0
|
||||
for order_line_obj_new in order_obj_new.order_line_li:
|
||||
order_total_amount += order_line_obj_new.quantity * order_line_obj_new.amount
|
||||
order_total_quantity += order_line_obj_new.quantity
|
||||
|
||||
order_obj_new.total_bill = order_total_amount # "amount" is used by order_cart and Stripe
|
||||
order_obj_new.total_quantity = order_total_quantity
|
||||
# order_obj_new.balance = order_total_amount - order_obj_new.total_paid # No longer used 2022-03-16
|
||||
|
||||
log.debug(order_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'order_line_li', 'cfg', 'created_on', 'updated_on'}))
|
||||
order_obj_data = order_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'order_line_li', 'cfg', 'created_on', 'updated_on'})
|
||||
|
||||
# SQL INSERT or UPDATE the order record
|
||||
log.info('SQL INSERT or UPDATE the order record')
|
||||
if order_obj_resp := sql_insert_or_update(data=order_obj_data, table_name='order', rm_id_random=True, id_random_length=8): pass
|
||||
else: return False
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(order_obj_resp)
|
||||
|
||||
if isinstance(order_obj_resp, bool) and order_obj_resp:
|
||||
if order_id := order_obj_new.id: pass
|
||||
elif order_id := order_obj_new.id_random: pass
|
||||
elif isinstance(order_obj_resp, int):
|
||||
order_id = order_obj_resp
|
||||
else:
|
||||
return False
|
||||
log.debug(f'Order ID={order_id}')
|
||||
|
||||
# Loop through the order_line list to SQL INSERT or UPDATE the records
|
||||
log.info('Loop through the order_line list to SQL INSERT or UPDATE the records')
|
||||
for order_line_obj_new in order_obj_new.order_line_li:
|
||||
log.info(f"New order_line: order_line_id_random={order_line_obj_new.id_random}; product_id_random={order_line_obj_new.product_id_random}")
|
||||
log.debug(order_line_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=False, exclude={'order_line_id_random', 'product_type_id', 'product_type', 'created_on', 'updated_on'}))
|
||||
|
||||
order_line_obj_data = order_line_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'order_line_id_random', 'product_type_id', 'product_type', 'created_on', 'updated_on'})
|
||||
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
try:
|
||||
order_line_obj_db = Order_Line_DB_Base(**order_line_obj_new)
|
||||
log.debug(order_line_obj_db)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
order_line_obj_db_data = order_line_obj_db.dict(by_alias=False, exclude_defaults=False, exclude_unset=True)
|
||||
log.debug(order_line_obj_db_data)
|
||||
|
||||
order_line_obj_data['order_id'] = order_id
|
||||
|
||||
if order_line_obj_resp := sql_insert_or_update(sql=None, data=order_line_obj_data, table_name='order_line', rm_id_random=True, id_random_length=8): pass
|
||||
else: return False
|
||||
log.debug(order_line_obj_resp)
|
||||
return order_id
|
||||
# ### END ### API Order Methods ### save_order_obj() ###
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# ### BEGIN ### API Order Methods ### get_order_rec_list() ###
|
||||
# Updated 2021-12-13
|
||||
# @logger_reset
|
||||
def get_order_rec_list(
|
||||
for_obj_type: str,
|
||||
for_obj_id: str,
|
||||
from_datetime: datetime.datetime = None,
|
||||
to_datetime: datetime.datetime = None,
|
||||
# balance_gt: int = 0, # $0 to $99999
|
||||
status: list|str = 'closed', # started, in progress, complete, all
|
||||
# checkout_status: str = 'none', # none, canceled, waiting, success, failed, unknown
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 500,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
# else: return False
|
||||
|
||||
data = {}
|
||||
if for_obj_type == 'account' and for_obj_id:
|
||||
data['account_id'] = redis_lookup_id_random(record_id_random=for_obj_id, table_name='account')
|
||||
sql_obj_type_id = f'`order`.account_id = :account_id'
|
||||
elif for_obj_type == 'person' and for_obj_id:
|
||||
data['person_id'] = redis_lookup_id_random(record_id_random=for_obj_id, table_name='person')
|
||||
sql_obj_type_id = f'`order`.person_id = :person_id'
|
||||
else:
|
||||
return False
|
||||
|
||||
# allowed_status_li = ['started', 'in progress', 'complete', 'all'] # OLD list
|
||||
# allowed_status_li = ['open', 'locked', 'reopened', 'closed', 'canceled', 'other'] # NEW list
|
||||
allowed_status_li = ['open', 'locked', 'in progress', 'reopened', 'closed', 'complete', 'canceled', 'other'] # TEMPORARY list...
|
||||
sql_status = ''
|
||||
if isinstance(status, list):
|
||||
data['status'] = status
|
||||
sql_status = f'AND `order`.status IN :status'
|
||||
elif status in allowed_status_li:
|
||||
if status == 'closed' or status == 'complete':
|
||||
data['status'] = ['closed', 'complete']
|
||||
sql_status = f'AND `order`.status IN :status'
|
||||
elif status == 'locked' or status == 'in progress':
|
||||
data['status'] = ['locked', 'in progress']
|
||||
sql_status = f'AND `order`.status IN :status'
|
||||
else:
|
||||
data['status'] = status
|
||||
sql_status = f'AND `order`.status = :status'
|
||||
elif status == 'all':
|
||||
sql_status = f'AND `order`.status IS NOT NULL'
|
||||
else:
|
||||
log.warning('The status value passed is not allowed. Returning None')
|
||||
return False
|
||||
|
||||
if from_datetime and to_datetime:
|
||||
data['from_datetime'] = from_datetime
|
||||
data['to_datetime'] = to_datetime
|
||||
sql_from_to_datetime = f'AND `order`.created_on >= :from_datetime AND `order`.created_on <= :to_datetime'
|
||||
elif from_datetime:
|
||||
data['from_datetime'] = from_datetime
|
||||
sql_from_to_datetime = f'AND `order`.created_on >= :from_datetime'
|
||||
elif to_datetime:
|
||||
data['to_datetime'] = to_datetime
|
||||
sql_from_to_datetime = f'AND `order`.created_on <= :to_datetime'
|
||||
else:
|
||||
sql_from_to_datetime = ''
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='order', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
log.debug(data)
|
||||
|
||||
sql = f"""
|
||||
SELECT `order`.id AS 'order_id', `order`.id_random AS 'order_id_random'
|
||||
FROM `order` AS `order`
|
||||
WHERE
|
||||
{sql_obj_type_id}
|
||||
{sql_status}
|
||||
{sql_from_to_datetime}
|
||||
{sql_enabled}
|
||||
ORDER BY `order`.created_on DESC, `order`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if order_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
log.info('Got a list result')
|
||||
order_rec_li = order_rec_li_result
|
||||
else: # [] or False
|
||||
log.info('No results or something went wrong')
|
||||
order_rec_li = order_rec_li_result
|
||||
|
||||
log.debug(order_rec_li_result)
|
||||
|
||||
return order_rec_li
|
||||
# ### END ### API Order Methods ### get_order_rec_list() ###
|
||||
250
app/methods/organization_methods.py
Normal file
250
app/methods/organization_methods.py
Normal file
@@ -0,0 +1,250 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging
|
||||
|
||||
from app.methods.contact_methods import create_contact_obj, create_update_contact_obj, load_contact_obj, update_contact_obj
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
from app.models.organization_models import Organization_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Organization Methods ### load_organization_obj() ###
|
||||
# NOTE: This needs to be updated to the newer method template. Like address, contact, or person -STI 2021-06-10
|
||||
def load_organization_obj(
|
||||
organization_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_contact: bool=False,
|
||||
inc_address: bool=False
|
||||
) -> Organization_Base|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if organization_id := redis_lookup_id_random(record_id_random=organization_id, table_name='organization'): pass
|
||||
else: return False
|
||||
|
||||
if organization_rec := sql_select(table_name='v_organization', record_id=organization_id): pass
|
||||
else: return False
|
||||
|
||||
#log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(organization_rec)
|
||||
|
||||
try:
|
||||
organization_obj = Organization_Base(**organization_rec)
|
||||
log.debug(organization_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
# Updated 2021-06-18
|
||||
if inc_contact:
|
||||
contact_id = organization_rec.get('contact_id', None)
|
||||
log.debug(contact_id)
|
||||
if contact_result := load_contact_obj(
|
||||
contact_id = contact_id,
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
inc_address = inc_address,
|
||||
):
|
||||
organization_obj.contact = contact_result
|
||||
else: organization_obj.contact = None
|
||||
|
||||
if model_as_dict:
|
||||
return organization_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return organization_obj
|
||||
# ### END ### API Organization Methods ### load_organization_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Organization Methods ### get_organization_rec_list() ###
|
||||
def get_organization_rec_list(
|
||||
for_obj_type: str,
|
||||
for_obj_id: str,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
else: return False
|
||||
data = {}
|
||||
data[f'{for_obj_type}_id'] = for_obj_id
|
||||
# data['for_obj_type'] = for_obj_type
|
||||
sql_obj_type_id = f'`tbl`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
# if enabled in ['enabled', 'disabled', 'all']:
|
||||
# if enabled == 'enabled':
|
||||
# data['enable'] = True
|
||||
# sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
# elif enabled == 'disabled':
|
||||
# data['enable'] = False
|
||||
# sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
# elif enabled == 'all':
|
||||
# sql_enabled = ''
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `tbl`.id AS 'organization_id', `tbl`.id_random AS 'organization_id_random'
|
||||
FROM `organization` AS `tbl`
|
||||
WHERE
|
||||
{sql_obj_type_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if organization_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
organization_rec_li = organization_rec_li_result
|
||||
else:
|
||||
organization_rec_li = []
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(organization_rec_li_result)
|
||||
|
||||
return organization_rec_li
|
||||
# ### END ### API Organization Methods ### get_organization_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Organization Methods ### update_organization_obj() ###
|
||||
# NOTE: This will create an organization and then also create a linked contact if organization_obj.contact data is passed. The create_contact_obj will create a contact and then also create a linked address if organization_obj.contact.address data is passed.
|
||||
# Reviewed and updated 2021-08-10
|
||||
def update_organization_obj(
|
||||
organization_id: int|str, # Ideally the int ID should be passed. This allows for updating of the id_random value.
|
||||
organization_obj_up: Organization_Base,
|
||||
create_sub_obj: bool = False,
|
||||
) -> bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if organization_obj_up.contact_id and organization_obj_up.contact:
|
||||
contact_id = organization_obj_up.contact_id
|
||||
contact_obj_up = organization_obj_up.contact
|
||||
log.debug(contact_id)
|
||||
log.debug(contact_obj_up)
|
||||
if contact_obj_up_result := update_contact_obj(
|
||||
contact_id = contact_id,
|
||||
contact_dict_obj = contact_obj_up,
|
||||
create_sub_obj = create_sub_obj,
|
||||
):
|
||||
log.debug(contact_obj_up_result)
|
||||
else:
|
||||
log.debug(contact_obj_up_result)
|
||||
return False
|
||||
elif organization_obj_up.contact and not organization_obj_up.contact.id:
|
||||
# NOTE: This will blindly create a new contact even if there was one associated but the organization.contact_id was not found.
|
||||
contact_obj_in = organization_obj_up.contact
|
||||
log.debug(contact_obj_in)
|
||||
if contact_obj_in_result := create_contact_obj(
|
||||
account_id = contact_obj_in.account_id,
|
||||
contact_dict_obj=contact_obj_in,
|
||||
):
|
||||
# log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(contact_obj_in_result)
|
||||
organization_obj_up.contact_id = contact_obj_in_result
|
||||
else:
|
||||
# log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(contact_obj_in_result)
|
||||
return False
|
||||
|
||||
organization_dict_up = organization_obj_up.dict(by_alias=False, exclude_unset=True, exclude={'contact', 'person', 'user'})
|
||||
log.debug(organization_dict_up)
|
||||
|
||||
if organization_obj_up_result := sql_update(data=organization_dict_up, table_name='organization', rm_id_random=True):
|
||||
log.debug(organization_obj_up_result)
|
||||
return True
|
||||
else:
|
||||
log.debug(organization_obj_up_result)
|
||||
return False
|
||||
# ### END ### API Organization Methods ### update_organization_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Organization Methods ### create_update_organization_obj() ###
|
||||
def create_update_organization_obj(
|
||||
organization_id: int|str|None, # Ideally the int ID should be passed. This allows for updating of the id_random value.
|
||||
organization_obj: Organization_Base,
|
||||
process_contact: bool = False,
|
||||
) -> bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if organization_id:
|
||||
if organization_id := redis_lookup_id_random(record_id_random=organization_id, table_name='organization'): pass
|
||||
else: return False
|
||||
organization_obj.id = organization_id
|
||||
else:
|
||||
# Insert record now and update later
|
||||
organization_dict_in = organization_obj.dict(by_alias=False, exclude_unset=True, exclude={'contact', 'person', 'user'})
|
||||
log.debug(organization_dict_in)
|
||||
organization_in_result = sql_insert(
|
||||
data = organization_dict_in,
|
||||
table_name = 'organization',
|
||||
rm_id_random = True,
|
||||
id_random_length = default_num_bytes,
|
||||
)
|
||||
log.debug(organization_in_result)
|
||||
if isinstance(organization_in_result, bool) and organization_in_result is True:
|
||||
return organization_in_result
|
||||
elif isinstance(organization_in_result, int):
|
||||
organization_id = organization_in_result
|
||||
organization_obj.id = organization_id
|
||||
else:
|
||||
return False # This should not happen.
|
||||
|
||||
# Process contact data
|
||||
if process_contact and organization_obj.contact:
|
||||
contact_obj = organization_obj.contact
|
||||
contact_obj.for_type = 'organization'
|
||||
contact_obj.for_id = organization_id
|
||||
contact_id = organization_obj.contact_id_random
|
||||
contact_result = create_update_contact_obj(
|
||||
contact_id = contact_id,
|
||||
contact_obj = contact_obj,
|
||||
process_address = True, # Setting to True under the assumption that if there is contact information then there is probably an address.
|
||||
)
|
||||
log.debug(contact_result)
|
||||
if isinstance(contact_result, bool) and contact_result is True:
|
||||
pass # Do not need to update organization object.
|
||||
elif isinstance(contact_result, bool) and contact_result is False:
|
||||
pass # Do not need to update organization object.
|
||||
elif isinstance(contact_result, int):
|
||||
organization_obj.contact_id = contact_result
|
||||
# pass # Do not need to update organization object.
|
||||
else:
|
||||
log.warning('Something may have gone wrong while trying to create or update a contact.')
|
||||
|
||||
# Process organization data
|
||||
organization_dict_up = organization_obj.dict(by_alias=False, exclude_unset=True, exclude={'contact', 'person', 'user'})
|
||||
log.debug(organization_dict_up)
|
||||
|
||||
# Update record
|
||||
organization_up_result = sql_update(
|
||||
data = organization_dict_up,
|
||||
table_name = 'organization',
|
||||
rm_id_random = True,
|
||||
)
|
||||
log.debug(organization_up_result)
|
||||
if isinstance(organization_up_result, bool) and organization_up_result is True:
|
||||
return organization_id
|
||||
elif isinstance(organization_up_result, bool) and organization_up_result is False:
|
||||
return False
|
||||
elif isinstance(organization_up_result, int):
|
||||
return organization_up_result
|
||||
else:
|
||||
return False
|
||||
# ### END ### API Organization Methods ### create_update_organization_obj() ###
|
||||
147
app/methods/page_methods.py
Normal file
147
app/methods/page_methods.py
Normal file
@@ -0,0 +1,147 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_insert_or_update, sql_select, sql_update
|
||||
from app.lib_general import log, logging
|
||||
|
||||
# from app.methods.page_methods import load_page_obj, get_page_rec_list
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
from app.models.page_models import Page_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Page Methods ### load_page_obj() ###
|
||||
# Updated 2021-08-20
|
||||
def load_page_obj(
|
||||
page_id: int|str,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> Page_Base|dict|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if page_id := redis_lookup_id_random(record_id_random=page_id, table_name='page'): pass
|
||||
else: return False
|
||||
|
||||
if page_rec := sql_select(table_name='page', record_id=page_id): pass
|
||||
else: return False
|
||||
|
||||
log.debug(page_rec)
|
||||
|
||||
try:
|
||||
page_obj = Page_Base(**page_rec)
|
||||
log.debug(page_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
if model_as_dict:
|
||||
return page_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return page_obj
|
||||
# ### END ### API Page Methods ### load_page_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Page Methods ### get_page_rec_list() ###
|
||||
# Partially updated 2021-08-20
|
||||
def get_page_rec_list(
|
||||
for_obj_type: str,
|
||||
for_obj_id: str,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
else: return False
|
||||
data = {}
|
||||
data[f'{for_obj_type}_id'] = for_obj_id
|
||||
# data['for_obj_type'] = for_obj_type
|
||||
sql_obj_type_id = f'`page`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `page`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `page`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `page`.id AS 'page_id', `page`.id_random AS 'page_id_random'
|
||||
FROM `page` AS `page`
|
||||
WHERE
|
||||
{sql_obj_type_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `page`.created_on DESC, `page`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if page_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
page_rec_li = page_rec_li_result
|
||||
else:
|
||||
page_rec_li = []
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(page_rec_li_result)
|
||||
|
||||
return page_rec_li
|
||||
# ### END ### API Page Methods ### get_page_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Page Methods ### get_page_rec_w_alias() ###
|
||||
# Updated 2021-08-19
|
||||
def get_page_rec_w_alias(
|
||||
account_id: str,
|
||||
alias: str,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> dict|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['account_id'] = account_id
|
||||
data['alias'] = alias
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `page`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `page`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `page`.id AS 'page_id', `page`.id_random AS 'page_id_random'
|
||||
FROM `page` AS `page`
|
||||
WHERE page.account_id = :account_id
|
||||
AND page.alias = :alias
|
||||
{sql_enabled}
|
||||
LIMIT 1;
|
||||
"""
|
||||
|
||||
if page_rec_result := sql_select(data=data, sql=sql):
|
||||
page_rec = page_rec_result
|
||||
else:
|
||||
page_rec = None
|
||||
log.debug(page_rec_result)
|
||||
|
||||
return page_rec
|
||||
# ### END ### API Page Methods ### get_page_rec_w_alias() ###
|
||||
1899
app/methods/person_methods.py
Normal file
1899
app/methods/person_methods.py
Normal file
File diff suppressed because it is too large
Load Diff
230
app/methods/post_comment_methods.py
Normal file
230
app/methods/post_comment_methods.py
Normal file
@@ -0,0 +1,230 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.methods.person_methods import load_person_obj
|
||||
# from app.methods.user_methods import load_user_obj
|
||||
|
||||
from app.models.post_comment_models import Post_Comment_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Post Comment Methods ### create_post_comment_obj() ###
|
||||
@logger_reset
|
||||
def create_post_comment_obj(post_comment_obj_new:Post_Comment_Base):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if not post_comment_obj_new:
|
||||
return False
|
||||
|
||||
post_comment_obj_data = post_comment_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'user', 'created_on', 'updated_on'})
|
||||
|
||||
if post_comment_obj_in_result := sql_insert(data=post_comment_obj_data, table_name='post_comment', rm_id_random=True, id_random_length=8): pass
|
||||
else:
|
||||
return False
|
||||
|
||||
log.debug(post_comment_obj_in_result)
|
||||
|
||||
post_comment_id = post_comment_obj_in_result
|
||||
|
||||
log.debug(f'Returning the new post_comment_id: {post_comment_id}')
|
||||
return post_comment_id
|
||||
# ### END ### API Post Comment Methods ### create_post_comment_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Post Comment Methods ### load_post_comment_obj() ###
|
||||
@logger_reset
|
||||
def load_post_comment_obj(
|
||||
post_comment_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_person: bool = False,
|
||||
inc_user: bool = False,
|
||||
) -> Post_Comment_Base|dict|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if post_comment_id := redis_lookup_id_random(record_id_random=post_comment_id, table_name='post_comment'): pass
|
||||
else: return False
|
||||
|
||||
if post_comment_rec := sql_select(table_name='v_post_comment', record_id=post_comment_id):
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(post_comment_rec)
|
||||
else:
|
||||
return False
|
||||
|
||||
try:
|
||||
post_comment_obj = Post_Comment_Base(**post_comment_rec)
|
||||
log.debug(post_comment_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
|
||||
# Updated 2021-06-22
|
||||
if inc_person:
|
||||
# from app.methods.person_methods import load_person_obj
|
||||
if person_result := load_person_obj(
|
||||
person_id = post_comment_rec.get('person_id', None),
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
):
|
||||
post_comment_obj.person = person_result
|
||||
else: post_comment_obj.person = None
|
||||
|
||||
|
||||
# Updated 2021-06-18
|
||||
if inc_user:
|
||||
log.warning(f'This is being deprecated? load_post_comment_obj() inc_user')
|
||||
# from app.methods.user_methods import load_user_obj
|
||||
# user_result = load_user_obj(
|
||||
# user_id = post_comment_rec.get('user_id', None),
|
||||
# limit = limit,
|
||||
# by_alias = by_alias,
|
||||
# exclude_unset = exclude_unset,
|
||||
# model_as_dict = model_as_dict,
|
||||
# enabled = enabled,
|
||||
# )
|
||||
# post_comment_obj.user = user_result
|
||||
pass
|
||||
|
||||
if model_as_dict:
|
||||
return post_comment_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return post_comment_obj
|
||||
# ### END ### API Post Comment Methods ### load_post_comment_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Post Comment Methods ### update_post_comment_obj() ###
|
||||
@logger_reset
|
||||
def update_post_comment_obj(
|
||||
post_comment_id: int|str, # Ideally the int ID should be passed. This allows for updating of the id_random value.
|
||||
post_comment_obj_up: Post_Comment_Base,
|
||||
create_sub_obj: bool = False,
|
||||
) -> bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if post_comment_id := redis_lookup_id_random(record_id_random=post_comment_id, table_name='post_comment'): pass
|
||||
else: return False
|
||||
|
||||
post_comment_obj_up.id = post_comment_id
|
||||
|
||||
log.debug(post_comment_obj_up)
|
||||
# log.debug(post_comment_obj_up.dict(by_alias=True, exclude_unset=True))
|
||||
log.debug(post_comment_obj_up.dict(by_alias=False, exclude_unset=True))
|
||||
# log.debug(post_comment_obj_up.dict(by_alias=False, exclude_unset=False))
|
||||
|
||||
#post_comment_dict_up = post_comment_obj_up.dict(by_alias=False, exclude_unset=True)
|
||||
|
||||
# if post_comment_obj_up.person_id and post_comment_obj_up.person:
|
||||
# person_id = post_comment_obj_up.person_id
|
||||
# person_obj_up = post_comment_obj_up.person
|
||||
# log.debug(person_id)
|
||||
# log.debug(person_obj_up)
|
||||
# if person_obj_up_result := update_person_obj(
|
||||
# person_id = person_id,
|
||||
# person_obj_up = person_obj_up,
|
||||
# create_sub_obj = create_sub_obj,
|
||||
# ):
|
||||
# log.debug(person_obj_up_result)
|
||||
# else:
|
||||
# log.debug(person_obj_up_result)
|
||||
# return False
|
||||
|
||||
# if post_comment_obj_up.user_id and post_comment_obj_up.user:
|
||||
# user_id = post_comment_obj_up.user_id
|
||||
# user_obj_up = post_comment_obj_up.user
|
||||
# log.debug(user_id)
|
||||
# log.debug(user_obj_up)
|
||||
# if user_obj_up_result := update_user_obj(
|
||||
# user_id = user_id,
|
||||
# user_dict_obj = user_obj_up,
|
||||
# create_sub_obj = create_sub_obj,
|
||||
# ):
|
||||
# log.debug(user_obj_up_result)
|
||||
# else:
|
||||
# log.debug(user_obj_up_result)
|
||||
# return False
|
||||
|
||||
post_comment_dict_up = post_comment_obj_up.dict(by_alias=False, exclude_unset=True, exclude={'user'})
|
||||
log.debug(post_comment_dict_up)
|
||||
|
||||
if post_comment_obj_up_result := sql_update(data=post_comment_dict_up, table_name='post_comment', rm_id_random=True):
|
||||
log.debug(post_comment_obj_up_result)
|
||||
return True
|
||||
else:
|
||||
log.debug(post_comment_obj_up_result)
|
||||
return False
|
||||
# ### END ### API Post Comment Methods ### update_post_comment_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Post Comment Methods ### get_post_comment_rec_list() ###
|
||||
# Updated 2021-12-13
|
||||
@logger_reset
|
||||
def get_post_comment_rec_list(
|
||||
for_obj_type: str,
|
||||
for_obj_id: str,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
else: return False
|
||||
data = {}
|
||||
data[f'{for_obj_type}_id'] = for_obj_id
|
||||
# data['for_obj_type'] = for_obj_type
|
||||
sql_obj_type_id = f'`post_comment`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
# if enabled in ['enabled', 'disabled', 'all']:
|
||||
# if enabled == 'enabled':
|
||||
# data['enable'] = True
|
||||
# sql_enabled = f'AND `post_comment`.enable = :enable'
|
||||
# elif enabled == 'disabled':
|
||||
# data['enable'] = False
|
||||
# sql_enabled = f'AND `post_comment`.enable = :enable'
|
||||
# elif enabled == 'all':
|
||||
# sql_enabled = ''
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `post_comment`.id AS 'post_comment_id', `post_comment`.id_random AS 'post_comment_id_random'
|
||||
FROM `post_comment` AS `post_comment`
|
||||
WHERE
|
||||
{sql_obj_type_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `post_comment`.created_on DESC, `post_comment`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if post_comment_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
log.info('Got a list result')
|
||||
post_comment_rec_li = post_comment_rec_li_result
|
||||
else: # [] or False
|
||||
log.info('No results or something went wrong')
|
||||
post_comment_rec_li = post_comment_rec_li_result
|
||||
|
||||
log.debug(post_comment_rec_li_result)
|
||||
|
||||
return post_comment_rec_li
|
||||
# ### END ### API Post Comment Methods ### get_post_comment_rec_list() ###
|
||||
263
app/methods/post_methods.py
Normal file
263
app/methods/post_methods.py
Normal file
@@ -0,0 +1,263 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.methods.person_methods import load_person_obj
|
||||
# from app.methods.post_comment_methods import create_post_comment_obj, update_post_comment_obj
|
||||
from app.methods.post_comment_methods import get_post_comment_rec_list, load_post_comment_obj
|
||||
# from app.methods.user_methods import load_user_obj
|
||||
|
||||
from app.models.post_models import Post_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Post Methods ### create_post_obj() ###
|
||||
@logger_reset
|
||||
def create_post_obj(post_obj_new:Post_Base):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if not post_obj_new:
|
||||
return False
|
||||
|
||||
post_obj_data = post_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'user', 'created_on', 'updated_on'})
|
||||
|
||||
if post_obj_in_result := sql_insert(data=post_obj_data, table_name='post', rm_id_random=True, id_random_length=8): pass
|
||||
else:
|
||||
return False
|
||||
|
||||
log.debug(post_obj_in_result)
|
||||
|
||||
post_id = post_obj_in_result
|
||||
|
||||
log.debug(f'Returning the new post_id: {post_id}')
|
||||
return post_id
|
||||
# ### END ### API Post Methods ### create_post_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Post Methods ### load_post_obj() ###
|
||||
# Updated 2021-12-16
|
||||
@logger_reset
|
||||
def load_post_obj(
|
||||
post_id: int|str,
|
||||
limit: int = 1000,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
inc_person: bool = False,
|
||||
inc_post_comment_list: bool = False,
|
||||
inc_user: bool = False,
|
||||
) -> Post_Base|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if post_id := redis_lookup_id_random(record_id_random=post_id, table_name='post'): pass
|
||||
else: return False
|
||||
|
||||
if post_rec := sql_select(table_name='v_post', record_id=post_id):
|
||||
log.debug(post_rec)
|
||||
else: return False
|
||||
|
||||
log.debug(post_rec)
|
||||
|
||||
try:
|
||||
post_obj = Post_Base(**post_rec)
|
||||
log.debug(post_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
# Updated 2021-06-22
|
||||
if inc_person:
|
||||
# from app.methods.person_methods import load_person_obj
|
||||
if person_result := load_person_obj(
|
||||
person_id = post_rec.get('person_id', None),
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
):
|
||||
post_obj.person = person_result
|
||||
else: post_obj.person = None
|
||||
|
||||
# Updated 2021-06-17
|
||||
if inc_post_comment_list:
|
||||
if post_comment_rec_list_result := get_post_comment_rec_list(
|
||||
for_obj_type = 'post',
|
||||
for_obj_id = post_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
post_comment_result_list = []
|
||||
for post_comment_rec in post_comment_rec_list_result:
|
||||
post_comment_result_list.append(
|
||||
load_post_comment_obj(
|
||||
post_comment_id = post_comment_rec.get('post_comment_id', None),
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
inc_person = inc_person,
|
||||
inc_user = inc_user,
|
||||
)
|
||||
)
|
||||
post_obj.post_comment_list = post_comment_result_list
|
||||
else: post_obj.post_comment_list = []
|
||||
|
||||
# Updated 2021-06-18
|
||||
if inc_user:
|
||||
log.warning(f'This is being deprecated? load_post_obj() inc_user')
|
||||
# from app.methods.user_methods import load_user_obj
|
||||
# user_result = load_user_obj(
|
||||
# user_id = post_rec.get('user_id', None),
|
||||
# limit = limit,
|
||||
# by_alias = by_alias,
|
||||
# exclude_unset = exclude_unset,
|
||||
# model_as_dict = model_as_dict,
|
||||
# enabled = enabled,
|
||||
# )
|
||||
# post_obj.user = user_result
|
||||
pass
|
||||
|
||||
if model_as_dict:
|
||||
return post_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return post_obj
|
||||
# ### END ### API Post Methods ### load_post_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Post Methods ### update_post_obj() ###
|
||||
@logger_reset
|
||||
def update_post_obj(
|
||||
post_id: int|str, # Ideally the int ID should be passed. This allows for updating of the id_random value.
|
||||
post_obj_up: Post_Base,
|
||||
create_sub_obj: bool = False,
|
||||
) -> bool:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if post_id := redis_lookup_id_random(record_id_random=post_id, table_name='post'): pass
|
||||
else: return False
|
||||
|
||||
post_obj_up.id = post_id
|
||||
|
||||
log.debug(post_obj_up)
|
||||
# log.debug(post_obj_up.dict(by_alias=True, exclude_unset=True))
|
||||
log.debug(post_obj_up.dict(by_alias=False, exclude_unset=True))
|
||||
# log.debug(post_obj_up.dict(by_alias=False, exclude_unset=False))
|
||||
|
||||
#post_dict_up = post_obj_up.dict(by_alias=False, exclude_unset=True)
|
||||
|
||||
# if post_obj_up.person_id and post_obj_up.person:
|
||||
# person_id = post_obj_up.person_id
|
||||
# person_obj_up = post_obj_up.person
|
||||
# log.debug(person_id)
|
||||
# log.debug(person_obj_up)
|
||||
# if person_obj_up_result := update_person_obj(
|
||||
# person_id=person_id,
|
||||
# person_obj_up=person_obj_up,
|
||||
# create_sub_obj=create_sub_obj,
|
||||
# ):
|
||||
# log.debug(person_obj_up_result)
|
||||
# else:
|
||||
# log.debug(person_obj_up_result)
|
||||
# return False
|
||||
|
||||
# if post_obj_up.user_id and post_obj_up.user:
|
||||
# user_id = post_obj_up.user_id
|
||||
# user_obj_up = post_obj_up.user
|
||||
# log.debug(user_id)
|
||||
# log.debug(user_obj_up)
|
||||
# if user_obj_up_result := update_user_obj(
|
||||
# user_id=user_id,
|
||||
# user_dict_obj=user_obj_up,
|
||||
# create_sub_obj=create_sub_obj,
|
||||
# ):
|
||||
# log.debug(user_obj_up_result)
|
||||
# else:
|
||||
# log.debug(user_obj_up_result)
|
||||
# return False
|
||||
|
||||
post_dict_up = post_obj_up.dict(by_alias=False, exclude_unset=True, exclude={'user'})
|
||||
log.debug(post_dict_up)
|
||||
|
||||
if post_obj_up_result := sql_update(data=post_dict_up, table_name='post', rm_id_random=True):
|
||||
log.debug(post_obj_up_result)
|
||||
return True
|
||||
else:
|
||||
log.debug(post_obj_up_result)
|
||||
return False
|
||||
# ### END ### API Post Methods ### update_post_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Post Methods ### get_post_rec_list() ###
|
||||
# Updated 2021-12-13
|
||||
@logger_reset
|
||||
def get_post_rec_list(
|
||||
for_obj_type: str,
|
||||
for_obj_id: str,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
archive_on: datetime.datetime = None,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
else: return False
|
||||
data = {}
|
||||
data[f'{for_obj_type}_id'] = for_obj_id
|
||||
# data['for_obj_type'] = for_obj_type
|
||||
sql_obj_type_id = f'`post`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `post`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `post`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
|
||||
if archive_on:
|
||||
data['archive_on'] = archive_on
|
||||
sql_archive_on = 'AND post.archive_on >= :archive_on'
|
||||
else:
|
||||
sql_archive_on = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `post`.id AS 'post_id', `post`.id_random AS 'post_id_random'
|
||||
FROM `post` AS `post`
|
||||
WHERE
|
||||
{sql_obj_type_id}
|
||||
{sql_enabled}
|
||||
{sql_archive_on}
|
||||
ORDER BY `post`.created_on DESC, `post`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if post_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
log.info('Got a list result')
|
||||
post_rec_li = post_rec_li_result
|
||||
else: # [] or False
|
||||
log.info('No results or something went wrong')
|
||||
post_rec_li = post_rec_li_result
|
||||
|
||||
log.debug(post_rec_li_result)
|
||||
|
||||
return post_rec_li
|
||||
# ### END ### API Post Methods ### get_post_rec_list() ###
|
||||
122
app/methods/product_methods.py
Normal file
122
app/methods/product_methods.py
Normal file
@@ -0,0 +1,122 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.lib_general import log, logging
|
||||
from app.db_sql import redis_lookup_id_random, sql_insert_or_update, sql_select
|
||||
|
||||
from app.models.product_models import Product_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Product Methods ### load_product_obj() ###
|
||||
def load_product_obj(
|
||||
product_id: int|str,
|
||||
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
) -> Product_Base:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if product_id := redis_lookup_id_random(record_id_random=product_id, table_name='product'): pass
|
||||
else: return False
|
||||
|
||||
if product_rec := sql_select(table_name='v_product', record_id=product_id): pass
|
||||
else: return False
|
||||
|
||||
try:
|
||||
product_obj = Product_Base(**product_rec)
|
||||
log.debug(product_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
if model_as_dict:
|
||||
return product_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return product_obj
|
||||
# ### END ### API Product Methods ### load_product_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Product Methods ### get_product_rec_list() ###
|
||||
# Updated 2021-07-01
|
||||
def get_product_rec_list(
|
||||
account_id: str = None,
|
||||
for_obj_type: str = None,
|
||||
for_obj_id: str = None,
|
||||
prod_type: str = None,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
|
||||
data = {}
|
||||
data['account_id'] = account_id
|
||||
data['for_obj_type'] = for_obj_type
|
||||
data['for_obj_id'] = for_obj_id
|
||||
|
||||
if account_id:
|
||||
sql_account_id = f'`product`.account_id = :account_id'
|
||||
else: sql_account_id = ''
|
||||
|
||||
if for_obj_type and for_obj_id: # event_exhibit, event_registration, fundraising, membership_group, membership_type
|
||||
if for_obj_type == 'account':
|
||||
sql_account_id = f'`product`.account_id = :for_obj_id'
|
||||
sql_for_obj_type_id = ''
|
||||
else:
|
||||
sql_for_obj_type_id = f'`product`.for_type = :for_obj_type AND `product`.for_id = :for_obj_id'
|
||||
else: sql_for_obj_type_id = ''
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `product`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `product`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
else: sql_enabled = ''
|
||||
|
||||
if prod_type in ['event', 'event_option', 'event_registration', 'fundraising', 'membership_group', 'membership_type']:
|
||||
data['type_name'] = prod_type
|
||||
|
||||
sql_product_type = f"""AND product.type_name = :type_name"""
|
||||
else: sql_product_type = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `product`.id AS 'product_id', `product`.id_random AS 'product_id_random'
|
||||
FROM `v_product` AS `product`
|
||||
WHERE
|
||||
{sql_account_id}
|
||||
{sql_for_obj_type_id}
|
||||
{sql_product_type}
|
||||
{sql_enabled}
|
||||
ORDER BY `product`.created_on DESC, `product`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(sql)
|
||||
|
||||
if product_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
product_rec_li = product_rec_li_result
|
||||
else:
|
||||
product_rec_li = []
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(product_rec_li_result)
|
||||
|
||||
return product_rec_li
|
||||
# ### END ### API Product Methods ### get_product_rec_list() ###
|
||||
179
app/methods/site_domain_methods.py
Normal file
179
app/methods/site_domain_methods.py
Normal file
@@ -0,0 +1,179 @@
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_enable_part, sql_insert, sql_limit_offset_part, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.models.site_domain_models import Site_Domain_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Site Domain Methods ### create_site_domain_obj() ###
|
||||
def create_site_domain_obj(site_domain_obj_new:Site_Domain_Base):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if not site_domain_obj_new:
|
||||
return False
|
||||
|
||||
site_domain_obj_data = site_domain_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'user', 'created_on', 'updated_on'})
|
||||
|
||||
if site_domain_obj_in_result := sql_insert(
|
||||
data=site_domain_obj_data,
|
||||
table_name='site_domain',
|
||||
rm_id_random=True,
|
||||
id_random_length=8
|
||||
): pass
|
||||
else: return False
|
||||
|
||||
log.debug(site_domain_obj_in_result)
|
||||
|
||||
site_domain_id = site_domain_obj_in_result
|
||||
|
||||
log.debug(f'New site_domain_id: {site_domain_id}')
|
||||
return site_domain_id
|
||||
# ### END ### API Site Domain Methods ### create_site_domain_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Site Domain Methods ### load_site_domain_obj() ###
|
||||
def load_site_domain_obj(
|
||||
site_domain_id: int|str,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
# inc_site_domain_list: bool = False,
|
||||
) -> Site_Domain_Base|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if site_domain_id := redis_lookup_id_random(record_id_random=site_domain_id, table_name='site_domain'): pass
|
||||
else: return False
|
||||
|
||||
if site_domain_rec := sql_select(table_name='v_site_domain', record_id=site_domain_id):
|
||||
log.debug(site_domain_rec)
|
||||
else: return False
|
||||
|
||||
# if site_domain_rec := sql_select(table_name='site_domain', record_id=site_domain_id):
|
||||
# log.debug(site_domain_rec)
|
||||
# else: return False
|
||||
|
||||
log.debug(site_domain_rec)
|
||||
|
||||
try:
|
||||
site_domain_obj = Site_Domain_Base(**site_domain_rec)
|
||||
log.debug(site_domain_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
if model_as_dict:
|
||||
return site_domain_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return site_domain_obj
|
||||
# ### END ### API Site Domain Methods ### load_site_domain_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Site Domain Methods ### update_site_domain_obj() ###
|
||||
def update_site_domain_obj(
|
||||
site_domain_id: int|str, # This allows for updating of the id_random value.
|
||||
site_domain_obj_up: Site_Domain_Base,
|
||||
create_sub_obj: bool = False,
|
||||
) -> bool:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if site_domain_id := redis_lookup_id_random(record_id_random=site_domain_id, table_name='site_domain'): pass
|
||||
else: return False
|
||||
|
||||
site_domain_obj_up.id = site_domain_id
|
||||
|
||||
log.debug(site_domain_obj_up)
|
||||
log.debug(site_domain_obj_up.dict(by_alias=False, exclude_unset=True))
|
||||
# log.debug(site_domain_obj_up.dict(by_alias=False, exclude_unset=False))
|
||||
|
||||
site_domain_dict_up = site_domain_obj_up.dict(by_alias=False, exclude_unset=True, exclude={'user'})
|
||||
log.debug(site_domain_dict_up)
|
||||
|
||||
if site_domain_obj_up_result := sql_update(data=site_domain_dict_up, table_name='site_domain', rm_id_random=True):
|
||||
log.debug(site_domain_obj_up_result)
|
||||
return True
|
||||
else:
|
||||
log.debug(site_domain_obj_up_result)
|
||||
return False
|
||||
# ### END ### API Site Domain Methods ### update_site_domain_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Site Domain Methods ### get_site_domain_rec_list() ###
|
||||
def get_site_domain_rec_list(
|
||||
site_id: int,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if site_id := redis_lookup_id_random(record_id_random=site_id, table_name='site'): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['site_id'] = site_id
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='site_domain', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
sql = f"""
|
||||
SELECT `site_domain`.id AS 'site_domain_id', `site_domain`.id_random AS 'site_domain_id_random'
|
||||
FROM `site_domain` AS `site_domain`
|
||||
WHERE
|
||||
`site_domain`.site_id = :site_id
|
||||
{sql_enabled}
|
||||
ORDER BY `site_domain`.fqdn ASC, `site_domain`.access_key ASC, `site_domain`.required_referrer ASC, `site_domain`.created_on DESC, `site_domain`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if site_domain_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
site_domain_rec_li = site_domain_rec_li_result
|
||||
else:
|
||||
site_domain_rec_li = []
|
||||
|
||||
return site_domain_rec_li
|
||||
# ### END ### API Site Domain Methods ### get_site_domain_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Site Domain Methods ### lookup_site_domain_fqdn() ###
|
||||
def lookup_site_domain_fqdn(
|
||||
fqdn: str,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
data = {}
|
||||
data['fqdn'] = fqdn
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='site_domain', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
sql = f"""
|
||||
SELECT `site_domain`.id AS 'site_domain_id', `site_domain`.id_random AS 'site_domain_id_random'
|
||||
FROM `v_site_domain` AS site_domain
|
||||
WHERE
|
||||
site_domain.fqdn = :fqdn
|
||||
{sql_enabled}
|
||||
ORDER BY `site_domain`.fqdn ASC, `site_domain`.access_key ASC, `site_domain`.required_referrer ASC, `site_domain`.created_on DESC, `site_domain`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if site_domain_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
site_domain_rec_li = site_domain_rec_li_result
|
||||
else:
|
||||
site_domain_rec_li = []
|
||||
|
||||
return site_domain_rec_li
|
||||
# ### END ### API Site Domain Methods ### get_site_domain_rec_list() ###
|
||||
164
app/methods/site_methods.py
Normal file
164
app/methods/site_methods.py
Normal file
@@ -0,0 +1,164 @@
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_enable_part, sql_insert, sql_limit_offset_part, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset
|
||||
|
||||
from app.methods.site_domain_methods import get_site_domain_rec_list, load_site_domain_obj
|
||||
|
||||
from app.models.site_models import Site_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Site Methods ### create_site_obj() ###
|
||||
def create_site_obj(site_obj_new:Site_Base):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if not site_obj_new:
|
||||
return False
|
||||
|
||||
site_obj_data = site_obj_new.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'user', 'created_on', 'updated_on'})
|
||||
|
||||
if site_obj_in_result := sql_insert(
|
||||
data=site_obj_data,
|
||||
table_name='site',
|
||||
rm_id_random=True,
|
||||
id_random_length=8
|
||||
): pass
|
||||
else: return False
|
||||
|
||||
log.debug(site_obj_in_result)
|
||||
|
||||
site_id = site_obj_in_result
|
||||
|
||||
log.debug(f'New site_id: {site_id}')
|
||||
return site_id
|
||||
# ### END ### API Site Methods ### create_site_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Site Methods ### load_site_obj() ###
|
||||
def load_site_obj(
|
||||
site_id: int|str,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
inc_site_domain_list: bool = False,
|
||||
) -> Site_Base|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if site_id := redis_lookup_id_random(record_id_random=site_id, table_name='site'): pass
|
||||
else: return False
|
||||
|
||||
if site_rec := sql_select(table_name='v_site', record_id=site_id): pass
|
||||
else: return False
|
||||
|
||||
log.debug(site_rec)
|
||||
|
||||
try:
|
||||
site_obj = Site_Base(**site_rec)
|
||||
log.debug(site_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
|
||||
# Updated 2021-06-18
|
||||
if inc_site_domain_list:
|
||||
if site_domain_rec_list_result := get_site_domain_rec_list(
|
||||
site_id = site_id,
|
||||
enabled = enabled,
|
||||
limit = limit,
|
||||
offset = offset,
|
||||
):
|
||||
site_domain_result_list = []
|
||||
for site_domain_rec in site_domain_rec_list_result:
|
||||
site_domain_result_list.append(
|
||||
load_site_domain_obj(
|
||||
site_domain_id = site_domain_rec.get('site_domain_id', None),
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
)
|
||||
)
|
||||
site_obj.site_domain_list = site_domain_result_list
|
||||
else: site_obj.site_domain_list = []
|
||||
|
||||
if model_as_dict:
|
||||
return site_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return site_obj
|
||||
# ### END ### API Site Methods ### load_site_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Site Methods ### update_site_obj() ###
|
||||
def update_site_obj(
|
||||
site_id: int|str, # This allows for updating of the id_random value.
|
||||
site_obj_up: Site_Base,
|
||||
create_sub_obj: bool = False,
|
||||
) -> bool:
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if site_id := redis_lookup_id_random(record_id_random=site_id, table_name='site'): pass
|
||||
else: return False
|
||||
|
||||
site_obj_up.id = site_id
|
||||
|
||||
log.debug(site_obj_up)
|
||||
log.debug(site_obj_up.dict(by_alias=False, exclude_unset=True))
|
||||
# log.debug(site_obj_up.dict(by_alias=False, exclude_unset=False))
|
||||
|
||||
site_dict_up = site_obj_up.dict(by_alias=False, exclude_unset=True, exclude={'user'})
|
||||
log.debug(site_dict_up)
|
||||
|
||||
if site_obj_up_result := sql_update(data=site_dict_up, table_name='site', rm_id_random=True):
|
||||
log.debug(site_obj_up_result)
|
||||
return True
|
||||
else:
|
||||
log.debug(site_obj_up_result)
|
||||
return False
|
||||
# ### END ### API Site Methods ### update_site_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API Site Methods ### get_site_rec_list() ###
|
||||
# Updated 2022-06-14
|
||||
@logger_reset
|
||||
def get_site_rec_list(
|
||||
account_id: int,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['account_id'] = account_id
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='site', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
sql = f"""
|
||||
SELECT `site`.id AS 'site_id', `site`.id_random AS 'site_id_random'
|
||||
FROM `site` AS `site`
|
||||
WHERE
|
||||
`site`.account_id = :account_id
|
||||
{sql_enabled}
|
||||
ORDER BY `site`.created_on DESC, `site`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
|
||||
if site_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
site_rec_li = site_rec_li_result
|
||||
else:
|
||||
site_rec_li = []
|
||||
|
||||
return site_rec_li
|
||||
# ### END ### API Site Methods ### get_site_rec_list() ###
|
||||
728
app/methods/user_methods.py
Normal file
728
app/methods/user_methods.py
Normal file
@@ -0,0 +1,728 @@
|
||||
import datetime, random, secrets
|
||||
import urllib.parse
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_enable_part, sql_insert, sql_limit_offset_part, sql_select, sql_update
|
||||
from app.lib_general import log, logging, logger_reset, secure_hash_string, send_email
|
||||
|
||||
# from app.methods.account_methods import load_account_cfg_obj
|
||||
# from app.methods.contact_methods import create_contact_obj, load_contact_obj, update_contact_obj
|
||||
from app.methods.order_methods import load_order_obj, get_order_rec_list
|
||||
from app.methods.organization_methods import load_organization_obj # , update_organization_obj
|
||||
from app.methods.person_methods import create_person_obj_v3, load_person_obj, update_person_obj
|
||||
# from app.methods.post_methods import get_post_rec_list, load_post_obj
|
||||
from app.methods.user_role_methods import get_user_role_rec_list, load_user_role_obj
|
||||
|
||||
from app.models.common_field_schema import default_num_bytes
|
||||
from app.models.user_models import User_Base, User_New_Base, User_Out_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API User Methods ### create_user_obj() ###
|
||||
# NOTE: This will create a new user and also hash a new password string if given.
|
||||
# NOTE: This uses the User_New_Base model, not User_Base or User_Out_Base
|
||||
# Updated 2022-01-06
|
||||
def create_user_obj(
|
||||
account_id: int|str,
|
||||
user_dict_obj: User_New_Base,
|
||||
person_id: int = None, # This should be required in the future
|
||||
allow_update: bool = False, # Allow updating the user account if one is found
|
||||
avoid_dup_username: bool = False, # Avoid creating a duplicate by modifying the supplied username
|
||||
set_default_password: bool = True,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = True, # Fail if any thing goes wrong for sub objects
|
||||
return_dict: bool = False,
|
||||
) -> bool|dict|int:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
# NOTE: Remove at future date. Is this check needed if we trust that the ID is checked ahead of time?
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
|
||||
if person_id := redis_lookup_id_random(record_id_random=person_id, table_name='person'): pass
|
||||
elif person_id is None: pass
|
||||
else: return False
|
||||
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
# log.debug(type(user_dict_obj))
|
||||
if isinstance(user_dict_obj, dict):
|
||||
user_dict = user_dict_obj
|
||||
try:
|
||||
user_obj = User_New_Base(**user_dict)
|
||||
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
user_obj = user_dict_obj
|
||||
user_obj.account_id = account_id
|
||||
|
||||
user_dict = user_obj.dict(by_alias=False, exclude_defaults=False, exclude_unset=True, exclude={'contact', 'contact_id_random', 'new_password', 'organization', 'person', 'person_id_random', 'created_on', 'updated_on'})
|
||||
log.debug(user_obj)
|
||||
log.debug(user_dict)
|
||||
|
||||
# ### SECTION ### Process data
|
||||
# Look for an account_id in the user_obj
|
||||
if account_id: pass
|
||||
elif account_id := user_obj.account_id: pass
|
||||
|
||||
user_obj.account_id = account_id # Is this needed?
|
||||
user_dict['account_id'] = account_id
|
||||
|
||||
if user_obj.new_password:
|
||||
log.info('A new password was passed.')
|
||||
log.debug(user_obj.new_password)
|
||||
elif set_default_password:
|
||||
log.warning('A new password was not passed. Setting a default password.')
|
||||
user_obj.new_password = secrets.token_urlsafe(default_num_bytes)
|
||||
log.debug(user_obj.new_password)
|
||||
|
||||
hash_string = secure_hash_string(string=user_obj.new_password)
|
||||
user_obj.password = hash_string
|
||||
user_dict['password'] = hash_string
|
||||
else:
|
||||
log.warning('A new password was not passed and not setting a default password.')
|
||||
|
||||
# user_dict['password'] = user_obj.password # There has to be a better way to do this??? It thinks "password" is unset and so is excluded?
|
||||
|
||||
# Look for a person_id in the user_obj
|
||||
if person_id: pass
|
||||
elif person_id := user_obj.person.id: pass
|
||||
|
||||
if person_id:
|
||||
# Link to an existing person
|
||||
log.info(f'Adding person_id to user_dict. User ID: {person_id}')
|
||||
user_obj.person_id = person_id # Is this needed?
|
||||
user_dict['person_id'] = person_id
|
||||
|
||||
log.debug(user_obj)
|
||||
log.debug(user_dict)
|
||||
|
||||
# if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
# elif account_id := user_dict.get('account_id', None): pass
|
||||
# else: return False
|
||||
|
||||
# account_id = user_dict.get('account_id', None)
|
||||
username = user_dict.get('username', None)
|
||||
|
||||
log.info(f'Checking if the username is already in use for the account... Account: {account_id}; Username: {username}')
|
||||
sql_select_user = f"""
|
||||
SELECT user.id, user.id_random, user.name, user.email
|
||||
FROM `user` AS user
|
||||
WHERE user.account_id = :account_id and user.username = :username
|
||||
"""
|
||||
|
||||
if sql_select_user_result := sql_select(sql=sql_select_user, data=user_dict, rm_id_random=True):
|
||||
if isinstance(sql_select_user_result, list):
|
||||
log.exception(f'Multiple user accounts already exists with this username. The database needs to be checked. Account ID: {account_id}; Username: {username}')
|
||||
return False
|
||||
user_id = sql_select_user_result.get('id', None)
|
||||
person_id_for_user_id = sql_select_user_result.get('person_id', None)
|
||||
log.info(f'A user account already exists with this username. Current User ID: {user_id}; Username: {username}; Person ID for User: {person_id_for_user_id}; Person ID: {person_id}')
|
||||
if allow_update:
|
||||
log.info(f'Updating instead of inserting. Current User ID: {user_id}; Username: {username}')
|
||||
# NOTE: Should this call the update_user_obj() function instead??? NOTE NOTE NOTE NOTE
|
||||
if person_id_for_user_id == person_id or person_id_for_user_id is None:
|
||||
user_dict['id'] = user_id
|
||||
user_dict['person_id'] = person_id
|
||||
if user_dict_up_result := sql_update(data=user_dict, table_name='user', rm_id_random=True):
|
||||
log.info(f'User updated with new user data. User ID: {user_id}')
|
||||
else:
|
||||
log.warning(f'User not updated with new user data. User ID: {user_id}')
|
||||
log.debug(user_dict_up_result)
|
||||
return False
|
||||
else:
|
||||
log.info(f'Updating is now allowed. Current User ID: {user_id}; Username: {username}')
|
||||
if avoid_dup_username:
|
||||
log.info(f'Avoiding duplicate username is now allowed. Suggested Username: {username}')
|
||||
new_username = username+'-'+str(random.randint(10, 99))
|
||||
user_dict['username'] = new_username
|
||||
if user_dict_in_result := sql_insert(
|
||||
data = user_dict,
|
||||
table_name = 'user',
|
||||
rm_id_random = True,
|
||||
id_random_length = default_num_bytes
|
||||
): pass
|
||||
else:
|
||||
log.warning(f'User not created.')
|
||||
log.debug(user_dict_in_result)
|
||||
return False
|
||||
user_id = user_dict_in_result
|
||||
else:
|
||||
log.warning(f'Updating is not allowed and avoid duplicate username is not allowed. Username: {username}')
|
||||
return False
|
||||
#log.setLevel(logging.DEBUG)
|
||||
# log.debug(user_dict_up_result)
|
||||
|
||||
log.debug(f'Returning the existing user_id: {user_id}')
|
||||
else:
|
||||
if user_dict_in_result := sql_insert(
|
||||
data = user_dict,
|
||||
table_name = 'user',
|
||||
rm_id_random = True,
|
||||
id_random_length = default_num_bytes
|
||||
): pass
|
||||
else:
|
||||
log.warning(f'User not created.')
|
||||
log.debug(user_dict_in_result)
|
||||
return False
|
||||
user_id = user_dict_in_result
|
||||
|
||||
log.info(f'Returning the new user_id: {user_id}')
|
||||
|
||||
return user_id
|
||||
# ### END ### API User Methods ### create_user_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API User Methods ### update_user_obj() ###
|
||||
# Updated 2022-01-06
|
||||
def update_user_obj(
|
||||
user_id: int|str, # Ideally the int ID should be passed. This allows for updating of the id_random value.
|
||||
user_dict_obj: User_Base,
|
||||
person_id: int = None, # This should be required in the future?
|
||||
set_default_password: bool = True,
|
||||
create_sub_obj: bool = False,
|
||||
fail_any: bool = True, # Fail if any thing goes wrong for sub objects
|
||||
return_dict: bool = False,
|
||||
) -> bool|int:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# ### SECTION ### Secondary data validation
|
||||
# NOTE: Remove at future date. Is this check needed if we trust that the ID is checked ahead of time?
|
||||
if user_id := redis_lookup_id_random(record_id_random=user_id, table_name='user'): pass
|
||||
else: return False
|
||||
|
||||
if person_id := redis_lookup_id_random(record_id_random=person_id, table_name='person'): pass
|
||||
elif person_id is None: pass
|
||||
else: return False
|
||||
|
||||
log.info('Create dictionary or Pydantic object')
|
||||
log.debug(type(user_dict_obj))
|
||||
if isinstance(user_dict_obj, dict):
|
||||
user_dict = user_dict_obj
|
||||
user_dict['id'] = user_id
|
||||
try:
|
||||
user_obj = User_Base(**user_dict)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
else:
|
||||
user_obj = user_dict_obj
|
||||
user_obj.id = user_id
|
||||
log.debug(user_obj)
|
||||
|
||||
# IMPORTANT NOTE: Need to be extra careful if allowing an update to password, super, or manager. Maybe other fields?
|
||||
user_dict = user_obj.dict(by_alias=False, exclude_unset=True, exclude={'password', 'super', 'manager', 'contact', 'organization', 'person', 'created_on', 'updated_on'})
|
||||
|
||||
|
||||
# log.debug(type(user_dict_obj))
|
||||
# if isinstance(user_dict_obj, dict):
|
||||
# try:
|
||||
# user_obj = User_Base(**user_dict_obj)
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(user_obj)
|
||||
# except ValidationError as e:
|
||||
# log.error(e.json())
|
||||
# return False
|
||||
|
||||
# user_obj.id = user_id
|
||||
|
||||
# log.debug(user_obj)
|
||||
# log.debug(user_obj.dict(by_alias=True, exclude_unset=True))
|
||||
log.debug(user_obj.dict(by_alias=False, exclude_unset=True))
|
||||
# log.debug(user_obj.dict(by_alias=False, exclude_unset=False))
|
||||
|
||||
# if user_obj.contact_id and user_obj.contact:
|
||||
# contact_id = user_obj.contact_id
|
||||
# contact_obj_up = user_obj.contact
|
||||
# log.debug(contact_id)
|
||||
# log.debug(contact_obj_up)
|
||||
# if contact_obj_up_result := update_contact_obj(
|
||||
# contact_id=contact_id,
|
||||
# contact_dict_obj=contact_obj_up,
|
||||
# create_sub_obj=create_sub_obj,
|
||||
# ):
|
||||
# log.debug(contact_obj_up_result)
|
||||
# else:
|
||||
# log.debug(contact_obj_up_result)
|
||||
# return False
|
||||
# elif user_obj.contact and not user_obj.contact.id:
|
||||
# # NOTE: This will blindly create a new contact even if there was one associated but the user_obj.contact_id was not found.
|
||||
# contact_obj_in = user_obj.contact
|
||||
# log.debug(contact_obj_in)
|
||||
# if contact_obj_in_result := create_contact_obj(contact_dict_obj=contact_obj_in):
|
||||
# # log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(contact_obj_in_result)
|
||||
# user_obj.contact_id = contact_obj_in_result
|
||||
# else:
|
||||
# # log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(contact_obj_in_result)
|
||||
# return False
|
||||
|
||||
# if organization_obj_update := user_obj.organization:
|
||||
# log.debug(organization_obj_update)
|
||||
# if organization_obj_up_result := update_organization_obj(organization_obj_update):
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(organization_obj_up_result)
|
||||
# return True
|
||||
# else:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(organization_obj_up_result)
|
||||
# return False
|
||||
# else:
|
||||
# if organization_obj_in_result := insert_organization_obj(organization_obj_insert):
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(organization_obj_in_result)
|
||||
# return True # NOTE: This needs to return the new organization ID
|
||||
# else:
|
||||
# log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(organization_obj_in_result)
|
||||
# return False
|
||||
|
||||
# if user_obj.person_id and user_obj.person:
|
||||
# person_id = user_obj.person_id
|
||||
# person_obj_up = user_obj.person
|
||||
# log.debug(person_id)
|
||||
# log.debug(person_obj_up)
|
||||
# if person_obj_up_result := update_person_obj(
|
||||
# person_id=person_id,
|
||||
# person_obj_up=person_obj_up,
|
||||
# create_sub_obj=create_sub_obj,
|
||||
# ):
|
||||
# log.debug(person_obj_up_result)
|
||||
# else:
|
||||
# log.debug(person_obj_up_result)
|
||||
# return False
|
||||
# elif user_obj.person and not user_obj.person.id:
|
||||
# # NOTE: This will blindly create a new person even if there was one associated but the user_obj.person_id was not found.
|
||||
# person_obj_in = user_obj.person
|
||||
# log.debug(person_obj_in)
|
||||
# if person_obj_in_result := create_person_obj_v3(person_obj_new=person_obj_in):
|
||||
# # log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(person_obj_in_result)
|
||||
# person_obj_up.person_id = person_obj_in_result
|
||||
# else:
|
||||
# # log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
# log.debug(person_obj_in_result)
|
||||
# return False
|
||||
|
||||
# IMPORTANT NOTE: Need to be extra careful if allowing an update to password, super, or manager. Maybe other fields?
|
||||
# user_dict = user_obj.dict(by_alias=False, exclude_unset=True, exclude={'password', 'super', 'manager', 'contact', 'organization', 'person'})
|
||||
# log.debug(user_dict)
|
||||
|
||||
# ### SECTION ### Process data
|
||||
user_obj.id = user_id # Is this needed?
|
||||
user_dict['id'] = user_id
|
||||
|
||||
# if user_obj.new_password:
|
||||
log.debug(user_obj.new_password)
|
||||
# if user_obj.password:
|
||||
log.debug(user_obj.password)
|
||||
# else:
|
||||
# user_obj.new_password = secrets.token_urlsafe(default_num_bytes)
|
||||
# hash_string = secure_hash_string(string=user_obj.new_password)
|
||||
# user_obj.password = hash_string
|
||||
# user_dict['password'] = hash_string
|
||||
|
||||
# log.debug(user_obj.new_password)
|
||||
|
||||
# Look for a person_id in the user_obj
|
||||
if person_id: pass
|
||||
elif person_id := user_obj.person.id: pass
|
||||
|
||||
if person_id:
|
||||
# Link to an existing person
|
||||
log.info(f'Adding person_id to person_dict. Person ID: {person_id}')
|
||||
user_obj.person_id = person_id # Is this needed?
|
||||
user_dict['person_id'] = person_id
|
||||
|
||||
log.debug(user_obj)
|
||||
log.debug(user_dict)
|
||||
|
||||
if user_dict_up_result := sql_update(
|
||||
data = user_dict,
|
||||
table_name = 'user',
|
||||
rm_id_random = True
|
||||
): pass
|
||||
else:
|
||||
log.warning(f'User not updated.')
|
||||
log.debug(user_dict_up_result)
|
||||
return False
|
||||
|
||||
log.debug(user_dict_up_result)
|
||||
|
||||
return True
|
||||
# ### END ### API User Methods ### update_user_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API User Methods ### load_user_obj() ###
|
||||
def load_user_obj(
|
||||
user_id: int|str,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 100,
|
||||
offset: int = 0,
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
inc_address: bool = False,
|
||||
# inc_archive_list: bool = False, # deprecated
|
||||
inc_contact: bool = False,
|
||||
inc_event_list: bool = False, # deprecated
|
||||
# inc_hosted_file_list: bool = False, # deprecated
|
||||
# inc_journal_list: bool = False, # deprecated
|
||||
# inc_journal_entry_list: bool = False, # deprecated
|
||||
# inc_membership_person: bool = False, # deprecated
|
||||
inc_order_cfg: bool = False, # deprecated
|
||||
inc_order_line_list: bool = False, # deprecated
|
||||
inc_order_list: bool = False, # deprecated
|
||||
inc_order_cart_list: bool = False, # deprecated
|
||||
inc_organization: bool = False, # deprecated
|
||||
inc_person: bool = False,
|
||||
# inc_person_list: bool = False, # deprecated
|
||||
# inc_post_list: bool = False, # deprecated
|
||||
# inc_post_comment_list: bool = False, # deprecated
|
||||
inc_user_role_list: bool = False,
|
||||
) -> User_Out_Base|dict|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if user_id := redis_lookup_id_random(record_id_random=user_id, table_name='user'): pass
|
||||
else: return False
|
||||
|
||||
if user_rec := sql_select(table_name='v_user', record_id=user_id): pass
|
||||
else: return False
|
||||
|
||||
log.debug(user_rec)
|
||||
|
||||
try:
|
||||
user_obj = User_Out_Base(**user_rec)
|
||||
log.debug(user_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
# Updated 2021-06-18
|
||||
if inc_contact:
|
||||
log.warning(f'This is being deprecated? load_user_obj() inc_contact')
|
||||
# contact_id = user_rec.get('contact_id', None)
|
||||
# log.debug(contact_id)
|
||||
# if contact_result := load_contact_obj(
|
||||
# contact_id = contact_id,
|
||||
# limit = limit,
|
||||
# by_alias = by_alias,
|
||||
# exclude_unset = exclude_unset,
|
||||
# model_as_dict = model_as_dict,
|
||||
# enabled = enabled,
|
||||
# inc_address = inc_address,
|
||||
# ):
|
||||
# user_obj.contact = contact_result
|
||||
# else: user_obj.contact = {} # None
|
||||
|
||||
if inc_event_list:
|
||||
log.warning(f'This is being deprecated? load_user_obj() inc_event_list')
|
||||
from app.methods.event_methods import load_event_obj_list
|
||||
if event_dict_list := load_event_obj_list(
|
||||
user_id = user_id,
|
||||
limit = limit,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
):
|
||||
user_obj.event_list = event_dict_list
|
||||
else: user_obj.event_list = []
|
||||
|
||||
# Updated 2021-06-18
|
||||
if inc_order_list:
|
||||
log.warning(f'This is being deprecated? load_user_obj() inc_order_list')
|
||||
if order_rec_list_result := get_order_rec_list(
|
||||
for_obj_type = 'user',
|
||||
for_obj_id = user_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
order_result_list = []
|
||||
for order_rec in order_rec_list_result:
|
||||
if load_order_result := load_order_obj(
|
||||
order_id = order_rec.get('order_id', None),
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
inc_order_cfg = inc_order_cfg,
|
||||
inc_order_line_list = inc_order_line_list,
|
||||
inc_person = inc_person,
|
||||
):
|
||||
order_result_list.append(load_order_result)
|
||||
else: order_result_list.append(None)
|
||||
user_obj.order_list = order_result_list
|
||||
else: user_obj.order_list = []
|
||||
|
||||
# Updated 2021-12-14
|
||||
if inc_organization:
|
||||
log.warning(f'This is being deprecated? load_user_obj() inc_organization')
|
||||
organization_id = user_rec.get('organization_id', None)
|
||||
log.debug(organization_id)
|
||||
if organization_result := load_organization_obj(
|
||||
organization_id = organization_id,
|
||||
limit = limit,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
enabled = enabled,
|
||||
inc_address = inc_address,
|
||||
inc_contact = inc_contact,
|
||||
):
|
||||
user_obj.organization = organization_result
|
||||
else: user_obj.organization = {} # None
|
||||
|
||||
# Updated 2021-12-14
|
||||
if inc_person:
|
||||
person_id = user_rec.get('person_id', None)
|
||||
log.debug(person_id)
|
||||
if person_result := load_person_obj(
|
||||
person_id = person_id,
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
inc_address = inc_address,
|
||||
inc_contact = inc_contact,
|
||||
inc_organization = inc_organization,
|
||||
):
|
||||
user_obj.person = person_result
|
||||
else: user_obj.person = {} # None
|
||||
log.debug(person_result)
|
||||
|
||||
# Updated 2021-06-18
|
||||
# if inc_post_list:
|
||||
# log.warning(f'This is being deprecated? load_user_obj() inc_post_list')
|
||||
# if post_rec_list_result := get_post_rec_list(
|
||||
# for_obj_type = 'user',
|
||||
# for_obj_id = user_id,
|
||||
# limit = limit,
|
||||
# enabled = enabled,
|
||||
# ):
|
||||
# post_result_list = []
|
||||
# for post_rec in post_rec_list_result:
|
||||
# if load_post_result := load_post_obj(
|
||||
# post_id = post_rec.get('post_id', None),
|
||||
# limit = limit,
|
||||
# by_alias = by_alias,
|
||||
# exclude_unset = exclude_unset,
|
||||
# model_as_dict = model_as_dict,
|
||||
# enabled = enabled,
|
||||
# inc_post_comment_list = inc_post_comment_list,
|
||||
# inc_person = inc_person,
|
||||
# # inc_user = inc_user,
|
||||
# ):
|
||||
# post_result_list.append(load_post_result)
|
||||
# else: post_result_list.append(None)
|
||||
# user_obj.post_list = post_result_list
|
||||
# else: user_obj.post_list = []
|
||||
|
||||
# Updated 2021-06-25
|
||||
if inc_user_role_list:
|
||||
if user_role_rec_list_result := get_user_role_rec_list(
|
||||
for_obj_type = 'user',
|
||||
for_obj_id = user_id,
|
||||
limit = limit,
|
||||
enabled = enabled,
|
||||
):
|
||||
user_role_result_list = []
|
||||
for user_role_rec in user_role_rec_list_result:
|
||||
if load_user_role_result := load_user_role_obj(
|
||||
user_role_id = user_role_rec.get('user_role_id', None),
|
||||
by_alias = by_alias,
|
||||
exclude_unset = exclude_unset,
|
||||
model_as_dict = model_as_dict,
|
||||
):
|
||||
user_role_result_list.append(load_user_role_result)
|
||||
else: user_role_result_list.append(None)
|
||||
user_obj.user_role_list = user_role_result_list
|
||||
else: user_obj.user_role_list = []
|
||||
|
||||
log.debug(user_obj)
|
||||
|
||||
if model_as_dict:
|
||||
return user_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return user_obj
|
||||
# ### END ### API User Methods ### load_user_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API User Methods ### get_user_rec_list() ###
|
||||
# Updated 2021-12-13
|
||||
@logger_reset
|
||||
def get_user_rec_list(
|
||||
account_id: int|str,
|
||||
hidden: str = 'not_hidden', # hidden, not_hidden, all
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
limit: int = 1000,
|
||||
offset: int = 0,
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
|
||||
data = {}
|
||||
data['account_id'] = account_id
|
||||
sql_where_account_id = f'`user`.account_id = :account_id'
|
||||
|
||||
# data[f'{for_obj_type}_id'] = for_obj_id
|
||||
# data['for_obj_type'] = for_obj_type
|
||||
# sql_obj_type_id = f'`user`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
sql_enabled, data['enable'] = sql_enable_part(table_name='user', enabled=enabled) # Reasonably safe return str and bool
|
||||
sql_limit = sql_limit_offset_part(limit=limit, offset=offset) # Reasonably safe return str
|
||||
|
||||
sql = f"""
|
||||
SELECT `user`.id AS 'user_id', `user`.id_random AS 'user_id_random'
|
||||
FROM `user` AS `user`
|
||||
WHERE
|
||||
{sql_where_account_id}
|
||||
{sql_enabled}
|
||||
ORDER BY user.name, user.email, user.username, `user`.created_on DESC, `user`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
log.debug(sql)
|
||||
|
||||
if user_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
log.info('Got a list result')
|
||||
user_rec_li = user_rec_li_result
|
||||
else: # [] or False
|
||||
log.info('No results or something went wrong')
|
||||
user_rec_li = user_rec_li_result
|
||||
|
||||
log.debug(user_rec_li_result)
|
||||
|
||||
return user_rec_li
|
||||
# ### END ### API User Methods ### get_user_rec_list() ###
|
||||
|
||||
|
||||
# ### BEGIN ### User Methods ### email_user_auth_key_url() ###
|
||||
# This generates a new auth_key token and emails the actual one time use sign in URL to the user's email.
|
||||
# Updated 2025-04-08
|
||||
def email_user_auth_key_url(
|
||||
account_id: int|str,
|
||||
user_id: int|str,
|
||||
root_url: str,
|
||||
key_param_name: str = 'auth_key',
|
||||
):
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if account_id := redis_lookup_id_random(record_id_random=account_id, table_name='account'): pass
|
||||
else: return False
|
||||
|
||||
if user_id := redis_lookup_id_random(record_id_random=user_id, table_name='user'): pass
|
||||
else: return False
|
||||
|
||||
if user_obj := load_user_obj(
|
||||
user_id = user_id,
|
||||
):
|
||||
log.info('User object loaded')
|
||||
if user_obj.enable and user_obj.allow_auth_key:
|
||||
new_auth_key = secrets.token_urlsafe(default_num_bytes)
|
||||
update_user_data = {}
|
||||
update_user_data['auth_key'] = new_auth_key
|
||||
|
||||
if user_rec_update_result := sql_update(
|
||||
table_name = 'user',
|
||||
record_id = user_id,
|
||||
data = update_user_data
|
||||
):
|
||||
log.info('The user record was updated with a new auth_key')
|
||||
else:
|
||||
log.warning('The user record was not updated with a new auth_key')
|
||||
return False
|
||||
else:
|
||||
log.warning('The user record was not enabled or auth_key is not allowed')
|
||||
return False
|
||||
else: return False
|
||||
log.debug(user_obj)
|
||||
|
||||
from app.methods.account_cfg_methods import load_account_cfg_obj
|
||||
if account_cfg := load_account_cfg_obj(
|
||||
account_id = account_id,
|
||||
):
|
||||
log.info('Account config loaded')
|
||||
else: return False
|
||||
log.debug(account_cfg)
|
||||
|
||||
user_id_random = user_obj.id_random # NOTE: Not user_id_random because of alias
|
||||
|
||||
from_email = account_cfg.default_no_reply_email
|
||||
from_name = account_cfg.default_no_reply_name
|
||||
|
||||
to_name = user_obj.name
|
||||
to_email = user_obj.email
|
||||
|
||||
bcc_email = account_cfg.confirm_email
|
||||
bcc_name = account_cfg.confirm_name
|
||||
|
||||
help_tech_email = account_cfg.help_tech_email
|
||||
help_tech_name = account_cfg.help_tech_name
|
||||
|
||||
account_short_name = account_cfg.account_short_name
|
||||
|
||||
username = user_obj.username
|
||||
enable = user_obj.enable
|
||||
if enable_from := user_obj.enable_from:
|
||||
# enable_from_datetime = datetime.datetime.fromisoformat(enable_from).replace(tzinfo=datetime.timezone.utc)
|
||||
enable_from_datetime = enable_from.replace(tzinfo=datetime.timezone.utc)
|
||||
enable_from_datetime = enable_from
|
||||
enable_from_str = enable_from_datetime.strftime('%A, %B %-d, %Y %-I:%M %p %Z')
|
||||
else: enable_from_str = '-- Not Set --'
|
||||
if enable_to := user_obj.enable_to:
|
||||
# enable_to_datetime = datetime.datetime.fromisoformat(enable_to).replace(tzinfo=datetime.timezone.utc)
|
||||
enable_to_datetime = enable_to.replace(tzinfo=datetime.timezone.utc)
|
||||
enable_to_str = enable_to_datetime.strftime('%A, %B %-d, %Y %-I:%M %p %Z')
|
||||
else: enable_to_str = '-- Not Set --'
|
||||
auth_key = user_obj.auth_key
|
||||
|
||||
user_login_url = f'{root_url}?username={urllib.parse.quote(username)}&user_email={urllib.parse.quote(to_email)}'
|
||||
# user_login_url = f'{root_url}user/login?username={urllib.parse.quote(username)}&email={urllib.parse.quote(to_email)}'
|
||||
|
||||
if key_param_name == 'auth_key':
|
||||
user_login_auth_key_url = f'{root_url}?user_id={urllib.parse.quote(user_id_random)}&auth_key={urllib.parse.quote(new_auth_key)}&valid_email={True}'
|
||||
elif key_param_name:
|
||||
user_login_auth_key_url = f'{root_url}?user_id={urllib.parse.quote(user_id_random)}&{key_param_name}={urllib.parse.quote(new_auth_key)}&valid_email={True}'
|
||||
|
||||
subject = f'{account_short_name}: One Time Use Sign In Link ({new_auth_key})'
|
||||
|
||||
body_html = f"""
|
||||
<p>{to_name},</p>
|
||||
|
||||
<p>If you did not request this sign in link, please delete this email. It is suggested that you delete this email after the sign in link has been used or if a new link has been requested.</p>
|
||||
|
||||
<p>The link below can only be used to sign in once. If you would like to sign in again using this method, you must <a href="{user_login_url}">request a new sign in link</a>. If you request multiple links, only the newest link will sign you in.</p>
|
||||
|
||||
<p><strong><a href="{user_login_auth_key_url}" style="appearance: button; display: inline-block; text-align: center; text-decoration: none; padding: .2rem .4rem; border: solid thin gray; border-radius: .2rem; background-color: lightyellow; color: black; font-size: larger;">Click to Sign In With One Time Use Link</a></strong></p>
|
||||
|
||||
<p>Or copy and paste the link:<br>
|
||||
<strong style="background-color: lightyellow; color: black; font-size: larger;"><a href="{user_login_auth_key_url}">{user_login_auth_key_url}</a></strong></p>
|
||||
|
||||
<p>Your username is: {username}<br>
|
||||
User account enabled: {enable}<br>
|
||||
User account enabled from: {enable_from_str}<br>
|
||||
User account enabled to: {enable_to_str}<br>
|
||||
Current one time use auth key for user account: {new_auth_key}</p>
|
||||
|
||||
<p>If you have questions about this email or trouble with this one time use link, you can email <a href="mailto:{help_tech_email}">{help_tech_name} ({help_tech_email})</a>.</p>
|
||||
|
||||
<p>Thank you!</p>
|
||||
"""
|
||||
|
||||
log.info('Trying send_email()...')
|
||||
if send_email(from_email=from_email, from_name=from_name, to_email=to_email, to_name=to_name, bcc_email=bcc_email, bcc_name=bcc_name, subject=subject, body_text=None, body_html=body_html):
|
||||
log.info(f'An email with a one time use sign in link was sent to {to_email}.')
|
||||
return True
|
||||
else:
|
||||
log.info(f'An email with a one time use sign in link was not sent to {to_email}.')
|
||||
return False
|
||||
# ### END ### User Methods ### email_user_auth_key_url() ###
|
||||
104
app/methods/user_role_methods.py
Normal file
104
app/methods/user_role_methods.py
Normal file
@@ -0,0 +1,104 @@
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random, sql_select
|
||||
from app.lib_general import log, logging
|
||||
|
||||
from app.models.user_role_models import User_Role_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API User Role Methods ### load_user_role_obj() ###
|
||||
# Updated 2021-06-25
|
||||
def load_user_role_obj(
|
||||
user_role_id: int|str, # NOTE: This is currently just an auto ID number, not a random string.
|
||||
by_alias: bool = True,
|
||||
exclude_unset: bool = True,
|
||||
model_as_dict: bool = False,
|
||||
) -> User_Role_Base|dict|bool:
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# if user_role_id := redis_lookup_id_random(record_id_random=user_role_id, table_name='user_role'): pass
|
||||
# else: return False
|
||||
|
||||
if user_role_rec := sql_select(table_name='v_user_role', record_id=user_role_id): pass
|
||||
else: return False
|
||||
|
||||
#log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(user_role_rec)
|
||||
|
||||
try:
|
||||
user_role_obj = User_Role_Base(**user_role_rec)
|
||||
log.debug(user_role_obj)
|
||||
except ValidationError as e:
|
||||
log.error(e.json())
|
||||
return False
|
||||
|
||||
if model_as_dict:
|
||||
return user_role_obj.dict(by_alias=by_alias, exclude_unset=exclude_unset) # pylint: disable=no-member
|
||||
else:
|
||||
return user_role_obj
|
||||
# ### END ### API User Role Methods ### load_user_role_obj() ###
|
||||
|
||||
|
||||
# ### BEGIN ### API User Role Methods ### get_user_role_rec_list() ###
|
||||
# Updated 2021-06-25
|
||||
def get_user_role_rec_list(
|
||||
for_obj_type: str,
|
||||
for_obj_id: str,
|
||||
limit: int = 1000,
|
||||
enabled: str = 'enabled', # enabled, disabled, all
|
||||
) -> list|bool:
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
if for_obj_id := redis_lookup_id_random(record_id_random=for_obj_id, table_name=for_obj_type): pass
|
||||
else: return False
|
||||
data = {}
|
||||
data[f'{for_obj_type}_id'] = for_obj_id
|
||||
# data['for_obj_type'] = for_obj_type
|
||||
sql_obj_type_id = f'`tbl`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
allowed_forign_key_li = ['user']
|
||||
if for_obj_type in allowed_forign_key_li:
|
||||
log.info(f'Query using forign key: {for_obj_type} {for_obj_id}')
|
||||
sql_obj_type_id = f'`tbl`.{for_obj_type}_id = :{for_obj_type}_id'
|
||||
|
||||
if enabled in ['enabled', 'disabled', 'all']:
|
||||
if enabled == 'enabled':
|
||||
data['enable'] = True
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'disabled':
|
||||
data['enable'] = False
|
||||
sql_enabled = f'AND `tbl`.enable = :enable'
|
||||
elif enabled == 'all':
|
||||
sql_enabled = ''
|
||||
|
||||
if limit:
|
||||
data['limit'] = limit
|
||||
sql_limit = f'LIMIT :limit'
|
||||
else:
|
||||
sql_limit = ''
|
||||
|
||||
sql = f"""
|
||||
SELECT `tbl`.id AS 'user_role_id'/*, `tbl`.id_random AS 'user_role_id_random'*/
|
||||
FROM `user_role` AS `tbl`
|
||||
WHERE
|
||||
{sql_obj_type_id}
|
||||
{sql_enabled}
|
||||
ORDER BY `tbl`.created_on DESC, `tbl`.updated_on DESC
|
||||
{sql_limit};
|
||||
"""
|
||||
else: return False
|
||||
if user_role_rec_li_result := sql_select(data=data, sql=sql, as_list=True):
|
||||
user_role_rec_li = user_role_rec_li_result
|
||||
else:
|
||||
user_role_rec_li = []
|
||||
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(user_role_rec_li_result)
|
||||
|
||||
return user_role_rec_li
|
||||
# ### END ### API User Role Methods ### get_user_role_rec_list() ###
|
||||
12
app/middleware.py
Normal file
12
app/middleware.py
Normal file
@@ -0,0 +1,12 @@
|
||||
import time
|
||||
from fastapi import Request
|
||||
|
||||
async def add_process_time_header(request: Request, call_next):
|
||||
"""
|
||||
Middleware to add the processing time to the response header.
|
||||
"""
|
||||
start_time = time.time()
|
||||
response = await call_next(request)
|
||||
process_time = time.time() - start_time
|
||||
response.headers['X-Process-Time'] = str(process_time)
|
||||
return response
|
||||
0
app/models/__init__.py
Normal file
0
app/models/__init__.py
Normal file
135
app/models/account_cfg_models.py
Normal file
135
app/models/account_cfg_models.py
Normal file
@@ -0,0 +1,135 @@
|
||||
import datetime, pytz
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random
|
||||
from app.lib_general import log, logging
|
||||
|
||||
from app.models.common_field_schema import base_fields, default_num_bytes
|
||||
from app.models.fundraising_cfg_models import Fundraising_Cfg_Base
|
||||
from app.models.membership_cfg_models import Membership_Cfg_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Account Cfg Models ### Account_Cfg_Base() ###
|
||||
class Account_Cfg_Base(BaseModel):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
id_random: Optional[str] = Field(
|
||||
# **base_fields['account_cfg_id_random'],
|
||||
alias = 'account_cfg_id_random',
|
||||
)
|
||||
id: Optional[int] = Field(
|
||||
alias = 'account_cfg_id'
|
||||
)
|
||||
|
||||
account_id_random: Optional[str]
|
||||
account_id: Optional[int]
|
||||
|
||||
account_code: Optional[str]
|
||||
account_name: Optional[str]
|
||||
account_short_name: Optional[str]
|
||||
account_description: Optional[str]
|
||||
|
||||
account_enable: Optional[bool]
|
||||
account_enable_from: Optional[datetime.datetime] = None
|
||||
account_enable_to: Optional[datetime.datetime] = None
|
||||
|
||||
modules_enabled: Optional[Json] = None
|
||||
|
||||
show_user_availability: Optional[bool]
|
||||
show_person_create: Optional[bool]
|
||||
person_create_label: Optional[str]
|
||||
show_person_view: Optional[bool]
|
||||
person_view_label: Optional[str]
|
||||
show_person_load: Optional[bool]
|
||||
person_load_label: Optional[str]
|
||||
show_cart: Optional[bool]
|
||||
cart_label: Optional[str]
|
||||
|
||||
default_no_reply_email: Optional[str]
|
||||
default_no_reply_name: Optional[str]
|
||||
default_reply_to_email: Optional[str]
|
||||
default_reply_to_name: Optional[str]
|
||||
|
||||
confirm_email: Optional[str]
|
||||
confirm_name: Optional[str]
|
||||
|
||||
# For general event help (attendees and registration)
|
||||
help_event_email: Optional[str]
|
||||
help_event_name: Optional[str]
|
||||
|
||||
# For event exhibit help
|
||||
help_event_exhibit_email: Optional[str]
|
||||
help_event_exhibit_name: Optional[str]
|
||||
|
||||
# For event presentation management help (chairs, organizers, persenters)
|
||||
help_event_presenter_email: Optional[str]
|
||||
help_event_presenter_name: Optional[str]
|
||||
|
||||
# General catch all help
|
||||
help_general_email: Optional[str]
|
||||
help_general_name: Optional[str]
|
||||
|
||||
# For contacting the organizations leadership (board, council, committee)
|
||||
help_leadership_email: Optional[str]
|
||||
help_leadership_name: Optional[str]
|
||||
|
||||
# For general membership help
|
||||
help_member_email: Optional[str]
|
||||
help_member_name: Optional[str]
|
||||
|
||||
# For general technical support
|
||||
help_tech_email: Optional[str]
|
||||
help_tech_name: Optional[str]
|
||||
|
||||
order_header: Optional[str]
|
||||
order_thanks: Optional[str]
|
||||
order_message: Optional[str]
|
||||
order_footer: Optional[str]
|
||||
order_fundraising_thanks: Optional[str]
|
||||
order_fundraising_message: Optional[str]
|
||||
fundraising_message: Optional[str]
|
||||
|
||||
post_rules: Optional[str]
|
||||
post_comment_rules: Optional[str]
|
||||
|
||||
show_post_title: Optional[bool]
|
||||
show_post_comment_title: Optional[bool]
|
||||
|
||||
hide_posts_after: Optional[int] # Should posts be singular?
|
||||
delete_posts_after: Optional[int] # Should posts be singular?
|
||||
|
||||
stripe_api_key: Optional[str] # Secret/Private
|
||||
stripe_publishable_key: Optional[str] # Publish/Sharable
|
||||
stripe_account_id: Optional[str] # Connected Stripe Account ID
|
||||
|
||||
created_on: Optional[datetime.datetime] = None
|
||||
updated_on: Optional[datetime.datetime] = None
|
||||
|
||||
# Including other related objects
|
||||
fundraising_cfg: Optional[Fundraising_Cfg_Base] # Priority l2
|
||||
membership_cfg: Optional[Membership_Cfg_Base] # Priority l2
|
||||
|
||||
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
|
||||
|
||||
@validator('id', always=True)
|
||||
def account_cfg_id_lookup(cls, v, values, **kwargs):
|
||||
if isinstance(v, int) and v > 0: return v
|
||||
elif id_random := values.get('id_random'):
|
||||
return redis_lookup_id_random(record_id_random=id_random, table_name='account_cfg')
|
||||
return None
|
||||
|
||||
@validator('account_id', always=True)
|
||||
def account_id_lookup(cls, v, values, **kwargs):
|
||||
if isinstance(v, int) and v > 0: return v
|
||||
elif id_random := values.get('account_id_random'):
|
||||
return redis_lookup_id_random(record_id_random=id_random, table_name='account')
|
||||
return None
|
||||
|
||||
class Config:
|
||||
underscore_attrs_are_private = True
|
||||
allow_population_by_field_name = True
|
||||
fields = base_fields
|
||||
# ### END ### API Account Cfg Models ### Account_Cfg_Base() ###
|
||||
104
app/models/account_models.py
Normal file
104
app/models/account_models.py
Normal file
@@ -0,0 +1,104 @@
|
||||
import datetime, pytz
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random
|
||||
from app.lib_general import log, logging
|
||||
|
||||
from app.models.common_field_schema import base_fields, default_num_bytes
|
||||
from app.models.account_cfg_models import Account_Cfg_Base
|
||||
# from app.models.address_models import Address_Base
|
||||
# from app.models.contact_models import Contact_Base
|
||||
# from app.models.event_models import Event_Base
|
||||
from app.models.fundraising_cfg_models import Fundraising_Cfg_Base
|
||||
from app.models.membership_cfg_models import Membership_Cfg_Base
|
||||
# from app.models.person_models import Person_Base
|
||||
# from app.models.user_models import User_Base
|
||||
|
||||
|
||||
# ### BEGIN ### API Account Models ### Account_Base() ###
|
||||
class Account_Base(BaseModel):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
id_random: Optional[str] = Field(
|
||||
**base_fields['account_id_random'],
|
||||
alias = 'account_id_random',
|
||||
# default_factory = lambda:secrets.token_urlsafe(default_num_bytes),
|
||||
)
|
||||
id: Optional[int] = Field(
|
||||
alias = 'account_id'
|
||||
)
|
||||
# account_id: Optional[int] = Field(
|
||||
# )
|
||||
|
||||
code: Optional[str]
|
||||
name: Optional[str]
|
||||
short_name: Optional[str]
|
||||
description: Optional[str]
|
||||
|
||||
hide: Optional[bool]
|
||||
priority: Optional[bool]
|
||||
sort: Optional[int]
|
||||
group: Optional[str]
|
||||
|
||||
enable: Optional[bool]
|
||||
enable_from: Optional[datetime.datetime] = None
|
||||
enable_to: Optional[datetime.datetime] = None
|
||||
|
||||
notes: Optional[str]
|
||||
created_on: Optional[datetime.datetime] = None
|
||||
updated_on: Optional[datetime.datetime] = None
|
||||
|
||||
# testing: Optional[str]
|
||||
|
||||
# Including other related objects
|
||||
account_cfg: Optional[Account_Cfg_Base] # Priority l1
|
||||
address_list: Optional[list] # Address_Base() # Priority l3
|
||||
archive_list: Optional[list] # Archive_Base() # Priority l1
|
||||
contact_list: Optional[list] # Contact_Base() # Priority l3
|
||||
event_list: Optional[list] # Event_Base() # Priority l1
|
||||
fundraising_cfg: Optional[Fundraising_Cfg_Base] # Priority l2
|
||||
hosted_file_list: Optional[list] # Hosted_File_Base() # Priority l2
|
||||
journal_list: Optional[list] # Journal_Base() # Priority l3
|
||||
membership_cfg: Optional[Membership_Cfg_Base] # Priority l2
|
||||
membership_group_list: Optional[list] # Membership_Group_Base() # Priority l2
|
||||
membership_person_list: Optional[list] # Membership_Person_Base() # Priority l2
|
||||
membership_type_list: Optional[list] # Membership_Type_Base() # Priority l2
|
||||
order_list: Optional[list] # Order_Base() # Priority l2
|
||||
organization_list: Optional[list] # Organization_Base() # Priority l3
|
||||
page_list: Optional[list] # Page_Base() # Priority l3
|
||||
person_list: Optional[list] # Person_Base() # Priority l2
|
||||
post_list: Optional[list] # Post_Base() # Priority l1
|
||||
product_list: Optional[list] # Product_Base() # Priority l3
|
||||
site_list: Optional[list] # Site_Base() # Priority l3
|
||||
user_list: Optional[list] # User_Base() # Priority l2
|
||||
|
||||
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
|
||||
|
||||
@validator('id', always=True)
|
||||
def account_id_lookup(cls, v, values, **kwargs):
|
||||
log.setLevel(logging.WARNING)
|
||||
log.debug(locals())
|
||||
|
||||
if values['id_random']:
|
||||
log.debug(values['id_random'])
|
||||
return redis_lookup_id_random(record_id_random=values['id_random'], table_name='account')
|
||||
return None
|
||||
|
||||
# @validator('account_id', always=True)
|
||||
# def account_id_duplicate(cls, v, values, **kwargs):
|
||||
# log.setLevel(logging.DEBUG)
|
||||
# log.debug(locals())
|
||||
|
||||
# if values['id']:
|
||||
# log.debug(values['id'])
|
||||
# return values['id']
|
||||
# return None
|
||||
|
||||
class Config:
|
||||
underscore_attrs_are_private = True
|
||||
fields = base_fields
|
||||
allow_population_by_field_name = True
|
||||
# ### END ### API Account Models ### Account_Base() ###
|
||||
128
app/models/activity_log_models.py
Normal file
128
app/models/activity_log_models.py
Normal file
@@ -0,0 +1,128 @@
|
||||
import datetime, pytz
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator
|
||||
|
||||
from app.db_sql import redis_lookup_id_random
|
||||
from app.lib_general import log, logging
|
||||
|
||||
from app.models.common_field_schema import base_fields, default_num_bytes
|
||||
|
||||
|
||||
# ### BEGIN ### API Activity Log Models ### Activity_Log_Base() ###
|
||||
class Activity_Log_Base(BaseModel):
|
||||
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
id_random: Optional[str] = Field(
|
||||
**base_fields['activity_log_id_random'],
|
||||
alias = 'activity_log_id_random',
|
||||
)
|
||||
id: Optional[int] = Field(
|
||||
alias = 'activity_log_id'
|
||||
)
|
||||
|
||||
account_id_random: Optional[str]
|
||||
account_id: Optional[int]
|
||||
|
||||
person_id_random: Optional[str]
|
||||
person_id: Optional[int]
|
||||
|
||||
user_id_random: Optional[str]
|
||||
user_id: Optional[int]
|
||||
|
||||
external_client_id: Optional[str]
|
||||
|
||||
google_ga: Optional[str]
|
||||
google_gid: Optional[str]
|
||||
|
||||
name: Optional[str]
|
||||
description: Optional[str]
|
||||
|
||||
source: Optional[str]
|
||||
url_root: Optional[str]
|
||||
url_full_path: Optional[str]
|
||||
url_params: Optional[str]
|
||||
|
||||
object_type: Optional[str]
|
||||
object_id_random: Optional[str]
|
||||
object_id: Optional[int]
|
||||
|
||||
action: Optional[str]
|
||||
action_with: Optional[str]
|
||||
action_on_type: Optional[str]
|
||||
action_on_id_random: Optional[str]
|
||||
action_on_id: Optional[int]
|
||||
action_on_code: Optional[str]
|
||||
action_data: Optional[str]
|
||||
|
||||
code: Optional[str]
|
||||
|
||||
type_id: Optional[int]
|
||||
type_name: Optional[str]
|
||||
|
||||
details: Optional[str]
|
||||
|
||||
# For now just using string instead of Json Pydantic data type
|
||||
other_json: Optional[str] # When getting the dict version for SQL this should be a string.
|
||||
meta_json: Optional[str] # When getting the dict version for SQL this should be a string.
|
||||
|
||||
enable: Optional[bool]
|
||||
|
||||
hide: Optional[bool]
|
||||
priority: Optional[bool]
|
||||
sort: Optional[int]
|
||||
group: Optional[str]
|
||||
|
||||
notes: Optional[str]
|
||||
|
||||
created_on: Optional[datetime.datetime] = None
|
||||
updated_on: Optional[datetime.datetime] = None
|
||||
|
||||
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
|
||||
|
||||
#@validator('activity_log_id_random', always=True)
|
||||
def activity_log_id_random_copy(cls, v, values, **kwargs):
|
||||
log.setLevel(logging.WARNING)
|
||||
log.debug(locals())
|
||||
|
||||
if id_random := values.get('id_random'):
|
||||
return id_random
|
||||
return None
|
||||
|
||||
@validator('id', always=True)
|
||||
def activity_log_id_lookup(cls, v, values, **kwargs):
|
||||
log.setLevel(logging.WARNING)
|
||||
log.debug(locals())
|
||||
|
||||
if values['id_random']:
|
||||
log.debug(values['id_random'])
|
||||
return redis_lookup_id_random(record_id_random=values['id_random'], table_name='activity_log')
|
||||
return None
|
||||
|
||||
@validator('account_id', always=True)
|
||||
def account_id_lookup(cls, v, values, **kwargs):
|
||||
if isinstance(v, int) and v > 0: return v
|
||||
elif id_random := values.get('account_id_random'):
|
||||
return redis_lookup_id_random(record_id_random=id_random, table_name='account')
|
||||
return None
|
||||
|
||||
@validator('person_id', always=True)
|
||||
def person_id_lookup(cls, v, values, **kwargs):
|
||||
if isinstance(v, int) and v > 0: return v
|
||||
elif id_random := values.get('person_id_random'):
|
||||
return redis_lookup_id_random(record_id_random=id_random, table_name='person')
|
||||
return None
|
||||
|
||||
@validator('user_id', always=True)
|
||||
def user_id_lookup(cls, v, values, **kwargs):
|
||||
if isinstance(v, int) and v > 0: return v
|
||||
elif id_random := values.get('user_id_random'):
|
||||
return redis_lookup_id_random(record_id_random=id_random, table_name='user')
|
||||
return None
|
||||
|
||||
class Config:
|
||||
underscore_attrs_are_private = True
|
||||
allow_population_by_field_name = True
|
||||
fields = base_fields
|
||||
# ### END ### API Activity Log Models ### Activity_Log_Base() ###
|
||||
94
app/models/address_models.py
Normal file
94
app/models/address_models.py
Normal file
@@ -0,0 +1,94 @@
|
||||
import datetime, pytz
|
||||
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator
|
||||
|
||||
from app.db_sql import get_id_random, redis_lookup_id_random
|
||||
from app.lib_general import log, logging
|
||||
|
||||
from app.models.common_field_schema import base_fields, default_num_bytes
|
||||
|
||||
|
||||
# ### BEGIN ### API Address Models ### Address_Base() ###
|
||||
class Address_Base(BaseModel):
|
||||
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
|
||||
log.debug(locals())
|
||||
|
||||
# --- Standardized Vision IDs (Strings) ---
|
||||
id: Optional[str] = Field(None, **base_fields['address_id_random'])
|
||||
address_id: Optional[str] = Field(None, **base_fields['address_id_random'])
|
||||
account_id: Optional[str] = Field(None, **base_fields['account_id_random'])
|
||||
contact_id: Optional[str] = Field(None, **base_fields['contact_id_random'])
|
||||
|
||||
for_type: Optional[str]
|
||||
for_id_random: Optional[str]
|
||||
for_id: Optional[int] = Field(None, exclude=True)
|
||||
|
||||
#organization: Optional[Organization_Base] = Organization_Base()
|
||||
|
||||
name: Optional[str]
|
||||
attention_to: Optional[str]
|
||||
organization_name: Optional[str]
|
||||
|
||||
line_1: Optional[str]
|
||||
line_2: Optional[str]
|
||||
line_3: Optional[str]
|
||||
city: Optional[str]
|
||||
country_subdivision_code: Optional[str]
|
||||
country_subdivision_name: Optional[str] # From country subdivision lookup table
|
||||
state_province: Optional[str] # Avoid using
|
||||
postal_code: Optional[str]
|
||||
country_alpha_2_code: Optional[str]
|
||||
country_name: Optional[str] # From country lookup table
|
||||
country: Optional[str] # Avoid using
|
||||
|
||||
lu_time_zone_id: Optional[str]
|
||||
timezone: Optional[str]
|
||||
|
||||
latitude: Optional[str]
|
||||
longitude: Optional[str]
|
||||
|
||||
map_url: Optional[str]
|
||||
|
||||
congressional_district: Optional[str]
|
||||
|
||||
enable: Optional[bool]
|
||||
hide: Optional[bool]
|
||||
priority: Optional[bool]
|
||||
sort: Optional[int]
|
||||
group: Optional[str]
|
||||
|
||||
notes: Optional[str]
|
||||
created_on: Optional[datetime.datetime] = None
|
||||
updated_on: Optional[datetime.datetime] = None
|
||||
|
||||
_processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
|
||||
|
||||
@root_validator(pre=True)
|
||||
def map_v3_ids(cls, values):
|
||||
"""
|
||||
Vision Transformer:
|
||||
Map DB keys to clean API keys and strip internal integers.
|
||||
"""
|
||||
# 1. Map Random Strings to Clean Names
|
||||
if rid := values.get('id_random') or values.get('address_id_random'):
|
||||
values['id'] = rid
|
||||
values['address_id'] = rid
|
||||
|
||||
if a_rid := values.get('account_id_random'):
|
||||
values['account_id'] = a_rid
|
||||
if c_rid := values.get('contact_id_random'):
|
||||
values['contact_id'] = c_rid
|
||||
|
||||
# 2. Prevent "Collision Population"
|
||||
for k in ['id', 'account_id', 'contact_id']:
|
||||
if k in values and not isinstance(values[k], str):
|
||||
del values[k]
|
||||
|
||||
return values
|
||||
|
||||
class Config:
|
||||
underscore_attrs_are_private = True
|
||||
allow_population_by_field_name = False
|
||||
fields = base_fields
|
||||
# ### END ### API Address Models ### Address_Base() ###
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user