1use std::fmt::Display;
2
3use serde::{Deserialize, Serialize};
4use tetratto_shared::{snow::Snowflake, unix_epoch_timestamp};
5use crate::{
6 database::app_data::{FREE_DATA_LIMIT, PASS_DATA_LIMIT},
7 model::{auth::User, oauth::AppScope, permissions::SecondaryPermission},
8};
9
10#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
11pub enum AppQuota {
12 Limited,
14 Unlimited,
16}
17
18impl Default for AppQuota {
19 fn default() -> Self {
20 Self::Limited
21 }
22}
23
24#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
28pub enum DeveloperPassStorageQuota {
29 Tier1,
31 Tier2,
33 Tier3,
35 Unlimited,
37}
38
39impl Default for DeveloperPassStorageQuota {
40 fn default() -> Self {
41 Self::Tier1
42 }
43}
44
45impl DeveloperPassStorageQuota {
46 pub fn limit(&self) -> usize {
47 match self {
48 DeveloperPassStorageQuota::Tier1 => 26214400,
49 DeveloperPassStorageQuota::Tier2 => 52428800,
50 DeveloperPassStorageQuota::Tier3 => 104857600,
51 DeveloperPassStorageQuota::Unlimited => usize::MAX,
52 }
53 }
54}
55
56#[derive(Serialize, Deserialize, Debug, Clone)]
60pub struct ThirdPartyApp {
61 pub id: usize,
62 pub created: usize,
63 pub owner: usize,
65 pub title: String,
67 pub homepage: String,
69 pub redirect: String,
106 pub quota_status: AppQuota,
108 pub banned: bool,
110 pub grants: usize,
112 pub scopes: Vec<AppScope>,
121 pub api_key: String,
123 pub data_used: usize,
125 pub storage_capacity: DeveloperPassStorageQuota,
127}
128
129impl ThirdPartyApp {
130 pub fn new(title: String, owner: usize, homepage: String, redirect: String) -> Self {
132 Self {
133 id: Snowflake::new().to_string().parse::<usize>().unwrap(),
134 created: unix_epoch_timestamp(),
135 owner,
136 title,
137 homepage,
138 redirect,
139 quota_status: AppQuota::default(),
140 banned: false,
141 grants: 0,
142 scopes: Vec::new(),
143 api_key: String::new(),
144 data_used: 0,
145 storage_capacity: DeveloperPassStorageQuota::default(),
146 }
147 }
148}
149
150#[derive(Serialize, Deserialize, Debug, Clone)]
151pub struct AppData {
152 pub id: usize,
153 pub app: usize,
154 pub key: String,
155 pub value: String,
156}
157
158impl AppData {
159 pub fn new(app: usize, key: String, value: String) -> Self {
161 Self {
162 id: Snowflake::new().to_string().parse::<usize>().unwrap(),
163 app,
164 key,
165 value,
166 }
167 }
168
169 pub fn user_limit(user: &User, app: &ThirdPartyApp) -> usize {
171 if user
172 .secondary_permissions
173 .check(SecondaryPermission::DEVELOPER_PASS)
174 {
175 if app.storage_capacity != DeveloperPassStorageQuota::Tier1 {
176 app.storage_capacity.limit()
177 } else {
178 PASS_DATA_LIMIT
179 }
180 } else {
181 FREE_DATA_LIMIT
182 }
183 }
184}
185
186#[derive(Serialize, Deserialize, Debug, Clone)]
187pub enum AppDataSelectQuery {
188 KeyIs(String),
189 KeyLike(String),
190 ValueLike(String),
191 LikeJson(String, String),
192}
193
194impl Display for AppDataSelectQuery {
195 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
196 f.write_str(&match self {
197 Self::KeyIs(k) => k.to_owned(),
198 Self::KeyLike(k) => k.to_owned(),
199 Self::ValueLike(v) => v.to_owned(),
200 Self::LikeJson(k, v) => format!("%\"{k}\":\"{v}\"%"),
201 })
202 }
203}
204
205impl AppDataSelectQuery {
206 pub fn selector(&self) -> String {
207 match self {
208 AppDataSelectQuery::KeyIs(_) => format!("k = $1"),
209 AppDataSelectQuery::KeyLike(_) => format!("k LIKE $1"),
210 AppDataSelectQuery::ValueLike(_) => format!("v LIKE $1"),
211 AppDataSelectQuery::LikeJson(_, _) => format!("v LIKE $1"),
212 }
213 }
214}
215
216#[derive(Serialize, Deserialize, Debug, Clone)]
217pub enum AppDataSelectMode {
218 One(usize),
220 Many(usize, usize),
224 ManyJson(String, usize, usize),
228}
229
230impl Display for AppDataSelectMode {
231 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
232 f.write_str(&match self {
233 Self::One(offset) => format!("LIMIT 1 OFFSET {offset}"),
234 Self::Many(limit, offset) => {
235 format!(
236 "ORDER BY k DESC LIMIT {} OFFSET {offset}",
237 if *limit > 24 { 24 } else { *limit }
238 )
239 }
240 Self::ManyJson(order_by_top_level_key, limit, offset) => {
241 format!(
242 "ORDER BY v::jsonb->>'{order_by_top_level_key}' DESC LIMIT {} OFFSET {offset}",
243 if *limit > 24 { 24 } else { *limit }
244 )
245 }
246 })
247 }
248}
249
250#[derive(Serialize, Deserialize, Debug, Clone)]
251pub struct AppDataQuery {
252 pub app: usize,
253 pub query: AppDataSelectQuery,
254 pub mode: AppDataSelectMode,
255}
256
257impl Display for AppDataQuery {
258 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
259 f.write_str(&format!(
260 "SELECT * FROM app_data WHERE app = {} AND %q% {}",
261 self.app, self.mode
262 ))
263 }
264}
265
266#[derive(Serialize, Deserialize)]
267pub enum AppDataQueryResult {
268 One(AppData),
269 Many(Vec<AppData>),
270}