Skip to content

Commit

Permalink
Add create project code
Browse files Browse the repository at this point in the history
  • Loading branch information
carlosthe19916 committed Dec 31, 2023
1 parent 5723bed commit 5d030f6
Show file tree
Hide file tree
Showing 13 changed files with 133 additions and 90 deletions.
2 changes: 1 addition & 1 deletion openubl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ docker-compose -f openubl/deploy/compose/compose.yaml up
```

```shell
RUST_LOG=info cargo watch -x 'run -p openubl-cli -- server --db-user user --db-password password'
RUST_LOG=info cargo watch -x 'run -p openubl-cli -- server --db-user user --db-password password --oidc-auth-server-url http://localhost:9001/realms/openubl'
```
82 changes: 51 additions & 31 deletions openubl/api/src/system/project.rs
Original file line number Diff line number Diff line change
@@ -1,44 +1,68 @@
use std::fmt::{Debug, Formatter};

use sea_orm::ActiveValue::Set;
use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter};
use sea_orm::{
ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, QuerySelect, RelationTrait,
};
use sea_query::JoinType;

use openubl_entity as entity;
use openubl_entity::project;
use openubl_entity::user_role;

use crate::db::Transactional;
use crate::system::error::Error;
use crate::system::InnerSystem;

impl InnerSystem {
pub async fn get_projects_by_user_id(
&self,
user_id: &str,
tx: Transactional<'_>,
) -> Result<Vec<ProjectContext>, Error> {
Ok(project::Entity::find()
.join(
JoinType::InnerJoin,
user_role::Relation::Project.def().rev(),
)
.filter(entity::user_role::Column::UserId.eq(user_id))
.all(&self.connection(tx))
.await?
.drain(0..)
.map(|project| (self, project).into())
.collect())
}

pub async fn create_project(
&self,
model: &project::Model,
user_id: &str,
tx: Transactional<'_>,
) -> Result<ProjectContext, Error> {
if let Some(found) = self.get_project(&model.name, tx).await? {
Ok(found)
} else {
let entity = project::ActiveModel {
name: Set(model.name.clone()),
description: Set(model.description.clone()),
sunat_username: Set(model.sunat_username.clone()),
sunat_password: Set(model.sunat_password.clone()),
sunat_factura_url: Set(model.sunat_factura_url.clone()),
sunat_guia_url: Set(model.sunat_guia_url.clone()),
sunat_percepcion_retencion_url: Set(model.sunat_percepcion_retencion_url.clone()),
};
let project_entity = project::ActiveModel {
name: Set(model.name.clone()),
description: Set(model.description.clone()),
..Default::default()
};

Ok((self, entity.insert(&self.connection(tx)).await?).into())
}
let result = project_entity.insert(&self.connection(tx)).await?;

let user_role_entity = user_role::ActiveModel {
project_id: Set(result.id),
user_id: Set(user_id.to_string()),
role: Set(user_role::Role::Owner),
};
user_role_entity.insert(&self.connection(tx)).await?;

Ok((self, result).into())
}

pub async fn get_project(
&self,
name: &str,
id: i32,
tx: Transactional<'_>,
) -> Result<Option<ProjectContext>, Error> {
Ok(project::Entity::find()
.filter(project::Column::Name.eq(name))
Ok(project::Entity::find_by_id(id)
.one(&self.connection(tx))
.await?
.map(|project| (self, project).into()))
Expand Down Expand Up @@ -67,17 +91,13 @@ impl From<(&InnerSystem, project::Model)> for ProjectContext {
}

impl ProjectContext {
// pub async fn set_owner(&self, tx: Transactional<'_>) -> Result<Vec<ProjectContext>, Error> {
// Ok(advisory::Entity::find()
// .join(
// JoinType::Join,
// advisory_vulnerability::Relation::Advisory.def().rev(),
// )
// .filter(advisory_vulnerability::Column::VulnerabilityId.eq(self.cve.id))
// .all(&self.system.connection(tx))
// .await?
// .drain(0..)
// .map(|advisory| (&self.system, advisory).into())
// .collect())
// }
pub async fn set_owner(&self, user_id: &str, tx: Transactional<'_>) -> Result<(), Error> {
let entity = user_role::ActiveModel {
project_id: Set(self.project.id),
user_id: Set(user_id.to_string()),
role: Set(user_role::Role::Owner),
};
entity.insert(&self.system.connection(tx)).await?;
Ok(())
}
}
7 changes: 2 additions & 5 deletions openubl/entity/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,11 @@ use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Deserialize, Serialize)]
#[sea_orm(table_name = "project")]
pub struct Model {
#[serde(skip_deserializing)]
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
pub description: Option<String>,
pub sunat_username: String,
pub sunat_password: String,
pub sunat_factura_url: String,
pub sunat_guia_url: String,
pub sunat_percepcion_retencion_url: String,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
Expand Down
18 changes: 13 additions & 5 deletions openubl/entity/src/user_role.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,26 @@ use sea_orm::entity::prelude::*;
#[sea_orm(table_name = "user_role")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub username: String,
pub user_id: String,
#[sea_orm(primary_key, auto_increment = false)]
pub project_name: i32,
pub roles: String,
pub project_id: i32,
#[sea_orm(primary_key, auto_increment = false)]
pub role: Role,
}

#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
#[sea_orm(rs_type = "String", db_type = "String(Some(1))")]
pub enum Role {
#[sea_orm(string_value = "o")]
Owner,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::project::Entity",
from = "Column::ProjectName",
to = "super::project::Column::Name",
from = "Column::ProjectId",
to = "super::project::Column::Id",
on_update = "NoAction",
on_delete = "Cascade"
)]
Expand Down
21 changes: 5 additions & 16 deletions openubl/migration/src/m20231223_071007_create_project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,14 @@ impl MigrationTrait for Migration {
.table(Project::Table)
.if_not_exists()
.col(
ColumnDef::new(Project::Name)
.string()
ColumnDef::new(Project::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(ColumnDef::new(Project::Name).string().not_null())
.col(ColumnDef::new(Project::Description).string())
.col(ColumnDef::new(Project::SunatUsername).string().not_null())
.col(ColumnDef::new(Project::SunatPassword).string().not_null())
.col(ColumnDef::new(Project::SunatFacturaUrl).string().not_null())
.col(ColumnDef::new(Project::SunatGuiaUrl).string().not_null())
.col(
ColumnDef::new(Project::SunatPercepcionRetencionUrl)
.string()
.not_null(),
)
.to_owned(),
)
.await
Expand All @@ -42,11 +35,7 @@ impl MigrationTrait for Migration {
#[derive(DeriveIden)]
pub enum Project {
Table,
Id,
Name,
Description,
SunatUsername,
SunatPassword,
SunatFacturaUrl,
SunatGuiaUrl,
SunatPercepcionRetencionUrl,
}
21 changes: 11 additions & 10 deletions openubl/migration/src/m20231223_075825_create_user_role.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,19 @@ impl MigrationTrait for Migration {
Table::create()
.table(UserRole::Table)
.if_not_exists()
.col(ColumnDef::new(UserRole::Username).string().not_null())
.col(ColumnDef::new(UserRole::ProjectName).string().not_null())
.col(ColumnDef::new(UserRole::Roles).string().not_null())
.col(ColumnDef::new(UserRole::UserId).string().not_null())
.col(ColumnDef::new(UserRole::ProjectId).integer().not_null())
.col(ColumnDef::new(UserRole::Role).string().not_null())
.primary_key(
Index::create()
.col(UserRole::Username)
.col(UserRole::ProjectName),
.col(UserRole::UserId)
.col(UserRole::ProjectId)
.col(UserRole::Role),
)
.foreign_key(
ForeignKey::create()
.from_col(UserRole::ProjectName)
.to(Project::Table, Project::Name)
.from_col(UserRole::ProjectId)
.to(Project::Table, Project::Id)
.on_delete(ForeignKeyAction::Cascade),
)
.to_owned(),
Expand All @@ -42,7 +43,7 @@ impl MigrationTrait for Migration {
#[derive(DeriveIden)]
pub enum UserRole {
Table,
Username,
ProjectName,
Roles,
UserId,
ProjectId,
Role,
}
2 changes: 1 addition & 1 deletion openubl/oidc/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#[derive(clap::Args, Debug)]
pub struct Oidc {
#[arg(id = "oidc-auth-server-url", long, env = "OIDC_AUTH-SERVER_URL")]
#[arg(id = "oidc-auth-server-url", long, env = "OIDC_AUTH_SERVER_URL")]
pub auth_server_url: String,
}
9 changes: 6 additions & 3 deletions openubl/oidc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ pub struct UserClaims {
pub iss: String,
pub sub: String,
pub aud: String,
pub name: String,
pub email: Option<String>,
pub email_verified: Option<bool>,
}

impl UserClaims {
pub fn user_id(&self) -> String {
self.sub.clone()
}
}
1 change: 1 addition & 0 deletions openubl/server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,6 @@ pub struct AppState {
pub fn configure(config: &mut web::ServiceConfig) {
config.service(health::liveness);
config.service(health::readiness);
config.service(project::list_projects);
config.service(project::create_project);
}
50 changes: 36 additions & 14 deletions openubl/server/src/server/project.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,57 @@
use actix_web::{post, web, HttpResponse, Responder};
use actix_4_jwt_auth::AuthenticatedUser;
use actix_web::{get, post, web, HttpResponse, Responder};

use openubl_api::db::Transactional;
use openubl_entity::project;
use openubl_oidc::UserClaims;

use crate::server::Error;
use crate::AppState;

#[utoipa::path(
responses(
(status = 200, description = "Create project"),
),
)]
#[post("projects")]
#[utoipa::path(responses((status = 200, description = "List projects")), )]
#[get("/projects")]
pub async fn list_projects(
state: web::Data<AppState>,
user: AuthenticatedUser<UserClaims>,
) -> Result<impl Responder, Error> {
let projects_ctx = state
.system
.get_projects_by_user_id(&user.claims.user_id(), Transactional::None)
.await
.map_err(Error::System)?;

Ok(HttpResponse::Ok().json(
projects_ctx
.iter()
.map(|ctx| &ctx.project)
.collect::<Vec<_>>(),
))
}

#[utoipa::path(responses((status = 200, description = "Create project")))]
#[post("/projects")]
pub async fn create_project(
state: web::Data<AppState>,
json: web::Json<project::Model>,
user: AuthenticatedUser<UserClaims>,
) -> Result<impl Responder, Error> {
let prev = state
.system
.get_project(&json.name, Transactional::None)
.await?;
.get_projects_by_user_id(&user.claims.user_id(), Transactional::None)
.await
.map_err(Error::System)?
.iter()
.any(|ctx| ctx.project.name == json.name);

match prev {
None => {
let ctx = state
false => {
let project_ctx = state
.system
.create_project(&json, Transactional::None)
.create_project(&json, &user.claims.sub, Transactional::None)
.await
.map_err(Error::System)?;
Ok(HttpResponse::Ok().json(ctx.project))
Ok(HttpResponse::Ok().json(project_ctx.project))
}
Some(_) => Ok(HttpResponse::Conflict().body("Project name already exists")),
true => Ok(HttpResponse::Conflict().body("Another project has the same name")),
}
}
2 changes: 1 addition & 1 deletion openubl/ui/client/src/app/layout/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const SidebarApp: React.FC = () => {
const routeParams = useMatch("/projects/:projectId/*");

let projectId = routeParams?.params.projectId;
let { project } = useFetchProjectById(projectId || "");
let { project } = useFetchProjectById(projectId);

const renderPageNav = () => {
return (
Expand Down
6 changes: 4 additions & 2 deletions openubl/ui/client/src/app/queries/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@ export const useFetchProjects = () => {
};
};

export const useFetchProjectById = (id: number | string) => {
export const useFetchProjectById = (id?: number | string) => {
const { data, isLoading, error } = useQuery({
queryKey: [ProjectsQueryKey, id],
queryFn: () => getProjectById(id),
queryFn: () =>
id === undefined ? Promise.resolve(undefined) : getProjectById(id),
onError: (error: AxiosError) => console.log("error", error),
enabled: id !== undefined,
});

return {
Expand Down
2 changes: 1 addition & 1 deletion openubl/ui/common/src/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { OPENUBL_ENV } from "./environment.js";

export const proxyMap: Record<string, Options> = {
"/hub": {
target: OPENUBL_ENV.OPENUBL_HUB_URL || "http://localhost:9002",
target: OPENUBL_ENV.OPENUBL_HUB_URL || "http://localhost:8080",
logLevel: process.env.DEBUG ? "debug" : "info",

changeOrigin: true,
Expand Down

0 comments on commit 5d030f6

Please sign in to comment.