use crate::handlers::templates::PercentEncoded;
use crate::network::responses::{Contents, FileEncoding, Item, Repo, ServerVersion, User};
use bytesize::ByteSize;
use serde::Deserialize;
use std::cmp::Ordering;
use url::Url;
pub fn gitlab_project_id(
username: &PercentEncoded,
project_pathname: &PercentEncoded,
) -> PercentEncoded {
let combined = format!("{}/{}", username.display(), project_pathname.display());
PercentEncoded::new(&combined)
}
#[derive(Deserialize, Debug)]
pub struct GitLabMetadata {
pub version: String,
pub revision: String,
}
impl From<GitLabMetadata> for ServerVersion {
fn from(metadata: GitLabMetadata) -> Self {
let version = &metadata.version;
let revision = &metadata.revision;
return Self {
version: format!("{version} ({revision})"),
};
}
}
#[derive(Deserialize, Debug)]
pub struct GitLabProjectNamespace {
pub path: String,
}
#[derive(Deserialize, Debug)]
pub struct GitLabProject {
pub default_branch: Option<String>,
pub web_url: Url,
pub name: String,
pub description: String,
pub namespace: GitLabProjectNamespace,
pub updated_at: Option<String>,
pub created_at: String,
pub forked_from_project: Option<Box<GitLabProject>>,
}
impl From<&GitLabProject> for Repo {
fn from(project: &GitLabProject) -> Self {
let owner = User {
login: project.namespace.path.clone(),
};
let default_branch = project
.default_branch
.clone()
.or(Some(String::from("main")))
.expect("");
let updated_at = project
.updated_at
.clone()
.or(Some(project.created_at.clone()))
.expect("");
return Self {
default_branch,
html_url: project.web_url.clone(),
name: project.name.clone(),
description: project.description.clone(),
website: String::new(), owner,
updated_at,
parent: project
.forked_from_project
.as_ref()
.map(|p| Box::new(p.as_ref().into())),
};
}
}
impl From<GitLabProject> for Repo {
fn from(project: GitLabProject) -> Self {
Self::from(&project)
}
}
#[derive(Deserialize, Debug)]
pub struct GitLabUser {
pub username: String,
}
impl From<&GitLabUser> for User {
fn from(user: &GitLabUser) -> Self {
let login = user.username.clone();
return Self { login };
}
}
#[derive(Deserialize, PartialEq, Eq, Debug)]
#[serde(rename_all = "lowercase")]
pub enum GitLabProjectFileEncoding {
Base64,
}
impl From<&GitLabProjectFileEncoding> for FileEncoding {
fn from(value: &GitLabProjectFileEncoding) -> Self {
match value {
GitLabProjectFileEncoding::Base64 => Self::Base64,
}
}
}
#[derive(Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "lowercase")]
pub enum GitLabProjectItemType {
Blob,
Tree,
}
#[derive(Deserialize, PartialEq, Eq, Clone, Debug)]
pub struct GitLabProjectItem {
#[serde(rename = "type")]
pub kind: GitLabProjectItemType,
#[serde(rename = "id")]
pub _id: String,
pub name: String,
pub path: String,
}
impl Ord for GitLabProjectItem {
fn cmp(&self, other: &Self) -> Ordering {
let a = self;
let b = other;
match a.kind {
GitLabProjectItemType::Blob => match b.kind {
GitLabProjectItemType::Tree => Ordering::Greater,
GitLabProjectItemType::Blob => a.name.to_lowercase().cmp(&b.name.to_lowercase()),
},
GitLabProjectItemType::Tree => match b.kind {
GitLabProjectItemType::Blob => Ordering::Less,
GitLabProjectItemType::Tree => a.name.to_lowercase().cmp(&b.name.to_lowercase()),
},
}
}
}
impl PartialOrd for GitLabProjectItem {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl GitLabProjectItem {
pub fn with_html_url(self, url: Url) -> GitLabProjectItemWithUrl {
GitLabProjectItemWithUrl {
item: self,
html_url: url,
}
}
}
pub struct GitLabProjectItemWithUrl {
item: GitLabProjectItem,
html_url: Url,
}
impl GitLabProjectItemWithUrl {
pub fn kind(&self) -> &GitLabProjectItemType {
&self.item.kind
}
pub fn name(&self) -> &String {
&self.item.name
}
pub fn path(&self) -> &String {
&self.item.path
}
}
impl From<&GitLabProjectItemWithUrl> for Item {
fn from(item: &GitLabProjectItemWithUrl) -> Self {
match item.kind() {
GitLabProjectItemType::Blob => Self::File {
content: None,
encoding: None,
name: item.name().clone(),
path: item.path().clone(),
size: ByteSize(0),
html_url: item.html_url.clone(),
},
GitLabProjectItemType::Tree => Self::Dir {
name: item.name().clone(),
path: item.path().clone(),
size: ByteSize(0),
html_url: item.html_url.clone(),
},
}
}
}
#[derive(Deserialize, PartialEq, Eq, Debug)]
pub struct GitLabProjectItemFile {
file_name: String,
file_path: String,
size: ByteSize,
encoding: GitLabProjectFileEncoding,
content: String,
}
impl Ord for GitLabProjectItemFile {
fn cmp(&self, other: &Self) -> Ordering {
let other_name = other.file_name.to_lowercase();
self.file_name.to_lowercase().cmp(&other_name)
}
}
impl PartialOrd for GitLabProjectItemFile {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl GitLabProjectItemFile {
pub fn with_html_url(self, url: Url) -> GitLabProjectItemFileWithUrl {
GitLabProjectItemFileWithUrl {
file: self,
html_url: url,
}
}
}
pub struct GitLabProjectItemFileWithUrl {
file: GitLabProjectItemFile,
html_url: Url,
}
impl GitLabProjectItemFileWithUrl {
pub fn content(&self) -> &String {
&self.file.content
}
pub fn encoding(&self) -> &GitLabProjectFileEncoding {
&self.file.encoding
}
pub fn file_name(&self) -> &String {
&self.file.file_name
}
pub fn file_path(&self) -> &String {
&self.file.file_path
}
pub fn size(&self) -> &ByteSize {
&self.file.size
}
}
pub enum GitLabContents {
Single(GitLabProjectItemFileWithUrl),
Multiple(Vec<GitLabProjectItemWithUrl>),
}
impl From<GitLabContents> for Contents<Item> {
fn from(contents: GitLabContents) -> Self {
match contents {
GitLabContents::Single(file) => Self::Single(Item::File {
content: Some(file.content().clone()),
encoding: Some(file.encoding().into()),
name: file.file_name().clone(),
path: file.file_path().clone(),
size: file.size().clone(),
html_url: file.html_url,
}),
GitLabContents::Multiple(items) => {
Self::Multiple(items.iter().map(Into::into).collect())
}
}
}
}