add: apps api

This commit is contained in:
trisua 2025-06-14 14:45:52 -04:00
parent 2a99d49c8a
commit ebded00fd3
33 changed files with 698 additions and 31 deletions

View file

@ -0,0 +1,60 @@
use serde::{Deserialize, Serialize};
use tetratto_shared::{snow::Snowflake, unix_epoch_timestamp};
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub enum AppQuota {
/// The app is limited to 5 grants.
Limited,
/// The app is allowed to maintain an unlimited number of grants.
Unlimited,
}
impl Default for AppQuota {
fn default() -> Self {
Self::Limited
}
}
/// An app is required to request grants on user accounts.
///
/// Users must approve grants through a web portal.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ThirdPartyApp {
pub id: usize,
pub created: usize,
/// The ID of the owner of the app.
pub owner: usize,
/// The name of the app.
pub title: String,
/// The URL of the app's homepage.
pub homepage: String,
/// The redirect URL for the app.
///
/// Upon accepting a grant request, the user will be redirected to this URL
/// with a query parameter named `token`, which should be saved by the app
/// for future authentication.
pub redirect: String,
/// The app's quota status, which determines how many grants the app is allowed to maintain.
pub quota_status: AppQuota,
/// If the app is banned. A banned app cannot use any of its grants.
pub banned: bool,
/// The number of accepted grants the app maintains.
pub grants: usize,
}
impl ThirdPartyApp {
/// Create a new [`ThirdPartyApp`].
pub fn new(title: String, owner: usize, homepage: String, redirect: String) -> Self {
Self {
id: Snowflake::new().to_string().parse::<usize>().unwrap(),
created: unix_epoch_timestamp() as usize,
owner,
title,
homepage,
redirect,
quota_status: AppQuota::Limited,
banned: false,
grants: 0,
}
}
}

View file

@ -403,6 +403,14 @@ impl User {
self.stripe_id = String::new();
self.connections = HashMap::new();
}
/// Get a grant from the user given the grant's `app` ID.
///
/// Should be used **before** adding another grant (to ensure the app doesn't
/// already have a grant for this user).
pub fn get_grant_by_app_id(&self, id: usize) -> Option<&AuthGrant> {
self.grants.iter().find(|x| x.app == id)
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]

View file

@ -1,4 +1,5 @@
pub mod addr;
pub mod apps;
pub mod auth;
pub mod communities;
pub mod communities_permissions;

View file

@ -6,8 +6,8 @@ use super::{Result, Error};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthGrant {
pub id: usize,
/// The name of the application associated with this grant.
pub name: String,
/// The ID of the application associated with this grant.
pub app: usize,
/// The code challenge for PKCE verifiers associated with this grant.
///
/// This challenge is *all* that is required to refresh this grant's auth token.

View file

@ -36,6 +36,7 @@ bitflags! {
const MANAGE_EMOJIS = 1 << 25;
const MANAGE_STACKS = 1 << 26;
const STAFF_BADGE = 1 << 27;
const MANAGE_APPS = 1 << 28;
const _ = !0;
}