diff --git a/.woodpecker/deployment.yaml b/.woodpecker/deployment.yaml new file mode 100644 index 0000000..a93b6e8 --- /dev/null +++ b/.woodpecker/deployment.yaml @@ -0,0 +1,23 @@ +steps: + - name: build-docker + image: docker:latest + commands: + - docker build -f backend.Dockerfile -t backend . + + - name: login-forgejo + image: docker:latest + commands: + - docker login -u $$FORGEJO_USERNAME -p $$FORGEJO_PASSWORD + environment: + FORGEJO_USERNAME: + from_secret: FORGEJO_USERNAME + FORGEJO_PASSWORD: + from_secret: FORGEJO_PASSWORD + + + - name: publish-forgejo + image: docker:latest + commands: + - export IMAGE_NAME=git.mixel.cloud/Turbo/peer-group-grading:$${CI_COMMIT_SHA:0:8} + - docker tag backend $$IMAGE_NAME + - docker push $$IMAGE_NAME \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 682fa20..c504bc1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1045,16 +1045,6 @@ dependencies = [ "cipher", ] -[[package]] -name = "ctrlc" -version = "3.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" -dependencies = [ - "nix", - "windows-sys 0.59.0", -] - [[package]] name = "darling" version = "0.20.10" @@ -2088,18 +2078,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e94e1e6445d314f972ff7395df2de295fe51b71821694f0b0e1e79c4f12c8577" -[[package]] -name = "nix" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" -dependencies = [ - "bitflags", - "cfg-if", - "cfg_aliases", - "libc", -] - [[package]] name = "num-bigint" version = "0.4.6" @@ -4178,14 +4156,6 @@ dependencies = [ "tap", ] -[[package]] -name = "xtask" -version = "0.1.0" -dependencies = [ - "clap", - "ctrlc", -] - [[package]] name = "yansi" version = "1.0.1" diff --git a/Cargo.toml b/Cargo.toml index 45dc1a4..279ac56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["crates/backend", "crates/migration", "crates/xtask"] +members = ["crates/backend", "crates/migration"] resolver = "3" [workspace.package] diff --git a/backend.Dockerfile b/backend.Dockerfile new file mode 100644 index 0000000..41c741a --- /dev/null +++ b/backend.Dockerfile @@ -0,0 +1,52 @@ +# ---- Stage 1: Build (Static Linking) ---- +FROM rust:latest as builder + +WORKDIR /usr/src/app + +# Install the musl target and musl-tools +RUN rustup target add x86_64-unknown-linux-musl +RUN apt-get update && apt-get install -y musl-tools + +# Create a .cargo directory and configure for static linking with musl +RUN mkdir -p .cargo +RUN echo '[target.x86_64-unknown-linux-musl]' > .cargo/config.toml +RUN echo 'linker = "rust-lld"' >> .cargo/config.toml + +# Copy configuration and lock files needed to resolve dependencies +COPY Cargo.toml ./Cargo.toml +COPY Cargo.lock ./Cargo.lock +COPY crates/backend/Cargo.toml crates/backend/Cargo.toml +COPY crates/migration/Cargo.toml crates/migration/Cargo.toml + +# Fetch dependencies based on the lock file. +RUN cargo fetch + +# Copy the actual source code for all workspace members +COPY crates/backend/ crates/backend/ +COPY crates/migration/ crates/migration/ + +# Build the release binary for the musl target +RUN cargo build --release --target x86_64-unknown-linux-musl + +# Debug: List the built binaries to verify what we have +RUN ls -la /usr/src/app/target/x86_64-unknown-linux-musl/release/ + +# ---- Stage 2: Runtime ---- +FROM alpine:latest + +# Install minimal runtime dependencies (ca-certificates is often needed) +RUN apk add --no-cache ca-certificates + +WORKDIR /app + +# Copy only the statically linked compiled binary from the builder stage +COPY --from=builder /usr/src/app/target/x86_64-unknown-linux-musl/release/backend /app/backend + +# Verify the binary exists and is executable +RUN ls -la /app && chmod +x /app/backend + +# Expose the port the application listens on +EXPOSE 8080 + +# Set the command to run the application +CMD ["/app/backend"] \ No newline at end of file diff --git a/crates/backend/Cargo.toml b/crates/backend/Cargo.toml index f6da6fd..b9b3a92 100644 --- a/crates/backend/Cargo.toml +++ b/crates/backend/Cargo.toml @@ -32,6 +32,9 @@ dotenvy = "0.15" [dev-dependencies] temp-env = "*" - [features] serve = [] + +[[bin]] +name = "backend" +path = "src/main.rs" diff --git a/crates/backend/src/controller/auth.rs b/crates/backend/src/controller/auth.rs index a24ce35..ebd00ea 100644 --- a/crates/backend/src/controller/auth.rs +++ b/crates/backend/src/controller/auth.rs @@ -30,6 +30,10 @@ async fn login( .verify_local_user(&login_request.username, &login_request.password) .await?; + if session.get::("user").is_ok() { + return Err(ApiError::AlreadyLoggedIn); + } + session.insert("user", user_id)?; Ok(HttpResponse::Ok()) diff --git a/crates/backend/src/error.rs b/crates/backend/src/error.rs index dd52cb2..e24b0a5 100644 --- a/crates/backend/src/error.rs +++ b/crates/backend/src/error.rs @@ -1,4 +1,4 @@ -use actix_web::{cookie::time::error, http::StatusCode, HttpResponse, ResponseError}; +use actix_web::{HttpResponse, ResponseError, cookie::time::error, http::StatusCode}; use sea_orm::TransactionError; use thiserror::Error; @@ -18,6 +18,8 @@ pub enum ApiError { Argon2Error(String), #[error("Session insert error: {0}")] SessionInsertError(#[from] actix_session::SessionInsertError), + #[error("Already logged in")] + AlreadyLoggedIn, } impl ResponseError for ApiError { @@ -30,6 +32,7 @@ impl ResponseError for ApiError { ApiError::ValidationError(..) => StatusCode::BAD_REQUEST, ApiError::Argon2Error(..) => StatusCode::INTERNAL_SERVER_ERROR, ApiError::SessionInsertError(..) => StatusCode::INTERNAL_SERVER_ERROR, + ApiError::AlreadyLoggedIn => StatusCode::BAD_REQUEST, } } diff --git a/dev-compose.yml b/dev-compose.yml index 5384b24..017b13c 100644 --- a/dev-compose.yml +++ b/dev-compose.yml @@ -52,6 +52,26 @@ services: interval: 30s retries: 3 + backend: + build: + context: . + dockerfile: ./backend.Dockerfile + image: peer-group-grading:latest + restart: unless-stopped + environment: + DB_NAME: ${DB_NAME} + DB_USER: ${DB_USER} + DB_PASSWORD: ${DB_PASSWORD} + DB_HOST: db + DB_PORT: 5432 + REDIS_HOST: redis + REDIS_PORT: 6379 + ports: + - "8080:8080" + depends_on: + - db + - redis + volumes: postgres_data: redis: