Jump to…
snowinitial commitqoxwzsukwmkx1mo
Matt W1//! Row types shared across crates.
Matt W2//!
Matt W3//! Only the types more than one crate needs live here. Query-specific shapes
Matt W4//! stay next to their queries.
Matt W5
Matt W6use chrono::{DateTime, Utc};
Matt W7use serde::{Deserialize, Serialize};
Matt W8use uuid::Uuid;
Matt W9
Matt W10#[derive(Debug, Clone, sqlx::FromRow)]
Matt W11pub struct User {
Matt W12 pub id: Uuid,
Matt W13 pub subject: String,
Matt W14 pub handle: String,
Matt W15 pub display_name: Option<String>,
Matt W16 pub email: Option<String>,
Matt W17 pub avatar_url: Option<String>,
Matt W18 pub is_admin: bool,
Matt W19 pub created_at: DateTime<Utc>,
Matt W20}
Matt W21
Matt W22impl User {
Matt W23 /// What to show in the UI: the display name if we have one, else the handle.
Matt W24 pub fn label(&self) -> &str {
Matt W25 self.display_name
Matt W26 .as_deref()
Matt W27 .filter(|s| !s.trim().is_empty())
Matt W28 .unwrap_or(&self.handle)
Matt W29 }
Matt W30}
Matt W31
Matt W32#[derive(Debug, Clone, Copy, PartialEq, Eq, sqlx::Type, Serialize, Deserialize)]
Matt W33#[sqlx(type_name = "owner_kind", rename_all = "lowercase")]
Matt W34#[serde(rename_all = "lowercase")]
Matt W35pub enum OwnerKind {
Matt W36 User,
Matt W37 Org,
Matt W38}
Matt W39
Matt W40#[derive(Debug, Clone, Copy, PartialEq, Eq, sqlx::Type, Serialize, Deserialize)]
Matt W41#[sqlx(type_name = "visibility", rename_all = "lowercase")]
Matt W42#[serde(rename_all = "lowercase")]
Matt W43pub enum Visibility {
Matt W44 Public,
Matt W45 Private,
Matt W46}
Matt W47
Matt W48/// Repository access level.
Matt W49///
Matt W50/// Ordered least- to most-privileged; `PartialOrd` is derived from that order so
Matt W51/// permission checks read as `role >= RepoRole::Write`.
Matt W52#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, sqlx::Type, Serialize, Deserialize)]
Matt W53#[sqlx(type_name = "repo_role", rename_all = "lowercase")]
Matt W54#[serde(rename_all = "lowercase")]
Matt W55pub enum RepoRole {
Matt W56 Read,
Matt W57 Write,
Matt W58 Maintain,
Matt W59 Admin,
Matt W60}
Matt W61
Matt W62#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, sqlx::Type, Serialize, Deserialize)]
Matt W63#[sqlx(type_name = "org_role", rename_all = "lowercase")]
Matt W64#[serde(rename_all = "lowercase")]
Matt W65pub enum OrgRole {
Matt W66 Member,
Matt W67 Admin,
Matt W68}
Matt W69
Matt W70#[derive(Debug, Clone, Copy, PartialEq, Eq, sqlx::Type, Serialize, Deserialize)]
Matt W71#[sqlx(type_name = "change_state", rename_all = "lowercase")]
Matt W72#[serde(rename_all = "lowercase")]
Matt W73pub enum ChangeState {
Matt W74 Draft,
Matt W75 Open,
Matt W76 Merged,
Matt W77 Abandoned,
Matt W78}
Matt W79
Matt W80#[derive(Debug, Clone, Copy, PartialEq, Eq, sqlx::Type, Serialize, Deserialize)]
Matt W81#[sqlx(type_name = "issue_state", rename_all = "lowercase")]
Matt W82#[serde(rename_all = "lowercase")]
Matt W83pub enum IssueState {
Matt W84 Open,
Matt W85 Closed,
Matt W86}
Matt W87
Matt W88#[derive(Debug, Clone, Copy, PartialEq, Eq, sqlx::Type, Serialize, Deserialize)]
Matt W89#[sqlx(type_name = "anchor_state", rename_all = "lowercase")]
Matt W90#[serde(rename_all = "lowercase")]
Matt W91pub enum AnchorState {
Matt W92 Current,
Matt W93 Outdated,
Matt W94 Orphaned,
Matt W95}
Matt W96
Matt W97#[derive(Debug, Clone, sqlx::FromRow)]
Matt W98pub struct Repo {
Matt W99 pub id: Uuid,
Matt W100 pub owner_kind: OwnerKind,
Matt W101 pub owner_user_id: Option<Uuid>,
Matt W102 pub owner_org_id: Option<Uuid>,
Matt W103 pub name: String,
Matt W104 pub description: Option<String>,
Matt W105 pub visibility: Visibility,
Matt W106 pub default_bookmark: String,
Matt W107 pub fork_of_repo_id: Option<Uuid>,
Matt W108 pub size_bytes: i64,
Matt W109 pub pushed_at: Option<DateTime<Utc>>,
Matt W110 pub archived: bool,
Matt W111 pub created_at: DateTime<Utc>,
Matt W112}
Matt W113
Matt W114impl Repo {
Matt W115 pub fn is_public(&self) -> bool {
Matt W116 matches!(self.visibility, Visibility::Public)
Matt W117 }
Matt W118
Matt W119 /// Whether this repo has ever received a push. An empty repo shows clone
Matt W120 /// instructions rather than a file listing.
Matt W121 pub fn is_empty(&self) -> bool {
Matt W122 self.pushed_at.is_none()
Matt W123 }
Matt W124}
Matt W125
Matt W126#[derive(Debug, Clone)]
Matt W127pub struct Session {
Matt W128 pub id: Uuid,
Matt W129 pub user_id: Uuid,
Matt W130 pub expires_at: DateTime<Utc>,
Matt W131}
Matt W132
Matt W133#[cfg(test)]
Matt W134mod tests {
Matt W135 use super::*;
Matt W136
Matt W137 #[test]
Matt W138 fn repo_roles_are_ordered_by_privilege() {
Matt W139 // Permission checks rely on this ordering, so it is worth pinning.
Matt W140 assert!(RepoRole::Read < RepoRole::Write);
Matt W141 assert!(RepoRole::Write < RepoRole::Maintain);
Matt W142 assert!(RepoRole::Maintain < RepoRole::Admin);
Matt W143 assert_eq!(
Matt W144 RepoRole::Admin.max(RepoRole::Read),
Matt W145 RepoRole::Admin,
Matt W146 "effective role is the maximum of the roles a user holds"
Matt W147 );
Matt W148 }
Matt W149
Matt W150 #[test]
Matt W151 fn user_label_falls_back_to_handle() {
Matt W152 let mut u = User {
Matt W153 id: Uuid::nil(),
Matt W154 subject: "s".into(),
Matt W155 handle: "alice".into(),
Matt W156 display_name: None,
Matt W157 email: None,
Matt W158 avatar_url: None,
Matt W159 is_admin: false,
Matt W160 created_at: Utc::now(),
Matt W161 };
Matt W162 assert_eq!(u.label(), "alice");
Matt W163 u.display_name = Some(" ".into());
Matt W164 assert_eq!(u.label(), "alice", "blank display names must not be shown");
Matt W165 u.display_name = Some("Alice Liddell".into());
Matt W166 assert_eq!(u.label(), "Alice Liddell");
Matt W167 }
Matt W168}

168 lines · Rust