2022-04-12 17:35:09 +05:30
|
|
|
/*
|
|
|
|
* ForgeFlux StarChart - A federated software forge spider
|
|
|
|
* Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License as
|
|
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Affero General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
#![warn(missing_docs)]
|
|
|
|
//! # `Starchart` database operations
|
|
|
|
//!
|
|
|
|
//! Traits and datastructures used in Starchart to interact with database.
|
|
|
|
//!
|
|
|
|
//! To use an unsupported database with Starchart, traits present within this crate should be
|
|
|
|
//! implemented.
|
|
|
|
//!
|
|
|
|
//!
|
|
|
|
//! ## Organisation
|
|
|
|
//!
|
|
|
|
//! Database functionallity is divided accross various modules:
|
|
|
|
//!
|
|
|
|
//! - [errors](crate::auth): error data structures used in this crate
|
|
|
|
//! - [ops](crate::ops): meta operations like connection pool creation, migrations and getting
|
|
|
|
//! connection from pool
|
|
|
|
use std::str::FromStr;
|
|
|
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
2022-04-30 23:45:37 +05:30
|
|
|
use url::Url;
|
2022-04-12 17:35:09 +05:30
|
|
|
|
|
|
|
pub mod errors;
|
|
|
|
pub mod ops;
|
|
|
|
#[cfg(feature = "test")]
|
|
|
|
pub mod tests;
|
|
|
|
|
2022-04-20 16:23:38 +05:30
|
|
|
use dev::*;
|
2022-04-12 17:35:09 +05:30
|
|
|
pub use ops::GetConnection;
|
|
|
|
|
|
|
|
pub mod prelude {
|
|
|
|
//! useful imports for users working with a supported database
|
|
|
|
|
|
|
|
pub use super::errors::*;
|
|
|
|
pub use super::ops::*;
|
|
|
|
pub use super::*;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub mod dev {
|
|
|
|
//! useful imports for supporting a new database
|
|
|
|
pub use super::prelude::*;
|
|
|
|
pub use async_trait::async_trait;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
/// create a new forge on the database
|
2022-07-14 23:47:37 +05:30
|
|
|
pub struct CreateForge {
|
|
|
|
/// url of the forge instance: with scheme but remove trailing slash
|
|
|
|
pub url: Url,
|
2022-04-12 17:35:09 +05:30
|
|
|
/// forge type: which software is the instance running?
|
|
|
|
pub forge_type: ForgeImplementation,
|
2023-02-11 19:40:04 +05:30
|
|
|
/// is this forge an import
|
|
|
|
pub import: bool,
|
2022-04-12 17:35:09 +05:30
|
|
|
}
|
|
|
|
|
2022-07-14 23:47:37 +05:30
|
|
|
/// Get url from URL
|
|
|
|
/// Utility function for uniform url format
|
|
|
|
pub fn clean_url(url: &Url) -> String {
|
|
|
|
let mut url = url.clone();
|
|
|
|
url.set_path("");
|
|
|
|
url.set_query(None);
|
|
|
|
url.set_fragment(None);
|
|
|
|
url.as_str().to_string()
|
2022-04-30 23:45:37 +05:30
|
|
|
}
|
|
|
|
|
2022-06-04 20:57:48 +05:30
|
|
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
/// user data
|
|
|
|
pub struct User {
|
2022-07-14 23:47:37 +05:30
|
|
|
/// url of the forge instance: with scheme but remove trailing slash
|
|
|
|
/// url can be derived from html_link also, but used to link to user's forge instance
|
|
|
|
pub url: String,
|
2022-06-04 20:57:48 +05:30
|
|
|
/// username of the user
|
|
|
|
pub username: String,
|
|
|
|
/// html link to the user profile
|
|
|
|
pub html_link: String,
|
|
|
|
/// OPTIONAL: html link to the user's profile photo
|
|
|
|
pub profile_photo: Option<String>,
|
2023-02-11 19:40:04 +05:30
|
|
|
/// is this user an import
|
|
|
|
pub import: bool,
|
2022-06-04 20:57:48 +05:30
|
|
|
}
|
|
|
|
|
2022-04-20 16:23:38 +05:30
|
|
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
/// add new user to database
|
|
|
|
pub struct AddUser<'a> {
|
2022-07-14 23:47:37 +05:30
|
|
|
/// url of the forge instance: with scheme but remove trailing slash
|
|
|
|
/// url can be derived from html_link also, but used to link to user's forge instance
|
|
|
|
pub url: Url,
|
2022-04-20 16:23:38 +05:30
|
|
|
/// username of the user
|
|
|
|
pub username: &'a str,
|
|
|
|
/// html link to the user profile
|
|
|
|
pub html_link: &'a str,
|
|
|
|
/// OPTIONAL: html link to the user's profile photo
|
|
|
|
pub profile_photo: Option<&'a str>,
|
2023-02-11 19:40:04 +05:30
|
|
|
/// is this user an import
|
|
|
|
pub import: bool,
|
2022-04-20 16:23:38 +05:30
|
|
|
}
|
|
|
|
|
2022-05-04 12:10:13 +05:30
|
|
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
/// add new repository to database
|
|
|
|
pub struct AddRepository<'a> {
|
|
|
|
/// html link to the repository
|
|
|
|
pub html_link: &'a str,
|
|
|
|
/// repository topic tags
|
2022-05-17 01:03:27 +05:30
|
|
|
pub tags: Option<Vec<&'a str>>,
|
2022-07-14 23:47:37 +05:30
|
|
|
/// url of the forge instance: with scheme but remove trailing slash
|
|
|
|
/// url can be derived from html_link also, but used to link to user's forge instance
|
|
|
|
pub url: Url,
|
2022-05-04 12:10:13 +05:30
|
|
|
/// repository name
|
|
|
|
pub name: &'a str,
|
|
|
|
/// repository owner
|
|
|
|
pub owner: &'a str,
|
|
|
|
/// repository description, if any
|
|
|
|
pub description: Option<&'a str>,
|
|
|
|
/// repository website, if any
|
|
|
|
pub website: Option<&'a str>,
|
2023-02-11 19:40:04 +05:30
|
|
|
/// is this repository an import
|
|
|
|
pub import: bool,
|
2022-05-04 12:10:13 +05:30
|
|
|
}
|
|
|
|
|
2022-06-03 23:05:09 +05:30
|
|
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
/// data representing a forge instance
|
|
|
|
pub struct Forge {
|
2022-07-14 23:47:37 +05:30
|
|
|
/// url of the forge
|
|
|
|
pub url: String,
|
2022-06-03 23:05:09 +05:30
|
|
|
/// type of the forge
|
|
|
|
pub forge_type: ForgeImplementation,
|
|
|
|
/// last crawl
|
|
|
|
pub last_crawl_on: Option<i64>,
|
2023-02-11 19:40:04 +05:30
|
|
|
/// is this forge an import
|
|
|
|
pub import: bool,
|
2022-06-03 23:05:09 +05:30
|
|
|
}
|
|
|
|
|
2022-05-19 21:38:01 +05:30
|
|
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
/// repository
|
|
|
|
pub struct Repository {
|
|
|
|
/// html link to the repository
|
|
|
|
pub html_url: String,
|
|
|
|
/// repository topic tags
|
|
|
|
pub tags: Option<Vec<String>>,
|
2022-07-14 23:47:37 +05:30
|
|
|
/// url of the forge instance: with scheme but remove trailing slash
|
|
|
|
/// url can be derived from html_link also, but used to link to user's forge instance
|
|
|
|
pub url: String,
|
2022-05-19 21:38:01 +05:30
|
|
|
/// repository name
|
|
|
|
pub name: String,
|
|
|
|
/// repository owner
|
|
|
|
pub username: String,
|
|
|
|
/// repository description, if any
|
|
|
|
pub description: Option<String>,
|
|
|
|
/// repository website, if any
|
|
|
|
pub website: Option<String>,
|
2023-02-11 19:40:04 +05:30
|
|
|
/// is this repository an import
|
|
|
|
pub import: bool,
|
2022-05-19 21:38:01 +05:30
|
|
|
}
|
|
|
|
|
2022-04-12 17:35:09 +05:30
|
|
|
#[async_trait]
|
|
|
|
/// Starchart's database requirements. To implement support for $Database, kindly implement this
|
|
|
|
/// trait.
|
|
|
|
pub trait SCDatabase: std::marker::Send + std::marker::Sync + CloneSPDatabase {
|
|
|
|
/// ping DB
|
|
|
|
async fn ping(&self) -> bool;
|
|
|
|
|
2022-07-05 14:05:57 +05:30
|
|
|
/// create forge instance
|
|
|
|
async fn create_forge_instance(&self, f: &CreateForge) -> DBResult<()>;
|
2022-04-12 17:35:09 +05:30
|
|
|
|
2022-07-05 14:05:57 +05:30
|
|
|
/// get forge instance data
|
2022-07-14 23:47:37 +05:30
|
|
|
async fn get_forge(&self, url: &Url) -> DBResult<Forge>;
|
2022-06-03 23:05:09 +05:30
|
|
|
|
2022-07-05 14:05:57 +05:30
|
|
|
/// delete forge instance
|
2022-07-14 23:47:37 +05:30
|
|
|
async fn delete_forge_instance(&self, url: &Url) -> DBResult<()>;
|
2022-04-12 17:35:09 +05:30
|
|
|
|
|
|
|
/// check if a forge instance exists
|
2022-07-14 23:47:37 +05:30
|
|
|
async fn forge_exists(&self, url: &Url) -> DBResult<bool>;
|
2022-04-12 17:44:21 +05:30
|
|
|
|
|
|
|
/// check if forge type exists
|
|
|
|
async fn forge_type_exists(&self, forge_type: &ForgeImplementation) -> DBResult<bool>;
|
2022-04-20 16:23:38 +05:30
|
|
|
|
2022-06-09 14:36:22 +05:30
|
|
|
/// Get all forges
|
|
|
|
async fn get_all_forges(&self, offset: u32, limit: u32) -> DBResult<Vec<Forge>>;
|
|
|
|
|
2022-04-20 16:23:38 +05:30
|
|
|
/// add new user to database
|
|
|
|
async fn add_user(&self, u: &AddUser) -> DBResult<()>;
|
|
|
|
|
2022-06-04 20:57:48 +05:30
|
|
|
/// get user data
|
2022-07-14 23:47:37 +05:30
|
|
|
async fn get_user(&self, username: &str, url: &Url) -> DBResult<User>;
|
2022-06-04 20:57:48 +05:30
|
|
|
|
2022-07-14 23:47:37 +05:30
|
|
|
/// check if an user exists. When url of a forge instance is provided, username search is
|
2022-04-20 16:23:38 +05:30
|
|
|
/// done only on that forge
|
2022-07-14 23:47:37 +05:30
|
|
|
async fn user_exists(&self, username: &str, url: Option<&Url>) -> DBResult<bool>;
|
2022-05-01 19:07:49 +05:30
|
|
|
|
2022-05-17 16:14:52 +05:30
|
|
|
/// delete user
|
2022-07-14 23:47:37 +05:30
|
|
|
async fn delete_user(&self, username: &str, url: &Url) -> DBResult<()>;
|
2022-05-17 16:14:52 +05:30
|
|
|
|
|
|
|
/// delete repository
|
2022-07-14 23:47:37 +05:30
|
|
|
async fn delete_repository(&self, owner: &str, name: &str, url: &Url) -> DBResult<()>;
|
2022-05-17 16:14:52 +05:30
|
|
|
|
2022-05-01 19:07:49 +05:30
|
|
|
/// check if a repository exists.
|
2022-07-14 23:47:37 +05:30
|
|
|
async fn repository_exists(&self, name: &str, owner: &str, url: &Url) -> DBResult<bool>;
|
2022-05-04 12:10:13 +05:30
|
|
|
|
2022-05-19 21:38:01 +05:30
|
|
|
/// Get all repositories
|
2022-06-09 14:36:22 +05:30
|
|
|
async fn get_all_repositories(&self, offset: u32, limit: u32) -> DBResult<Vec<Repository>>;
|
2022-05-19 21:38:01 +05:30
|
|
|
|
2022-05-04 12:10:13 +05:30
|
|
|
/// add new repository to database.
|
|
|
|
async fn create_repository(&self, r: &AddRepository) -> DBResult<()>;
|
2022-04-12 17:35:09 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/// Trait to clone SCDatabase
|
|
|
|
pub trait CloneSPDatabase {
|
|
|
|
/// clone DB
|
|
|
|
fn clone_db(&self) -> Box<dyn SCDatabase>;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> CloneSPDatabase for T
|
|
|
|
where
|
|
|
|
T: SCDatabase + Clone + 'static,
|
|
|
|
{
|
|
|
|
fn clone_db(&self) -> Box<dyn SCDatabase> {
|
|
|
|
Box::new(self.clone())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Clone for Box<dyn SCDatabase> {
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
(**self).clone_db()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Forge type: Gitea, Sourcehut, GitLab, etc. Support is currently only available for Gitea
|
|
|
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
#[serde(rename_all = "lowercase")]
|
|
|
|
pub enum ForgeImplementation {
|
|
|
|
/// [Gitea](https://gitea.io) softare forge
|
|
|
|
Gitea,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ForgeImplementation {
|
|
|
|
/// Convert [ForgeImplementation] to [str]
|
|
|
|
pub const fn to_str(&self) -> &'static str {
|
|
|
|
match self {
|
|
|
|
ForgeImplementation::Gitea => "gitea",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FromStr for ForgeImplementation {
|
|
|
|
type Err = DBError;
|
|
|
|
|
|
|
|
/// Convert [str] to [ForgeImplementation]
|
|
|
|
fn from_str(s: &str) -> DBResult<Self> {
|
|
|
|
const GITEA: &str = ForgeImplementation::Gitea.to_str();
|
|
|
|
let s = s.trim();
|
|
|
|
match s {
|
|
|
|
GITEA => Ok(Self::Gitea),
|
|
|
|
_ => Err(DBError::UnknownForgeType(s.to_owned())),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|