Skip to content

Commit

Permalink
Lot's of work
Browse files Browse the repository at this point in the history
  • Loading branch information
wyatt-herkamp committed Aug 25, 2024
1 parent 680f360 commit d0796c2
Show file tree
Hide file tree
Showing 92 changed files with 2,010 additions and 881 deletions.
217 changes: 108 additions & 109 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ http-body-util = "0.1"
http-body = "1"
bytes = "1"
pin-project = "1"

url = "2"
## Hashing
digestible = { version = "0.2", features = ["base64"] }
digest = { version = "0.10", features = ["std", "alloc"] }
Expand Down
1 change: 1 addition & 0 deletions crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ http.workspace = true
derive_builder.workspace = true
derive_more.workspace = true
digestible.workspace = true
url.workspace = true
[lints]
workspace = true
12 changes: 6 additions & 6 deletions crates/core/src/database/project/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ mod new;
pub mod utils;
use crate::repository::project::{ReleaseType, VersionData};
pub use new::*;

pub mod update;
use super::DateTime;
/// Implemented on different types of Project query result. Such as ProjectLookupResult
pub trait ProjectDBType: for<'r> FromRow<'r, PgRow> + Unpin + Send + Sync {
Expand Down Expand Up @@ -41,7 +41,7 @@ pub trait ProjectDBType: for<'r> FromRow<'r, PgRow> + Unpin + Send + Sync {
) -> Result<Option<Self>, sqlx::Error> {
let columns = Self::format_columns(None);
let project = sqlx::query_as::<_, Self>(&format!(
"SELECT {} FROM projects WHERE repository = $1 AND LOWER(project_key) = $2",
"SELECT {} FROM projects WHERE repository_id = $1 AND LOWER(project_key) = $2",
columns
))
.bind(repository)
Expand All @@ -58,7 +58,7 @@ pub trait ProjectDBType: for<'r> FromRow<'r, PgRow> + Unpin + Send + Sync {
) -> Result<Option<Self>, sqlx::Error> {
let columns = Self::format_columns(None);
let project = sqlx::query_as::<_, Self>(&format!(
"SELECT {} FROM projects WHERE repository = $1 AND LOWER(storage_path) = $2",
"SELECT {} FROM projects WHERE repository_id = $1 AND LOWER(storage_path) = $2",
columns
))
.bind(repository)
Expand Down Expand Up @@ -87,7 +87,7 @@ pub trait ProjectDBType: for<'r> FromRow<'r, PgRow> + Unpin + Send + Sync {
let columns = Self::format_columns(Some("P"));
let project = sqlx::query_as::<_, Self>(
&format!(
"SELECT {} FROM projects as P FULL JOIN project_versions as V ON LOWER(V.release_path) = $1 AND V.project_id = P.id WHERE P.repository = $2",
"SELECT {} FROM projects as P FULL JOIN project_versions as V ON LOWER(V.release_path) = $1 AND V.project_id = P.id WHERE P.repository_id = $2",
columns
),
)
Expand Down Expand Up @@ -124,7 +124,7 @@ pub struct DBProject {
/// Can be empty
pub tags: Vec<String>,
/// The repository it belongs to
pub repository: Uuid,
pub repository_id: Uuid,
/// Storage Path
pub storage_path: String,
/// Last time the project was updated. This is updated when a new version is added
Expand Down Expand Up @@ -192,7 +192,7 @@ impl DBProjectVersion {
database: &PgPool,
) -> Result<Option<Self>, sqlx::Error> {
let version = sqlx::query_as::<_, Self>(
r#"SELECT project_versions.* FROM project_versions FULL JOIN projects ON projects.id = project_versions.project_id AND projects.repository = $1 WHERE LOWER(project_versions.version_path) = $2"#,
r#"SELECT project_versions.* FROM project_versions FULL JOIN projects ON projects.id = project_versions.project_id AND projects.repository_id = $1 WHERE LOWER(project_versions.version_path) = $2"#,
)
.bind(repository_id)
.bind(directory.to_lowercase())
Expand Down
5 changes: 3 additions & 2 deletions crates/core/src/database/project/new.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl NewProject {

let insert = sqlx::query_as::<_,DBProject>(
r#"
INSERT INTO projects (scope, project_key, name, latest_release, latest_pre_release, description, tags, repository, storage_path)
INSERT INTO projects (scope, project_key, name, latest_release, latest_pre_release, description, tags, repository_id, storage_path)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING *
"#
).bind(scope)
Expand Down Expand Up @@ -120,7 +120,8 @@ pub struct NewVersion {
/// The path to the release
pub version_path: String,
/// The publisher of the version
pub publisher: i32,
#[builder(default)]
pub publisher: Option<i32>,
/// The version page. Such as a README
#[builder(default)]
pub version_page: Option<String>,
Expand Down
52 changes: 52 additions & 0 deletions crates/core/src/database/project/update.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use derive_builder::Builder;
use http::version;
use sqlx::{types::Json, Execute, PgPool, QueryBuilder};
use tracing::{info, instrument, warn};

use crate::repository::project::{ReleaseType, VersionData};

#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct UpdateProjectVersion {
pub release_type: Option<ReleaseType>,
//#[builder(default)]
//pub publisher: Option<i32>,
//#[builder(default)]
//pub version_page: Option<String>,
pub extra: Option<VersionData>,
}

impl UpdateProjectVersion {
#[instrument(name = "UpdateProjectVersion::update")]
pub async fn update(self, version_id: i32, db: &PgPool) -> Result<(), sqlx::Error> {
let mut query = QueryBuilder::new("UPDATE project_versions SET updated_at = NOW(), ");
let mut separated = query.separated(", ");
if let Some(release_type) = self.release_type {
separated.push("release_type = ");
separated.push_bind_unseparated(release_type);
}
//if let Some(version_page) = self.version_page {
// separated.push("user_manager = ");
// separated.push_bind_unseparated(version_page);
//}
if let Some(extra) = self.extra {
separated.push("extra = ");
separated.push_bind_unseparated(Json(extra));
}
query.push(" WHERE id = ");
query.push_bind(version_id);
let query: sqlx::query::Query<sqlx::Postgres, sqlx::postgres::PgArguments> = query.build();
info!(
"Updating project_version for version_id {} {}",
version_id,
query.sql()
);
let result = query.execute(db).await?;
if result.rows_affected() == 0 {
warn!(
"No rows affected when updating project_version for version_id {}",
version_id
);
}
Ok(())
}
}
2 changes: 1 addition & 1 deletion crates/core/src/database/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ impl DBRepositoryConfig<Value> {
.await?;
if let Some(config) = config {
sqlx::query(
r#"UPDATE repository_configs SET value = $1, updated = NOW() WHERE id = $2"#,
r#"UPDATE repository_configs SET value = $1, updated_at = NOW() WHERE id = $2"#,
)
.bind(Json(value))
.bind(config.id)
Expand Down
5 changes: 1 addition & 4 deletions crates/core/src/database/user/auth_token/repository_scope.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use derive_builder::Builder;
use serde::{Deserialize, Serialize};
use sqlx::{
prelude::{FromRow, Type},
PgPool,
};
use sqlx::{prelude::FromRow, PgPool};
use tracing::{debug, instrument, span};
use uuid::Uuid;

Expand Down
6 changes: 6 additions & 0 deletions crates/core/src/database/user/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,12 @@ impl HasPermissions for UserSafeData {
default_repository_actions: self.default_repository_actions.clone(),
})
}
fn is_admin_or_system_manager(&self) -> bool {
self.admin || self.system_manager
}
fn is_admin_or_user_manager(&self) -> bool {
self.admin || self.user_manager
}
}
impl From<UserModel> for UserSafeData {
fn from(user: UserModel) -> Self {
Expand Down
2 changes: 2 additions & 0 deletions crates/core/src/repository/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ pub enum RepositoryConfigError {
InvalidConfig(&'static str),
#[error("Invalid Config: {0}")]
SerdeError(#[from] serde_json::Error),
#[error("Invalid Change: {0}")]
InvalidChange(&'static str, &'static str),
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, Digestible)]
pub struct ConfigDescription {
Expand Down
2 changes: 1 addition & 1 deletion crates/core/src/repository/config/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ impl Default for BadgeSettings {
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BadgeStyle(Style);
pub struct BadgeStyle(pub Style);
impl Default for BadgeStyle {
fn default() -> Self {
BadgeStyle(Style::Flat)
Expand Down
1 change: 1 addition & 0 deletions crates/core/src/repository/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use utoipa::ToSchema;
use crate::utils::validations;
pub mod config;
pub mod project;
pub mod proxy_url;
#[derive(
Debug,
Clone,
Expand Down
3 changes: 3 additions & 0 deletions crates/core/src/repository/project/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use derive_builder::Builder;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use sqlx::prelude::Type;
use strum::{Display, EnumIs, EnumString, IntoStaticStr};
use utoipa::ToSchema;
Expand Down Expand Up @@ -87,6 +88,8 @@ pub struct VersionData {
pub source: Option<ProjectSource>,
#[builder(default)]
pub licence: Option<Licence>,
#[builder(default)]
pub extra: Option<Value>,
}
/// Author of the project
///
Expand Down
70 changes: 70 additions & 0 deletions crates/core/src/repository/proxy_url.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use std::fmt::Display;

use derive_more::derive::{AsRef, Deref};
use schemars::JsonSchema;
use serde::Serialize;
use tracing::{instrument, trace};
use url::Url;

use crate::storage::StoragePath;

#[derive(Debug, Clone, PartialEq, Eq, JsonSchema, Deref, AsRef)]
pub struct ProxyURL(String);

impl Serialize for ProxyURL {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.0.serialize(serializer)
}
}

impl<'de> serde::Deserialize<'de> for ProxyURL {
fn deserialize<D>(deserializer: D) -> Result<ProxyURL, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;

Ok(ProxyURL::try_from(s).map_err(serde::de::Error::custom)?)
}
}

impl TryFrom<String> for ProxyURL {
type Error = url::ParseError;

fn try_from(value: String) -> Result<Self, Self::Error> {
let mut s = value;
if s.ends_with("/") {
s.pop();
}
let url = url::Url::parse(&s)?;
trace!(url = %url, "Parsed URL");
Ok(ProxyURL(s))
}
}
impl Display for ProxyURL {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl From<ProxyURL> for String {
fn from(url: ProxyURL) -> String {
url.0
}
}
impl ProxyURL {
/// Creates a URL from a proxyURL and a path
#[instrument]
pub fn add_storage_path(&self, path: StoragePath) -> Result<Url, url::ParseError> {
let mut path = path.to_string();
if path.starts_with("/") {
path = path[1..].to_string();
}
let raw_url = format!("{}/{}", self.0, path);
trace!(url = %raw_url, "Creating URL");
let url = Url::parse(&format!("{}/{}", self.0, path))?;
Ok(url)
}
}
28 changes: 28 additions & 0 deletions crates/core/src/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,31 @@ impl Display for StorageName {
}

validations::from_impls!(StorageName, InvalidStorageName);
/// Check if a file is a directory or a file
///
/// This trait is implemented for `Option<T>` where `T` implements `FileTypeCheck`. Will return false if `None`
pub trait FileTypeCheck: Sized {
fn is_directory(&self) -> bool;
fn is_file(&self) -> bool;
}

/// Implement `FileTypeCheck` for `Option<T>` where `T` implements `FileTypeCheck`
/// Will return false if `None`
impl<T> FileTypeCheck for Option<T>
where
T: FileTypeCheck,
{
fn is_directory(&self) -> bool {
match self {
Some(t) => t.is_directory(),
None => false,
}
}

fn is_file(&self) -> bool {
match self {
Some(t) => t.is_file(),
None => false,
}
}
}
3 changes: 3 additions & 0 deletions crates/core/src/storage/storage_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ impl StoragePath {
.map(|v| v.0.ends_with(extension))
.unwrap_or(false)
}
pub fn push(&mut self, component: &str) {
self.0.push(StoragePathComponent(component.to_string()));
}
}
impl From<StoragePath> for PathBuf {
fn from(value: StoragePath) -> Self {
Expand Down
2 changes: 1 addition & 1 deletion crates/core/src/user/permissions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ pub async fn does_user_and_token_have_repository_action<T: HasPermissions + Debu
.await
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Type)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Type, ToSchema)]
#[sqlx(type_name = "TEXT")]
pub enum RepositoryActions {
Read,
Expand Down
7 changes: 7 additions & 0 deletions crates/macros/src/dyn_repository_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ pub(crate) fn expand(derive_input: DeriveInput) -> Result<TokenStream> {
)*
}
}
fn site(&self) -> NitroRepo{
match self {
#(
#ident::#variants(variant) => variant.site(),
)*
}
}
fn name(&self) -> String{
match self {
#(
Expand Down
23 changes: 23 additions & 0 deletions crates/storage/src/fs/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::{is_hidden_file, FileMeta};
use super::{utils::MetadataUtils, FileHashes, SerdeMime, StorageFileReader};
use chrono::{DateTime, FixedOffset, Local};

use nr_core::storage::FileTypeCheck;
use serde::{Deserialize, Serialize};

use strum::EnumIs;
Expand All @@ -24,6 +25,20 @@ pub enum StorageFile {
content: StorageFileReader,
},
}
impl FileTypeCheck for StorageFile {
fn is_file(&self) -> bool {
match self {
StorageFile::File { .. } => true,
_ => false,
}
}
fn is_directory(&self) -> bool {
match self {
StorageFile::Directory { .. } => true,
_ => false,
}
}
}

impl StorageFile {
pub fn meta(&self) -> &StorageFileMeta {
Expand Down Expand Up @@ -68,6 +83,14 @@ pub struct StorageFileMeta {
/// The first time it was created.
pub created: DateTime<FixedOffset>,
}
impl FileTypeCheck for StorageFileMeta {
fn is_file(&self) -> bool {
self.file_type.is_file()
}
fn is_directory(&self) -> bool {
self.file_type.is_directory()
}
}
impl StorageFileMeta {
#[instrument(name = "StorageFileMeta::new_from_file", skip(path))]
pub fn new_from_file(path: impl AsRef<Path>) -> Result<Self, io::Error> {
Expand Down
Loading

0 comments on commit d0796c2

Please sign in to comment.