Compare commits
No commits in common. "e5d0219df8da6d83b97f5b61eee679c1cfd603e3" and "17d0709ed61ce6306caa79010da25a6617e26bd4" have entirely different histories.
e5d0219df8
...
17d0709ed6
8 changed files with 26 additions and 150 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
name: Publish Release
|
name: Publish Cargo Package
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
|
@ -11,6 +11,8 @@ jobs:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
env:
|
env:
|
||||||
CARGO_TERM_COLOR: always
|
CARGO_TERM_COLOR: always
|
||||||
|
CARGO_REGISTRIES_FORGEJO_TOKEN: Bearer ${{ secrets.FORGEJO_CARGO_TOKEN }}
|
||||||
|
FORGEJO_CARGO_INDEX: ${{ github.server_url }}/${{ github.repository_owner }}/_cargo-index.git
|
||||||
steps:
|
steps:
|
||||||
- name: Check out repository
|
- name: Check out repository
|
||||||
uses: https://data.forgejo.org/actions/checkout@v4
|
uses: https://data.forgejo.org/actions/checkout@v4
|
||||||
|
|
@ -27,6 +29,17 @@ jobs:
|
||||||
rustup default stable
|
rustup default stable
|
||||||
cargo --version
|
cargo --version
|
||||||
|
|
||||||
|
- name: Configure Cargo registry
|
||||||
|
run: |
|
||||||
|
mkdir -p "$HOME/.cargo"
|
||||||
|
cat > "$HOME/.cargo/config.toml" <<EOF
|
||||||
|
[registries.forgejo]
|
||||||
|
index = "${FORGEJO_CARGO_INDEX}"
|
||||||
|
|
||||||
|
[net]
|
||||||
|
git-fetch-with-cli = true
|
||||||
|
EOF
|
||||||
|
|
||||||
- name: Verify tag matches package version
|
- name: Verify tag matches package version
|
||||||
if: startsWith(github.ref, 'refs/tags/v')
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -43,17 +56,12 @@ jobs:
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Build release binary
|
- name: Check package can be published
|
||||||
run: |
|
run: |
|
||||||
. "$HOME/.cargo/env"
|
. "$HOME/.cargo/env"
|
||||||
cargo build --release --locked
|
cargo publish --dry-run --locked --registry forgejo
|
||||||
mv target/release/upvoters upvoters-linux-x86_64
|
|
||||||
|
|
||||||
- name: Create release
|
- name: Publish package
|
||||||
uses: https://data.forgejo.org/actions/forgejo-release@v2
|
run: |
|
||||||
with:
|
. "$HOME/.cargo/env"
|
||||||
direction: upload
|
cargo publish --locked --registry forgejo
|
||||||
tag: ${{ github.ref_name }}
|
|
||||||
release-notes: "Release ${{ github.ref_name }}"
|
|
||||||
files: upvoters-linux-x86_64
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
|
||||||
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -1961,7 +1961,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "upvoters"
|
name = "uprs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "upvoters"
|
name = "uprs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT"
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
|
|
|
||||||
15
Dockerfile
15
Dockerfile
|
|
@ -1,15 +0,0 @@
|
||||||
FROM rust:1.88-slim AS builder
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY Cargo.toml Cargo.lock ./
|
|
||||||
RUN mkdir src && echo "fn main() {}" > src/main.rs && cargo build --release && rm -rf src
|
|
||||||
|
|
||||||
COPY src ./src
|
|
||||||
RUN touch src/main.rs && cargo build --release --locked
|
|
||||||
|
|
||||||
FROM debian:bookworm-slim
|
|
||||||
|
|
||||||
COPY --from=builder /app/target/release/upvoters /usr/local/bin/upvoters
|
|
||||||
|
|
||||||
CMD ["upvoters"]
|
|
||||||
21
LICENSE
21
LICENSE
|
|
@ -1,21 +0,0 @@
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2026 Alex Selimov
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
87
README.md
87
README.md
|
|
@ -1,86 +1,3 @@
|
||||||
# upvoters ☝️
|
# uprs
|
||||||
|
|
||||||
upvoters is a basic anonymous voting system that can be added to a blog.
|
Simple Rust backend for supporting anonymous like/upvote functionality in hugo sites.
|
||||||
I recently reworked my personal blog with the Hugo Bear blog theme.
|
|
||||||
I came across the [creator's (Herman Martinus) blogging site](https://herman.bearblog.dev/) which had this really cool anonymous upvote system.
|
|
||||||
I wanted something similar and decided to implement it myself.
|
|
||||||
The goal is maximum simplicity.
|
|
||||||
|
|
||||||
## Important Notes
|
|
||||||
|
|
||||||
This service does NOT have any authentication/authorization, so you should NOT serve this to the public web.
|
|
||||||
I'm using this by just serving it on the same VPS as my blog.
|
|
||||||
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
- Rust (stable)
|
|
||||||
- PostgreSQL 16
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
The following environment variables are required:
|
|
||||||
|
|
||||||
| Variable | Description |
|
|
||||||
|------------------------------|----------------------------------------------------------------------------------------|
|
|
||||||
| `POSTGRES_CONNECTION_STRING` | PostgreSQL connection string (e.g. `postgres://user:password@localhost:5432/upvoters`) |
|
|
||||||
|
|
||||||
## Running locally
|
|
||||||
|
|
||||||
### With Docker Compose
|
|
||||||
|
|
||||||
Builds and starts both the database and app:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
docker compose up --build
|
|
||||||
```
|
|
||||||
|
|
||||||
The server will be available at `http://localhost:3000`.
|
|
||||||
|
|
||||||
### Without Docker
|
|
||||||
|
|
||||||
Start the database:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
docker compose up -d db
|
|
||||||
```
|
|
||||||
|
|
||||||
Run the server:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
POSTGRES_CONNECTION_STRING=postgres://uprs:password123@localhost:5432/uprs cargo run
|
|
||||||
```
|
|
||||||
|
|
||||||
The server listens on port `3000`.
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
| Method | Endpoint | Description |
|
|
||||||
|---|---|---|
|
|
||||||
| `GET` | `/health` | Health check |
|
|
||||||
| `POST` | `/posts/{slug}/vote` | Upvote a post |
|
|
||||||
| `DELETE` | `/posts/{slug}/vote` | Remove a vote from a post |
|
|
||||||
| `GET` | `/posts/{slug}/votes` | Get vote count and whether the current user has voted |
|
|
||||||
|
|
||||||
Voter identity is tracked via a `voter_id` cookie. One is set automatically on first request.
|
|
||||||
|
|
||||||
### `GET /posts/{slug}/votes` response
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"vote_count": 42,
|
|
||||||
"voted": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Running tests
|
|
||||||
|
|
||||||
Tests require a running PostgreSQL instance at `postgres://uprs:password123@localhost:5432/uprs`.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cargo test
|
|
||||||
```
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
MIT — see [LICENSE](LICENSE).
|
|
||||||
|
|
|
||||||
|
|
@ -12,17 +12,5 @@ services:
|
||||||
- ./db/migrations:/docker-entrypoint-initdb.d # run initial schema
|
- ./db/migrations:/docker-entrypoint-initdb.d # run initial schema
|
||||||
ports:
|
ports:
|
||||||
- "5432:5432"
|
- "5432:5432"
|
||||||
|
|
||||||
app:
|
|
||||||
build: .
|
|
||||||
container_name: uprs_app
|
|
||||||
restart: always
|
|
||||||
environment:
|
|
||||||
POSTGRES_CONNECTION_STRING: postgres://uprs:password123@db:5432/uprs
|
|
||||||
ports:
|
|
||||||
- "3000:3000"
|
|
||||||
depends_on:
|
|
||||||
- db
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
pgdata:
|
pgdata:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||||
use upvoters::state::AppState;
|
use uprs::state::AppState;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
|
@ -14,7 +14,7 @@ async fn main() {
|
||||||
|
|
||||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
||||||
tracing::info!("listening on {}", listener.local_addr().unwrap());
|
tracing::info!("listening on {}", listener.local_addr().unwrap());
|
||||||
axum::serve(listener, upvoters::app(AppState::new().await))
|
axum::serve(listener, uprs::app(AppState::new().await))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue