You've already forked AstralRinth
forked from didirus/AstralRinth
Initial work on payouts (badges, perms, splits) (#440)
* Initial work on payouts (badges, perms, splits) * Fix clippy error, bitflag consistency
This commit is contained in:
7
migrations/20220902025606_initial-payouts.sql
Normal file
7
migrations/20220902025606_initial-payouts.sql
Normal file
@@ -0,0 +1,7 @@
|
||||
ALTER TABLE team_members ADD COLUMN payouts_split REAL NOT NULL DEFAULT 0;
|
||||
|
||||
UPDATE team_members
|
||||
SET permissions = 1023, payouts_split = 100
|
||||
WHERE role = 'Owner';
|
||||
|
||||
ALTER TABLE users ADD COLUMN badges bigint default 0 NOT NULL;
|
||||
1559
sqlx-data.json
1559
sqlx-data.json
File diff suppressed because it is too large
Load Diff
@@ -28,8 +28,6 @@ pub enum DatabaseError {
|
||||
Database(#[from] sqlx::error::Error),
|
||||
#[error("Error while trying to generate random ID")]
|
||||
RandomId,
|
||||
#[error("Invalid permissions bitflag!")]
|
||||
Bitflag,
|
||||
#[error("A database request failed")]
|
||||
Other(String),
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use super::ids::*;
|
||||
use crate::database::models::User;
|
||||
use crate::models::teams::Permissions;
|
||||
use crate::models::users::Badges;
|
||||
|
||||
pub struct TeamBuilder {
|
||||
pub members: Vec<TeamMemberBuilder>,
|
||||
@@ -10,6 +11,7 @@ pub struct TeamMemberBuilder {
|
||||
pub role: String,
|
||||
pub permissions: Permissions,
|
||||
pub accepted: bool,
|
||||
pub payouts_split: f32,
|
||||
}
|
||||
|
||||
impl TeamBuilder {
|
||||
@@ -41,6 +43,7 @@ impl TeamBuilder {
|
||||
role: member.role,
|
||||
permissions: member.permissions,
|
||||
accepted: member.accepted,
|
||||
payouts_split: member.payouts_split,
|
||||
};
|
||||
|
||||
sqlx::query!(
|
||||
@@ -78,6 +81,7 @@ pub struct TeamMember {
|
||||
pub role: String,
|
||||
pub permissions: Permissions,
|
||||
pub accepted: bool,
|
||||
pub payouts_split: f32,
|
||||
}
|
||||
|
||||
/// A member of a team
|
||||
@@ -89,6 +93,7 @@ pub struct QueryTeamMember {
|
||||
pub role: String,
|
||||
pub permissions: Permissions,
|
||||
pub accepted: bool,
|
||||
pub payouts_split: f32,
|
||||
}
|
||||
|
||||
impl TeamMember {
|
||||
@@ -104,7 +109,7 @@ impl TeamMember {
|
||||
|
||||
let team_members = sqlx::query!(
|
||||
"
|
||||
SELECT id, user_id, role, permissions, accepted
|
||||
SELECT id, user_id, role, permissions, accepted, payouts_split
|
||||
FROM team_members
|
||||
WHERE team_id = $1
|
||||
",
|
||||
@@ -113,19 +118,16 @@ impl TeamMember {
|
||||
.fetch_many(executor)
|
||||
.try_filter_map(|e| async {
|
||||
if let Some(m) = e.right() {
|
||||
let permissions = Permissions::from_bits(m.permissions as u64);
|
||||
if let Some(perms) = permissions {
|
||||
Ok(Some(Ok(TeamMember {
|
||||
id: TeamMemberId(m.id),
|
||||
team_id: id,
|
||||
user_id: UserId(m.user_id),
|
||||
role: m.role,
|
||||
permissions: perms,
|
||||
accepted: m.accepted,
|
||||
})))
|
||||
} else {
|
||||
Ok(Some(Err(super::DatabaseError::Bitflag)))
|
||||
}
|
||||
Ok(Some(Ok(TeamMember {
|
||||
id: TeamMemberId(m.id),
|
||||
team_id: id,
|
||||
user_id: UserId(m.user_id),
|
||||
role: m.role,
|
||||
permissions: Permissions::from_bits(m.permissions as u64)
|
||||
.unwrap_or_default(),
|
||||
accepted: m.accepted,
|
||||
payouts_split: m.payouts_split,
|
||||
})))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
@@ -152,10 +154,10 @@ impl TeamMember {
|
||||
|
||||
let team_members = sqlx::query!(
|
||||
"
|
||||
SELECT tm.id id, tm.role member_role, tm.permissions permissions, tm.accepted accepted,
|
||||
SELECT tm.id id, tm.role member_role, tm.permissions permissions, tm.accepted accepted, tm.payouts_split payouts_split,
|
||||
u.id user_id, u.github_id github_id, u.name user_name, u.email email,
|
||||
u.avatar_url avatar_url, u.username username, u.bio bio,
|
||||
u.created created, u.role user_role
|
||||
u.created created, u.role user_role, u.badges badges
|
||||
FROM team_members tm
|
||||
INNER JOIN users u ON u.id = tm.user_id
|
||||
WHERE tm.team_id = $1
|
||||
@@ -165,13 +167,12 @@ impl TeamMember {
|
||||
.fetch_many(executor)
|
||||
.try_filter_map(|e| async {
|
||||
if let Some(m) = e.right() {
|
||||
let permissions = Permissions::from_bits(m.permissions as u64);
|
||||
if let Some(perms) = permissions {
|
||||
|
||||
Ok(Some(Ok(QueryTeamMember {
|
||||
id: TeamMemberId(m.id),
|
||||
team_id: id,
|
||||
role: m.member_role,
|
||||
permissions: perms,
|
||||
permissions: Permissions::from_bits(m.permissions as u64).unwrap_or_default(),
|
||||
accepted: m.accepted,
|
||||
user: User {
|
||||
id: UserId(m.user_id),
|
||||
@@ -183,11 +184,10 @@ impl TeamMember {
|
||||
bio: m.bio,
|
||||
created: m.created,
|
||||
role: m.user_role,
|
||||
badges: Badges::from_bits(m.badges as u64).unwrap_or_default(),
|
||||
},
|
||||
payouts_split: m.payouts_split
|
||||
})))
|
||||
} else {
|
||||
Ok(Some(Err(super::DatabaseError::Bitflag)))
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
@@ -216,10 +216,10 @@ impl TeamMember {
|
||||
|
||||
let teams = sqlx::query!(
|
||||
"
|
||||
SELECT tm.id id, tm.team_id team_id, tm.role member_role, tm.permissions permissions, tm.accepted accepted,
|
||||
SELECT tm.id id, tm.team_id team_id, tm.role member_role, tm.permissions permissions, tm.accepted accepted, tm.payouts_split payouts_split,
|
||||
u.id user_id, u.github_id github_id, u.name user_name, u.email email,
|
||||
u.avatar_url avatar_url, u.username username, u.bio bio,
|
||||
u.created created, u.role user_role
|
||||
u.created created, u.role user_role, u.badges badges
|
||||
FROM team_members tm
|
||||
INNER JOIN users u ON u.id = tm.user_id
|
||||
WHERE tm.team_id = ANY($1)
|
||||
@@ -230,13 +230,12 @@ impl TeamMember {
|
||||
.fetch_many(exec)
|
||||
.try_filter_map(|e| async {
|
||||
if let Some(m) = e.right() {
|
||||
let permissions = Permissions::from_bits(m.permissions as u64);
|
||||
if let Some(perms) = permissions {
|
||||
|
||||
Ok(Some(Ok(QueryTeamMember {
|
||||
id: TeamMemberId(m.id),
|
||||
team_id: TeamId(m.team_id),
|
||||
role: m.member_role,
|
||||
permissions: perms,
|
||||
permissions: Permissions::from_bits(m.permissions as u64).unwrap_or_default(),
|
||||
accepted: m.accepted,
|
||||
user: User {
|
||||
id: UserId(m.user_id),
|
||||
@@ -248,11 +247,10 @@ impl TeamMember {
|
||||
bio: m.bio,
|
||||
created: m.created,
|
||||
role: m.user_role,
|
||||
badges: Badges::from_bits(m.badges as u64).unwrap_or_default(),
|
||||
},
|
||||
payouts_split: m.payouts_split
|
||||
})))
|
||||
} else {
|
||||
Ok(Some(Err(super::DatabaseError::Bitflag)))
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
@@ -279,7 +277,7 @@ impl TeamMember {
|
||||
|
||||
let team_members = sqlx::query!(
|
||||
"
|
||||
SELECT id, team_id, role, permissions, accepted
|
||||
SELECT id, team_id, role, permissions, accepted, payouts_split
|
||||
FROM team_members
|
||||
WHERE (user_id = $1 AND accepted = TRUE)
|
||||
",
|
||||
@@ -288,19 +286,16 @@ impl TeamMember {
|
||||
.fetch_many(executor)
|
||||
.try_filter_map(|e| async {
|
||||
if let Some(m) = e.right() {
|
||||
let permissions = Permissions::from_bits(m.permissions as u64);
|
||||
if let Some(perms) = permissions {
|
||||
Ok(Some(Ok(TeamMember {
|
||||
id: TeamMemberId(m.id),
|
||||
team_id: TeamId(m.team_id),
|
||||
user_id: id,
|
||||
role: m.role,
|
||||
permissions: perms,
|
||||
accepted: m.accepted,
|
||||
})))
|
||||
} else {
|
||||
Ok(Some(Err(super::DatabaseError::Bitflag)))
|
||||
}
|
||||
Ok(Some(Ok(TeamMember {
|
||||
id: TeamMemberId(m.id),
|
||||
team_id: TeamId(m.team_id),
|
||||
user_id: id,
|
||||
role: m.role,
|
||||
permissions: Permissions::from_bits(m.permissions as u64)
|
||||
.unwrap_or_default(),
|
||||
accepted: m.accepted,
|
||||
payouts_split: m.payouts_split,
|
||||
})))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
@@ -327,7 +322,7 @@ impl TeamMember {
|
||||
|
||||
let team_members = sqlx::query!(
|
||||
"
|
||||
SELECT id, team_id, role, permissions, accepted
|
||||
SELECT id, team_id, role, permissions, accepted, payouts_split
|
||||
FROM team_members
|
||||
WHERE user_id = $1
|
||||
",
|
||||
@@ -336,19 +331,16 @@ impl TeamMember {
|
||||
.fetch_many(executor)
|
||||
.try_filter_map(|e| async {
|
||||
if let Some(m) = e.right() {
|
||||
let permissions = Permissions::from_bits(m.permissions as u64);
|
||||
if let Some(perms) = permissions {
|
||||
Ok(Some(Ok(TeamMember {
|
||||
id: TeamMemberId(m.id),
|
||||
team_id: TeamId(m.team_id),
|
||||
user_id: id,
|
||||
role: m.role,
|
||||
permissions: perms,
|
||||
accepted: m.accepted,
|
||||
})))
|
||||
} else {
|
||||
Ok(Some(Err(super::DatabaseError::Bitflag)))
|
||||
}
|
||||
Ok(Some(Ok(TeamMember {
|
||||
id: TeamMemberId(m.id),
|
||||
team_id: TeamId(m.team_id),
|
||||
user_id: id,
|
||||
role: m.role,
|
||||
permissions: Permissions::from_bits(m.permissions as u64)
|
||||
.unwrap_or_default(),
|
||||
accepted: m.accepted,
|
||||
payouts_split: m.payouts_split,
|
||||
})))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
@@ -374,7 +366,7 @@ impl TeamMember {
|
||||
{
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT id, user_id, role, permissions, accepted
|
||||
SELECT id, user_id, role, permissions, accepted, payouts_split
|
||||
FROM team_members
|
||||
WHERE (team_id = $1 AND user_id = $2 AND accepted = TRUE)
|
||||
",
|
||||
@@ -391,8 +383,9 @@ impl TeamMember {
|
||||
user_id,
|
||||
role: m.role,
|
||||
permissions: Permissions::from_bits(m.permissions as u64)
|
||||
.ok_or(super::DatabaseError::Bitflag)?,
|
||||
.unwrap_or_default(),
|
||||
accepted: m.accepted,
|
||||
payouts_split: m.payouts_split,
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
@@ -415,7 +408,7 @@ impl TeamMember {
|
||||
|
||||
let team_members = sqlx::query!(
|
||||
"
|
||||
SELECT id, team_id, user_id, role, permissions, accepted
|
||||
SELECT id, team_id, user_id, role, permissions, accepted, payouts_split
|
||||
FROM team_members
|
||||
WHERE (team_id = ANY($1) AND user_id = $2 AND accepted = TRUE)
|
||||
",
|
||||
@@ -425,19 +418,15 @@ impl TeamMember {
|
||||
.fetch_many(executor)
|
||||
.try_filter_map(|e| async {
|
||||
if let Some(m) = e.right() {
|
||||
let permissions = Permissions::from_bits(m.permissions as u64);
|
||||
if let Some(perms) = permissions {
|
||||
Ok(Some(Ok(TeamMember {
|
||||
id: TeamMemberId(m.id),
|
||||
team_id: TeamId(m.team_id),
|
||||
user_id,
|
||||
role: m.role,
|
||||
permissions: perms,
|
||||
permissions: Permissions::from_bits(m.permissions as u64).unwrap_or_default(),
|
||||
accepted: m.accepted,
|
||||
payouts_split: m.payouts_split
|
||||
})))
|
||||
} else {
|
||||
Ok(Some(Err(super::DatabaseError::Bitflag)))
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
@@ -463,7 +452,7 @@ impl TeamMember {
|
||||
{
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT id, user_id, role, permissions, accepted
|
||||
SELECT id, user_id, role, permissions, accepted, payouts_split
|
||||
FROM team_members
|
||||
WHERE (team_id = $1 AND user_id = $2)
|
||||
",
|
||||
@@ -480,8 +469,9 @@ impl TeamMember {
|
||||
user_id,
|
||||
role: m.role,
|
||||
permissions: Permissions::from_bits(m.permissions as u64)
|
||||
.ok_or(super::DatabaseError::Bitflag)?,
|
||||
.unwrap_or_default(),
|
||||
accepted: m.accepted,
|
||||
payouts_split: m.payouts_split,
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
@@ -550,6 +540,7 @@ impl TeamMember {
|
||||
new_permissions: Option<Permissions>,
|
||||
new_role: Option<String>,
|
||||
new_accepted: Option<bool>,
|
||||
new_payouts_split: Option<f32>,
|
||||
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||
) -> Result<(), super::DatabaseError> {
|
||||
if let Some(permissions) = new_permissions {
|
||||
@@ -598,6 +589,21 @@ impl TeamMember {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(payouts_split) = new_payouts_split {
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE team_members
|
||||
SET payouts_split = $1
|
||||
WHERE (team_id = $2 AND user_id = $3)
|
||||
",
|
||||
payouts_split,
|
||||
id as TeamId,
|
||||
user_id as UserId,
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -611,7 +617,7 @@ impl TeamMember {
|
||||
{
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.permissions, tm.accepted FROM mods m
|
||||
SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.permissions, tm.accepted, tm.payouts_split FROM mods m
|
||||
INNER JOIN team_members tm ON tm.team_id = m.team_id AND user_id = $2 AND accepted = TRUE
|
||||
WHERE m.id = $1
|
||||
",
|
||||
@@ -628,8 +634,9 @@ impl TeamMember {
|
||||
user_id,
|
||||
role: m.role,
|
||||
permissions: Permissions::from_bits(m.permissions as u64)
|
||||
.ok_or(super::DatabaseError::Bitflag)?,
|
||||
.unwrap_or_default(),
|
||||
accepted: m.accepted,
|
||||
payouts_split: m.payouts_split,
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
@@ -646,7 +653,7 @@ impl TeamMember {
|
||||
{
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.permissions, tm.accepted FROM versions v
|
||||
SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.permissions, tm.accepted, tm.payouts_split FROM versions v
|
||||
INNER JOIN mods m ON m.id = v.mod_id
|
||||
INNER JOIN team_members tm ON tm.team_id = m.team_id AND tm.user_id = $2 AND tm.accepted = TRUE
|
||||
WHERE v.id = $1
|
||||
@@ -664,8 +671,9 @@ impl TeamMember {
|
||||
user_id,
|
||||
role: m.role,
|
||||
permissions: Permissions::from_bits(m.permissions as u64)
|
||||
.ok_or(super::DatabaseError::Bitflag)?,
|
||||
.unwrap_or_default(),
|
||||
accepted: m.accepted,
|
||||
payouts_split: m.payouts_split,
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use super::ids::{ProjectId, UserId};
|
||||
use crate::models::users::Badges;
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
pub struct User {
|
||||
@@ -11,6 +12,7 @@ pub struct User {
|
||||
pub bio: Option<String>,
|
||||
pub created: DateTime<Utc>,
|
||||
pub role: String,
|
||||
pub badges: Badges,
|
||||
}
|
||||
|
||||
impl User {
|
||||
@@ -54,7 +56,7 @@ impl User {
|
||||
"
|
||||
SELECT u.github_id, u.name, u.email,
|
||||
u.avatar_url, u.username, u.bio,
|
||||
u.created, u.role
|
||||
u.created, u.role, u.badges
|
||||
FROM users u
|
||||
WHERE u.id = $1
|
||||
",
|
||||
@@ -74,6 +76,8 @@ impl User {
|
||||
bio: row.bio,
|
||||
created: row.created,
|
||||
role: row.role,
|
||||
badges: Badges::from_bits(row.badges as u64)
|
||||
.unwrap_or_default(),
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
@@ -91,7 +95,7 @@ impl User {
|
||||
"
|
||||
SELECT u.id, u.name, u.email,
|
||||
u.avatar_url, u.username, u.bio,
|
||||
u.created, u.role
|
||||
u.created, u.role, u.badges
|
||||
FROM users u
|
||||
WHERE u.github_id = $1
|
||||
",
|
||||
@@ -111,6 +115,8 @@ impl User {
|
||||
bio: row.bio,
|
||||
created: row.created,
|
||||
role: row.role,
|
||||
badges: Badges::from_bits(row.badges as u64)
|
||||
.unwrap_or_default(),
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
@@ -128,7 +134,7 @@ impl User {
|
||||
"
|
||||
SELECT u.id, u.github_id, u.name, u.email,
|
||||
u.avatar_url, u.username, u.bio,
|
||||
u.created, u.role
|
||||
u.created, u.role, u.badges
|
||||
FROM users u
|
||||
WHERE LOWER(u.username) = LOWER($1)
|
||||
",
|
||||
@@ -148,6 +154,8 @@ impl User {
|
||||
bio: row.bio,
|
||||
created: row.created,
|
||||
role: row.role,
|
||||
badges: Badges::from_bits(row.badges as u64)
|
||||
.unwrap_or_default(),
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
@@ -169,7 +177,8 @@ impl User {
|
||||
"
|
||||
SELECT u.id, u.github_id, u.name, u.email,
|
||||
u.avatar_url, u.username, u.bio,
|
||||
u.created, u.role FROM users u
|
||||
u.created, u.role, u.badges
|
||||
FROM users u
|
||||
WHERE u.id = ANY($1)
|
||||
",
|
||||
&user_ids_parsed
|
||||
@@ -186,6 +195,7 @@ impl User {
|
||||
bio: u.bio,
|
||||
created: u.created,
|
||||
role: u.role,
|
||||
badges: Badges::from_bits(u.badges as u64).unwrap_or_default(),
|
||||
}))
|
||||
})
|
||||
.try_collect::<Vec<User>>()
|
||||
|
||||
@@ -34,7 +34,9 @@ bitflags::bitflags! {
|
||||
const REMOVE_MEMBER = 1 << 5;
|
||||
const EDIT_MEMBER = 1 << 6;
|
||||
const DELETE_PROJECT = 1 << 7;
|
||||
const ALL = 0b11111111;
|
||||
const VIEW_ANALYTICS = 1 << 8;
|
||||
const VIEW_PAYOUTS = 1 << 9;
|
||||
const ALL = 0b1111111111;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +59,9 @@ pub struct TeamMember {
|
||||
pub permissions: Option<Permissions>,
|
||||
/// Whether the user has joined the team or is just invited to it
|
||||
pub accepted: bool,
|
||||
/// Payouts split. This is a weighted average. For example. if a team has two members with this
|
||||
/// value set to 25.0 for both members, they split revenue 50/50
|
||||
pub payouts_split: Option<f32>,
|
||||
}
|
||||
|
||||
impl TeamMember {
|
||||
@@ -71,6 +76,11 @@ impl TeamMember {
|
||||
Some(data.permissions)
|
||||
},
|
||||
accepted: data.accepted,
|
||||
payouts_split: if override_permissions {
|
||||
None
|
||||
} else {
|
||||
Some(data.payouts_split)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,29 @@ pub struct UserId(pub u64);
|
||||
|
||||
pub const DELETED_USER: UserId = UserId(127155982985829);
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct Badges: u64 {
|
||||
const MIDAS = 1 << 0;
|
||||
const EARLY_MODPACK_ADOPTER = 1 << 1;
|
||||
const EARLY_RESPACK_ADOPTER = 1 << 2;
|
||||
const EARLY_PLUGIN_ADOPTER = 1 << 3;
|
||||
const ALPHA_TESTER = 1 << 4;
|
||||
const CONTRIBUTOR = 1 << 5;
|
||||
const TRANSLATOR = 1 << 6;
|
||||
|
||||
const ALL = 0b1111111;
|
||||
const NONE = 0b0;
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Badges {
|
||||
fn default() -> Badges {
|
||||
Badges::NONE
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct User {
|
||||
pub id: UserId,
|
||||
@@ -20,6 +43,7 @@ pub struct User {
|
||||
pub bio: Option<String>,
|
||||
pub created: DateTime<Utc>,
|
||||
pub role: Role,
|
||||
pub badges: Badges,
|
||||
}
|
||||
|
||||
use crate::database::models::user_item::User as DBUser;
|
||||
@@ -35,6 +59,7 @@ impl From<DBUser> for User {
|
||||
bio: data.bio,
|
||||
created: data.created,
|
||||
role: Role::from_string(&*data.role),
|
||||
badges: data.badges,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ use crate::database::models::{generate_state_id, User};
|
||||
use crate::models::error::ApiError;
|
||||
use crate::models::ids::base62_impl::{parse_base62, to_base62};
|
||||
use crate::models::ids::DecodingError;
|
||||
use crate::models::users::Role;
|
||||
use crate::models::users::{Badges, Role};
|
||||
use crate::parse_strings_from_var;
|
||||
use crate::util::auth::get_github_user_from_token;
|
||||
use actix_web::http::StatusCode;
|
||||
@@ -272,6 +272,7 @@ pub async fn auth_callback(
|
||||
bio: user.bio,
|
||||
created: Utc::now(),
|
||||
role: Role::Developer.to_string(),
|
||||
badges: Badges::default(),
|
||||
}
|
||||
.insert(&mut transaction)
|
||||
.await?;
|
||||
|
||||
@@ -628,6 +628,7 @@ pub async fn project_create_inner(
|
||||
role: crate::models::teams::OWNER_ROLE.to_owned(),
|
||||
permissions: crate::models::teams::Permissions::ALL,
|
||||
accepted: true,
|
||||
payouts_split: 100.0,
|
||||
}],
|
||||
};
|
||||
|
||||
|
||||
@@ -189,6 +189,7 @@ pub async fn join_team(
|
||||
None,
|
||||
None,
|
||||
Some(true),
|
||||
None,
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
@@ -214,6 +215,8 @@ pub struct NewTeamMember {
|
||||
pub role: String,
|
||||
#[serde(default = "Permissions::default")]
|
||||
pub permissions: Permissions,
|
||||
#[serde(default)]
|
||||
pub payouts_split: f32,
|
||||
}
|
||||
|
||||
#[post("{id}/members")]
|
||||
@@ -255,6 +258,13 @@ pub async fn add_team_member(
|
||||
"The `Owner` role is restricted to one person".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if !(0.0..=5000.0).contains(&new_member.payouts_split) {
|
||||
return Err(ApiError::InvalidInput(
|
||||
"Payouts split must be between 0 and 5000!".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let request = crate::database::models::team_item::TeamMember::get_from_user_id_pending(
|
||||
team_id,
|
||||
new_member.user_id.into(),
|
||||
@@ -291,6 +301,7 @@ pub async fn add_team_member(
|
||||
role: new_member.role.clone(),
|
||||
permissions: new_member.permissions,
|
||||
accepted: false,
|
||||
payouts_split: new_member.payouts_split,
|
||||
}
|
||||
.insert(&mut transaction)
|
||||
.await?;
|
||||
@@ -349,6 +360,7 @@ pub async fn add_team_member(
|
||||
pub struct EditTeamMember {
|
||||
pub permissions: Option<Permissions>,
|
||||
pub role: Option<String>,
|
||||
pub payouts_split: Option<f32>,
|
||||
}
|
||||
|
||||
#[patch("{id}/members/{user_id}")]
|
||||
@@ -406,6 +418,14 @@ pub async fn edit_team_member(
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(payouts_split) = edit_member.payouts_split {
|
||||
if !(0.0..=5000.0).contains(&payouts_split) {
|
||||
return Err(ApiError::InvalidInput(
|
||||
"Payouts split must be between 0 and 5000!".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if edit_member.role.as_deref() == Some(crate::models::teams::OWNER_ROLE) {
|
||||
return Err(ApiError::InvalidInput(
|
||||
"The `Owner` role is restricted to one person".to_string(),
|
||||
@@ -418,6 +438,7 @@ pub async fn edit_team_member(
|
||||
edit_member.permissions,
|
||||
edit_member.role.clone(),
|
||||
None,
|
||||
edit_member.payouts_split,
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
@@ -491,6 +512,7 @@ pub async fn transfer_ownership(
|
||||
None,
|
||||
Some(crate::models::teams::DEFAULT_ROLE.to_string()),
|
||||
None,
|
||||
None,
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
@@ -501,6 +523,7 @@ pub async fn transfer_ownership(
|
||||
Some(Permissions::ALL),
|
||||
Some(crate::models::teams::OWNER_ROLE.to_string()),
|
||||
None,
|
||||
None,
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::database::models::User;
|
||||
use crate::file_hosting::FileHost;
|
||||
use crate::models::notifications::Notification;
|
||||
use crate::models::projects::{Project, ProjectStatus};
|
||||
use crate::models::users::{Role, UserId};
|
||||
use crate::models::users::{Badges, Role, UserId};
|
||||
use crate::routes::ApiError;
|
||||
use crate::util::auth::get_user_from_headers;
|
||||
use crate::util::routes::read_from_payload;
|
||||
@@ -154,6 +154,7 @@ pub struct EditUser {
|
||||
#[validate(length(max = 160))]
|
||||
pub bio: Option<Option<String>>,
|
||||
pub role: Option<Role>,
|
||||
pub badges: Option<Badges>,
|
||||
}
|
||||
|
||||
#[patch("{id}")]
|
||||
@@ -277,6 +278,27 @@ pub async fn user_edit(
|
||||
.await?;
|
||||
}
|
||||
|
||||
if let Some(badges) = &new_user.badges {
|
||||
if !user.role.is_admin() {
|
||||
return Err(ApiError::CustomAuthentication(
|
||||
"You do not have the permissions to edit the badges of this user!"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE users
|
||||
SET badges = $1
|
||||
WHERE (id = $2)
|
||||
",
|
||||
badges.bits() as i64,
|
||||
id as crate::database::models::ids::UserId,
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
}
|
||||
|
||||
transaction.commit().await?;
|
||||
Ok(HttpResponse::NoContent().body(""))
|
||||
} else {
|
||||
|
||||
@@ -72,6 +72,7 @@ where
|
||||
bio: result.bio,
|
||||
created: result.created,
|
||||
role: Role::from_string(&result.role),
|
||||
badges: result.badges,
|
||||
}),
|
||||
None => Err(AuthenticationError::InvalidCredentials),
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ pub struct LiteLoaderValidator;
|
||||
|
||||
impl super::Validator for LiteLoaderValidator {
|
||||
fn get_file_extensions(&self) -> &[&str] {
|
||||
&["litemod"]
|
||||
&["litemod", "jar"]
|
||||
}
|
||||
|
||||
fn get_project_types(&self) -> &[&str] {
|
||||
|
||||
Reference in New Issue
Block a user