Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove contribution guidelines #49

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,42 @@
# Items

This project aims at creating an organization tool for all the stuff you have, be it books, food, camping items or what have you.
This project aims at creating an organization tool for all the stuff you have, be it books, food, camping items or what have you.

## Setup Instructions

### Backend

1. Install Rust: https://www.rust-lang.org/tools/install
2. Clone the repository: `git clone <repository-url>`
3. Navigate to the backend directory: `cd backend`
4. Create a `.env` file in the backend directory with the following content:
```
DATABASE_URL=postgresql://postgres:admin@localhost:5432/postgres
```
5. Start the database and MinIO services using Docker Compose: `docker-compose up`
6. Run the backend: `cargo run`

### Frontend

1. Install Deno: https://deno.land/manual/getting_started/installation
2. Navigate to the frontend directory: `cd frontend`
3. Start the frontend: `deno task start`

## Usage Examples

### Backend

- To get the health status of the backend, send a GET request to `/status/health`.
- To get all items, send a GET request to `/api/items`.
- To add a new item, send a POST request to `/api/items` with the following JSON payload:
```json
{
"name": "Item Name",
"description": "Item Description",
"date_origin": "2023-01-01"
}
```

### Frontend

- Open your browser and navigate to `http://localhost:8000` to view the frontend.
15 changes: 13 additions & 2 deletions backend/src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@ use sqlx::{prelude::FromRow, PgPool};

static BUCKET_NAME: &'static str = "files";

/// Generates a file name based on the id and hash.
fn file_name(id: i32, hash: &str) -> String {
format!("{}-{}", id, hash)
}

/// Retrieves S3 credentials from the environment.
fn get_s3_credentials() -> Result<(Credentials, Region)> {
Ok((Credentials::default()?, Region::from_default_env()?))
}

type Content = Vec<u8>;

/// Represents a file with its content.
#[derive(Debug)]
pub struct File {
content: Content,
Expand All @@ -27,6 +30,7 @@ impl File {
Self { content }
}

/// Uploads the file to S3.
pub async fn put_into_s3(
&self,
id: i32,
Expand Down Expand Up @@ -54,6 +58,7 @@ impl File {
Ok(())
}

/// Retrieves the file from S3.
pub async fn get_from_s3(
id: i32,
hash: &str,
Expand All @@ -68,6 +73,7 @@ impl File {
Ok(Self::new(result.into()))
}

/// Deletes the file from S3.
pub async fn delete_from_s3(
id: i32,
hash: &str,
Expand All @@ -84,6 +90,7 @@ impl File {
}
}

/// Represents file information stored in the database.
#[derive(FromRow, Serialize, Deserialize, Clone, Debug)]
pub struct FileInfo {
id: i32,
Expand All @@ -101,11 +108,10 @@ impl FileInfo {
}
}

/// Inserts content into S3 and database
/// Inserts content into S3 and database.
///
/// # Errors
///
///
/// This function will return an error if S3 or DB is unavailable.
pub async fn insert_into_db(pool: &PgPool, content: &[u8]) -> Result<()> {
let hash = digest(content);
Expand All @@ -124,13 +130,15 @@ impl FileInfo {
Ok(())
}

/// Reads all file information from the database.
pub async fn read_from_db(pool: &PgPool) -> Result<Vec<FileInfo>> {
let files = sqlx::query_as::<_, FileInfo>("SELECT * FROM files")
.fetch_all(pool)
.await?;
Ok(files)
}

/// Deletes file information from the database and S3.
pub async fn delete_from_db(pool: &PgPool, id: i32) -> Result<()> {
let file_info = Self::read_from_db_by_id(pool, id).await?;
let (credentials, region) = get_s3_credentials()?;
Expand All @@ -142,6 +150,7 @@ impl FileInfo {
Ok(())
}

/// Reads file information by id from the database.
pub async fn read_from_db_by_id(pool: &PgPool, id: i32) -> Result<FileInfo> {
let file_info = sqlx::query_as::<_, FileInfo>("SELECT * FROM files WHERE id = $1")
.bind(id)
Expand All @@ -150,13 +159,15 @@ impl FileInfo {
Ok(file_info)
}

/// Retrieves file content by id from the database and S3.
pub async fn get_file_by_id(pool: &PgPool, id: i32) -> Result<Content> {
let file_info = Self::read_from_db_by_id(pool, id).await?;
let (credentials, region) = get_s3_credentials()?;
let file = File::get_from_s3(file_info.id, &file_info.hash, credentials, region).await?;
Ok(file.content)
}

/// Reads all file information from the database and retrieves the corresponding files from S3.
pub async fn read_from_db_and_s3(pool: &PgPool) -> Result<Vec<(FileInfo, File)>> {
let (credentials, region) = get_s3_credentials()?;
let file_infos = sqlx::query_as::<_, FileInfo>("SELECT * FROM files")
Expand Down
12 changes: 7 additions & 5 deletions backend/src/location.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ use anyhow::Result;
use serde::{Deserialize, Serialize};
use sqlx::{FromRow, PgPool};

/// Represents a location with its details.
#[derive(FromRow, Serialize, Deserialize, Clone, Debug)]
pub struct Location {
pub id: i32,
pub name: String,
pub description: String,
}

/// Represents a new location to be added.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct NewLocation {
pub name: String,
Expand All @@ -23,15 +25,15 @@ impl NewLocation {
}

impl Location {
/// Reads all locations from database
/// Reads all locations from the database.
pub async fn read_from_db(pool: &PgPool) -> Result<Vec<Location>> {
let locations = sqlx::query_as::<_, Location>("SELECT * FROM locations")
.fetch_all(pool)
.await?;
Ok(locations)
}

/// Reads a location by id from database
/// Reads a location by id from the database.
pub async fn read_from_db_by_id(pool: &PgPool, id: i32) -> Result<Location> {
let location = sqlx::query_as::<_, Location>("SELECT * FROM locations l WHERE l.id = $1")
.bind(id)
Expand All @@ -40,7 +42,7 @@ impl Location {
Ok(location)
}

/// Insert location into database
/// Inserts a new location into the database.
pub async fn insert_into_db(pool: &PgPool, name: &str, description: &str) -> Result<()> {
sqlx::query("INSERT INTO locations (name, description) VALUES ($1, $2)")
.bind(name)
Expand All @@ -50,7 +52,7 @@ impl Location {
Ok(())
}

/// Deletes a location from the database
/// Deletes a location from the database by id.
pub async fn delete_from_db(pool: &PgPool, id: i32) -> Result<()> {
sqlx::query("DELETE FROM locations l WHERE l.id = $1")
.bind(id)
Expand All @@ -59,7 +61,7 @@ impl Location {
Ok(())
}

/// Updates a location by id in the database
/// Updates a location in the database by id.
pub async fn update_in_db(pool: &PgPool, location: &Location) -> Result<()> {
sqlx::query("UPDATE locations SET name = $1, description = $2 WHERE id = $3")
.bind(&location.name)
Expand Down
14 changes: 14 additions & 0 deletions backend/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@ use simple_logger::SimpleLogger;
use sqlx::PgPool;
use structopt::StructOpt;

/// Command line options for the application.
#[derive(Debug, Clone, StructOpt)]
pub struct Opts {
/// Host address to bind the server to.
#[structopt(short, long, default_value = "0.0.0.0:3000")]
host: String,

/// Database URL for connecting to the PostgreSQL database.
#[structopt(
short,
long,
Expand All @@ -26,22 +29,33 @@ pub struct Opts {
)]
db_url: String,

/// Log level for the application.
#[structopt(short, long, default_value = "info")]
log_level: String,
}

#[tokio::main]
async fn main() -> Result<()> {
// Parse command line options.
let opts = Opts::from_args();

// Initialize the logger with the specified log level.
SimpleLogger::new()
.with_level(log::LevelFilter::from_str(&opts.log_level)?)
.init()?;

info!("Connecting to DB at {}", opts.db_url);

// Connect to the PostgreSQL database.
let connection = PgPool::connect(&opts.db_url).await.unwrap();

// Create the router with the database connection.
let router = router::create_router(connection);

// Bind the server to the specified host address.
let listener = tokio::net::TcpListener::bind(opts.host).await?;

// Start the server.
axum::serve(listener, router).await?;
Ok(())
}
Loading
Loading