Compare commits

..
Author SHA1 Message Date
phoenix 8317f41e3c Claim update (#26)
Release Tagging / release (push) Successful in 47s
Rust Build / Check (push) Successful in 56s
Rust Build / Rustfmt (push) Successful in 27s
Rust Build / Test Suite (push) Successful in 1m34s
Rust Build / Clippy (push) Successful in 50s
Rust Build / build (push) Successful in 40s
Release Tagging / release (pull_request) Successful in 46s
Rust Build / Rustfmt (pull_request) Successful in 28s
Rust Build / Check (pull_request) Successful in 1m15s
Rust Build / Test Suite (pull_request) Successful in 1m20s
Rust Build / Clippy (pull_request) Successful in 43s
Rust Build / build (pull_request) Successful in 1m2s
Reviewed-on: phoenix/textsender_models#26
2026-06-13 18:02:25 -04:00
phoenix ba998096cb Contact update (#25)
Release Tagging / release (push) Successful in 52s
Rust Build / Check (push) Successful in 1m4s
Rust Build / Test Suite (push) Successful in 1m7s
Rust Build / Clippy (push) Successful in 34s
Rust Build / build (push) Successful in 51s
Rust Build / Rustfmt (push) Successful in 1m30s
Release Tagging / release (pull_request) Successful in 58s
Rust Build / Test Suite (pull_request) Successful in 1m14s
Rust Build / Check (pull_request) Successful in 1m24s
Rust Build / Rustfmt (pull_request) Successful in 49s
Rust Build / build (pull_request) Successful in 47s
Rust Build / Clippy (pull_request) Successful in 1m6s
Reviewed-on: phoenix/textsender_models#25
2026-06-13 16:25:48 -04:00
phoenix d504108745 Merge pull request 'V0.3.0' (#21) from v0.3.0-migrate into main
Rust Build / Check (push) Successful in 27s
Release Tagging / release (push) Successful in 55s
Rust Build / Test Suite (push) Successful in 52s
Rust Build / Rustfmt (push) Successful in 27s
Rust Build / build (push) Successful in 39s
Rust Build / Clippy (push) Successful in 44s
Rust Build / Check (pull_request) Successful in 52s
Release Tagging / release (pull_request) Successful in 1m1s
Rust Build / Test Suite (pull_request) Successful in 1m8s
Rust Build / Rustfmt (pull_request) Successful in 41s
Rust Build / build (pull_request) Successful in 57s
Rust Build / Clippy (pull_request) Successful in 1m58s
Reviewed-on: phoenix/textsender-models#21
2026-06-07 14:54:19 -04:00
phoenix c6d2d19619 Get ready (#23)
Release Tagging / release (pull_request) Failing after 39s
Rust Build / Check (pull_request) Successful in 39s
Rust Build / Test Suite (pull_request) Successful in 55s
Rust Build / Rustfmt (pull_request) Successful in 1m27s
Rust Build / Clippy (pull_request) Successful in 37s
Rust Build / build (pull_request) Successful in 36s
Reviewed-on: phoenix/textsender-models#23
2026-06-07 14:51:07 -04:00
phoenix 38dbcb09f7 Model changes (#22)
Release Tagging / release (push) Successful in 33s
Rust Build / Test Suite (push) Successful in 27s
Rust Build / Check (push) Successful in 1m3s
Rust Build / Rustfmt (push) Successful in 38s
Rust Build / Clippy (push) Successful in 37s
Rust Build / build (push) Successful in 27s
Release Tagging / release (pull_request) Successful in 2m29s
Rust Build / Check (pull_request) Successful in 3m42s
Rust Build / Test Suite (pull_request) Successful in 1m41s
Rust Build / Clippy (pull_request) Successful in 43s
Rust Build / Rustfmt (pull_request) Successful in 1m40s
Rust Build / build (pull_request) Successful in 41s
Reviewed-on: phoenix/textsender-models#22
2026-06-03 21:34:09 -04:00
phoenix 766d38ea0e Skipping serialization of fields in Contact (#20)
Release Tagging / release (push) Successful in 40s
Rust Build / Test Suite (push) Successful in 26s
Rust Build / Check (push) Successful in 1m28s
Rust Build / Rustfmt (push) Successful in 26s
Rust Build / Clippy (push) Successful in 40s
Rust Build / build (push) Successful in 1m11s
Reviewed-on: phoenix/textsender-models#20
2026-06-01 22:15:17 -04:00
phoenix 2be0337da0 User utoipa (#19)
Rust Build / Check (push) Successful in 36s
Rust Build / Rustfmt (push) Successful in 31s
Rust Build / Test Suite (push) Successful in 41s
Rust Build / build (push) Successful in 31s
Rust Build / Clippy (push) Successful in 45s
Release Tagging / release (push) Successful in 40s
Reviewed-on: phoenix/textsender-models#19
2026-05-31 17:48:09 -04:00
phoenix 910ecfc0e0 Extending user (#18)
Rust Build / Check (push) Successful in 39s
Rust Build / Rustfmt (push) Successful in 33s
Rust Build / Test Suite (push) Successful in 37s
Rust Build / build (push) Successful in 34s
Rust Build / Clippy (push) Successful in 40s
Release Tagging / release (push) Successful in 40s
Reviewed-on: phoenix/textsender-models#18
2026-05-31 17:22:52 -04:00
phoenix 43c636a280 Token create (#17)
Release Tagging / release (push) Failing after 28s
Rust Build / Check (push) Successful in 37s
Rust Build / Rustfmt (push) Successful in 25s
Rust Build / Test Suite (push) Successful in 1m1s
Rust Build / Clippy (push) Successful in 26s
Rust Build / build (push) Successful in 25s
Rust Build / Rustfmt (pull_request) Successful in 28s
Rust Build / Clippy (pull_request) Successful in 34s
Rust Build / build (pull_request) Successful in 33s
Release Tagging / release (pull_request) Successful in 33s
Rust Build / Check (pull_request) Successful in 42s
Rust Build / Test Suite (pull_request) Successful in 36s
Reviewed-on: phoenix/textsender-models#17
2026-05-31 17:14:16 -04:00
phoenix 1340440fec Envy (#16)
Rust Build / Rustfmt (push) Successful in 25s
Rust Build / Clippy (push) Successful in 31s
Rust Build / build (push) Successful in 58s
Rust Build / Check (push) Successful in 32s
Rust Build / Test Suite (push) Successful in 25s
Release Tagging / release (push) Successful in 1m24s
Reviewed-on: phoenix/textsender-models#16
2026-05-31 15:45:17 -04:00
phoenix 638da70649 Adding scheduling module (#15)
Release Tagging / release (push) Successful in 33s
Rust Build / Check (push) Successful in 52s
Rust Build / Test Suite (push) Successful in 43s
Rust Build / Rustfmt (push) Successful in 27s
Rust Build / Clippy (push) Successful in 29s
Rust Build / build (push) Successful in 32s
Reviewed-on: phoenix/textsender-models#15
2026-05-30 22:56:13 -04:00
phoenix 7bffed3f9d Adding statuses (#14)
Rust Build / Check (push) Successful in 33s
Release Tagging / release (push) Successful in 41s
Rust Build / Test Suite (push) Successful in 39s
Rust Build / Rustfmt (push) Successful in 35s
Rust Build / build (push) Successful in 35s
Rust Build / Clippy (push) Successful in 41s
Reviewed-on: phoenix/textsender-models#14
2026-05-30 16:15:35 -04:00
phoenix 3527f1aff3 Adding event module (#13)
Rust Build / Check (push) Successful in 37s
Release Tagging / release (push) Failing after 40s
Rust Build / Rustfmt (push) Successful in 34s
Rust Build / Test Suite (push) Successful in 39s
Rust Build / build (push) Successful in 26s
Rust Build / Clippy (push) Successful in 1m8s
Reviewed-on: phoenix/textsender-models#13
2026-05-30 15:56:13 -04:00
phoenix e965cdeed9 Adding message module (#12)
Rust Build / Check (push) Successful in 41s
Release Tagging / release (push) Successful in 1m18s
Rust Build / Rustfmt (push) Successful in 26s
Rust Build / Test Suite (push) Successful in 1m5s
Rust Build / Clippy (push) Successful in 27s
Rust Build / build (push) Successful in 33s
Reviewed-on: phoenix/textsender-models#12
2026-05-30 15:15:15 -04:00
phoenix 34c47ac529 Organization (#11)
Release Tagging / release (push) Successful in 28s
Rust Build / Check (push) Successful in 37s
Rust Build / Rustfmt (push) Successful in 28s
Rust Build / Clippy (push) Successful in 30s
Rust Build / build (push) Successful in 26s
Rust Build / Test Suite (push) Successful in 28s
Reviewed-on: phoenix/textsender-models#11
2026-05-29 22:55:32 -04:00
phoenix e5ae5e1828 Adding UserProfile (#10)
Release Tagging / release (push) Failing after 26s
Rust Build / Check (push) Successful in 35s
Rust Build / Test Suite (push) Successful in 27s
Rust Build / Rustfmt (push) Successful in 29s
Rust Build / Clippy (push) Successful in 30s
Rust Build / build (push) Successful in 24s
Reviewed-on: phoenix/textsender-models#10
2026-05-29 22:22:15 -04:00
phoenix 179a550034 Adding Login history (#9)
Release Tagging / release (push) Failing after 36s
Rust Build / Check (push) Successful in 46s
Rust Build / Test Suite (push) Successful in 39s
Rust Build / Rustfmt (push) Successful in 32s
Rust Build / Clippy (push) Successful in 33s
Rust Build / build (push) Successful in 33s
Reviewed-on: phoenix/textsender-models#9
2026-05-29 21:41:40 -04:00
phoenix a8e173d831 ServiceUser (#8)
Release Tagging / release (push) Successful in 29s
Rust Build / Check (push) Successful in 39s
Rust Build / Test Suite (push) Successful in 25s
Rust Build / Rustfmt (push) Successful in 27s
Rust Build / Clippy (push) Successful in 28s
Rust Build / build (push) Successful in 26s
Reviewed-on: phoenix/textsender-models#8
2026-05-29 10:02:51 -04:00
phoenix 6975475330 Added user module (#7)
Release Tagging / release (push) Successful in 34s
Rust Build / Check (push) Successful in 34s
Rust Build / Test Suite (push) Successful in 26s
Rust Build / Rustfmt (push) Successful in 35s
Rust Build / Clippy (push) Successful in 29s
Rust Build / build (push) Successful in 27s
Reviewed-on: phoenix/textsender-models#7
2026-05-29 09:50:59 -04:00
phoenix b28d26e26b Added fields to Claims (#6)
Release Tagging / release (push) Successful in 36s
Rust Build / Check (push) Successful in 36s
Rust Build / Rustfmt (push) Successful in 32s
Rust Build / Test Suite (push) Successful in 37s
Rust Build / Clippy (push) Successful in 33s
Rust Build / build (push) Successful in 34s
Reviewed-on: phoenix/textsender-models#6
2026-05-29 09:38:53 -04:00
phoenix c85ca95016 Adding token module (#5)
Release Tagging / release (push) Successful in 29s
Rust Build / Check (push) Successful in 37s
Rust Build / Test Suite (push) Successful in 29s
Rust Build / Rustfmt (push) Successful in 27s
Rust Build / Clippy (push) Successful in 31s
Rust Build / build (push) Successful in 28s
Reviewed-on: phoenix/textsender-models#5
2026-05-28 22:25:57 -04:00
phoenix cfd5050f98 Added code (#4)
Release Tagging / release (push) Successful in 36s
Rust Build / Check (push) Successful in 43s
Rust Build / Test Suite (push) Successful in 28s
Rust Build / Rustfmt (push) Successful in 29s
Rust Build / Clippy (push) Successful in 27s
Rust Build / build (push) Successful in 26s
Reviewed-on: phoenix/textsender-models#4
2026-05-28 21:42:42 -04:00
phoenix b4d1e59ba5 Clean slate 2026-05-28 20:41:34 -04:00
phoenix f39d48d85a Organization (#3)
Go Release / build-and-release (push) Successful in 6s
Go CI / Test and Lint (push) Successful in 7s
Reviewed-on: phoenix/textsender-models#3
2026-05-28 20:04:12 -04:00
phoenix 3ccc1a9a6d UserProfile (#1)
Go Release / build-and-release (push) Successful in 5s
Go CI / Test and Lint (push) Successful in 6s
Reviewed-on: phoenix/textsender-models#1
2026-05-27 22:59:45 -04:00
phoenix 5b36e5c42e Login History (#2)
Go Release / build-and-release (push) Successful in 6s
Go CI / Test and Lint (push) Successful in 12s
Reviewed-on: phoenix/textsender-models#2
2026-05-26 22:08:05 -04:00
36 changed files with 1498 additions and 327 deletions
@@ -1,4 +1,4 @@
name: Go Release
name: Release Tagging
on:
push:
@@ -9,27 +9,28 @@ on:
- main
jobs:
build-and-release:
release:
runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: '1.26.2'
fetch-depth: 0 # Important for git describe --tags
- name: Create version
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: 1.95
components: cargo
- name: Extract Version from Cargo.toml
id: version
run: |
echo "Creating version"
VERSION="0.2.1"
VERSION=$(grep '^version = "' Cargo.toml | sed -E 's/version = "([^"]+)"/\1/')
PROJECT_COMMIT_HASH=$(git rev-parse HEAD | cut -c 1-10)
BRANCH_REF="${{ gitea.ref }}"
BRANCH_NAME=$(echo "$BRANCH_REF" | cut -d '/' -f 3)
PROJECT_TAG_RELEASE="v$VERSION-$BRANCH_NAME-$PROJECT_COMMIT_HASH-556"
PROJECT_TAG_RELEASE="v$VERSION-$BRANCH_NAME-$PROJECT_COMMIT_HASH-111"
echo "::set-output name=project_tag_release::$PROJECT_TAG_RELEASE"
+67
View File
@@ -0,0 +1,67 @@
name: Rust Build
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
check:
name: Check
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.95
- uses: Swatinem/rust-cache@v2
- run: cargo check
test:
name: Test Suite
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.95
- uses: Swatinem/rust-cache@v2
- run: cargo test
fmt:
name: Rustfmt
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.95
- uses: Swatinem/rust-cache@v2
- run: rustup component add rustfmt
- run: cargo fmt --all -- --check
clippy:
name: Clippy
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.95
- uses: Swatinem/rust-cache@v2
- run: rustup component add clippy
- run: cargo clippy -- -D warnings
build:
name: build
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.95
- uses: Swatinem/rust-cache@v2
- run: cargo build
-27
View File
@@ -1,27 +0,0 @@
name: Go CI
on: [push, pull_request] # Triggers on push or pull request events
jobs:
test:
name: Test and Lint
runs-on: ubuntu-24.04
steps:
- name: Check out repository code
uses: actions/checkout@v5
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: '1.26.2'
- name: Configure Git for SSH
run: |
git config --global url."git@${{ secrets.GIT_HOST_ROOT }}:".insteadOf "https://${{ secrets.GIT_HOST_ROOT }}/"
go env -w GOPRIVATE=${{ secrets.GIT_HOST_ROOT }}/phoenix/*
- name: Download dependencies
run: |
go mod download
- name: Run tests
run: go test -v ./... # Runs all tests in the project
+1 -1
View File
@@ -1 +1 @@
/vendor/
target/
Generated
+837
View File
@@ -0,0 +1,837 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "adler2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "aho-corasick"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bitflags"
version = "2.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
[[package]]
name = "bumpalo"
version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "cc"
version = "1.2.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dad887fd958be91b5098c0248def011f4523ab786cd411be668777e55063501f"
dependencies = [
"find-msvc-tools",
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "const_format"
version = "0.2.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4481a617ad9a412be3b97c5d403fef8ed023103368908b9c50af598ff467cc1e"
dependencies = [
"const_format_proc_macros",
"konst",
]
[[package]]
name = "const_format_proc_macros"
version = "0.2.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "crc32fast"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
dependencies = [
"cfg-if",
]
[[package]]
name = "deranged"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
dependencies = [
"powerfmt",
"serde_core",
]
[[package]]
name = "dotenvy"
version = "0.15.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "find-msvc-tools"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
[[package]]
name = "flate2"
version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "foldhash"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "futures-core"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
[[package]]
name = "futures-task"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
[[package]]
name = "futures-util"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
dependencies = [
"futures-core",
"futures-task",
"pin-project-lite",
"slab",
]
[[package]]
name = "getrandom"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasip2",
"wasip3",
]
[[package]]
name = "hashbrown"
version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [
"foldhash",
]
[[package]]
name = "hashbrown"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "id-arena"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
[[package]]
name = "indexmap"
version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [
"equivalent",
"hashbrown 0.17.1",
"serde",
"serde_core",
]
[[package]]
name = "itoa"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "josekit"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a808e078330e6af222eb0044b71d4b1ff981bfef43e7bc8133a88234e0c86a0c"
dependencies = [
"anyhow",
"base64",
"flate2",
"openssl",
"regex",
"serde",
"serde_json",
"thiserror",
"time",
]
[[package]]
name = "js-sys"
version = "0.3.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31"
dependencies = [
"cfg-if",
"futures-util",
"wasm-bindgen",
]
[[package]]
name = "konst"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb"
dependencies = [
"konst_macro_rules",
]
[[package]]
name = "konst_macro_rules"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37"
[[package]]
name = "leb128fmt"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]]
name = "libc"
version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
name = "log"
version = "0.4.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a"
[[package]]
name = "memchr"
version = "2.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
[[package]]
name = "miniz_oxide"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
"simd-adler32",
]
[[package]]
name = "num-conv"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
[[package]]
name = "once_cell"
version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "openssl"
version = "0.10.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45"
dependencies = [
"bitflags",
"cfg-if",
"foreign-types",
"libc",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "openssl-sys"
version = "0.9.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "pin-project-lite"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
[[package]]
name = "pkg-config"
version = "0.3.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "prettyplease"
version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
dependencies = [
"proc-macro2",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [
"proc-macro2",
]
[[package]]
name = "r-efi"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
[[package]]
name = "regex"
version = "1.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
[[package]]
name = "rustversion"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "semver"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
dependencies = [
"indexmap",
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "shlex"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
[[package]]
name = "simd-adler32"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
[[package]]
name = "slab"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]]
name = "syn"
version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "textsender_models"
version = "0.3.2"
dependencies = [
"const_format",
"dotenvy",
"josekit",
"serde",
"serde_json",
"time",
"utoipa",
"uuid",
]
[[package]]
name = "thiserror"
version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "time"
version = "0.3.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
dependencies = [
"deranged",
"itoa",
"num-conv",
"powerfmt",
"serde_core",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
[[package]]
name = "time-macros"
version = "0.2.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "unicode-xid"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "utoipa"
version = "5.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bde15df68e80b16c7d16b9616e80770ad158988daa56a27dccd1e55558b0160"
dependencies = [
"indexmap",
"serde",
"serde_json",
"utoipa-gen",
]
[[package]]
name = "utoipa-gen"
version = "5.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ba0b99ee52df3028635d93840c797102da61f8a7bb3cf751032455895b52ef8"
dependencies = [
"proc-macro2",
"quote",
"syn",
"uuid",
]
[[package]]
name = "uuid"
version = "1.23.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "144d6b123cef80b301b8f72a9e2ca4370ddec21950d0a103dd22c437006d2db7"
dependencies = [
"getrandom",
"js-sys",
"serde_core",
"wasm-bindgen",
]
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "wasip2"
version = "1.0.4+wasi-0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
dependencies = [
"wit-bindgen 0.57.1",
]
[[package]]
name = "wasip3"
version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
dependencies = [
"wit-bindgen 0.51.0",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f"
dependencies = [
"unicode-ident",
]
[[package]]
name = "wasm-encoder"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
dependencies = [
"leb128fmt",
"wasmparser",
]
[[package]]
name = "wasm-metadata"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
dependencies = [
"anyhow",
"indexmap",
"wasm-encoder",
"wasmparser",
]
[[package]]
name = "wasmparser"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
dependencies = [
"bitflags",
"hashbrown 0.15.5",
"indexmap",
"semver",
]
[[package]]
name = "wit-bindgen"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
dependencies = [
"wit-bindgen-rust-macro",
]
[[package]]
name = "wit-bindgen"
version = "0.57.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
[[package]]
name = "wit-bindgen-core"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
dependencies = [
"anyhow",
"heck",
"wit-parser",
]
[[package]]
name = "wit-bindgen-rust"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
dependencies = [
"anyhow",
"heck",
"indexmap",
"prettyplease",
"syn",
"wasm-metadata",
"wit-bindgen-core",
"wit-component",
]
[[package]]
name = "wit-bindgen-rust-macro"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
dependencies = [
"anyhow",
"prettyplease",
"proc-macro2",
"quote",
"syn",
"wit-bindgen-core",
"wit-bindgen-rust",
]
[[package]]
name = "wit-component"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
dependencies = [
"anyhow",
"bitflags",
"indexmap",
"log",
"serde",
"serde_derive",
"serde_json",
"wasm-encoder",
"wasm-metadata",
"wasmparser",
"wit-parser",
]
[[package]]
name = "wit-parser"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
dependencies = [
"anyhow",
"id-arena",
"indexmap",
"log",
"semver",
"serde",
"serde_derive",
"serde_json",
"unicode-xid",
"wasmparser",
]
[[package]]
name = "zmij"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
+18
View File
@@ -0,0 +1,18 @@
[package]
name = "textsender_models"
version = "0.3.2"
edition = "2024"
rust-version = "1.95"
description = "Models used for the textsender project"
[dependencies]
serde = { version = "1.0.228", features = ["derive"] }
serde_json = { version = "1.0.149" }
time = { version = "0.3.47", features = ["formatting", "macros", "parsing", "serde"] }
uuid = { version = "1.23.1", features = ["v4", "serde"] }
dotenvy = { version = "0.15.7" }
const_format = { version = "0.2.36" }
josekit = { version = "0.10.3" }
utoipa = { version = "5.4.0", features = ["uuid", "time"] }
[dev-dependencies]
-10
View File
@@ -1,10 +0,0 @@
# textsender-models
A library containing functions, structs, types, and other code for the textsender
project
### Building project
```SHELL
go mod tidy
go mod vendor
```
-15
View File
@@ -1,15 +0,0 @@
module git.kundeng.us/phoenix/textsender-models
go 1.26.2
require (
github.com/golang-jwt/jwt/v5 v5.3.1
github.com/google/uuid v1.6.0
github.com/stretchr/testify v1.11.1
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
-14
View File
@@ -1,14 +0,0 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+23
View File
@@ -0,0 +1,23 @@
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct TwilioConfig {
#[serde(alias = "auth_id")]
pub account_sid: String,
#[serde(skip_serializing_if = "String::is_empty")]
pub service_sid: String,
#[serde(skip_serializing_if = "String::is_empty")]
pub auth_token: String,
#[serde(skip_serializing_if = "String::is_empty")]
pub phone_number: String,
}
impl TwilioConfig {
pub fn print_config(&self) {
println!("Twilio config");
println!("Account SID: {:?}", self.account_sid);
println!("Service SID: {:?}", self.service_sid);
println!("Auth Token: {:?}", self.auth_token);
println!("Number: {:?}", self.phone_number);
}
}
+1
View File
@@ -0,0 +1 @@
pub mod auxiliary;
+19
View File
@@ -0,0 +1,19 @@
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, Deserialize, Serialize, utoipa::ToSchema)]
pub struct Contact {
#[serde(skip_serializing_if = "crate::init::is_uuid_nil")]
pub id: Option<uuid::Uuid>,
// empty?
#[serde(skip_serializing_if = "Option::is_none")]
pub firstname: Option<String>,
// empty?
#[serde(skip_serializing_if = "Option::is_none")]
pub lastname: Option<String>,
// empty?
#[serde(skip_serializing_if = "Option::is_none")]
pub nickname: Option<String>,
pub phone_number: String,
#[serde(skip_serializing_if = "crate::init::is_uuid_nil")]
pub user_id: Option<uuid::Uuid>,
}
+106
View File
@@ -0,0 +1,106 @@
pub async fn get_db_url() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::DB_URL;
let value = std::env::var(key).expect(key);
crate::envy::init_envvar(key, &value)
}
pub async fn get_secret_main_key() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::SECRET_MAIN_KEY;
let value = std::env::var(key).expect(key);
crate::envy::init_envvar(key, &value)
}
pub async fn get_service_passphrase() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::SERVICE_PASSPHRASE;
let value = std::env::var(key).expect(key);
crate::envy::init_envvar(key, &value)
}
pub async fn get_secret_key() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::SECRET_KEY;
let value = std::env::var(key).expect(key);
crate::envy::init_envvar(key, &value)
}
pub async fn get_root_directory() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::ROOT_DIRECTORY;
let value = std::env::var(key).expect(key);
crate::envy::init_envvar(key, &value)
}
pub async fn get_app_base_api_url() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::TEXTSENDER_BASE_API_URL;
let value = std::env::var(key).expect(key);
crate::envy::init_envvar(key, &value)
}
pub async fn get_app_auth_base_api_url() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::TEXTSENDER_AUTH_BASE_API_URL;
let value = std::env::var(key).expect(key);
crate::envy::init_envvar(key, &value)
}
pub async fn get_app_env() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::APP_ENV;
let value = std::env::var(key).expect(key);
crate::envy::init_envvar(key, &value)
}
pub async fn get_backend_port() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::BACKEND_PORT;
let value = std::env::var(key).expect(key);
crate::envy::init_envvar(key, &value)
}
pub async fn get_frontend_url() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::FRONTEND_URL;
let value = std::env::var(key).expect(key);
crate::envy::init_envvar(key, &value)
}
pub async fn get_rust_log() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::RUST_LOG;
let value = std::env::var(key).expect(key);
crate::envy::init_envvar(key, &value)
}
pub async fn get_allowed_origins() -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let key = crate::envy::keys::ALLOWED_ORIGINS;
let value = std::env::var(key).expect(key);
let mut envvar = crate::envy::init_envvar(key, &value);
crate::envy::init_delimiter(&mut envvar, ',');
envvar
}
/// Get environment not specified in the code
pub async fn get_env(environment: &str) -> crate::envy::EnvVar {
dotenvy::dotenv().ok();
let my_error = format!("{environment} {}", crate::envy::keys::error::GENERAL_ERROR);
let value = std::env::var(environment).expect(&my_error);
crate::envy::init_envvar(environment, &value)
}
+53
View File
@@ -0,0 +1,53 @@
/// Environment key for Database management
pub const DB_URL: &str = "DATABASE_URL";
/// Environment key for secret main key
/// Used for the textsender app
pub const SECRET_MAIN_KEY: &str = "SECRET_MAIN_KEY";
/// Environment key for service logins
pub const SERVICE_PASSPHRASE: &str = "SERVICE_PASSPHRASE";
/// Environment key for secret key
/// Generic use of secret key that could be found in various apps
pub const SECRET_KEY: &str = "SECRET_KEY";
/// Environment key for root directory for the textsender app
pub const ROOT_DIRECTORY: &str = "ROOT_DIRECTORY";
/// Environment key for textsender api url
pub const TEXTSENDER_BASE_API_URL: &str = "TEXTSENDER_BASE_API_URL";
/// Environment key for textsender auth api url
pub const TEXTSENDER_AUTH_BASE_API_URL: &str = "TEXTSENDER_AUTH_BASE_API_URL";
/// Environment key for App status
pub const APP_ENV: &str = "APP_ENV";
/// Environment key for backend port. Used for both auth and core functionality
pub const BACKEND_PORT: &str = "BACKEND_PORT";
/// Environment key for frontend url
pub const FRONTEND_URL: &str = "FRONTEND_URL";
/// Environment key for application logging
pub const RUST_LOG: &str = "RUST_LOG";
/// Environment key for allowed origins for CORS support
pub const ALLOWED_ORIGINS: &str = "ALLOWED_ORIGINS";
pub mod error {
use const_format::concatcp;
pub const GENERAL_ERROR: &str = "must not be set in enviornment file";
pub const DB_URL: &str = concatcp!(super::DB_URL, " ", GENERAL_ERROR);
pub const SECRET_MAIN_KEY: &str = concatcp!(super::SECRET_MAIN_KEY, " ", GENERAL_ERROR);
pub const SERVICE_LOGIN: &str = concatcp!(super::SERVICE_PASSPHRASE, " ", GENERAL_ERROR);
pub const SECRET_KEY: &str = concatcp!(super::SECRET_KEY, " ", GENERAL_ERROR);
pub const ROOT_DIRECTORY: &str = concatcp!(super::ROOT_DIRECTORY, " ", GENERAL_ERROR);
pub const TEXTSENDER_BASE_API_URL: &str =
concatcp!(super::TEXTSENDER_BASE_API_URL, " ", GENERAL_ERROR);
pub const TEXTSENDER_AUTH_BASE_API_URL: &str =
concatcp!(super::TEXTSENDER_AUTH_BASE_API_URL, " ", GENERAL_ERROR);
pub const APP_ENV: &str = concatcp!(super::APP_ENV, " ", GENERAL_ERROR);
pub const BACKEND_PORT: &str = concatcp!(super::BACKEND_PORT, " ", GENERAL_ERROR);
pub const FRONTEND_URL: &str = concatcp!(super::FRONTEND_URL, " ", GENERAL_ERROR);
pub const RUST_LOG: &str = concatcp!(super::RUST_LOG, " ", GENERAL_ERROR);
pub const ALLOWED_ORIGINS: &str = concatcp!(super::ALLOWED_ORIGINS, " ", GENERAL_ERROR);
}
+39
View File
@@ -0,0 +1,39 @@
pub mod environment;
pub mod keys;
pub mod utility;
#[derive(Debug, Default, Clone)]
pub struct EnvVar {
pub key: String,
pub value: String,
pub has_delimiter: bool,
pub delimiter: char,
}
pub fn init_envvar(key: &str, value: &str) -> EnvVar {
EnvVar {
key: key.to_string(),
value: value.to_string(),
has_delimiter: false,
..Default::default()
}
}
pub fn init_delimiter(envvar: &mut EnvVar, delimiter: char) {
let mut amount_of_delimiters_found: i32 = 0;
for v in envvar.value.chars() {
if v == delimiter {
amount_of_delimiters_found += 1;
}
}
let has_delimiter = amount_of_delimiters_found >= 1;
if has_delimiter {
envvar.has_delimiter = has_delimiter;
envvar.delimiter = delimiter;
} else {
envvar.has_delimiter = has_delimiter;
}
}
+15
View File
@@ -0,0 +1,15 @@
/// Take the Environment variable and delimitize it. If the value has a delimiter,
/// extract it into some strings
pub fn delimitize(var: &crate::envy::EnvVar) -> Result<Vec<String>, std::io::Error> {
if var.has_delimiter {
Ok(var
.value
.split(var.delimiter)
.map(|c| c.parse::<String>().unwrap())
.collect())
} else {
Err(std::io::Error::other(
"Environment variable does not have a delimiter",
))
}
}
+15
View File
@@ -0,0 +1,15 @@
pub mod config;
pub mod contact;
pub mod envy;
pub mod message;
pub mod token;
pub mod user;
pub mod init {
pub fn is_uuid_nil(uuid: &Option<uuid::Uuid>) -> bool {
match uuid {
Some(id) => id.is_nil(),
None => true,
}
}
}
+18
View File
@@ -0,0 +1,18 @@
use serde::{Deserialize, Serialize};
pub const MESSAGE_EVENT_RESPONSE_STATUS_INSTANT: &str = "INSTANT";
pub const MESSAGE_EVENT_RESPONSE_STATUS_SCHEDULED: &str = "SCHEDULED";
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct MessageEventResponse {
pub id: uuid::Uuid,
pub scheduled_message_event_id: uuid::Uuid,
// Json field
pub response: String,
pub user_id: uuid::Uuid,
pub contact_id: uuid::Uuid,
pub message_id: uuid::Uuid,
pub status: String,
#[serde(with = "time::serde::rfc3339::option")]
pub sent: Option<time::OffsetDateTime>,
}
+13
View File
@@ -0,0 +1,13 @@
pub mod event;
pub mod scheduling;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, Deserialize, Serialize, utoipa::ToSchema)]
pub struct Message {
#[serde(skip_serializing_if = "crate::init::is_uuid_nil")]
pub id: Option<uuid::Uuid>,
pub content: String,
#[serde(skip_serializing_if = "crate::init::is_uuid_nil")]
pub user_id: Option<uuid::Uuid>,
}
+27
View File
@@ -0,0 +1,27 @@
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, Deserialize, Serialize, utoipa::ToSchema)]
pub struct ScheduledMessageEvent {
id: uuid::Uuid,
contact_id: uuid::Uuid,
message_id: uuid::Uuid,
scheduled_message_id: uuid::Uuid,
#[serde(with = "time::serde::rfc3339::option")]
created: Option<time::OffsetDateTime>,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct ScheduledMessage {
id: uuid::Uuid,
#[serde(with = "time::serde::rfc3339::option")]
scheduled: Option<time::OffsetDateTime>,
#[serde(with = "time::serde::rfc3339::option")]
created: Option<time::OffsetDateTime>,
status: String,
user_id: uuid::Uuid,
}
pub const READY: &str = "READY";
pub const PENDING: &str = "PENDING";
pub const PROCESSING: &str = "PROCESSING";
pub const DONE: &str = "DONE";
+110
View File
@@ -0,0 +1,110 @@
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Claims {
pub user_id: uuid::Uuid,
pub role: String,
#[serde(alias = "iss")]
pub issued: String,
#[serde(alias = "exp")]
#[serde(deserialize_with = "deserialize_i64_from_f64")]
pub expired: i64,
#[serde(alias = "iat")]
#[serde(deserialize_with = "deserialize_i64_from_f64")]
pub issued_at: i64,
}
fn deserialize_i64_from_f64<'de, D>(deserializer: D) -> Result<i64, D::Error>
where
D: serde::Deserializer<'de>,
{
let val = f64::deserialize(deserializer)?;
// Handle NaN and infinity cases
if val.is_nan() || val.is_infinite() {
return Err(serde::de::Error::custom("invalid float value"));
}
// Round to nearest integer and convert
let rounded = val.round();
// Check if the rounded value can fit in i64
if rounded < (i64::MIN as f64) || rounded > (i64::MAX as f64) {
Err(serde::de::Error::custom("float out of i64 range"))
} else {
Ok(rounded as i64)
}
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, utoipa::ToSchema)]
pub struct LoginResult {
pub user_id: uuid::Uuid,
pub access_token: String,
pub token_type: String,
pub expires_in: i64,
pub issued_at: i64,
}
// Alias for LoginResult
pub type Login = LoginResult;
pub fn get_issued() -> time::Result<time::OffsetDateTime> {
Ok(time::OffsetDateTime::now_utc())
}
mod util {
pub fn time_to_std_time(
provided_time: &time::OffsetDateTime,
) -> Result<std::time::SystemTime, std::time::SystemTimeError> {
let converted = std::time::SystemTime::from(*provided_time);
Ok(converted)
}
}
#[derive(Debug, utoipa::ToSchema)]
pub struct TokenResource {
pub message: String,
pub issuer: String,
pub audiences: Vec<String>,
pub id: uuid::Uuid,
}
pub const TOKEN_TYPE: &str = "JWT";
pub fn create_token(
key: &String,
token_resource: &TokenResource,
duration: time::Duration,
) -> Result<(String, i64), josekit::JoseError> {
let mut header = josekit::jws::JwsHeader::new();
header.set_token_type(TOKEN_TYPE);
let mut payload = josekit::jwt::JwtPayload::new();
let message = &token_resource.message;
let issuer = &token_resource.issuer;
let audiences: &Vec<String> = &token_resource.audiences;
payload.set_subject(message);
payload.set_issuer(issuer);
payload.set_audience(audiences.clone());
if !token_resource.id.is_nil() {
match payload.set_claim("id", Some(serde_json::json!(token_resource.id))) {
Ok(_) => {}
Err(err) => {
return Err(err);
}
}
}
match get_issued() {
Ok(issued) => {
let expire = issued + duration;
payload.set_issued_at(&util::time_to_std_time(&issued).unwrap());
payload.set_expires_at(&util::time_to_std_time(&expire).unwrap());
let signer = josekit::jws::alg::hmac::HmacJwsAlgorithm::Hs256
.signer_from_bytes(key.as_bytes())
.unwrap();
Ok((
josekit::jwt::encode_with_signer(&payload, &header, &signer).unwrap(),
(expire - time::OffsetDateTime::UNIX_EPOCH).whole_seconds(),
))
}
Err(e) => Err(josekit::JoseError::InvalidClaim(e.into())),
}
}
+124
View File
@@ -0,0 +1,124 @@
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, Deserialize, Serialize, utoipa::ToSchema)]
pub struct User {
pub id: uuid::Uuid,
pub phone_number: String,
pub username: String,
pub password: String,
// Firstname is a pointer
pub firstname: String,
// Lastname is a pointer
pub lastname: String,
#[serde(with = "time::serde::rfc3339::option")]
pub created: Option<time::OffsetDateTime>,
#[serde(with = "time::serde::rfc3339::option")]
pub last_login: Option<time::OffsetDateTime>,
#[serde(skip)]
pub salt_id: uuid::Uuid,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, utoipa::ToSchema)]
pub struct ServiceUser {
pub id: uuid::Uuid,
pub username: String,
pub passphrase: String,
#[serde(with = "time::serde::rfc3339::option")]
pub created: Option<time::OffsetDateTime>,
// When serializing to json, if empty do not populate
#[serde(with = "time::serde::rfc3339::option")]
pub last_login: Option<time::OffsetDateTime>,
#[serde(skip)]
pub salt_id: uuid::Uuid,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, utoipa::ToSchema)]
pub struct Organization {
pub id: uuid::Uuid,
pub name: String,
#[serde(with = "time::serde::rfc3339::option")]
pub created: Option<time::OffsetDateTime>,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, utoipa::ToSchema)]
pub struct UserLoginHistory {
pub id: uuid::Uuid,
#[serde(with = "time::serde::rfc3339::option")]
pub login_time: Option<time::OffsetDateTime>,
pub user_id: uuid::Uuid,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, utoipa::ToSchema)]
pub struct ServiceUserLoginHistory {
pub id: uuid::Uuid,
#[serde(with = "time::serde::rfc3339::option")]
pub login_time: Option<time::OffsetDateTime>,
pub service_user_id: uuid::Uuid,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, utoipa::ToSchema)]
pub struct UserProfile {
pub user_id: uuid::Uuid,
pub phone_number: String,
pub username: String,
pub firstname: String,
pub lastname: String,
#[serde(with = "time::serde::rfc3339::option")]
pub created: Option<time::OffsetDateTime>,
#[serde(with = "time::serde::rfc3339::option")]
pub last_login: Option<time::OffsetDateTime>,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Salt {
// #[serde(skip_serializing_if = "crate::init::is_uuid_nil")]
pub id: uuid::Uuid,
#[serde(skip_serializing_if = "String::is_empty")]
pub salt: String,
}
impl Salt {
pub fn to_json(&self, output_pretty: bool) -> Result<String, serde_json::Error> {
if output_pretty {
serde_json::to_string_pretty(&self)
} else {
serde_json::to_string(&self)
}
}
}
pub fn init_user_profile(usr: &User) -> UserProfile {
UserProfile {
user_id: usr.id,
phone_number: usr.phone_number.clone(),
username: usr.username.clone(),
firstname: usr.firstname.clone(),
lastname: usr.lastname.clone(),
created: usr.created,
last_login: usr.last_login,
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_init_user_profile() {
let usr = super::User {
id: uuid::Uuid::new_v4(),
phone_number: String::from("+12308438462"),
username: String::from("Cowboy99"),
password: String::from("238n7cyr2q89d3xhe2"),
firstname: String::from("BillyBob"),
lastname: String::from("Jones"),
created: Some(time::OffsetDateTime::now_utc()),
last_login: Some(time::OffsetDateTime::now_utc()),
..Default::default()
};
let profile = super::init_user_profile(&usr);
assert_eq!(
usr.phone_number, profile.phone_number,
"Phone numbers are not equal"
);
}
}
-20
View File
@@ -1,20 +0,0 @@
package auxiliary
import (
"fmt"
)
type TwilioConfig struct {
AccountSID string `json:"auth_sid"`
ServiceSID string `json:"service_sid"`
AuthToken string `json:"auth_token"`
Number string `json:"phone_number"`
}
func (config *TwilioConfig) PrintConfig() {
fmt.Println("Twilio config")
fmt.Println("Account SID:", config.AccountSID)
fmt.Println("Service SID:", config.ServiceSID)
fmt.Println("Auth Token:", config.AuthToken)
fmt.Println("Number:", config.Number)
}
-14
View File
@@ -1,14 +0,0 @@
package contact
import (
"github.com/google/uuid"
)
type Contact struct {
Id *uuid.UUID `json:"id,omitempty"`
Firstname *string `json:"first_name,omitempty"`
Lastname *string `json:"last_name,omitempty"`
Nickname *string `json:"nickname,omitempty"`
PhoneNumber string `json:"phone_number"`
UserId *uuid.UUID `json:"user_id,omitempty"`
}
-18
View File
@@ -1,18 +0,0 @@
package event
import (
"time"
"github.com/google/uuid"
)
type MessageEventResponse struct {
Id uuid.UUID `json:"id,omitempty"`
ScheduledMessageEventId uuid.UUID `json:"scheduled_message_event_id,omitempty"`
Response map[string]any `json:"response"`
UserId uuid.UUID `json:"user_id,omitempty"`
ContactId *uuid.UUID `json:"contact_id,omitempty"`
MessageId *uuid.UUID `json:"message_id,omitempty"`
Status string `json:"status"`
Sent time.Time `json:"sent"`
}
-6
View File
@@ -1,6 +0,0 @@
package event
const (
Message_Event_Response_Status_Instant = "INSTANT"
Message_Event_Response_Status_Scheduled = "SCHEDULED"
)
-11
View File
@@ -1,11 +0,0 @@
package message
import (
"github.com/google/uuid"
)
type Message struct {
Id *uuid.UUID `json:"id,omitempty"`
Content string `json:"content"`
UserId *uuid.UUID `json:"user_id,omitempty"`
}
-15
View File
@@ -1,15 +0,0 @@
package scheduling
import (
"time"
"github.com/google/uuid"
)
type ScheduledMessageEvent struct {
Id uuid.UUID `json:"id"`
ContactId uuid.UUID `json:"contact_id"`
MessageId uuid.UUID `json:"message_id"`
ScheduledMessageId uuid.UUID `json:"scheduled_message_id"`
Created time.Time `json:"created"`
}
-15
View File
@@ -1,15 +0,0 @@
package scheduling
import (
"time"
"github.com/google/uuid"
)
type ScheduledMessage struct {
Id uuid.UUID `json:"id"`
Scheduled time.Time `json:"scheduled"`
Created time.Time `json:"created"`
Status string `json:"status"`
UserId uuid.UUID `json:"user_id"`
}
-8
View File
@@ -1,8 +0,0 @@
package scheduling
const (
Ready = "READY"
Pending = "PENDING"
Processing = "PROCESSING"
Done = "DONE"
)
-24
View File
@@ -1,24 +0,0 @@
package token
import (
"github.com/golang-jwt/jwt/v5"
"github.com/google/uuid"
)
type Claims struct {
UserId uuid.UUID `json:"user_id"`
Role string `json:"role"`
jwt.RegisteredClaims
}
type LoginResult struct {
UserId uuid.UUID `json:"user_id"`
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
ExpiresIn int64 `json:"expires_in"`
IssuedAt int64 `json:"issued_at"`
}
// Alias for LoginResult
// Will be deprecated at some point
type Login = LoginResult
-42
View File
@@ -1,42 +0,0 @@
package types
import (
"database/sql/driver"
"encoding/json"
"fmt"
)
// NOTE: Might end up removing this
type JSONB json.RawMessage
// Scan implements sql.Scanner
func (j *JSONB) Scan(value interface{}) error {
if value == nil {
*j = nil
return nil
}
var data []byte
switch v := value.(type) {
case []byte:
// pgx may pass data as []byte in binary format
data = v
case string:
// pgx may pass data as string in text format
data = []byte(v)
default:
return fmt.Errorf("unsupported type: %T", v)
}
*j = JSONB(data)
return nil
}
// Value implements driver.Valuer
func (j JSONB) Value() (driver.Value, error) {
if j == nil {
return nil, nil
} else {
return []byte(j), nil
}
}
-16
View File
@@ -1,16 +0,0 @@
package user
import (
"time"
"github.com/google/uuid"
)
type ServiceUser struct {
Id uuid.UUID `json:"id"`
// TODO: Remove the omitempty tags at a later point
Username string `json:"username,omitempty"`
Passphrase string `json:"passphrase,omitempty"`
Created time.Time `json:"created"`
LastLogin *time.Time `json:"last_login,omitempty"`
}
-18
View File
@@ -1,18 +0,0 @@
package user
import (
"time"
"github.com/google/uuid"
)
type User struct {
Id uuid.UUID `json:"id"`
PhoneNumber string `json:"phone_number"`
Username string `json:"username"`
Password string `json:"password"`
Firstname *string `json:"first_name,omitempty"`
Lastname *string `json:"last_name,omitempty"`
Created time.Time `json:"created"`
LastLogin *time.Time `json:"last_login,omitempty"`
}
-24
View File
@@ -1,24 +0,0 @@
package user
type UserProfile struct {
Usr *User `json:"user"`
}
func InitUserProfile(usr *User) (usrProfile *UserProfile, done bool) {
if usr == nil {
return nil, false
} else {
usrProfile = new(UserProfile)
if len(usr.Password) > 0 {
newUsr := User(Id: usr.Id, PhoneNumber: usr.PhoneNumber, Username: usr.Username, Firstname: usr.Firstname, Lastname: usr.Lastname, Created: usr.Created, LastLogin: usr.LastLogin,)
usrProfile.Usr = &newUsr
return usrProfile, true
} else {
usrProfile.Usr = usr
return usrProfile, true
}
}
}
-18
View File
@@ -1,18 +0,0 @@
package user
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestInitUserProfile(t *testing.T) {
usr := User{Username: "Bob", PhoneNumber: "+12224572351", Password: "TheNight!"}
profile, done := InitUserProfile(&usr)
assert.Equal(t, done, true, "Error")
assert.NotEmpty(t, profile, "UserProfile is empty")
assert.Empty(t, profile.Usr.Password, "Password should be empty")
}