diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md
new file mode 100644
index 000000000..faf7d9089
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug-report.md
@@ -0,0 +1,26 @@
+---
+name: "☢️ Bug"
+about: Create a report to help us improve
+title: "☢️ bug: [Short description of the bug]"
+labels: ["☢️ bug"]
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+
+1. Go to '...'
+2. Click on '...'
+3. Scroll down to '...'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/chore.md b/.github/ISSUE_TEMPLATE/chore.md
new file mode 100644
index 000000000..d498e5cb8
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/chore.md
@@ -0,0 +1,18 @@
+---
+name: "🧹 Chore"
+about: Something you'd like to see done but not urgently
+title: "🧹 chore: [Short description of the chore]"
+labels: ["🧹 chore"]
+---
+
+**Please describe.**
+A clear and concise description of what you'd like to see. Ex. We should [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md
new file mode 100644
index 000000000..c460abd38
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature-request.md
@@ -0,0 +1,18 @@
+---
+name: "📝 Feature Request"
+about: Suggest an idea for this project
+title: "📝 feat: [Short description of the feature]"
+labels: ["📝 feature"]
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml
index 2329a3cac..aacb559fd 100644
--- a/.github/workflows/backend.yml
+++ b/.github/workflows/backend.yml
@@ -8,12 +8,6 @@ on:
- backend/**
- config/**
- .github/workflows/backend.yml
- pull_request:
- types: [opened]
- paths:
- - backend/**
- - config/**
- - .github/workflows/backend.yml
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
diff --git a/.github/workflows/backend_codeql.yml b/.github/workflows/backend_codeql.yml
index 65d6ff4d1..a40539efb 100644
--- a/.github/workflows/backend_codeql.yml
+++ b/.github/workflows/backend_codeql.yml
@@ -5,11 +5,6 @@ on:
paths:
- "backend/**"
- ".github/workflows/backend_codeql.yml"
- pull_request:
- types: [opened]
- paths:
- - "backend/**"
- - ".github/workflows/backend_codeql.yml"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml
index c7021a398..fa584ba5d 100644
--- a/.github/workflows/cli.yml
+++ b/.github/workflows/cli.yml
@@ -8,12 +8,6 @@ on:
- cli/**
- config/**
- .github/workflows/cli.yml
- pull_request:
- types: [opened]
- paths:
- - cli/**
- - config/**
- - .github/workflows/cli.yml
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
diff --git a/.github/workflows/cli_codeql.yml b/.github/workflows/cli_codeql.yml
index a8c9851a8..cb09497e5 100644
--- a/.github/workflows/cli_codeql.yml
+++ b/.github/workflows/cli_codeql.yml
@@ -5,11 +5,6 @@ on:
paths:
- "cli/**"
- ".github/workflows/cli_codeql.yml"
- pull_request:
- types: [opened]
- paths:
- - "cli/**"
- - ".github/workflows/cli_codeql.yml"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
diff --git a/.github/workflows/dashboard.yml b/.github/workflows/dashboard.yml
index 3ffda6e45..2c13b7a0d 100644
--- a/.github/workflows/dashboard.yml
+++ b/.github/workflows/dashboard.yml
@@ -7,11 +7,6 @@ on:
paths:
- frontend/dashboard/**
- .github/workflows/dashboard.yml
- pull_request:
- types: opened
- paths:
- - frontend/dashboard/**
- - .github/workflows/dashboard.yml
jobs:
format:
diff --git a/.github/workflows/dashboard_codeql.yml b/.github/workflows/dashboard_codeql.yml
index 5ecfeaa0b..a5b966dbd 100644
--- a/.github/workflows/dashboard_codeql.yml
+++ b/.github/workflows/dashboard_codeql.yml
@@ -5,11 +5,6 @@ on:
paths:
- "frontend/dashboard/**"
- ".github/workflows/dashboard_codeql.yml"
- pull_request:
- types: [opened]
- paths:
- - "frontend/dashboard/**"
- - ".github/workflows/dashboard_codeql.yml"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
diff --git a/.github/workflows/frontend_lib.yml b/.github/workflows/frontend_lib.yml
index 75b35ba61..029ea34ae 100644
--- a/.github/workflows/frontend_lib.yml
+++ b/.github/workflows/frontend_lib.yml
@@ -7,11 +7,6 @@ on:
paths:
- frontend/lib/**
- .github/workflows/frontend_lib.yml
- pull_request:
- types: opened
- paths:
- - frontend/lib/**
- - .github/workflows/frontend_lib.yml
jobs:
format:
@@ -74,3 +69,33 @@ jobs:
run: |
cd frontend/lib
yarn test
+ release-check:
+ name: Release Check
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout current branch
+ uses: actions/checkout@v3
+
+ - name: Get new version of package.json
+ id: get_new_version
+ run: |
+ echo "new_version=$(jq -r '.version' frontend/lib/package.json)" >> $GITHUB_OUTPUT
+
+ - name: Checkout main
+ uses: actions/checkout@v3
+ with:
+ ref: main
+
+ - name: Get old version of package.json
+ id: get_old_version
+ run: |
+ echo "old_version=$(jq -r '.version' frontend/lib/package.json)" >> $GITHUB_OUTPUT
+
+ - name: Compare versions
+ run: |
+ if [ "${{ steps.get_old_version.outputs.old_version }}" = "${{ steps.get_new_version.outputs.new_version }}" ]; then
+ echo "Old and new versions of package.json are identical, please bump the version number"
+ exit 1
+ else
+ echo "New package version idenitied!"
+ fi
diff --git a/.github/workflows/frontend_lib_codeql.yml b/.github/workflows/frontend_lib_codeql.yml
index 1f2fc2395..b7b3cbdc9 100644
--- a/.github/workflows/frontend_lib_codeql.yml
+++ b/.github/workflows/frontend_lib_codeql.yml
@@ -5,11 +5,6 @@ on:
paths:
- "frontend/lib/**"
- ".github/workflows/frontend_lib_codeql.yml"
- pull_request:
- types: [opened]
- paths:
- - "frontend/lib/**"
- - ".github/workflows/frontend_lib_codeql.yml"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
diff --git a/.github/workflows/frontend_lib_release.yml b/.github/workflows/frontend_lib_release.yml
new file mode 100644
index 000000000..d79243cb9
--- /dev/null
+++ b/.github/workflows/frontend_lib_release.yml
@@ -0,0 +1,25 @@
+name: Frontend Lib Release
+
+on:
+ push:
+ branches:
+ - main
+ paths:
+ - "frontend/lib/**"
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: '20.x'
+ registry-url: 'https://registry.npmjs.org'
+ scope: '@octocat'
+ - run: |
+ cd frontend/lib
+ yarn
+ yarn build
+ NODE_AUTH_TOKEN=${{ secrets.NPM_AUTH_TOKEN }}
+ yarn publish --access public
\ No newline at end of file
diff --git a/.github/workflows/mobile.yml b/.github/workflows/mobile.yml
index e2a0822bd..39304c8e7 100644
--- a/.github/workflows/mobile.yml
+++ b/.github/workflows/mobile.yml
@@ -7,11 +7,6 @@ on:
paths:
- frontend/mobile/**
- .github/workflows/mobile.yml
- pull_request:
- types: opened
- paths:
- - frontend/mobile/**
- - .github/workflows/mobile.yml
jobs:
format:
diff --git a/.github/workflows/mobile_codeql.yml b/.github/workflows/mobile_codeql.yml
index a2c7c043b..eb437fdc7 100644
--- a/.github/workflows/mobile_codeql.yml
+++ b/.github/workflows/mobile_codeql.yml
@@ -5,11 +5,6 @@ on:
paths:
- "frontend/mobile/**"
- ".github/workflows/mobile_codeql.yml"
- pull_request:
- types: [opened]
- paths:
- - "frontend/mobile/**"
- - ".github/workflows/mobile_codeql.yml"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
diff --git a/.github/workflows/mock_data.yml b/.github/workflows/mock_data.yml
deleted file mode 100644
index 0f1732add..000000000
--- a/.github/workflows/mock_data.yml
+++ /dev/null
@@ -1,105 +0,0 @@
-name: Mock Data
-
-permissions: read-all
-
-on:
- push:
- paths:
- - mock_data/**
- - .github/workflows/mock_data.yml
- pull_request:
- types: [opened]
- paths:
- - mock_data/**
- - .github/workflows/mock_data.yml
-
-concurrency:
- group: ${{ github.workflow }}-${{ github.ref }}
- cancel-in-progress: true
-
-env:
- CARGO_TERM_COLOR: always
- MANIFEST_PATH: ./mock_data/Cargo.toml
-
-jobs:
- test:
- name: Test
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v3
- - uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: stable
- override: true
- - uses: actions-rs/cargo@v1
- with:
- command: test
- args: --manifest-path ${{ env.MANIFEST_PATH }}
- fmt:
- name: Format
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v3
- - uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: stable
- override: true
- - run: rustup component add rustfmt
- - uses: actions-rs/cargo@v1
- with:
- command: fmt
- args: --manifest-path ${{ env.MANIFEST_PATH }} --all -- --check
-
- clippy:
- name: Clippy
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v3
- - uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: stable
- override: true
- - run: rustup component add clippy
- - uses: actions-rs/cargo@v1
- with:
- command: clippy
- args: --manifest-path ${{ env.MANIFEST_PATH }} --all-targets --all-features -- -D warnings
-
- check:
- name: Check
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v3
- - uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: stable
- override: true
- - uses: Swatinem/rust-cache@v1
- with:
- key: ${{ runner.os }}-check
- - uses: actions-rs/cargo@v1
- with:
- command: check
- args: --manifest-path ${{ env.MANIFEST_PATH }}
- env:
- RUSTFLAGS: -D warnings
-
- coverage:
- name: Code Coverage
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v3
- - uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: stable
- override: true
- - run: cargo install cargo-tarpaulin
- - uses: actions-rs/cargo@v1
- with:
- command: tarpaulin
- args: --manifest-path ${{ env.MANIFEST_PATH }} --verbose --workspace
diff --git a/.github/workflows/web.yml b/.github/workflows/web.yml
index 90f5a49d0..81b216117 100644
--- a/.github/workflows/web.yml
+++ b/.github/workflows/web.yml
@@ -7,11 +7,6 @@ on:
paths:
- frontend/web/**
- .github/workflows/web.yml
- pull_request:
- types: opened
- paths:
- - frontend/web/**
- - .github/workflows/web.yml
jobs:
format:
diff --git a/.github/workflows/web_codeql.yml b/.github/workflows/web_codeql.yml
index 24e3dc933..54e5f298a 100644
--- a/.github/workflows/web_codeql.yml
+++ b/.github/workflows/web_codeql.yml
@@ -5,11 +5,6 @@ on:
paths:
- "frontend/web/**"
- ".github/workflows/web_codeql.yml"
- pull_request:
- types: [opened]
- paths:
- - "frontend/web/**"
- - ".github/workflows/web_codeql.yml"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
diff --git a/README.md b/README.md
index bbb531416..d8ca72bba 100644
--- a/README.md
+++ b/README.md
@@ -1,75 +1,5 @@
sac
-
-
-
-
## Repo Activity
![Repo Activity](https://repobeats.axiom.co/api/embed/0c57b86b156d377fcc75a6e482bf921acc8c550b.svg "Repobeats Analytics Image")
diff --git a/backend/auth/jwt.go b/backend/auth/jwt.go
index ffb415034..c0c52a7c7 100644
--- a/backend/auth/jwt.go
+++ b/backend/auth/jwt.go
@@ -6,7 +6,8 @@ import (
"github.com/GenerateNU/sac/backend/config"
"github.com/GenerateNU/sac/backend/constants"
- "github.com/GenerateNU/sac/backend/errors"
+
+ "github.com/GenerateNU/sac/backend/utilities"
m "github.com/garrettladley/mattress"
"github.com/gofiber/fiber/v2"
"github.com/golang-jwt/jwt"
@@ -19,15 +20,15 @@ type CustomClaims struct {
// From extracts the CustomClaims from the fiber context
// Returns nil if the claims are not present
-func From(c *fiber.Ctx) (*CustomClaims, *errors.Error) {
+func From(c *fiber.Ctx) (*CustomClaims, error) {
rawClaims := c.Locals("claims")
if rawClaims == nil {
- return nil, &errors.Forbidden
+ return nil, utilities.Forbidden()
}
claims, ok := rawClaims.(*CustomClaims)
if !ok {
- return nil, &errors.FailedToCastToCustomClaims
+ return nil, fmt.Errorf("claims are not of type CustomClaims. got: %T", rawClaims)
}
return claims, nil
@@ -51,12 +52,12 @@ type Claims struct {
}
type JWTClientInterface interface {
- GenerateTokenPair(accessClaims, refreshClaims Claims) (*Token, *errors.Error)
- GenerateToken(claims Claims, tokenType JWTType) ([]byte, *errors.Error)
- RefreshToken(token, refreshToken string, tokenType JWTType, newClaims jwt.MapClaims) ([]byte, *errors.Error)
- ExtractClaims(tokenString string, tokenType JWTType) (jwt.MapClaims, *errors.Error)
- ParseToken(tokenString string, tokenType JWTType) (*jwt.Token, *errors.Error)
- IsTokenValid(tokenString string, tokenType JWTType) (bool, *errors.Error)
+ GenerateTokenPair(accessClaims, refreshClaims Claims) (*Token, error)
+ GenerateToken(claims Claims, tokenType JWTType) ([]byte, error)
+ RefreshToken(token, refreshToken string, tokenType JWTType, newClaims jwt.MapClaims) ([]byte, error)
+ ExtractClaims(tokenString string, tokenType JWTType) (jwt.MapClaims, error)
+ ParseToken(tokenString string, tokenType JWTType) (*jwt.Token, error)
+ IsTokenValid(tokenString string, tokenType JWTType) (bool, error)
}
type JWTClient struct {
@@ -77,7 +78,7 @@ func NewJWTClient(authSettings config.AuthSettings, signingMethod jwt.SigningMet
}
}
-func (j *JWTClient) GenerateTokenPair(accessClaims, refreshClaims Claims) (*Token, *errors.Error) {
+func (j *JWTClient) GenerateTokenPair(accessClaims, refreshClaims Claims) (*Token, error) {
accessToken, err := j.GenerateToken(accessClaims, AccessToken)
if err != nil {
return nil, err
@@ -96,7 +97,7 @@ func (j *JWTClient) GenerateTokenPair(accessClaims, refreshClaims Claims) (*Toke
// GenerateToken generates a token with the claims passed in.
// It returns the token if successful, otherwise it returns an error.
-func (j *JWTClient) GenerateToken(claims Claims, tokenType JWTType) ([]byte, *errors.Error) {
+func (j *JWTClient) GenerateToken(claims Claims, tokenType JWTType) ([]byte, error) {
// create a new map to store the combined claims
combinedClaims := make(jwt.MapClaims)
@@ -126,9 +127,9 @@ func (j *JWTClient) GenerateToken(claims Claims, tokenType JWTType) ([]byte, *er
// create a new token with the combined claims
token := jwt.NewWithClaims(j.SigningMethod, combinedClaims)
- signedToken, signErr := token.SignedString([]byte(secretKey))
- if signErr != nil {
- return nil, &errors.FailedToSignToken
+ signedToken, err := token.SignedString([]byte(secretKey))
+ if err != nil {
+ return nil, fmt.Errorf("failed to sign token: %w", err)
}
return []byte(signedToken), nil
@@ -136,7 +137,7 @@ func (j *JWTClient) GenerateToken(claims Claims, tokenType JWTType) ([]byte, *er
// ParseToken parses the token string and returns the token if successful, otherwise it returns an error.
// It uses the secret key for the token type to parse the token.
-func (j *JWTClient) ParseToken(tokenString string, tokenType JWTType) (*jwt.Token, *errors.Error) {
+func (j *JWTClient) ParseToken(tokenString string, tokenType JWTType) (*jwt.Token, error) {
secretKey, err := j.getSecretKey(tokenType)
if err != nil {
return nil, err
@@ -146,7 +147,7 @@ func (j *JWTClient) ParseToken(tokenString string, tokenType JWTType) (*jwt.Toke
return []byte(secretKey), nil
})
if parseErr != nil {
- return nil, &errors.FailedToParseToken
+ return nil, fmt.Errorf("failed to parse token: %w", parseErr)
}
return token, nil
@@ -154,7 +155,7 @@ func (j *JWTClient) ParseToken(tokenString string, tokenType JWTType) (*jwt.Toke
// ExtractClaims extracts the claims from the token.
// It returns the claims if successful, otherwise it returns an error.
-func (j *JWTClient) ExtractClaims(tokenString string, tokenType JWTType) (jwt.MapClaims, *errors.Error) {
+func (j *JWTClient) ExtractClaims(tokenString string, tokenType JWTType) (jwt.MapClaims, error) {
token, err := j.ParseToken(tokenString, tokenType)
if err != nil {
return nil, err
@@ -162,7 +163,7 @@ func (j *JWTClient) ExtractClaims(tokenString string, tokenType JWTType) (jwt.Ma
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
- return nil, err
+ return nil, fmt.Errorf("failed to extract claims from token. got: %T", token.Claims)
}
return claims, nil
@@ -170,7 +171,7 @@ func (j *JWTClient) ExtractClaims(tokenString string, tokenType JWTType) (jwt.Ma
// IsTokenValid checks if the token is valid.
// It returns true if the token is valid, otherwise it returns false.
-func (j *JWTClient) IsTokenValid(tokenString string, tokenType JWTType) (bool, *errors.Error) {
+func (j *JWTClient) IsTokenValid(tokenString string, tokenType JWTType) (bool, error) {
token, err := j.ParseToken(tokenString, tokenType)
if err != nil {
return false, err
@@ -183,7 +184,7 @@ func (j *JWTClient) IsTokenValid(tokenString string, tokenType JWTType) (bool, *
// It checks if the refresh token is valid and extracts the claims from the access token.
// It then updates the issued at and expires at claims and gives the new claims priority over the old claims.
// It returns the new access token if successful, otherwise it returns an error.
-func (j *JWTClient) RefreshToken(token, refreshToken string, tokenType JWTType, newClaims jwt.MapClaims) ([]byte, *errors.Error) {
+func (j *JWTClient) RefreshToken(token, refreshToken string, tokenType JWTType, newClaims jwt.MapClaims) ([]byte, error) {
ok, err := j.IsTokenValid(refreshToken, RefreshToken)
if err != nil || !ok {
return nil, err
@@ -208,7 +209,7 @@ func (j *JWTClient) RefreshToken(token, refreshToken string, tokenType JWTType,
// getSecretKey returns the secret key for the token type.
// If the token type is not present in the client, it returns an error.
-func (j *JWTClient) getSecretKey(tokenType JWTType) (string, *errors.Error) {
+func (j *JWTClient) getSecretKey(tokenType JWTType) (string, error) {
switch tokenType {
case AccessToken:
return j.AccessKey.Expose(), nil
@@ -216,7 +217,7 @@ func (j *JWTClient) getSecretKey(tokenType JWTType) (string, *errors.Error) {
return j.RefreshKey.Expose(), nil
}
- return "", &errors.InvalidTokenType
+ return "", utilities.BadRequest(fmt.Errorf("invalid token type: %s", tokenType))
}
// getExpiry returns the expiry time for the token type.
@@ -300,7 +301,7 @@ func GenerateRefreshCookie(value string) *fiber.Cookie {
}
}
-func SetResponseTokens(c *fiber.Ctx, tokens *Token) *errors.Error {
+func SetResponseTokens(c *fiber.Ctx, tokens *Token) error {
// Set the tokens in the response
// should also blacklist the old refresh and access tokens
diff --git a/backend/auth/password.go b/backend/auth/password.go
index d2c90ca04..724e63563 100644
--- a/backend/auth/password.go
+++ b/backend/auth/password.go
@@ -1,24 +1,31 @@
package auth
import (
+ "errors"
+ "fmt"
"regexp"
"strings"
"github.com/GenerateNU/sac/backend/constants"
- "github.com/GenerateNU/sac/backend/errors"
)
-func ValidatePassword(password string) *errors.Error {
+func ValidatePassword(password string) error {
+ var errs []string
+
if len(password) < 8 {
- return &errors.InvalidPasswordNotLongEnough
+ errs = append(errs, "must be at least 8 characters long")
}
if !hasDigit(password) {
- return &errors.InvalidPasswordNoDigit
+ errs = append(errs, "must contain at least one digit")
}
if !hasSpecialChar(password) {
- return &errors.InvalidPasswordNoSpecialCharacter
+ errs = append(errs, fmt.Sprintf("must contain at least one special character from: [%v]", string(constants.SPECIAL_CHARACTERS)))
+ }
+
+ if len(errs) > 0 {
+ return errors.New(strings.Join(errs, ", "))
}
return nil
diff --git a/backend/config/calendar.go b/backend/config/calendar.go
new file mode 100644
index 000000000..f131b056c
--- /dev/null
+++ b/backend/config/calendar.go
@@ -0,0 +1,24 @@
+package config
+
+import (
+ "time"
+)
+
+type CalendarSettings struct {
+ MaxTerminationDate time.Time
+}
+
+type intermediateCalendarSettings struct {
+ MaxTerminationDate string `yaml:"maxterminationdate"`
+}
+
+func (int *intermediateCalendarSettings) into() (*CalendarSettings, error) {
+ t, err := time.Parse("01-02-2006", int.MaxTerminationDate)
+ if err != nil {
+ return nil, err
+ }
+
+ return &CalendarSettings{
+ MaxTerminationDate: t,
+ }, nil
+}
diff --git a/backend/config/config.go b/backend/config/config.go
index d8814e787..ff19ecb23 100644
--- a/backend/config/config.go
+++ b/backend/config/config.go
@@ -8,14 +8,15 @@ import (
)
type Settings struct {
- Application ApplicationSettings
- Database DatabaseSettings
- SuperUser SuperUserSettings
- Auth AuthSettings
- AWS AWSSettings
- PineconeSettings PineconeSettings
- OpenAISettings OpenAISettings
- ResendSettings ResendSettings
+ Application ApplicationSettings
+ Database DatabaseSettings
+ SuperUser SuperUserSettings
+ Auth AuthSettings
+ AWS AWSSettings
+ Pinecone PineconeSettings
+ OpenAI OpenAISettings
+ Resend ResendSettings
+ Calendar CalendarSettings
}
type intermediateSettings struct {
@@ -23,6 +24,7 @@ type intermediateSettings struct {
Database intermediateDatabaseSettings `yaml:"database"`
SuperUser intermediateSuperUserSettings `yaml:"superuser"`
Auth intermediateAuthSettings `yaml:"authsecret"`
+ Calendar intermediateCalendarSettings `yaml:"calendar"`
}
func (int *intermediateSettings) into() (*Settings, error) {
@@ -41,11 +43,17 @@ func (int *intermediateSettings) into() (*Settings, error) {
return nil, err
}
+ calendarSettings, err := int.Calendar.into()
+ if err != nil {
+ return nil, err
+ }
+
return &Settings{
Application: int.Application,
Database: *databaseSettings,
SuperUser: *superUserSettings,
Auth: *authSettings,
+ Calendar: *calendarSettings,
}, nil
}
diff --git a/backend/config/local.go b/backend/config/local.go
index 301c4306a..864140f4f 100644
--- a/backend/config/local.go
+++ b/backend/config/local.go
@@ -42,14 +42,14 @@ func readLocal(v *viper.Viper, path string, useDevDotEnv bool) (*Settings, error
return nil, fmt.Errorf("failed to read Pinecone settings: %w", err)
}
- settings.PineconeSettings = *pineconeSettings
+ settings.Pinecone = *pineconeSettings
openAISettings, err := readOpenAISettings()
if err != nil {
return nil, fmt.Errorf("failed to read OpenAI settings: %w", err)
}
- settings.OpenAISettings = *openAISettings
+ settings.OpenAI = *openAISettings
awsSettings, err := readAWSSettings()
if err != nil {
@@ -63,7 +63,7 @@ func readLocal(v *viper.Viper, path string, useDevDotEnv bool) (*Settings, error
return nil, fmt.Errorf("failed to read Resend settings: %w", err)
}
- settings.ResendSettings = *resendSettings
+ settings.Resend = *resendSettings
return settings, nil
}
diff --git a/backend/config/production.go b/backend/config/production.go
index 9e441ce69..43e10f0f4 100644
--- a/backend/config/production.go
+++ b/backend/config/production.go
@@ -14,6 +14,7 @@ import (
type ProductionSettings struct {
Database ProductionDatabaseSettings `yaml:"database"`
Application ProductionApplicationSettings `yaml:"application"`
+ Calendar CalendarSettings `yaml:"calendar"`
}
type ProductionDatabaseSettings struct {
@@ -118,9 +119,10 @@ func readProd(v *viper.Viper) (*Settings, error) {
AccessKey: authAccessKey,
RefreshKey: authRefreshKey,
},
- PineconeSettings: *pineconeSettings,
- OpenAISettings: *openAISettings,
- AWS: *awsSettings,
- ResendSettings: *resendSettings,
+ Pinecone: *pineconeSettings,
+ OpenAI: *openAISettings,
+ AWS: *awsSettings,
+ Resend: *resendSettings,
+ Calendar: prodSettings.Calendar,
}, nil
}
diff --git a/backend/constants/email.go b/backend/constants/email.go
index b3958861c..7b999344a 100644
--- a/backend/constants/email.go
+++ b/backend/constants/email.go
@@ -1,3 +1,7 @@
package constants
-const DOMAIN string = "@generatesac.davidoduneye.com"
+const (
+ DOMAIN string = "@generatesac.davidoduneye.com"
+ ONBOARDING_EMAIL string = "onboarding" + DOMAIN
+ DEFAULT_FROM_EMAIL string = "no-reply" + DOMAIN
+)
diff --git a/backend/constants/pagination.go b/backend/constants/pagination.go
deleted file mode 100644
index 1601b5908..000000000
--- a/backend/constants/pagination.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package constants
-
-import "strconv"
-
-const (
- DEFAULT_LIMIT int = 10
- DEFAULT_PAGE int = 1
-)
-
-var (
- DEFAULT_LIMIT_STRING string = strconv.Itoa(DEFAULT_LIMIT)
- DEFAULT_PAGE_STRING string = strconv.Itoa(DEFAULT_PAGE)
-)
diff --git a/backend/database/db.go b/backend/database/db.go
index 7038ee44f..c2652aefa 100644
--- a/backend/database/db.go
+++ b/backend/database/db.go
@@ -1,7 +1,7 @@
package database
import (
- stdliberrors "errors"
+ "errors"
"github.com/GenerateNU/sac/backend/config"
"github.com/GenerateNU/sac/backend/constants"
@@ -37,6 +37,7 @@ func EstablishConn(dsn string, opts ...OptionalFunc) (*gorm.DB, error) {
rootConfig := gorm.Config{
SkipDefaultTransaction: true,
TranslateError: true,
+ PrepareStmt: true,
}
for _, opt := range opts {
@@ -67,7 +68,7 @@ func CreateSuperUserIfNotExists(settings config.Settings, db *gorm.DB) error {
var superUser models.User
if err := db.Where("role = ?", models.Super).First(&superUser).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
if err := createSuperUser(settings, db); err != nil {
return err
}
@@ -81,6 +82,11 @@ func CreateSuperUserIfNotExists(settings config.Settings, db *gorm.DB) error {
func createSuperUser(settings config.Settings, db *gorm.DB) error {
tx := db.Begin()
+ defer func() {
+ if r := recover(); r != nil {
+ tx.Rollback()
+ }
+ }()
if err := tx.Error; err != nil {
return err
@@ -143,5 +149,5 @@ func createSuperUser(settings config.Settings, db *gorm.DB) error {
return tx.Commit().Error
}
- return nil
+ return tx.Commit().Error
}
diff --git a/backend/database/super.go b/backend/database/super.go
index 938f31b2e..403f79ff6 100644
--- a/backend/database/super.go
+++ b/backend/database/super.go
@@ -1,19 +1,20 @@
package database
import (
+ "fmt"
+
"github.com/GenerateNU/sac/backend/auth"
"github.com/GenerateNU/sac/backend/config"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/google/uuid"
)
var SuperUserUUID uuid.UUID
-func SuperUser(superUserSettings config.SuperUserSettings) (*models.User, *errors.Error) {
+func SuperUser(superUserSettings config.SuperUserSettings) (*models.User, error) {
passwordHash, err := auth.ComputeHash(superUserSettings.Password.Expose())
if err != nil {
- return nil, &errors.FailedToComputePasswordHash
+ return nil, fmt.Errorf("failed to hash super user password: %w", err)
}
return &models.User{
diff --git a/backend/docs/docs.go b/backend/docs/docs.go
index f893581fd..38a673141 100644
--- a/backend/docs/docs.go
+++ b/backend/docs/docs.go
@@ -49,21 +49,15 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"429": {
"description": "Too Many Requests",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -89,7 +83,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.LoginUserResponseBody"
+ "$ref": "#/definitions/auth.LoginResponseBody"
}
}
],
@@ -102,21 +96,15 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -173,27 +161,19 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -221,21 +201,62 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
+ "schema": {}
+ }
+ }
+ }
+ },
+ "/auth/register": {
+ "post": {
+ "description": "Registers a user",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "auth"
+ ],
+ "summary": "Registers a user",
+ "operationId": "register-user",
+ "parameters": [
+ {
+ "description": "User Body",
+ "name": "userBody",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/base.CreateUserRequestBody"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "Created",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "$ref": "#/definitions/models.User"
}
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {}
+ },
+ "404": {
+ "description": "Not Found",
+ "schema": {}
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {}
}
}
}
@@ -274,21 +295,15 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"429": {
"description": "Too Many Requests",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -314,7 +329,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.VerifyEmailRequestBody"
+ "$ref": "#/definitions/base.VerifyEmailRequestBody"
}
}
],
@@ -327,21 +342,15 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"429": {
"description": "Too Many Requests",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -372,7 +381,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.VerifyPasswordResetTokenRequestBody"
+ "$ref": "#/definitions/base.VerifyPasswordResetTokenRequestBody"
}
}
],
@@ -385,21 +394,15 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"429": {
"description": "Too Many Requests",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -479,7 +482,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.CategoryRequestBody"
+ "$ref": "#/definitions/categories.CategoryRequestBody"
}
}
],
@@ -649,7 +652,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.CategoryRequestBody"
+ "$ref": "#/definitions/categories.CategoryRequestBody"
}
}
],
@@ -731,21 +734,15 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -786,21 +783,15 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -842,15 +833,11 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
@@ -874,7 +861,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.CreateClubRequestBody"
+ "$ref": "#/definitions/base.CreateClubRequestBody"
}
}
],
@@ -887,27 +874,19 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -941,21 +920,15 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
@@ -987,27 +960,19 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
@@ -1038,7 +1003,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.UpdateClubRequestBody"
+ "$ref": "#/definitions/base.UpdateClubRequestBody"
}
}
],
@@ -1051,27 +1016,19 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -1108,21 +1065,15 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
@@ -1153,7 +1104,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.PutContactRequestBody"
+ "$ref": "#/definitions/contacts.PutContactRequestBody"
}
}
],
@@ -1166,27 +1117,19 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -1235,21 +1178,15 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -1298,21 +1235,15 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -1361,27 +1292,124 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
+ "schema": {}
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {}
+ }
+ }
+ },
+ "post": {
+ "description": "Creates a new member associated with a club",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "club-member"
+ ],
+ "summary": "Create a new member for a club",
+ "operationId": "create-member-for-club",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "Club ID",
+ "name": "clubID",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "User ID",
+ "name": "userID",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "Created",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "$ref": "#/definitions/models.User"
}
},
+ "400": {
+ "description": "Bad Request",
+ "schema": {}
+ },
+ "401": {
+ "description": "Unauthorized",
+ "schema": {}
+ },
+ "404": {
+ "description": "Not Found",
+ "schema": {}
+ },
"500": {
"description": "Internal Server Error",
+ "schema": {}
+ }
+ }
+ },
+ "delete": {
+ "description": "Deletes a member associated with a club",
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "club-member"
+ ],
+ "summary": "Delete a member from a club",
+ "operationId": "delete-member-from-club",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "Club ID",
+ "name": "clubID",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "User ID",
+ "name": "userID",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "No Content",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "$ref": "#/definitions/models.User"
}
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {}
+ },
+ "401": {
+ "description": "Unauthorized",
+ "schema": {}
+ },
+ "404": {
+ "description": "Not Found",
+ "schema": {}
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {}
}
}
}
@@ -1418,27 +1446,19 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -1482,27 +1502,19 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
@@ -1538,21 +1550,15 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
@@ -1594,27 +1600,19 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -1651,21 +1649,15 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -1706,21 +1698,15 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -1757,21 +1743,15 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
@@ -1802,7 +1782,7 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.CreateClubTagsRequestBody"
+ "$ref": "#/definitions/tags.CreateClubTagsRequestBody"
}
}
],
@@ -1818,27 +1798,19 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -1879,27 +1851,19 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -2097,45 +2061,135 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
+ "schema": {}
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {}
+ }
+ }
+ }
+ },
+ "/events/{eventID}/": {
+ "get": {
+ "description": "Retrieves an event",
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "event"
+ ],
+ "summary": "Retrieve an event",
+ "operationId": "get-event",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "Event ID",
+ "name": "eventID",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "$ref": "#/definitions/models.Event"
}
},
+ "400": {
+ "description": "Bad Request",
+ "schema": {}
+ },
+ "404": {
+ "description": "Not Found",
+ "schema": {}
+ },
"500": {
"description": "Internal Server Error",
+ "schema": {}
+ }
+ }
+ }
+ },
+ "/files/": {
+ "get": {
+ "description": "Retrieves all files",
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "file"
+ ],
+ "summary": "Retrieve all files",
+ "operationId": "get-files",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "Limit",
+ "name": "limit",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "Page",
+ "name": "page",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/models.File"
+ }
}
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {}
+ },
+ "401": {
+ "description": "Unauthorized",
+ "schema": {}
+ },
+ "404": {
+ "description": "Not Found",
+ "schema": {}
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {}
}
}
},
"post": {
- "description": "Creates an event",
+ "description": "Creates a file",
"consumes": [
- "application/json"
+ "multipart/form-data"
],
"produces": [
"application/json"
],
"tags": [
- "event"
+ "file"
],
- "summary": "Create an event",
- "operationId": "create-event",
+ "summary": "Create a file",
+ "operationId": "create-file",
"parameters": [
{
- "description": "Event Body",
- "name": "event",
+ "description": "File",
+ "name": "file",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.CreateEventRequestBody"
+ "$ref": "#/definitions/base.CreateFileRequestBody"
}
}
],
@@ -2143,52 +2197,44 @@ const docTemplate = `{
"201": {
"description": "Created",
"schema": {
- "$ref": "#/definitions/models.Event"
+ "$ref": "#/definitions/models.File"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
},
- "/events/{eventID}/": {
+ "/files/:fileID": {
"get": {
- "description": "Retrieves an event",
+ "description": "Retrieves a file",
"produces": [
"application/json"
],
"tags": [
- "event"
+ "file"
],
- "summary": "Retrieve an event",
- "operationId": "get-event",
+ "summary": "Retrieve a file",
+ "operationId": "get-file",
"parameters": [
{
"type": "string",
- "description": "Event ID",
- "name": "eventID",
+ "description": "File ID",
+ "name": "fileID",
"in": "path",
"required": true
}
@@ -2197,100 +2243,95 @@ const docTemplate = `{
"200": {
"description": "OK",
"schema": {
- "$ref": "#/definitions/models.Event"
+ "$ref": "#/definitions/models.File"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
+ },
+ "401": {
+ "description": "Unauthorized",
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
"delete": {
- "description": "Deletes an event",
+ "description": "Deletes a file",
"produces": [
"application/json"
],
"tags": [
- "event"
+ "file"
],
- "summary": "Delete an event",
- "operationId": "delete-event",
+ "summary": "Delete a file",
+ "operationId": "delete-file",
"parameters": [
{
"type": "string",
- "description": "Event ID",
- "name": "eventID",
+ "description": "File ID",
+ "name": "fileID",
"in": "path",
"required": true
}
],
"responses": {
- "204": {
- "description": "No Content",
+ "201": {
+ "description": "Created",
"schema": {
- "type": "string"
+ "$ref": "#/definitions/models.File"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
},
- "/events/{eventID}/hosts": {
+ "/pocs/": {
"get": {
- "description": "Retrieves all hosts associated with an event",
+ "description": "Retrieves all point of contacts",
"produces": [
"application/json"
],
"tags": [
- "event"
+ "point of contact"
],
- "summary": "Retrieve all hosts by event",
- "operationId": "get-hosts-by-event",
+ "summary": "Retrieve all point of contacts",
+ "operationId": "get-point-of-contacts",
"parameters": [
{
- "type": "string",
- "description": "Event ID",
- "name": "eventID",
- "in": "path",
- "required": true
+ "type": "integer",
+ "description": "Limit",
+ "name": "limit",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "Page",
+ "name": "page",
+ "in": "query"
}
],
"responses": {
@@ -2299,47 +2340,47 @@ const docTemplate = `{
"schema": {
"type": "array",
"items": {
- "$ref": "#/definitions/models.Club"
+ "$ref": "#/definitions/models.PointOfContact"
}
}
},
"400": {
"description": "Bad Request",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "type": "string"
}
},
"404": {
"description": "Not Found",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "type": "string"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "type": "string"
}
}
}
}
},
- "/events/{eventID}/series/": {
+ "/pocs/{pocID}/": {
"get": {
- "description": "Retrieves all series associated with an event",
+ "description": "Retrieves a point of contact by id",
"produces": [
"application/json"
],
"tags": [
- "event"
+ "point of contact"
],
- "summary": "Retrieve all series by event",
- "operationId": "get-series-by-event",
+ "summary": "Retrieves a point of contact",
+ "operationId": "get-point-of-contact",
"parameters": [
{
"type": "string",
- "description": "Event ID",
- "name": "eventID",
+ "description": "Point of Contact ID",
+ "name": "pocID",
"in": "path",
"required": true
}
@@ -2348,86 +2389,83 @@ const docTemplate = `{
"200": {
"description": "OK",
"schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/models.Series"
- }
+ "$ref": "#/definitions/models.PointOfContact"
}
},
"400": {
"description": "Bad Request",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "type": "string"
}
},
"404": {
"description": "Not Found",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "type": "string"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "type": "string"
}
}
}
- },
- "delete": {
- "description": "Deletes all series associated with an event",
+ }
+ },
+ "/tags": {
+ "get": {
+ "description": "Retrieves all tags",
"produces": [
"application/json"
],
"tags": [
- "event"
+ "tag"
],
- "summary": "Delete all series by event",
- "operationId": "delete-series-by-event",
+ "summary": "Retrieve all tags",
+ "operationId": "get-all-tags",
"parameters": [
{
- "type": "string",
- "description": "Event ID",
- "name": "eventID",
- "in": "path",
- "required": true
+ "type": "integer",
+ "description": "Limit",
+ "name": "limit",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "Page",
+ "name": "page",
+ "in": "query"
}
],
"responses": {
- "204": {
- "description": "No Content",
+ "200": {
+ "description": "OK",
"schema": {
- "type": "string"
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/models.Tag"
+ }
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
- },
- "patch": {
- "description": "Creates a series",
+ }
+ },
+ "/tags/": {
+ "post": {
+ "description": "Creates a tag",
"consumes": [
"application/json"
],
@@ -2435,25 +2473,18 @@ const docTemplate = `{
"application/json"
],
"tags": [
- "event"
+ "tag"
],
- "summary": "Create a series",
- "operationId": "create-series",
+ "summary": "Create a tag",
+ "operationId": "create-tag",
"parameters": [
{
- "type": "string",
- "description": "Event ID",
- "name": "eventID",
- "in": "path",
- "required": true
- },
- {
- "description": "Series Body",
- "name": "seriesBody",
+ "description": "Tag Body",
+ "name": "tagBody",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.UpdateEventRequestBody"
+ "$ref": "#/definitions/base.CreateTagRequestBody"
}
}
],
@@ -2461,59 +2492,44 @@ const docTemplate = `{
"201": {
"description": "Created",
"schema": {
- "$ref": "#/definitions/models.Series"
+ "$ref": "#/definitions/models.Tag"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
},
- "/events/{eventID}/series/{seriesID}/": {
+ "/tags/{tagID}/": {
"get": {
- "description": "Retrieves a series by ID",
+ "description": "Retrieves a tag",
"produces": [
"application/json"
],
"tags": [
- "event"
+ "tag"
],
- "summary": "Retrieve a series by ID",
- "operationId": "get-series-by-id",
+ "summary": "Retrieve a tag",
+ "operationId": "get-tag",
"parameters": [
{
"type": "string",
- "description": "Event ID",
- "name": "eventID",
- "in": "path",
- "required": true
- },
- {
- "type": "string",
- "description": "Series ID",
- "name": "seriesID",
+ "description": "Tag ID",
+ "name": "tagID",
"in": "path",
"required": true
}
@@ -2522,51 +2538,38 @@ const docTemplate = `{
"200": {
"description": "OK",
"schema": {
- "$ref": "#/definitions/models.Series"
+ "$ref": "#/definitions/models.Tag"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
"delete": {
- "description": "Deletes a series by ID",
+ "description": "Deletes a tag",
"produces": [
"application/json"
],
"tags": [
- "event"
+ "tag"
],
- "summary": "Delete a series by ID",
- "operationId": "delete-series-by-id",
+ "summary": "Delete a tag",
+ "operationId": "delete-tag",
"parameters": [
{
"type": "string",
- "description": "Event ID",
- "name": "eventID",
- "in": "path",
- "required": true
- },
- {
- "type": "string",
- "description": "Series ID",
- "name": "seriesID",
+ "description": "Tag ID",
+ "name": "tagID",
"in": "path",
"required": true
}
@@ -2580,32 +2583,24 @@ const docTemplate = `{
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
"patch": {
- "description": "Updates a series by event ID",
+ "description": "Updates a tag",
"consumes": [
"application/json"
],
@@ -2613,25 +2608,25 @@ const docTemplate = `{
"application/json"
],
"tags": [
- "event"
+ "tag"
],
- "summary": "Update a series by event ID",
- "operationId": "update-series-by-event-id",
+ "summary": "Update a tag",
+ "operationId": "update-tag",
"parameters": [
{
"type": "string",
- "description": "Event ID",
- "name": "eventID",
+ "description": "Tag ID",
+ "name": "tagID",
"in": "path",
"required": true
},
{
- "description": "Series Body",
- "name": "seriesBody",
+ "description": "Tag",
+ "name": "tag",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.UpdateSeriesRequestBody"
+ "$ref": "#/definitions/base.UpdateTagRequestBody"
}
}
],
@@ -2639,54 +2634,51 @@ const docTemplate = `{
"200": {
"description": "OK",
"schema": {
- "$ref": "#/definitions/models.Series"
+ "$ref": "#/definitions/models.Tag"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
},
- "/events/{eventID}/tags": {
+ "/users/": {
"get": {
- "description": "Retrieves all tags associated with an event",
+ "description": "Retrieves all users",
"produces": [
"application/json"
],
"tags": [
- "event"
+ "user"
],
- "summary": "Retrieve all tags by event",
- "operationId": "get-tags-by-event",
+ "summary": "Retrieve all users",
+ "operationId": "get-users",
"parameters": [
{
- "type": "string",
- "description": "Event ID",
- "name": "eventID",
- "in": "path",
- "required": true
+ "type": "integer",
+ "description": "Limit",
+ "name": "limit",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "Page",
+ "name": "page",
+ "in": "query"
}
],
"responses": {
@@ -2695,383 +2687,340 @@ const docTemplate = `{
"schema": {
"type": "array",
"items": {
- "$ref": "#/definitions/models.Tag"
+ "$ref": "#/definitions/models.User"
}
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "401": {
+ "description": "Unauthorized",
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
},
- "/files/": {
+ "/users/{userID}/": {
"get": {
- "description": "Retrieves all files",
+ "description": "Retrieves a user",
"produces": [
"application/json"
],
"tags": [
- "file"
+ "user"
],
- "summary": "Retrieve all files",
- "operationId": "get-files",
+ "summary": "Retrieve a user",
+ "operationId": "get-user",
"parameters": [
{
- "type": "integer",
- "description": "Limit",
- "name": "limit",
- "in": "query"
- },
- {
- "type": "integer",
- "description": "Page",
- "name": "page",
- "in": "query"
+ "type": "string",
+ "description": "User ID",
+ "name": "userID",
+ "in": "path",
+ "required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/models.File"
- }
+ "$ref": "#/definitions/models.User"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
- "post": {
- "description": "Creates a file",
- "consumes": [
- "multipart/form-data"
- ],
+ "delete": {
+ "description": "Deletes a user",
"produces": [
"application/json"
],
"tags": [
- "file"
+ "user"
],
- "summary": "Create a file",
- "operationId": "create-file",
+ "summary": "Delete a user",
+ "operationId": "delete-user",
"parameters": [
{
- "description": "File",
- "name": "file",
- "in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/models.CreateFileRequestBody"
- }
+ "type": "string",
+ "description": "User ID",
+ "name": "userID",
+ "in": "path",
+ "required": true
}
],
"responses": {
- "201": {
- "description": "Created",
+ "204": {
+ "description": "No Content",
"schema": {
- "$ref": "#/definitions/models.File"
+ "type": "string"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
- }
- },
- "/files/:fileID": {
- "get": {
- "description": "Retrieves a file",
+ },
+ "patch": {
+ "description": "Updates a user",
+ "consumes": [
+ "application/json"
+ ],
"produces": [
"application/json"
],
"tags": [
- "file"
+ "user"
],
- "summary": "Retrieve a file",
- "operationId": "get-file",
+ "summary": "Update a user",
+ "operationId": "update-user",
"parameters": [
{
"type": "string",
- "description": "File ID",
- "name": "fileID",
+ "description": "User ID",
+ "name": "userID",
"in": "path",
"required": true
+ },
+ {
+ "description": "User Body",
+ "name": "userBody",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/base.UpdateUserRequestBody"
+ }
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
- "$ref": "#/definitions/models.File"
+ "$ref": "#/definitions/models.User"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
- },
- "delete": {
- "description": "Deletes a file",
+ }
+ },
+ "/users/{userID}/follower/": {
+ "get": {
+ "description": "Retrieves all clubs a user is following",
"produces": [
"application/json"
],
"tags": [
- "file"
+ "user-follower"
],
- "summary": "Delete a file",
- "operationId": "delete-file",
+ "summary": "Retrieve all clubs a user is following",
+ "operationId": "get-following",
"parameters": [
{
"type": "string",
- "description": "File ID",
- "name": "fileID",
+ "description": "User ID",
+ "name": "userID",
"in": "path",
"required": true
}
],
"responses": {
- "201": {
- "description": "Created",
+ "200": {
+ "description": "OK",
"schema": {
- "$ref": "#/definitions/models.File"
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/models.Club"
+ }
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
},
- "/pocs/": {
- "get": {
- "description": "Retrieves all point of contacts",
+ "/users/{userID}/follower/{clubID}/": {
+ "post": {
+ "description": "Follow a club",
+ "consumes": [
+ "application/json"
+ ],
"produces": [
"application/json"
],
"tags": [
- "point of contact"
+ "user-follower"
],
- "summary": "Retrieve all point of contacts",
- "operationId": "get-point-of-contacts",
+ "summary": "Follow a club",
+ "operationId": "create-following",
"parameters": [
{
- "type": "integer",
- "description": "Limit",
- "name": "limit",
- "in": "query"
+ "type": "string",
+ "description": "User ID",
+ "name": "userID",
+ "in": "path",
+ "required": true
},
{
- "type": "integer",
- "description": "Page",
- "name": "page",
- "in": "query"
+ "type": "string",
+ "description": "Club ID",
+ "name": "clubID",
+ "in": "path",
+ "required": true
}
],
"responses": {
- "200": {
- "description": "OK",
+ "201": {
+ "description": "Created",
"schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/models.PointOfContact"
- }
+ "$ref": "#/definitions/utilities.SuccessResponse"
}
},
- "400": {
- "description": "Bad Request",
- "schema": {
- "type": "string"
- }
+ "401": {
+ "description": "Unauthorized",
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "type": "string"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "type": "string"
- }
+ "schema": {}
}
}
- }
- },
- "/pocs/{pocID}/": {
- "get": {
- "description": "Retrieves a point of contact by id",
+ },
+ "delete": {
+ "description": "Unfollow a club",
+ "consumes": [
+ "application/json"
+ ],
"produces": [
"application/json"
],
"tags": [
- "point of contact"
+ "user-follower"
],
- "summary": "Retrieves a point of contact",
- "operationId": "get-point-of-contact",
+ "summary": "Unfollow a club",
+ "operationId": "delete-following",
"parameters": [
{
"type": "string",
- "description": "Point of Contact ID",
- "name": "pocID",
+ "description": "User ID",
+ "name": "userID",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "Club ID",
+ "name": "clubID",
"in": "path",
"required": true
}
],
"responses": {
- "200": {
- "description": "OK",
+ "204": {
+ "description": "No Content",
"schema": {
- "$ref": "#/definitions/models.PointOfContact"
+ "$ref": "#/definitions/utilities.SuccessResponse"
}
},
- "400": {
- "description": "Bad Request",
- "schema": {
- "type": "string"
- }
+ "401": {
+ "description": "Unauthorized",
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "type": "string"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "type": "string"
- }
+ "schema": {}
}
}
}
},
- "/tags": {
+ "/users/{userID}/member/": {
"get": {
- "description": "Retrieves all tags",
+ "description": "Retrieves all clubs a user is a member of",
"produces": [
"application/json"
],
"tags": [
- "tag"
+ "user-member"
],
- "summary": "Retrieve all tags",
- "operationId": "get-all-tags",
+ "summary": "Retrieve all clubs a user is a member of",
+ "operationId": "get-membership",
"parameters": [
{
- "type": "integer",
- "description": "Limit",
- "name": "limit",
- "in": "query"
- },
- {
- "type": "integer",
- "description": "Page",
- "name": "page",
- "in": "query"
+ "type": "string",
+ "description": "User ID",
+ "name": "userID",
+ "in": "path",
+ "required": true
}
],
"responses": {
@@ -3080,34 +3029,32 @@ const docTemplate = `{
"schema": {
"type": "array",
"items": {
- "$ref": "#/definitions/models.Tag"
+ "$ref": "#/definitions/models.Club"
}
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
+ },
+ "401": {
+ "description": "Unauthorized",
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
},
- "/tags/": {
- "post": {
- "description": "Creates a tag",
+ "/users/{userID}/password": {
+ "patch": {
+ "description": "Updates a user's password",
"consumes": [
"application/json"
],
@@ -3115,71 +3062,70 @@ const docTemplate = `{
"application/json"
],
"tags": [
- "tag"
+ "user"
],
- "summary": "Create a tag",
- "operationId": "create-tag",
+ "summary": "Update a user's password",
+ "operationId": "update-password",
"parameters": [
{
- "description": "Tag Body",
- "name": "tagBody",
+ "type": "string",
+ "description": "User ID",
+ "name": "userID",
+ "in": "path",
+ "required": true
+ },
+ {
+ "description": "Password Body",
+ "name": "passwordBody",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.CreateTagRequestBody"
+ "$ref": "#/definitions/auth.UpdatePasswordRequestBody"
}
}
],
"responses": {
- "201": {
- "description": "Created",
+ "200": {
+ "description": "OK",
"schema": {
- "$ref": "#/definitions/models.Tag"
+ "type": "string"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
},
- "/tags/{tagID}/": {
+ "/users/{userID}/tags/": {
"get": {
- "description": "Retrieves a tag",
+ "description": "Retrieves all tags associated with a user",
"produces": [
"application/json"
],
"tags": [
- "tag"
+ "user-tag"
],
- "summary": "Retrieve a tag",
- "operationId": "get-tag",
+ "summary": "Retrieve all tags for a user",
+ "operationId": "get-tags-by-user",
"parameters": [
{
"type": "string",
- "description": "Tag ID",
- "name": "tagID",
+ "description": "User ID",
+ "name": "userID",
"in": "path",
"required": true
}
@@ -3188,83 +3134,32 @@ const docTemplate = `{
"200": {
"description": "OK",
"schema": {
- "$ref": "#/definitions/models.Tag"
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/models.Tag"
+ }
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
+ },
+ "401": {
+ "description": "Unauthorized",
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
- }
- },
- "delete": {
- "description": "Deletes a tag",
- "produces": [
- "application/json"
- ],
- "tags": [
- "tag"
- ],
- "summary": "Delete a tag",
- "operationId": "delete-tag",
- "parameters": [
- {
- "type": "string",
- "description": "Tag ID",
- "name": "tagID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "204": {
- "description": "No Content",
- "schema": {
- "type": "string"
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
- "patch": {
- "description": "Updates a tag",
+ "post": {
+ "description": "Creates tags for a user",
"consumes": [
"application/json"
],
@@ -3272,119 +3167,58 @@ const docTemplate = `{
"application/json"
],
"tags": [
- "tag"
+ "user-tag"
],
- "summary": "Update a tag",
- "operationId": "update-tag",
+ "summary": "Create user tags",
+ "operationId": "create-user-tags",
"parameters": [
{
"type": "string",
- "description": "Tag ID",
- "name": "tagID",
+ "description": "User ID",
+ "name": "userID",
"in": "path",
"required": true
},
{
- "description": "Tag",
- "name": "tag",
+ "description": "User Tags Body",
+ "name": "userTagsBody",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.UpdateTagRequestBody"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "$ref": "#/definitions/models.Tag"
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
+ "$ref": "#/definitions/tags.CreateUserTagsBody"
}
}
- }
- }
- },
- "/users/": {
- "get": {
- "description": "Retrieves all users",
- "produces": [
- "application/json"
- ],
- "tags": [
- "user"
- ],
- "summary": "Retrieve all users",
- "operationId": "get-users",
- "parameters": [
- {
- "type": "integer",
- "description": "Limit",
- "name": "limit",
- "in": "query"
- },
- {
- "type": "integer",
- "description": "Page",
- "name": "page",
- "in": "query"
- }
],
"responses": {
- "200": {
- "description": "OK",
+ "201": {
+ "description": "Created",
"schema": {
"type": "array",
"items": {
- "$ref": "#/definitions/models.User"
+ "$ref": "#/definitions/models.Tag"
}
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
+ },
+ "404": {
+ "description": "Not Found",
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
- "post": {
- "description": "Creates a user",
+ "delete": {
+ "description": "Creates tags for a user",
"consumes": [
"application/json"
],
@@ -3392,72 +3226,10 @@ const docTemplate = `{
"application/json"
],
"tags": [
- "user"
- ],
- "summary": "Create a user",
- "operationId": "create-user",
- "parameters": [
- {
- "description": "User Body",
- "name": "userBody",
- "in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/models.CreateUserRequestBody"
- }
- }
- ],
- "responses": {
- "201": {
- "description": "Created",
- "schema": {
- "$ref": "#/definitions/models.User"
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "409": {
- "description": "Conflict",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
- }
- }
- },
- "/users/{userID}/": {
- "get": {
- "description": "Retrieves a user",
- "produces": [
- "application/json"
- ],
- "tags": [
- "user"
+ "user-tag"
],
- "summary": "Retrieve a user",
- "operationId": "get-user",
+ "summary": "Create user tags",
+ "operationId": "create-user-tags",
"parameters": [
{
"type": "string",
@@ -3468,1254 +3240,801 @@ const docTemplate = `{
}
],
"responses": {
- "200": {
- "description": "OK",
- "schema": {
- "$ref": "#/definitions/models.User"
- }
+ "201": {
+ "description": "Created"
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
- },
- "delete": {
- "description": "Deletes a user",
- "produces": [
- "application/json"
- ],
- "tags": [
- "user"
- ],
- "summary": "Delete a user",
- "operationId": "delete-user",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "204": {
- "description": "No Content",
- "schema": {
- "type": "string"
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
+ }
+ }
+ },
+ "definitions": {
+ "auth.LoginResponseBody": {
+ "type": "object",
+ "required": [
+ "email",
+ "password"
+ ],
+ "properties": {
+ "email": {
+ "type": "string"
+ },
+ "password": {
+ "description": "MARK: must be validated manually",
+ "type": "string",
+ "maxLength": 255
}
- },
- "patch": {
- "description": "Updates a user",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "user"
- ],
- "summary": "Update a user",
- "operationId": "update-user",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- },
- {
- "description": "User Body",
- "name": "userBody",
- "in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/models.UpdateUserRequestBody"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "$ref": "#/definitions/models.User"
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
+ }
+ },
+ "auth.UpdatePasswordRequestBody": {
+ "type": "object",
+ "required": [
+ "new_password",
+ "old_password"
+ ],
+ "properties": {
+ "new_password": {
+ "description": "MARK: must be validated manually",
+ "type": "string",
+ "maxLength": 255
+ },
+ "old_password": {
+ "description": "MARK: must be validated manually",
+ "type": "string",
+ "maxLength": 255
}
}
},
- "/users/{userID}/follower/": {
- "get": {
- "description": "Retrieves all clubs a user is following",
- "produces": [
- "application/json"
- ],
- "tags": [
- "user-follower"
- ],
- "summary": "Retrieve all clubs a user is following",
- "operationId": "get-following",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/models.Club"
- }
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
+ "base.CreateClubRequestBody": {
+ "type": "object",
+ "required": [
+ "application_link",
+ "description",
+ "is_recruiting",
+ "name",
+ "preview",
+ "recruitment_cycle",
+ "recruitment_type",
+ "user_id"
+ ],
+ "properties": {
+ "application_link": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "is_recruiting": {
+ "type": "boolean"
+ },
+ "logo": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "one_word_to_describe_us": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "preview": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "recruitment_cycle": {
+ "maxLength": 255,
+ "enum": [
+ "fall",
+ "spring",
+ "fallSpring",
+ "always"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.RecruitmentCycle"
}
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
+ ]
+ },
+ "recruitment_type": {
+ "maxLength": 255,
+ "enum": [
+ "unrestricted",
+ "tryout",
+ "application"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.RecruitmentType"
}
- }
+ ]
+ },
+ "user_id": {
+ "type": "string"
+ },
+ "weekly_time_commitment": {
+ "type": "integer",
+ "minimum": 1
}
}
},
- "/users/{userID}/follower/{clubID}/": {
- "post": {
- "description": "Follow a club",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "user-follower"
- ],
- "summary": "Follow a club",
- "operationId": "create-following",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- },
- {
- "type": "string",
- "description": "Club ID",
- "name": "clubID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "201": {
- "description": "Created",
- "schema": {
- "$ref": "#/definitions/utilities.SuccessResponse"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
- }
- },
- "delete": {
- "description": "Unfollow a club",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "user-follower"
- ],
- "summary": "Unfollow a club",
- "operationId": "delete-following",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- },
- {
- "type": "string",
- "description": "Club ID",
- "name": "clubID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "204": {
- "description": "No Content",
- "schema": {
- "$ref": "#/definitions/utilities.SuccessResponse"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
+ "base.CreateFileRequestBody": {
+ "type": "object",
+ "required": [
+ "owner_id",
+ "owner_type"
+ ],
+ "properties": {
+ "owner_id": {
+ "type": "string"
+ },
+ "owner_type": {
+ "type": "string",
+ "maxLength": 255
}
}
},
- "/users/{userID}/member/": {
- "get": {
- "description": "Retrieves all clubs a user is a member of",
- "produces": [
- "application/json"
- ],
- "tags": [
- "user-member"
- ],
- "summary": "Retrieve all clubs a user is a member of",
- "operationId": "get-membership",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/models.Club"
- }
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
+ "base.CreateTagRequestBody": {
+ "type": "object",
+ "required": [
+ "category_id",
+ "name"
+ ],
+ "properties": {
+ "category_id": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255
}
}
},
- "/users/{userID}/member/{clubID}/": {
- "post": {
- "description": "Join a club",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "user-member"
- ],
- "summary": "Join a club",
- "operationId": "create-membership",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- },
- {
- "type": "string",
- "description": "Club ID",
- "name": "clubID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "201": {
- "description": "Created",
- "schema": {
- "$ref": "#/definitions/utilities.SuccessResponse"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
+ "base.CreateUserRequestBody": {
+ "type": "object",
+ "required": [
+ "email",
+ "first_name",
+ "last_name",
+ "password"
+ ],
+ "properties": {
+ "college": {
+ "enum": [
+ "CAMD",
+ "DMSB",
+ "KCCS",
+ "CE",
+ "BCHS",
+ "SL",
+ "CPS",
+ "CS",
+ "CSSH"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.College"
}
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
+ ]
+ },
+ "email": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "first_name": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "graduation_cycle": {
+ "maxLength": 255,
+ "enum": [
+ "december",
+ "may"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.GraduationCycle"
}
- }
- }
- },
- "delete": {
- "description": "Leave a club",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "user-member"
- ],
- "summary": "Leave a club",
- "operationId": "delete-membership",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- },
- {
- "type": "string",
- "description": "Club ID",
- "name": "clubID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "204": {
- "description": "No Content",
- "schema": {
- "$ref": "#/definitions/utilities.SuccessResponse"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
+ ]
+ },
+ "graduation_year": {
+ "type": "integer"
+ },
+ "last_name": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "major0": {
+ "description": "Optional fields",
+ "maxLength": 255,
+ "enum": [
+ "africanaStudies",
+ "americanSignLanguage",
+ "americanSignLanguage-EnglishInterpreting",
+ "appliedPhysics",
+ "architecturalStudies",
+ "architecture",
+ "art:ArtVisualStudies",
+ "behavioralNeuroscience",
+ "biochemistry",
+ "bioengineering",
+ "biology",
+ "biomedicalPhysics",
+ "businessAdministration",
+ "businessAdministration:Accounting",
+ "businessAdministration:AccountingAndAdvisoryServices",
+ "businessAdministration:BrandManagement",
+ "businessAdministration:BusinessAnalytics",
+ "businessAdministration:CorporateInnovation",
+ "businessAdministration:EntrepreneurialStartups",
+ "businessAdministration:FamilyBusiness",
+ "businessAdministration:Finance",
+ "businessAdministration:Fintech",
+ "businessAdministration:HealthcareManagementAndConsulting",
+ "businessAdministration:Management",
+ "businessAdministration:ManagementInformationSystems",
+ "businessAdministration:Marketing",
+ "businessAdministration:MarketingAnalytics",
+ "businessAdministration:SocialInnovationAndEntrepreneurship",
+ "businessAdministration:SupplyChainManagement",
+ "cellAndMolecularBiology",
+ "chemicalEngineering",
+ "chemistry",
+ "civilEngineering",
+ "communicationStudies",
+ "computerEngineering",
+ "computerScience",
+ "computingAndLaw",
+ "criminologyAndCriminalJustice",
+ "culturalAnthropology",
+ "cybersecurity",
+ "dataScience",
+ "design",
+ "economics",
+ "electricalEngineering",
+ "english",
+ "environmentalAndSustainabilityStudies",
+ "environmentalEngineering",
+ "environmentalScience",
+ "environmentalStudies",
+ "gameArtAndAnimation",
+ "gameDesign",
+ "globalAsianStudies",
+ "healthScience",
+ "history",
+ "historyCultureAndLaw",
+ "humanServices",
+ "industrialEngineering",
+ "internationalAffairs",
+ "internationalBusiness",
+ "internationalBusiness:Accounting",
+ "internationalBusiness:AccountingAndAdvisoryServices",
+ "internationalBusiness:BrandManagement",
+ "internationalBusiness:BusinessAnalytics",
+ "internationalBusiness:CorporateInnovation",
+ "internationalBusiness:EntrepreneurialStartups",
+ "internationalBusiness:FamilyBusiness",
+ "internationalBusiness:Finance",
+ "internationalBusiness:Fintech",
+ "internationalBusiness:HealthcareManagementAndConsulting",
+ "internationalBusiness:Management",
+ "internationalBusiness:ManagementInformationSystems",
+ "internationalBusiness:Marketing",
+ "internationalBusiness:MarketingAnalytics",
+ "internationalBusiness:SocialInnovationAndEntrepreneurship",
+ "internationalBusiness:SupplyChainManagement",
+ "journalism",
+ "landscapeArchitecture",
+ "linguistics",
+ "marineBiology",
+ "mathematics",
+ "mechanicalEngineering",
+ "mediaAndScreenStudies",
+ "mediaArts",
+ "music",
+ "musicTechnology",
+ "nursing",
+ "pharmaceuticalSciences",
+ "pharmacy(PharmD)",
+ "philosophy",
+ "physics",
+ "politicalScience",
+ "politicsPhilosophyEconomics",
+ "psychology",
+ "publicHealth",
+ "publicRelations",
+ "religiousStudies",
+ "sociology",
+ "spanish",
+ "speechLanguagePathologyAndAudiology",
+ "theatre"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.Major"
}
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
+ ]
+ },
+ "major1": {
+ "maxLength": 255,
+ "enum": [
+ "africanaStudies",
+ "americanSignLanguage",
+ "americanSignLanguage-EnglishInterpreting",
+ "appliedPhysics",
+ "architecturalStudies",
+ "architecture",
+ "art:ArtVisualStudies",
+ "behavioralNeuroscience",
+ "biochemistry",
+ "bioengineering",
+ "biology",
+ "biomedicalPhysics",
+ "businessAdministration",
+ "businessAdministration:Accounting",
+ "businessAdministration:AccountingAndAdvisoryServices",
+ "businessAdministration:BrandManagement",
+ "businessAdministration:BusinessAnalytics",
+ "businessAdministration:CorporateInnovation",
+ "businessAdministration:EntrepreneurialStartups",
+ "businessAdministration:FamilyBusiness",
+ "businessAdministration:Finance",
+ "businessAdministration:Fintech",
+ "businessAdministration:HealthcareManagementAndConsulting",
+ "businessAdministration:Management",
+ "businessAdministration:ManagementInformationSystems",
+ "businessAdministration:Marketing",
+ "businessAdministration:MarketingAnalytics",
+ "businessAdministration:SocialInnovationAndEntrepreneurship",
+ "businessAdministration:SupplyChainManagement",
+ "cellAndMolecularBiology",
+ "chemicalEngineering",
+ "chemistry",
+ "civilEngineering",
+ "communicationStudies",
+ "computerEngineering",
+ "computerScience",
+ "computingAndLaw",
+ "criminologyAndCriminalJustice",
+ "culturalAnthropology",
+ "cybersecurity",
+ "dataScience",
+ "design",
+ "economics",
+ "electricalEngineering",
+ "english",
+ "environmentalAndSustainabilityStudies",
+ "environmentalEngineering",
+ "environmentalScience",
+ "environmentalStudies",
+ "gameArtAndAnimation",
+ "gameDesign",
+ "globalAsianStudies",
+ "healthScience",
+ "history",
+ "historyCultureAndLaw",
+ "humanServices",
+ "industrialEngineering",
+ "internationalAffairs",
+ "internationalBusiness",
+ "internationalBusiness:Accounting",
+ "internationalBusiness:AccountingAndAdvisoryServices",
+ "internationalBusiness:BrandManagement",
+ "internationalBusiness:BusinessAnalytics",
+ "internationalBusiness:CorporateInnovation",
+ "internationalBusiness:EntrepreneurialStartups",
+ "internationalBusiness:FamilyBusiness",
+ "internationalBusiness:Finance",
+ "internationalBusiness:Fintech",
+ "internationalBusiness:HealthcareManagementAndConsulting",
+ "internationalBusiness:Management",
+ "internationalBusiness:ManagementInformationSystems",
+ "internationalBusiness:Marketing",
+ "internationalBusiness:MarketingAnalytics",
+ "internationalBusiness:SocialInnovationAndEntrepreneurship",
+ "internationalBusiness:SupplyChainManagement",
+ "journalism",
+ "landscapeArchitecture",
+ "linguistics",
+ "marineBiology",
+ "mathematics",
+ "mechanicalEngineering",
+ "mediaAndScreenStudies",
+ "mediaArts",
+ "music",
+ "musicTechnology",
+ "nursing",
+ "pharmaceuticalSciences",
+ "pharmacy(PharmD)",
+ "philosophy",
+ "physics",
+ "politicalScience",
+ "politicsPhilosophyEconomics",
+ "psychology",
+ "publicHealth",
+ "publicRelations",
+ "religiousStudies",
+ "sociology",
+ "spanish",
+ "speechLanguagePathologyAndAudiology",
+ "theatre"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.Major"
}
- }
- }
- }
- },
- "/users/{userID}/password": {
- "patch": {
- "description": "Updates a user's password",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "user"
- ],
- "summary": "Update a user's password",
- "operationId": "update-password",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- },
- {
- "description": "Password Body",
- "name": "passwordBody",
- "in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/models.UpdatePasswordRequestBody"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "type": "string"
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
+ ]
+ },
+ "major2": {
+ "maxLength": 255,
+ "enum": [
+ "africanaStudies",
+ "americanSignLanguage",
+ "americanSignLanguage-EnglishInterpreting",
+ "appliedPhysics",
+ "architecturalStudies",
+ "architecture",
+ "art:ArtVisualStudies",
+ "behavioralNeuroscience",
+ "biochemistry",
+ "bioengineering",
+ "biology",
+ "biomedicalPhysics",
+ "businessAdministration",
+ "businessAdministration:Accounting",
+ "businessAdministration:AccountingAndAdvisoryServices",
+ "businessAdministration:BrandManagement",
+ "businessAdministration:BusinessAnalytics",
+ "businessAdministration:CorporateInnovation",
+ "businessAdministration:EntrepreneurialStartups",
+ "businessAdministration:FamilyBusiness",
+ "businessAdministration:Finance",
+ "businessAdministration:Fintech",
+ "businessAdministration:HealthcareManagementAndConsulting",
+ "businessAdministration:Management",
+ "businessAdministration:ManagementInformationSystems",
+ "businessAdministration:Marketing",
+ "businessAdministration:MarketingAnalytics",
+ "businessAdministration:SocialInnovationAndEntrepreneurship",
+ "businessAdministration:SupplyChainManagement",
+ "cellAndMolecularBiology",
+ "chemicalEngineering",
+ "chemistry",
+ "civilEngineering",
+ "communicationStudies",
+ "computerEngineering",
+ "computerScience",
+ "computingAndLaw",
+ "criminologyAndCriminalJustice",
+ "culturalAnthropology",
+ "cybersecurity",
+ "dataScience",
+ "design",
+ "economics",
+ "electricalEngineering",
+ "english",
+ "environmentalAndSustainabilityStudies",
+ "environmentalEngineering",
+ "environmentalScience",
+ "environmentalStudies",
+ "gameArtAndAnimation",
+ "gameDesign",
+ "globalAsianStudies",
+ "healthScience",
+ "history",
+ "historyCultureAndLaw",
+ "humanServices",
+ "industrialEngineering",
+ "internationalAffairs",
+ "internationalBusiness",
+ "internationalBusiness:Accounting",
+ "internationalBusiness:AccountingAndAdvisoryServices",
+ "internationalBusiness:BrandManagement",
+ "internationalBusiness:BusinessAnalytics",
+ "internationalBusiness:CorporateInnovation",
+ "internationalBusiness:EntrepreneurialStartups",
+ "internationalBusiness:FamilyBusiness",
+ "internationalBusiness:Finance",
+ "internationalBusiness:Fintech",
+ "internationalBusiness:HealthcareManagementAndConsulting",
+ "internationalBusiness:Management",
+ "internationalBusiness:ManagementInformationSystems",
+ "internationalBusiness:Marketing",
+ "internationalBusiness:MarketingAnalytics",
+ "internationalBusiness:SocialInnovationAndEntrepreneurship",
+ "internationalBusiness:SupplyChainManagement",
+ "journalism",
+ "landscapeArchitecture",
+ "linguistics",
+ "marineBiology",
+ "mathematics",
+ "mechanicalEngineering",
+ "mediaAndScreenStudies",
+ "mediaArts",
+ "music",
+ "musicTechnology",
+ "nursing",
+ "pharmaceuticalSciences",
+ "pharmacy(PharmD)",
+ "philosophy",
+ "physics",
+ "politicalScience",
+ "politicsPhilosophyEconomics",
+ "psychology",
+ "publicHealth",
+ "publicRelations",
+ "religiousStudies",
+ "sociology",
+ "spanish",
+ "speechLanguagePathologyAndAudiology",
+ "theatre"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.Major"
}
- }
+ ]
+ },
+ "password": {
+ "description": "MARK: must be validated manually",
+ "type": "string",
+ "maxLength": 255
}
}
},
- "/users/{userID}/tags/": {
- "get": {
- "description": "Retrieves all tags associated with a user",
- "produces": [
- "application/json"
- ],
- "tags": [
- "user-tag"
- ],
- "summary": "Retrieve all tags for a user",
- "operationId": "get-tags-by-user",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/models.Tag"
- }
+ "base.UpdateClubRequestBody": {
+ "type": "object",
+ "required": [
+ "application_link",
+ "recruitment_cycle",
+ "recruitment_type"
+ ],
+ "properties": {
+ "application_link": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "is_recruiting": {
+ "type": "boolean"
+ },
+ "logo": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "one_word_to_describe_us": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "preview": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "recruitment_cycle": {
+ "maxLength": 255,
+ "enum": [
+ "fall",
+ "spring",
+ "fallSpring",
+ "always"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.RecruitmentCycle"
}
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
+ ]
+ },
+ "recruitment_type": {
+ "maxLength": 255,
+ "enum": [
+ "unrestricted",
+ "tryout",
+ "application"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.RecruitmentType"
}
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
- }
- },
- "post": {
- "description": "Creates tags for a user",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "user-tag"
- ],
- "summary": "Create user tags",
- "operationId": "create-user-tags",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- },
- {
- "description": "User Tags Body",
- "name": "userTagsBody",
- "in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/tag.CreateUserTagsBody"
- }
- }
- ],
- "responses": {
- "201": {
- "description": "Created",
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/models.Tag"
- }
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
- }
- },
- "delete": {
- "description": "Creates tags for a user",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "user-tag"
- ],
- "summary": "Create user tags",
- "operationId": "create-user-tags",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "201": {
- "description": "Created"
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
- }
- }
- }
- },
- "definitions": {
- "errors.Error": {
- "type": "object",
- "properties": {
- "message": {
- "type": "string"
+ ]
},
- "statusCode": {
- "type": "integer"
+ "weekly_time_commitment": {
+ "type": "integer",
+ "minimum": 1
}
}
},
- "models.Category": {
+ "base.UpdateTagRequestBody": {
"type": "object",
- "required": [
- "name"
- ],
"properties": {
- "created_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- },
- "id": {
- "type": "string",
- "example": "123e4567-e89b-12d3-a456-426614174000"
- },
- "name": {
- "type": "string",
- "maxLength": 255
+ "category_id": {
+ "type": "string"
},
- "updated_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- }
- }
- },
- "models.CategoryRequestBody": {
- "type": "object",
- "required": [
- "name"
- ],
- "properties": {
"name": {
"type": "string",
"maxLength": 255
}
}
},
- "models.Club": {
+ "base.UpdateUserRequestBody": {
"type": "object",
- "required": [
- "application_link",
- "description",
- "is_recruiting",
- "name",
- "num_members",
- "preview",
- "recruitment_cycle",
- "recruitment_type"
- ],
"properties": {
- "application_link": {
- "type": "string",
- "maxLength": 255
- },
- "created_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- },
- "description": {
- "type": "string",
- "maxLength": 255
- },
- "id": {
- "type": "string",
- "example": "123e4567-e89b-12d3-a456-426614174000"
- },
- "is_recruiting": {
- "type": "boolean"
- },
- "logo": {
- "type": "string",
- "maxLength": 255
- },
- "name": {
- "type": "string",
- "maxLength": 255
- },
- "num_members": {
- "type": "integer",
- "minimum": 1
- },
- "one_word_to_describe_us": {
- "type": "string",
- "maxLength": 255
- },
- "preview": {
- "type": "string",
- "maxLength": 255
- },
- "recruitment_cycle": {
- "maxLength": 255,
+ "college": {
"enum": [
- "fall",
- "spring",
- "fallSpring",
- "always"
+ "CAMD",
+ "DMSB",
+ "KCCS",
+ "CE",
+ "BCHS",
+ "SL",
+ "CPS",
+ "CS",
+ "CSSH"
],
"allOf": [
{
- "$ref": "#/definitions/models.RecruitmentCycle"
+ "$ref": "#/definitions/models.College"
}
]
},
- "recruitment_type": {
+ "first_name": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "graduation_cycle": {
"maxLength": 255,
"enum": [
- "unrestricted",
- "tryout",
- "application"
+ "december",
+ "may"
],
"allOf": [
{
- "$ref": "#/definitions/models.RecruitmentType"
+ "$ref": "#/definitions/models.GraduationCycle"
}
]
},
- "updated_at": {
+ "graduation_year": {
+ "type": "integer"
+ },
+ "last_name": {
"type": "string",
- "example": "2023-09-20T16:34:50Z"
+ "maxLength": 255
},
- "weekly_time_commitment": {
- "type": "integer",
- "minimum": 1
- }
- }
- },
- "models.College": {
- "type": "string",
- "enum": [
- "CAMD",
- "DMSB",
- "KCCS",
- "CE",
- "BCHS",
- "SL",
- "CPS",
- "CS",
- "CSSH"
- ],
- "x-enum-comments": {
- "BCHS": "Bouvé College of Health Sciences",
- "CAMD": "College of Arts, Media and Design",
- "CE": "College of Engineering",
- "CPS": "College of Professional Studies",
- "CS": "College of Science",
- "CSSH": "College of Social Sciences and Humanities",
- "DMSB": "D'Amore-McKim School of Business",
- "KCCS": "Khoury College of Computer Sciences",
- "SL": "School of Law"
- },
- "x-enum-varnames": [
- "CAMD",
- "DMSB",
- "KCCS",
- "CE",
- "BCHS",
- "SL",
- "CPS",
- "CS",
- "CSSH"
- ]
- },
- "models.Contact": {
- "type": "object",
- "required": [
- "content",
- "type"
- ],
- "properties": {
- "content": {
- "type": "string",
- "maxLength": 255
- },
- "created_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- },
- "id": {
- "type": "string",
- "example": "123e4567-e89b-12d3-a456-426614174000"
- },
- "type": {
+ "major0": {
"maxLength": 255,
"enum": [
- "facebook",
- "instagram",
- "x",
- "linkedin",
- "youtube",
- "github",
- "slack",
- "discord",
- "email",
- "customSite"
+ "africanaStudies",
+ "americanSignLanguage",
+ "americanSignLanguage-EnglishInterpreting",
+ "appliedPhysics",
+ "architecturalStudies",
+ "architecture",
+ "art:ArtVisualStudies",
+ "behavioralNeuroscience",
+ "biochemistry",
+ "bioengineering",
+ "biology",
+ "biomedicalPhysics",
+ "businessAdministration",
+ "businessAdministration:Accounting",
+ "businessAdministration:AccountingAndAdvisoryServices",
+ "businessAdministration:BrandManagement",
+ "businessAdministration:BusinessAnalytics",
+ "businessAdministration:CorporateInnovation",
+ "businessAdministration:EntrepreneurialStartups",
+ "businessAdministration:FamilyBusiness",
+ "businessAdministration:Finance",
+ "businessAdministration:Fintech",
+ "businessAdministration:HealthcareManagementAndConsulting",
+ "businessAdministration:Management",
+ "businessAdministration:ManagementInformationSystems",
+ "businessAdministration:Marketing",
+ "businessAdministration:MarketingAnalytics",
+ "businessAdministration:SocialInnovationAndEntrepreneurship",
+ "businessAdministration:SupplyChainManagement",
+ "cellAndMolecularBiology",
+ "chemicalEngineering",
+ "chemistry",
+ "civilEngineering",
+ "communicationStudies",
+ "computerEngineering",
+ "computerScience",
+ "computingAndLaw",
+ "criminologyAndCriminalJustice",
+ "culturalAnthropology",
+ "cybersecurity",
+ "dataScience",
+ "design",
+ "economics",
+ "electricalEngineering",
+ "english",
+ "environmentalAndSustainabilityStudies",
+ "environmentalEngineering",
+ "environmentalScience",
+ "environmentalStudies",
+ "gameArtAndAnimation",
+ "gameDesign",
+ "globalAsianStudies",
+ "healthScience",
+ "history",
+ "historyCultureAndLaw",
+ "humanServices",
+ "industrialEngineering",
+ "internationalAffairs",
+ "internationalBusiness",
+ "internationalBusiness:Accounting",
+ "internationalBusiness:AccountingAndAdvisoryServices",
+ "internationalBusiness:BrandManagement",
+ "internationalBusiness:BusinessAnalytics",
+ "internationalBusiness:CorporateInnovation",
+ "internationalBusiness:EntrepreneurialStartups",
+ "internationalBusiness:FamilyBusiness",
+ "internationalBusiness:Finance",
+ "internationalBusiness:Fintech",
+ "internationalBusiness:HealthcareManagementAndConsulting",
+ "internationalBusiness:Management",
+ "internationalBusiness:ManagementInformationSystems",
+ "internationalBusiness:Marketing",
+ "internationalBusiness:MarketingAnalytics",
+ "internationalBusiness:SocialInnovationAndEntrepreneurship",
+ "internationalBusiness:SupplyChainManagement",
+ "journalism",
+ "landscapeArchitecture",
+ "linguistics",
+ "marineBiology",
+ "mathematics",
+ "mechanicalEngineering",
+ "mediaAndScreenStudies",
+ "mediaArts",
+ "music",
+ "musicTechnology",
+ "nursing",
+ "pharmaceuticalSciences",
+ "pharmacy(PharmD)",
+ "philosophy",
+ "physics",
+ "politicalScience",
+ "politicsPhilosophyEconomics",
+ "psychology",
+ "publicHealth",
+ "publicRelations",
+ "religiousStudies",
+ "sociology",
+ "spanish",
+ "speechLanguagePathologyAndAudiology",
+ "theatre"
],
"allOf": [
{
- "$ref": "#/definitions/models.ContactType"
+ "$ref": "#/definitions/models.Major"
}
]
},
- "updated_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- }
- }
- },
- "models.ContactType": {
- "type": "string",
- "enum": [
- "facebook",
- "instagram",
- "x",
- "linkedin",
- "youtube",
- "github",
- "slack",
- "discord",
- "email",
- "customSite"
- ],
- "x-enum-varnames": [
- "Facebook",
- "Instagram",
- "X",
- "LinkedIn",
- "YouTube",
- "GitHub",
- "Slack",
- "Discord",
- "Email",
- "CustomSite"
- ]
- },
- "models.CreateClubRequestBody": {
- "type": "object",
- "required": [
- "application_link",
- "description",
- "is_recruiting",
- "name",
- "preview",
- "recruitment_cycle",
- "recruitment_type",
- "user_id"
- ],
- "properties": {
- "application_link": {
- "type": "string",
- "maxLength": 255
- },
- "description": {
- "type": "string",
- "maxLength": 255
- },
- "is_recruiting": {
- "type": "boolean"
- },
- "logo": {
- "type": "string",
- "maxLength": 255
- },
- "name": {
- "type": "string",
- "maxLength": 255
- },
- "one_word_to_describe_us": {
- "type": "string",
- "maxLength": 255
- },
- "preview": {
- "type": "string",
- "maxLength": 255
- },
- "recruitment_cycle": {
- "maxLength": 255,
- "enum": [
- "fall",
- "spring",
- "fallSpring",
- "always"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.RecruitmentCycle"
- }
- ]
- },
- "recruitment_type": {
- "maxLength": 255,
- "enum": [
- "unrestricted",
- "tryout",
- "application"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.RecruitmentType"
- }
- ]
- },
- "user_id": {
- "type": "string"
- },
- "weekly_time_commitment": {
- "type": "integer",
- "minimum": 1
- }
- }
- },
- "models.CreateClubTagsRequestBody": {
- "type": "object",
- "required": [
- "tags"
- ],
- "properties": {
- "tags": {
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- }
- },
- "models.CreateEventRequestBody": {
- "type": "object",
- "required": [
- "content",
- "end_time",
- "event_type",
- "host",
- "is_recurring",
- "location",
- "name",
- "preview",
- "start_time"
- ],
- "properties": {
- "content": {
- "type": "string",
- "maxLength": 255
- },
- "end_time": {
- "type": "string"
- },
- "event_type": {
- "maxLength": 255,
- "enum": [
- "open",
- "membersOnly"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.EventType"
- }
- ]
- },
- "host": {
- "description": "TODO club/tag/notification logic",
- "type": "string"
- },
- "is_recurring": {
- "type": "boolean"
- },
- "location": {
- "type": "string",
- "maxLength": 255
- },
- "name": {
- "type": "string",
- "maxLength": 255
- },
- "preview": {
- "type": "string",
- "maxLength": 255
- },
- "series": {
- "description": "TODO validate if isRecurring, then series is required",
- "allOf": [
- {
- "$ref": "#/definitions/models.CreateSeriesRequestBody"
- }
- ]
- },
- "start_time": {
- "type": "string"
- }
- }
- },
- "models.CreateFileRequestBody": {
- "type": "object",
- "required": [
- "owner_id",
- "owner_type"
- ],
- "properties": {
- "owner_id": {
- "type": "string"
- },
- "owner_type": {
- "type": "string",
- "maxLength": 255
- }
- }
- },
- "models.CreateSeriesRequestBody": {
- "type": "object",
- "required": [
- "max_occurrences",
- "recurring_type"
- ],
- "properties": {
- "max_occurrences": {
- "type": "integer",
- "minimum": 2
- },
- "recurring_type": {
- "maxLength": 255,
- "enum": [
- "daily",
- "weekly",
- "monthly"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.RecurringType"
- }
- ]
- }
- }
- },
- "models.CreateTagRequestBody": {
- "type": "object",
- "required": [
- "category_id",
- "name"
- ],
- "properties": {
- "category_id": {
- "type": "string"
- },
- "name": {
- "type": "string",
- "maxLength": 255
- }
- }
- },
- "models.CreateUserRequestBody": {
- "type": "object",
- "required": [
- "email",
- "first_name",
- "last_name",
- "password"
- ],
- "properties": {
- "college": {
- "enum": [
- "CAMD",
- "DMSB",
- "KCCS",
- "CE",
- "BCHS",
- "SL",
- "CPS",
- "CS",
- "CSSH"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.College"
- }
- ]
- },
- "email": {
- "type": "string",
- "maxLength": 255
- },
- "first_name": {
- "type": "string",
- "maxLength": 255
- },
- "graduation_cycle": {
- "maxLength": 255,
- "enum": [
- "december",
- "may"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.GraduationCycle"
- }
- ]
- },
- "graduation_year": {
- "type": "integer"
- },
- "last_name": {
- "type": "string",
- "maxLength": 255
- },
- "major0": {
- "description": "Optional fields",
+ "major1": {
"maxLength": 255,
"enum": [
"africanaStudies",
@@ -4825,7 +4144,7 @@ const docTemplate = `{
}
]
},
- "major1": {
+ "major2": {
"maxLength": 255,
"enum": [
"africanaStudies",
@@ -4934,241 +4253,212 @@ const docTemplate = `{
"$ref": "#/definitions/models.Major"
}
]
+ }
+ }
+ },
+ "base.VerifyEmailRequestBody": {
+ "type": "object",
+ "required": [
+ "email",
+ "token"
+ ],
+ "properties": {
+ "email": {
+ "type": "string"
},
- "major2": {
+ "token": {
+ "type": "string"
+ }
+ }
+ },
+ "base.VerifyPasswordResetTokenRequestBody": {
+ "type": "object",
+ "required": [
+ "new_password",
+ "token",
+ "verify_new_password"
+ ],
+ "properties": {
+ "new_password": {
+ "type": "string",
+ "minLength": 8
+ },
+ "token": {
+ "type": "string"
+ },
+ "verify_new_password": {
+ "type": "string",
+ "minLength": 8
+ }
+ }
+ },
+ "categories.CategoryRequestBody": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "maxLength": 255
+ }
+ }
+ },
+ "contacts.PutContactRequestBody": {
+ "type": "object",
+ "required": [
+ "content",
+ "type"
+ ],
+ "properties": {
+ "content": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "type": {
"maxLength": 255,
"enum": [
- "africanaStudies",
- "americanSignLanguage",
- "americanSignLanguage-EnglishInterpreting",
- "appliedPhysics",
- "architecturalStudies",
- "architecture",
- "art:ArtVisualStudies",
- "behavioralNeuroscience",
- "biochemistry",
- "bioengineering",
- "biology",
- "biomedicalPhysics",
- "businessAdministration",
- "businessAdministration:Accounting",
- "businessAdministration:AccountingAndAdvisoryServices",
- "businessAdministration:BrandManagement",
- "businessAdministration:BusinessAnalytics",
- "businessAdministration:CorporateInnovation",
- "businessAdministration:EntrepreneurialStartups",
- "businessAdministration:FamilyBusiness",
- "businessAdministration:Finance",
- "businessAdministration:Fintech",
- "businessAdministration:HealthcareManagementAndConsulting",
- "businessAdministration:Management",
- "businessAdministration:ManagementInformationSystems",
- "businessAdministration:Marketing",
- "businessAdministration:MarketingAnalytics",
- "businessAdministration:SocialInnovationAndEntrepreneurship",
- "businessAdministration:SupplyChainManagement",
- "cellAndMolecularBiology",
- "chemicalEngineering",
- "chemistry",
- "civilEngineering",
- "communicationStudies",
- "computerEngineering",
- "computerScience",
- "computingAndLaw",
- "criminologyAndCriminalJustice",
- "culturalAnthropology",
- "cybersecurity",
- "dataScience",
- "design",
- "economics",
- "electricalEngineering",
- "english",
- "environmentalAndSustainabilityStudies",
- "environmentalEngineering",
- "environmentalScience",
- "environmentalStudies",
- "gameArtAndAnimation",
- "gameDesign",
- "globalAsianStudies",
- "healthScience",
- "history",
- "historyCultureAndLaw",
- "humanServices",
- "industrialEngineering",
- "internationalAffairs",
- "internationalBusiness",
- "internationalBusiness:Accounting",
- "internationalBusiness:AccountingAndAdvisoryServices",
- "internationalBusiness:BrandManagement",
- "internationalBusiness:BusinessAnalytics",
- "internationalBusiness:CorporateInnovation",
- "internationalBusiness:EntrepreneurialStartups",
- "internationalBusiness:FamilyBusiness",
- "internationalBusiness:Finance",
- "internationalBusiness:Fintech",
- "internationalBusiness:HealthcareManagementAndConsulting",
- "internationalBusiness:Management",
- "internationalBusiness:ManagementInformationSystems",
- "internationalBusiness:Marketing",
- "internationalBusiness:MarketingAnalytics",
- "internationalBusiness:SocialInnovationAndEntrepreneurship",
- "internationalBusiness:SupplyChainManagement",
- "journalism",
- "landscapeArchitecture",
- "linguistics",
- "marineBiology",
- "mathematics",
- "mechanicalEngineering",
- "mediaAndScreenStudies",
- "mediaArts",
- "music",
- "musicTechnology",
- "nursing",
- "pharmaceuticalSciences",
- "pharmacy(PharmD)",
- "philosophy",
- "physics",
- "politicalScience",
- "politicsPhilosophyEconomics",
- "psychology",
- "publicHealth",
- "publicRelations",
- "religiousStudies",
- "sociology",
- "spanish",
- "speechLanguagePathologyAndAudiology",
- "theatre"
+ "facebook",
+ "instagram",
+ "x",
+ "linkedin",
+ "youtube",
+ "github",
+ "slack",
+ "discord",
+ "email",
+ "customSite"
],
"allOf": [
{
- "$ref": "#/definitions/models.Major"
+ "$ref": "#/definitions/models.ContactType"
}
]
- },
- "password": {
- "description": "MARK: must be validated manually",
- "type": "string",
- "maxLength": 255
}
}
},
- "models.Event": {
+ "models.Category": {
"type": "object",
- "required": [
- "content",
- "end_time",
- "event_type",
- "location",
- "name",
- "preview",
- "start_time"
- ],
"properties": {
- "content": {
- "type": "string",
- "maxLength": 255
- },
"created_at": {
"type": "string",
"example": "2023-09-20T16:34:50Z"
},
- "end_time": {
+ "id": {
+ "type": "string",
+ "example": "123e4567-e89b-12d3-a456-426614174000"
+ },
+ "name": {
"type": "string"
},
- "event_type": {
- "maxLength": 255,
- "enum": [
- "open",
- "membersOnly"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.EventType"
- }
- ]
+ "updated_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
+ }
+ }
+ },
+ "models.Club": {
+ "type": "object",
+ "properties": {
+ "application_link": {
+ "type": "string"
},
- "host": {
+ "created_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
+ },
+ "description": {
"type": "string"
},
"id": {
"type": "string",
"example": "123e4567-e89b-12d3-a456-426614174000"
},
- "is_recurring": {
+ "is_recruiting": {
"type": "boolean"
},
- "location": {
- "type": "string",
- "maxLength": 255
- },
- "meeting_link": {
+ "logo": {
"type": "string"
},
"name": {
- "type": "string",
- "maxLength": 255
+ "type": "string"
},
- "preview": {
- "type": "string",
- "maxLength": 255
+ "num_members": {
+ "type": "integer"
},
- "start_time": {
+ "one_word_to_describe_us": {
+ "type": "string"
+ },
+ "preview": {
"type": "string"
},
+ "recruitment_cycle": {
+ "$ref": "#/definitions/models.RecruitmentCycle"
+ },
+ "recruitment_type": {
+ "$ref": "#/definitions/models.RecruitmentType"
+ },
"updated_at": {
"type": "string",
"example": "2023-09-20T16:34:50Z"
+ },
+ "weekly_time_commitment": {
+ "type": "integer"
}
}
},
- "models.EventType": {
+ "models.College": {
"type": "string",
"enum": [
- "open",
- "membersOnly"
+ "CAMD",
+ "DMSB",
+ "KCCS",
+ "CE",
+ "BCHS",
+ "SL",
+ "CPS",
+ "CS",
+ "CSSH"
],
+ "x-enum-comments": {
+ "BCHS": "Bouvé College of Health Sciences",
+ "CAMD": "College of Arts, Media and Design",
+ "CE": "College of Engineering",
+ "CPS": "College of Professional Studies",
+ "CS": "College of Science",
+ "CSSH": "College of Social Sciences and Humanities",
+ "DMSB": "D'Amore-McKim School of Business",
+ "KCCS": "Khoury College of Computer Sciences",
+ "SL": "School of Law"
+ },
"x-enum-varnames": [
- "Open",
- "MembersOnly"
+ "CAMD",
+ "DMSB",
+ "KCCS",
+ "CE",
+ "BCHS",
+ "SL",
+ "CPS",
+ "CS",
+ "CSSH"
]
},
- "models.File": {
+ "models.Contact": {
"type": "object",
- "required": [
- "file_name",
- "file_size",
- "file_type",
- "file_url",
- "object_key"
- ],
"properties": {
+ "content": {
+ "type": "string"
+ },
"created_at": {
"type": "string",
"example": "2023-09-20T16:34:50Z"
},
- "file_name": {
- "type": "string",
- "maxLength": 255
- },
- "file_size": {
- "type": "integer",
- "minimum": 1
- },
- "file_type": {
- "type": "string",
- "maxLength": 255
- },
- "file_url": {
- "type": "string",
- "maxLength": 255
- },
"id": {
"type": "string",
"example": "123e4567-e89b-12d3-a456-426614174000"
},
- "object_key": {
- "type": "string",
- "maxLength": 255
+ "type": {
+ "$ref": "#/definitions/models.ContactType"
},
"updated_at": {
"type": "string",
@@ -5176,34 +4466,150 @@ const docTemplate = `{
}
}
},
- "models.GraduationCycle": {
+ "models.ContactType": {
"type": "string",
"enum": [
- "december",
- "may"
+ "facebook",
+ "instagram",
+ "x",
+ "linkedin",
+ "youtube",
+ "github",
+ "slack",
+ "discord",
+ "email",
+ "customSite"
],
"x-enum-varnames": [
- "December",
- "May"
+ "Facebook",
+ "Instagram",
+ "X",
+ "LinkedIn",
+ "YouTube",
+ "GitHub",
+ "Slack",
+ "Discord",
+ "Email",
+ "CustomSite"
]
},
- "models.LoginUserResponseBody": {
+ "models.Event": {
"type": "object",
- "required": [
- "email",
- "password"
+ "properties": {
+ "created_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
+ },
+ "description": {
+ "type": "string"
+ },
+ "end_time": {
+ "type": "string"
+ },
+ "event_type": {
+ "description": "geoshi",
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.EventType"
+ }
+ ]
+ },
+ "host": {
+ "type": "string"
+ },
+ "id": {
+ "type": "string",
+ "example": "123e4567-e89b-12d3-a456-426614174000"
+ },
+ "is_archived": {
+ "type": "boolean"
+ },
+ "is_draft": {
+ "type": "boolean"
+ },
+ "is_public": {
+ "description": "internal housekeeping states",
+ "type": "boolean"
+ },
+ "link": {
+ "type": "string"
+ },
+ "location": {
+ "type": "string"
+ },
+ "name": {
+ "description": "details",
+ "type": "string"
+ },
+ "preview": {
+ "type": "string"
+ },
+ "start_time": {
+ "description": "timing",
+ "type": "string"
+ },
+ "updated_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
+ }
+ }
+ },
+ "models.EventType": {
+ "type": "string",
+ "enum": [
+ "hybrid",
+ "in_person",
+ "virtual"
],
+ "x-enum-varnames": [
+ "Hybrid",
+ "InPerson",
+ "Virtual"
+ ]
+ },
+ "models.File": {
+ "type": "object",
"properties": {
- "email": {
+ "created_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
+ },
+ "file_name": {
"type": "string"
},
- "password": {
- "description": "MARK: must be validated manually",
+ "file_size": {
+ "type": "integer"
+ },
+ "file_type": {
+ "type": "string"
+ },
+ "file_url": {
+ "type": "string"
+ },
+ "id": {
"type": "string",
- "maxLength": 255
+ "example": "123e4567-e89b-12d3-a456-426614174000"
+ },
+ "object_key": {
+ "type": "string"
+ },
+ "updated_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
}
}
},
+ "models.GraduationCycle": {
+ "type": "string",
+ "enum": [
+ "december",
+ "may"
+ ],
+ "x-enum-varnames": [
+ "December",
+ "May"
+ ]
+ },
"models.Major": {
"type": "string",
"enum": [
@@ -5393,1135 +4799,46 @@ const docTemplate = `{
"MediaAndScreenStudies",
"MediaArts",
"Music",
- "MusicTechnology",
- "Nursing",
- "PharmaceuticalSciences",
- "PharmacyPharmD",
- "Philosophy",
- "Physics",
- "PoliticalScience",
- "PoliticsPhilosophyEconomics",
- "Psychology",
- "PublicHealth",
- "PublicRelations",
- "ReligiousStudies",
- "Sociology",
- "Spanish",
- "SpeechLanguagePathologyAndAudiology",
- "Theatre"
- ]
- },
- "models.PointOfContact": {
- "type": "object",
- "required": [
- "email",
- "name",
- "position"
- ],
- "properties": {
- "created_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- },
- "email": {
- "type": "string",
- "maxLength": 255
- },
- "id": {
- "type": "string",
- "example": "123e4567-e89b-12d3-a456-426614174000"
- },
- "name": {
- "type": "string",
- "maxLength": 255
- },
- "photo_file": {
- "$ref": "#/definitions/models.File"
- },
- "position": {
- "type": "string",
- "maxLength": 255
- },
- "updated_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- }
- }
- },
- "models.PutContactRequestBody": {
- "type": "object",
- "required": [
- "content",
- "type"
- ],
- "properties": {
- "content": {
- "type": "string",
- "maxLength": 255
- },
- "type": {
- "maxLength": 255,
- "enum": [
- "facebook",
- "instagram",
- "x",
- "linkedin",
- "youtube",
- "github",
- "slack",
- "discord",
- "email",
- "customSite"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.ContactType"
- }
- ]
- }
- }
- },
- "models.RecruitmentCycle": {
- "type": "string",
- "enum": [
- "fall",
- "spring",
- "fallSpring",
- "always"
- ],
- "x-enum-varnames": [
- "Fall",
- "Spring",
- "FallSpring",
- "Always"
- ]
- },
- "models.RecruitmentType": {
- "type": "string",
- "enum": [
- "unrestricted",
- "tryout",
- "application"
- ],
- "x-enum-varnames": [
- "Unrestricted",
- "Tryout",
- "Application"
- ]
- },
- "models.RecurringType": {
- "type": "string",
- "enum": [
- "daily",
- "weekly",
- "monthly"
- ],
- "x-enum-varnames": [
- "Daily",
- "Weekly",
- "Monthly"
- ]
- },
- "models.Series": {
- "type": "object",
- "properties": {
- "created_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- },
- "events": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/models.Event"
- }
- },
- "id": {
- "type": "string",
- "example": "123e4567-e89b-12d3-a456-426614174000"
- },
- "max_occurrences": {
- "type": "integer",
- "minimum": 1
- },
- "recurring_type": {
- "maxLength": 255,
- "allOf": [
- {
- "$ref": "#/definitions/models.RecurringType"
- }
- ]
- },
- "updated_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- }
- }
- },
- "models.Tag": {
- "type": "object",
- "required": [
- "category_id",
- "name"
- ],
- "properties": {
- "category_id": {
- "type": "string"
- },
- "created_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- },
- "id": {
- "type": "string",
- "example": "123e4567-e89b-12d3-a456-426614174000"
- },
- "name": {
- "type": "string",
- "maxLength": 255
- },
- "updated_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- }
- }
- },
- "models.UpdateClubRequestBody": {
- "type": "object",
- "required": [
- "application_link",
- "recruitment_cycle",
- "recruitment_type"
- ],
- "properties": {
- "application_link": {
- "type": "string",
- "maxLength": 255
- },
- "description": {
- "type": "string",
- "maxLength": 255
- },
- "is_recruiting": {
- "type": "boolean"
- },
- "logo": {
- "type": "string",
- "maxLength": 255
- },
- "name": {
- "type": "string",
- "maxLength": 255
- },
- "one_word_to_describe_us": {
- "type": "string",
- "maxLength": 255
- },
- "preview": {
- "type": "string",
- "maxLength": 255
- },
- "recruitment_cycle": {
- "maxLength": 255,
- "enum": [
- "fall",
- "spring",
- "fallSpring",
- "always"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.RecruitmentCycle"
- }
- ]
- },
- "recruitment_type": {
- "maxLength": 255,
- "enum": [
- "unrestricted",
- "tryout",
- "application"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.RecruitmentType"
- }
- ]
- },
- "weekly_time_commitment": {
- "type": "integer",
- "minimum": 1
- }
- }
- },
- "models.UpdateEventRequestBody": {
- "type": "object",
- "properties": {
- "content": {
- "type": "string",
- "maxLength": 255
- },
- "end_time": {
- "type": "string"
- },
- "event_type": {
- "maxLength": 255,
- "enum": [
- "open",
- "membersOnly"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.EventType"
- }
- ]
- },
- "host": {
- "type": "string"
- },
- "location": {
- "type": "string",
- "maxLength": 255
- },
- "name": {
- "type": "string",
- "maxLength": 255
- },
- "preview": {
- "type": "string",
- "maxLength": 255
- },
- "start_time": {
- "type": "string"
- }
- }
- },
- "models.UpdatePasswordRequestBody": {
- "type": "object",
- "required": [
- "new_password",
- "old_password"
- ],
- "properties": {
- "new_password": {
- "description": "MARK: must be validated manually",
- "type": "string",
- "maxLength": 255
- },
- "old_password": {
- "description": "MARK: must be validated manually",
- "type": "string",
- "maxLength": 255
- }
- }
- },
- "models.UpdateSeriesRequestBody": {
- "type": "object",
- "properties": {
- "event_details": {
- "$ref": "#/definitions/models.UpdateEventRequestBody"
- },
- "max_occurrences": {
- "type": "integer",
- "minimum": 2
- },
- "recurring_type": {
- "maxLength": 255,
- "enum": [
- "daily",
- "weekly",
- "monthly"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.RecurringType"
- }
- ]
- }
- }
- },
- "models.UpdateTagRequestBody": {
- "type": "object",
- "properties": {
- "category_id": {
- "type": "string"
- },
- "name": {
- "type": "string",
- "maxLength": 255
- }
- }
- },
- "models.UpdateUserRequestBody": {
- "type": "object",
- "properties": {
- "college": {
- "enum": [
- "CAMD",
- "DMSB",
- "KCCS",
- "CE",
- "BCHS",
- "SL",
- "CPS",
- "CS",
- "CSSH"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.College"
- }
- ]
- },
- "first_name": {
- "type": "string",
- "maxLength": 255
- },
- "graduation_cycle": {
- "maxLength": 255,
- "enum": [
- "december",
- "may"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.GraduationCycle"
- }
- ]
- },
- "graduation_year": {
- "type": "integer"
- },
- "last_name": {
- "type": "string",
- "maxLength": 255
- },
- "major0": {
- "maxLength": 255,
- "enum": [
- "africanaStudies",
- "americanSignLanguage",
- "americanSignLanguage-EnglishInterpreting",
- "appliedPhysics",
- "architecturalStudies",
- "architecture",
- "art:ArtVisualStudies",
- "behavioralNeuroscience",
- "biochemistry",
- "bioengineering",
- "biology",
- "biomedicalPhysics",
- "businessAdministration",
- "businessAdministration:Accounting",
- "businessAdministration:AccountingAndAdvisoryServices",
- "businessAdministration:BrandManagement",
- "businessAdministration:BusinessAnalytics",
- "businessAdministration:CorporateInnovation",
- "businessAdministration:EntrepreneurialStartups",
- "businessAdministration:FamilyBusiness",
- "businessAdministration:Finance",
- "businessAdministration:Fintech",
- "businessAdministration:HealthcareManagementAndConsulting",
- "businessAdministration:Management",
- "businessAdministration:ManagementInformationSystems",
- "businessAdministration:Marketing",
- "businessAdministration:MarketingAnalytics",
- "businessAdministration:SocialInnovationAndEntrepreneurship",
- "businessAdministration:SupplyChainManagement",
- "cellAndMolecularBiology",
- "chemicalEngineering",
- "chemistry",
- "civilEngineering",
- "communicationStudies",
- "computerEngineering",
- "computerScience",
- "computingAndLaw",
- "criminologyAndCriminalJustice",
- "culturalAnthropology",
- "cybersecurity",
- "dataScience",
- "design",
- "economics",
- "electricalEngineering",
- "english",
- "environmentalAndSustainabilityStudies",
- "environmentalEngineering",
- "environmentalScience",
- "environmentalStudies",
- "gameArtAndAnimation",
- "gameDesign",
- "globalAsianStudies",
- "healthScience",
- "history",
- "historyCultureAndLaw",
- "humanServices",
- "industrialEngineering",
- "internationalAffairs",
- "internationalBusiness",
- "internationalBusiness:Accounting",
- "internationalBusiness:AccountingAndAdvisoryServices",
- "internationalBusiness:BrandManagement",
- "internationalBusiness:BusinessAnalytics",
- "internationalBusiness:CorporateInnovation",
- "internationalBusiness:EntrepreneurialStartups",
- "internationalBusiness:FamilyBusiness",
- "internationalBusiness:Finance",
- "internationalBusiness:Fintech",
- "internationalBusiness:HealthcareManagementAndConsulting",
- "internationalBusiness:Management",
- "internationalBusiness:ManagementInformationSystems",
- "internationalBusiness:Marketing",
- "internationalBusiness:MarketingAnalytics",
- "internationalBusiness:SocialInnovationAndEntrepreneurship",
- "internationalBusiness:SupplyChainManagement",
- "journalism",
- "landscapeArchitecture",
- "linguistics",
- "marineBiology",
- "mathematics",
- "mechanicalEngineering",
- "mediaAndScreenStudies",
- "mediaArts",
- "music",
- "musicTechnology",
- "nursing",
- "pharmaceuticalSciences",
- "pharmacy(PharmD)",
- "philosophy",
- "physics",
- "politicalScience",
- "politicsPhilosophyEconomics",
- "psychology",
- "publicHealth",
- "publicRelations",
- "religiousStudies",
- "sociology",
- "spanish",
- "speechLanguagePathologyAndAudiology",
- "theatre"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.Major"
- }
- ]
- },
- "major1": {
- "maxLength": 255,
- "enum": [
- "africanaStudies",
- "americanSignLanguage",
- "americanSignLanguage-EnglishInterpreting",
- "appliedPhysics",
- "architecturalStudies",
- "architecture",
- "art:ArtVisualStudies",
- "behavioralNeuroscience",
- "biochemistry",
- "bioengineering",
- "biology",
- "biomedicalPhysics",
- "businessAdministration",
- "businessAdministration:Accounting",
- "businessAdministration:AccountingAndAdvisoryServices",
- "businessAdministration:BrandManagement",
- "businessAdministration:BusinessAnalytics",
- "businessAdministration:CorporateInnovation",
- "businessAdministration:EntrepreneurialStartups",
- "businessAdministration:FamilyBusiness",
- "businessAdministration:Finance",
- "businessAdministration:Fintech",
- "businessAdministration:HealthcareManagementAndConsulting",
- "businessAdministration:Management",
- "businessAdministration:ManagementInformationSystems",
- "businessAdministration:Marketing",
- "businessAdministration:MarketingAnalytics",
- "businessAdministration:SocialInnovationAndEntrepreneurship",
- "businessAdministration:SupplyChainManagement",
- "cellAndMolecularBiology",
- "chemicalEngineering",
- "chemistry",
- "civilEngineering",
- "communicationStudies",
- "computerEngineering",
- "computerScience",
- "computingAndLaw",
- "criminologyAndCriminalJustice",
- "culturalAnthropology",
- "cybersecurity",
- "dataScience",
- "design",
- "economics",
- "electricalEngineering",
- "english",
- "environmentalAndSustainabilityStudies",
- "environmentalEngineering",
- "environmentalScience",
- "environmentalStudies",
- "gameArtAndAnimation",
- "gameDesign",
- "globalAsianStudies",
- "healthScience",
- "history",
- "historyCultureAndLaw",
- "humanServices",
- "industrialEngineering",
- "internationalAffairs",
- "internationalBusiness",
- "internationalBusiness:Accounting",
- "internationalBusiness:AccountingAndAdvisoryServices",
- "internationalBusiness:BrandManagement",
- "internationalBusiness:BusinessAnalytics",
- "internationalBusiness:CorporateInnovation",
- "internationalBusiness:EntrepreneurialStartups",
- "internationalBusiness:FamilyBusiness",
- "internationalBusiness:Finance",
- "internationalBusiness:Fintech",
- "internationalBusiness:HealthcareManagementAndConsulting",
- "internationalBusiness:Management",
- "internationalBusiness:ManagementInformationSystems",
- "internationalBusiness:Marketing",
- "internationalBusiness:MarketingAnalytics",
- "internationalBusiness:SocialInnovationAndEntrepreneurship",
- "internationalBusiness:SupplyChainManagement",
- "journalism",
- "landscapeArchitecture",
- "linguistics",
- "marineBiology",
- "mathematics",
- "mechanicalEngineering",
- "mediaAndScreenStudies",
- "mediaArts",
- "music",
- "musicTechnology",
- "nursing",
- "pharmaceuticalSciences",
- "pharmacy(PharmD)",
- "philosophy",
- "physics",
- "politicalScience",
- "politicsPhilosophyEconomics",
- "psychology",
- "publicHealth",
- "publicRelations",
- "religiousStudies",
- "sociology",
- "spanish",
- "speechLanguagePathologyAndAudiology",
- "theatre"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.Major"
- }
- ]
- },
- "major2": {
- "maxLength": 255,
- "enum": [
- "africanaStudies",
- "americanSignLanguage",
- "americanSignLanguage-EnglishInterpreting",
- "appliedPhysics",
- "architecturalStudies",
- "architecture",
- "art:ArtVisualStudies",
- "behavioralNeuroscience",
- "biochemistry",
- "bioengineering",
- "biology",
- "biomedicalPhysics",
- "businessAdministration",
- "businessAdministration:Accounting",
- "businessAdministration:AccountingAndAdvisoryServices",
- "businessAdministration:BrandManagement",
- "businessAdministration:BusinessAnalytics",
- "businessAdministration:CorporateInnovation",
- "businessAdministration:EntrepreneurialStartups",
- "businessAdministration:FamilyBusiness",
- "businessAdministration:Finance",
- "businessAdministration:Fintech",
- "businessAdministration:HealthcareManagementAndConsulting",
- "businessAdministration:Management",
- "businessAdministration:ManagementInformationSystems",
- "businessAdministration:Marketing",
- "businessAdministration:MarketingAnalytics",
- "businessAdministration:SocialInnovationAndEntrepreneurship",
- "businessAdministration:SupplyChainManagement",
- "cellAndMolecularBiology",
- "chemicalEngineering",
- "chemistry",
- "civilEngineering",
- "communicationStudies",
- "computerEngineering",
- "computerScience",
- "computingAndLaw",
- "criminologyAndCriminalJustice",
- "culturalAnthropology",
- "cybersecurity",
- "dataScience",
- "design",
- "economics",
- "electricalEngineering",
- "english",
- "environmentalAndSustainabilityStudies",
- "environmentalEngineering",
- "environmentalScience",
- "environmentalStudies",
- "gameArtAndAnimation",
- "gameDesign",
- "globalAsianStudies",
- "healthScience",
- "history",
- "historyCultureAndLaw",
- "humanServices",
- "industrialEngineering",
- "internationalAffairs",
- "internationalBusiness",
- "internationalBusiness:Accounting",
- "internationalBusiness:AccountingAndAdvisoryServices",
- "internationalBusiness:BrandManagement",
- "internationalBusiness:BusinessAnalytics",
- "internationalBusiness:CorporateInnovation",
- "internationalBusiness:EntrepreneurialStartups",
- "internationalBusiness:FamilyBusiness",
- "internationalBusiness:Finance",
- "internationalBusiness:Fintech",
- "internationalBusiness:HealthcareManagementAndConsulting",
- "internationalBusiness:Management",
- "internationalBusiness:ManagementInformationSystems",
- "internationalBusiness:Marketing",
- "internationalBusiness:MarketingAnalytics",
- "internationalBusiness:SocialInnovationAndEntrepreneurship",
- "internationalBusiness:SupplyChainManagement",
- "journalism",
- "landscapeArchitecture",
- "linguistics",
- "marineBiology",
- "mathematics",
- "mechanicalEngineering",
- "mediaAndScreenStudies",
- "mediaArts",
- "music",
- "musicTechnology",
- "nursing",
- "pharmaceuticalSciences",
- "pharmacy(PharmD)",
- "philosophy",
- "physics",
- "politicalScience",
- "politicsPhilosophyEconomics",
- "psychology",
- "publicHealth",
- "publicRelations",
- "religiousStudies",
- "sociology",
- "spanish",
- "speechLanguagePathologyAndAudiology",
- "theatre"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.Major"
- }
- ]
- }
- }
- },
- "models.User": {
- "type": "object",
- "required": [
- "college",
- "email",
- "first_name",
- "graduation_cycle",
- "graduation_year",
- "last_name",
- "major0",
- "role"
- ],
- "properties": {
- "college": {
- "maxLength": 255,
- "allOf": [
- {
- "$ref": "#/definitions/models.College"
- }
- ]
- },
- "created_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- },
- "email": {
- "type": "string",
- "maxLength": 255
- },
- "first_name": {
- "type": "string",
- "maxLength": 255
- },
- "graduation_cycle": {
- "maxLength": 255,
- "enum": [
- "december",
- "may"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.GraduationCycle"
- }
- ]
- },
- "graduation_year": {
- "type": "integer"
- },
- "id": {
- "type": "string",
- "example": "123e4567-e89b-12d3-a456-426614174000"
- },
- "is_verified": {
- "type": "boolean"
- },
- "last_name": {
- "type": "string",
- "maxLength": 255
- },
- "major0": {
- "maxLength": 255,
- "enum": [
- "africanaStudies",
- "americanSignLanguage",
- "americanSignLanguage-EnglishInterpreting",
- "appliedPhysics",
- "architecturalStudies",
- "architecture",
- "art:ArtVisualStudies",
- "behavioralNeuroscience",
- "biochemistry",
- "bioengineering",
- "biology",
- "biomedicalPhysics",
- "businessAdministration",
- "businessAdministration:Accounting",
- "businessAdministration:AccountingAndAdvisoryServices",
- "businessAdministration:BrandManagement",
- "businessAdministration:BusinessAnalytics",
- "businessAdministration:CorporateInnovation",
- "businessAdministration:EntrepreneurialStartups",
- "businessAdministration:FamilyBusiness",
- "businessAdministration:Finance",
- "businessAdministration:Fintech",
- "businessAdministration:HealthcareManagementAndConsulting",
- "businessAdministration:Management",
- "businessAdministration:ManagementInformationSystems",
- "businessAdministration:Marketing",
- "businessAdministration:MarketingAnalytics",
- "businessAdministration:SocialInnovationAndEntrepreneurship",
- "businessAdministration:SupplyChainManagement",
- "cellAndMolecularBiology",
- "chemicalEngineering",
- "chemistry",
- "civilEngineering",
- "communicationStudies",
- "computerEngineering",
- "computerScience",
- "computingAndLaw",
- "criminologyAndCriminalJustice",
- "culturalAnthropology",
- "cybersecurity",
- "dataScience",
- "design",
- "economics",
- "electricalEngineering",
- "english",
- "environmentalAndSustainabilityStudies",
- "environmentalEngineering",
- "environmentalScience",
- "environmentalStudies",
- "gameArtAndAnimation",
- "gameDesign",
- "globalAsianStudies",
- "healthScience",
- "history",
- "historyCultureAndLaw",
- "humanServices",
- "industrialEngineering",
- "internationalAffairs",
- "internationalBusiness",
- "internationalBusiness:Accounting",
- "internationalBusiness:AccountingAndAdvisoryServices",
- "internationalBusiness:BrandManagement",
- "internationalBusiness:BusinessAnalytics",
- "internationalBusiness:CorporateInnovation",
- "internationalBusiness:EntrepreneurialStartups",
- "internationalBusiness:FamilyBusiness",
- "internationalBusiness:Finance",
- "internationalBusiness:Fintech",
- "internationalBusiness:HealthcareManagementAndConsulting",
- "internationalBusiness:Management",
- "internationalBusiness:ManagementInformationSystems",
- "internationalBusiness:Marketing",
- "internationalBusiness:MarketingAnalytics",
- "internationalBusiness:SocialInnovationAndEntrepreneurship",
- "internationalBusiness:SupplyChainManagement",
- "journalism",
- "landscapeArchitecture",
- "linguistics",
- "marineBiology",
- "mathematics",
- "mechanicalEngineering",
- "mediaAndScreenStudies",
- "mediaArts",
- "music",
- "musicTechnology",
- "nursing",
- "pharmaceuticalSciences",
- "pharmacy(PharmD)",
- "philosophy",
- "physics",
- "politicalScience",
- "politicsPhilosophyEconomics",
- "psychology",
- "publicHealth",
- "publicRelations",
- "religiousStudies",
- "sociology",
- "spanish",
- "speechLanguagePathologyAndAudiology",
- "theatre"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.Major"
- }
- ]
- },
- "major1": {
- "maxLength": 255,
- "enum": [
- "africanaStudies",
- "americanSignLanguage",
- "americanSignLanguage-EnglishInterpreting",
- "appliedPhysics",
- "architecturalStudies",
- "architecture",
- "art:ArtVisualStudies",
- "behavioralNeuroscience",
- "biochemistry",
- "bioengineering",
- "biology",
- "biomedicalPhysics",
- "businessAdministration",
- "businessAdministration:Accounting",
- "businessAdministration:AccountingAndAdvisoryServices",
- "businessAdministration:BrandManagement",
- "businessAdministration:BusinessAnalytics",
- "businessAdministration:CorporateInnovation",
- "businessAdministration:EntrepreneurialStartups",
- "businessAdministration:FamilyBusiness",
- "businessAdministration:Finance",
- "businessAdministration:Fintech",
- "businessAdministration:HealthcareManagementAndConsulting",
- "businessAdministration:Management",
- "businessAdministration:ManagementInformationSystems",
- "businessAdministration:Marketing",
- "businessAdministration:MarketingAnalytics",
- "businessAdministration:SocialInnovationAndEntrepreneurship",
- "businessAdministration:SupplyChainManagement",
- "cellAndMolecularBiology",
- "chemicalEngineering",
- "chemistry",
- "civilEngineering",
- "communicationStudies",
- "computerEngineering",
- "computerScience",
- "computingAndLaw",
- "criminologyAndCriminalJustice",
- "culturalAnthropology",
- "cybersecurity",
- "dataScience",
- "design",
- "economics",
- "electricalEngineering",
- "english",
- "environmentalAndSustainabilityStudies",
- "environmentalEngineering",
- "environmentalScience",
- "environmentalStudies",
- "gameArtAndAnimation",
- "gameDesign",
- "globalAsianStudies",
- "healthScience",
- "history",
- "historyCultureAndLaw",
- "humanServices",
- "industrialEngineering",
- "internationalAffairs",
- "internationalBusiness",
- "internationalBusiness:Accounting",
- "internationalBusiness:AccountingAndAdvisoryServices",
- "internationalBusiness:BrandManagement",
- "internationalBusiness:BusinessAnalytics",
- "internationalBusiness:CorporateInnovation",
- "internationalBusiness:EntrepreneurialStartups",
- "internationalBusiness:FamilyBusiness",
- "internationalBusiness:Finance",
- "internationalBusiness:Fintech",
- "internationalBusiness:HealthcareManagementAndConsulting",
- "internationalBusiness:Management",
- "internationalBusiness:ManagementInformationSystems",
- "internationalBusiness:Marketing",
- "internationalBusiness:MarketingAnalytics",
- "internationalBusiness:SocialInnovationAndEntrepreneurship",
- "internationalBusiness:SupplyChainManagement",
- "journalism",
- "landscapeArchitecture",
- "linguistics",
- "marineBiology",
- "mathematics",
- "mechanicalEngineering",
- "mediaAndScreenStudies",
- "mediaArts",
- "music",
- "musicTechnology",
- "nursing",
- "pharmaceuticalSciences",
- "pharmacy(PharmD)",
- "philosophy",
- "physics",
- "politicalScience",
- "politicsPhilosophyEconomics",
- "psychology",
- "publicHealth",
- "publicRelations",
- "religiousStudies",
- "sociology",
- "spanish",
- "speechLanguagePathologyAndAudiology",
- "theatre"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.Major"
- }
- ]
+ "MusicTechnology",
+ "Nursing",
+ "PharmaceuticalSciences",
+ "PharmacyPharmD",
+ "Philosophy",
+ "Physics",
+ "PoliticalScience",
+ "PoliticsPhilosophyEconomics",
+ "Psychology",
+ "PublicHealth",
+ "PublicRelations",
+ "ReligiousStudies",
+ "Sociology",
+ "Spanish",
+ "SpeechLanguagePathologyAndAudiology",
+ "Theatre"
+ ]
+ },
+ "models.PointOfContact": {
+ "type": "object",
+ "properties": {
+ "created_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
},
- "major2": {
- "maxLength": 255,
- "enum": [
- "africanaStudies",
- "americanSignLanguage",
- "americanSignLanguage-EnglishInterpreting",
- "appliedPhysics",
- "architecturalStudies",
- "architecture",
- "art:ArtVisualStudies",
- "behavioralNeuroscience",
- "biochemistry",
- "bioengineering",
- "biology",
- "biomedicalPhysics",
- "businessAdministration",
- "businessAdministration:Accounting",
- "businessAdministration:AccountingAndAdvisoryServices",
- "businessAdministration:BrandManagement",
- "businessAdministration:BusinessAnalytics",
- "businessAdministration:CorporateInnovation",
- "businessAdministration:EntrepreneurialStartups",
- "businessAdministration:FamilyBusiness",
- "businessAdministration:Finance",
- "businessAdministration:Fintech",
- "businessAdministration:HealthcareManagementAndConsulting",
- "businessAdministration:Management",
- "businessAdministration:ManagementInformationSystems",
- "businessAdministration:Marketing",
- "businessAdministration:MarketingAnalytics",
- "businessAdministration:SocialInnovationAndEntrepreneurship",
- "businessAdministration:SupplyChainManagement",
- "cellAndMolecularBiology",
- "chemicalEngineering",
- "chemistry",
- "civilEngineering",
- "communicationStudies",
- "computerEngineering",
- "computerScience",
- "computingAndLaw",
- "criminologyAndCriminalJustice",
- "culturalAnthropology",
- "cybersecurity",
- "dataScience",
- "design",
- "economics",
- "electricalEngineering",
- "english",
- "environmentalAndSustainabilityStudies",
- "environmentalEngineering",
- "environmentalScience",
- "environmentalStudies",
- "gameArtAndAnimation",
- "gameDesign",
- "globalAsianStudies",
- "healthScience",
- "history",
- "historyCultureAndLaw",
- "humanServices",
- "industrialEngineering",
- "internationalAffairs",
- "internationalBusiness",
- "internationalBusiness:Accounting",
- "internationalBusiness:AccountingAndAdvisoryServices",
- "internationalBusiness:BrandManagement",
- "internationalBusiness:BusinessAnalytics",
- "internationalBusiness:CorporateInnovation",
- "internationalBusiness:EntrepreneurialStartups",
- "internationalBusiness:FamilyBusiness",
- "internationalBusiness:Finance",
- "internationalBusiness:Fintech",
- "internationalBusiness:HealthcareManagementAndConsulting",
- "internationalBusiness:Management",
- "internationalBusiness:ManagementInformationSystems",
- "internationalBusiness:Marketing",
- "internationalBusiness:MarketingAnalytics",
- "internationalBusiness:SocialInnovationAndEntrepreneurship",
- "internationalBusiness:SupplyChainManagement",
- "journalism",
- "landscapeArchitecture",
- "linguistics",
- "marineBiology",
- "mathematics",
- "mechanicalEngineering",
- "mediaAndScreenStudies",
- "mediaArts",
- "music",
- "musicTechnology",
- "nursing",
- "pharmaceuticalSciences",
- "pharmacy(PharmD)",
- "philosophy",
- "physics",
- "politicalScience",
- "politicsPhilosophyEconomics",
- "psychology",
- "publicHealth",
- "publicRelations",
- "religiousStudies",
- "sociology",
- "spanish",
- "speechLanguagePathologyAndAudiology",
- "theatre"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.Major"
- }
- ]
+ "email": {
+ "type": "string"
},
- "role": {
+ "id": {
"type": "string",
- "enum": [
- "super",
- "student"
- ]
+ "example": "123e4567-e89b-12d3-a456-426614174000"
+ },
+ "name": {
+ "type": "string"
+ },
+ "photo_file": {
+ "$ref": "#/definitions/models.File"
+ },
+ "position": {
+ "type": "string"
},
"updated_at": {
"type": "string",
@@ -6529,43 +4846,122 @@ const docTemplate = `{
}
}
},
- "models.VerifyEmailRequestBody": {
- "type": "object",
- "required": [
- "email",
- "token"
+ "models.RecruitmentCycle": {
+ "type": "string",
+ "enum": [
+ "fall",
+ "spring",
+ "fallSpring",
+ "always"
],
+ "x-enum-varnames": [
+ "Fall",
+ "Spring",
+ "FallSpring",
+ "Always"
+ ]
+ },
+ "models.RecruitmentType": {
+ "type": "string",
+ "enum": [
+ "unrestricted",
+ "tryout",
+ "application"
+ ],
+ "x-enum-varnames": [
+ "Unrestricted",
+ "Tryout",
+ "Application"
+ ]
+ },
+ "models.Tag": {
+ "type": "object",
"properties": {
- "email": {
+ "category_id": {
"type": "string"
},
- "token": {
+ "created_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
+ },
+ "id": {
+ "type": "string",
+ "example": "123e4567-e89b-12d3-a456-426614174000"
+ },
+ "name": {
"type": "string"
+ },
+ "updated_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
}
}
},
- "models.VerifyPasswordResetTokenRequestBody": {
+ "models.User": {
"type": "object",
- "required": [
- "new_password",
- "token",
- "verify_new_password"
- ],
"properties": {
- "new_password": {
+ "college": {
+ "$ref": "#/definitions/models.College"
+ },
+ "created_at": {
"type": "string",
- "minLength": 8
+ "example": "2023-09-20T16:34:50Z"
},
- "token": {
+ "email": {
"type": "string"
},
- "verify_new_password": {
+ "first_name": {
+ "type": "string"
+ },
+ "graduation_cycle": {
+ "$ref": "#/definitions/models.GraduationCycle"
+ },
+ "graduation_year": {
+ "type": "integer"
+ },
+ "id": {
"type": "string",
- "minLength": 8
+ "example": "123e4567-e89b-12d3-a456-426614174000"
+ },
+ "is_verified": {
+ "type": "boolean"
+ },
+ "last_name": {
+ "type": "string"
+ },
+ "major0": {
+ "$ref": "#/definitions/models.Major"
+ },
+ "major1": {
+ "$ref": "#/definitions/models.Major"
+ },
+ "major2": {
+ "$ref": "#/definitions/models.Major"
+ },
+ "role": {
+ "type": "string"
+ },
+ "updated_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
+ }
+ }
+ },
+ "tags.CreateClubTagsRequestBody": {
+ "type": "object",
+ "required": [
+ "tags"
+ ],
+ "properties": {
+ "tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
}
}
},
- "tag.CreateUserTagsBody": {
+ "tags.CreateUserTagsBody": {
"type": "object",
"required": [
"tags"
diff --git a/backend/docs/swagger.json b/backend/docs/swagger.json
index 2e2633237..bbfe208db 100644
--- a/backend/docs/swagger.json
+++ b/backend/docs/swagger.json
@@ -38,21 +38,15 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"429": {
"description": "Too Many Requests",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -78,7 +72,7 @@
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.LoginUserResponseBody"
+ "$ref": "#/definitions/auth.LoginResponseBody"
}
}
],
@@ -91,21 +85,15 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -162,27 +150,19 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -210,21 +190,62 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
+ "schema": {}
+ }
+ }
+ }
+ },
+ "/auth/register": {
+ "post": {
+ "description": "Registers a user",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "auth"
+ ],
+ "summary": "Registers a user",
+ "operationId": "register-user",
+ "parameters": [
+ {
+ "description": "User Body",
+ "name": "userBody",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/base.CreateUserRequestBody"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "Created",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "$ref": "#/definitions/models.User"
}
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {}
+ },
+ "404": {
+ "description": "Not Found",
+ "schema": {}
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {}
}
}
}
@@ -263,21 +284,15 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"429": {
"description": "Too Many Requests",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -303,7 +318,7 @@
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.VerifyEmailRequestBody"
+ "$ref": "#/definitions/base.VerifyEmailRequestBody"
}
}
],
@@ -316,21 +331,15 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"429": {
"description": "Too Many Requests",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -361,7 +370,7 @@
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.VerifyPasswordResetTokenRequestBody"
+ "$ref": "#/definitions/base.VerifyPasswordResetTokenRequestBody"
}
}
],
@@ -374,21 +383,15 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"429": {
"description": "Too Many Requests",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -468,7 +471,7 @@
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.CategoryRequestBody"
+ "$ref": "#/definitions/categories.CategoryRequestBody"
}
}
],
@@ -638,7 +641,7 @@
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.CategoryRequestBody"
+ "$ref": "#/definitions/categories.CategoryRequestBody"
}
}
],
@@ -720,21 +723,15 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -775,21 +772,15 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -831,15 +822,11 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
@@ -863,7 +850,7 @@
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.CreateClubRequestBody"
+ "$ref": "#/definitions/base.CreateClubRequestBody"
}
}
],
@@ -876,27 +863,19 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -930,21 +909,15 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
@@ -976,27 +949,19 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
@@ -1027,7 +992,7 @@
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.UpdateClubRequestBody"
+ "$ref": "#/definitions/base.UpdateClubRequestBody"
}
}
],
@@ -1040,27 +1005,19 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -1097,21 +1054,15 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
@@ -1142,7 +1093,7 @@
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.PutContactRequestBody"
+ "$ref": "#/definitions/contacts.PutContactRequestBody"
}
}
],
@@ -1155,27 +1106,19 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -1224,21 +1167,15 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -1287,21 +1224,15 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -1350,27 +1281,124 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
+ "schema": {}
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {}
+ }
+ }
+ },
+ "post": {
+ "description": "Creates a new member associated with a club",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "club-member"
+ ],
+ "summary": "Create a new member for a club",
+ "operationId": "create-member-for-club",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "Club ID",
+ "name": "clubID",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "User ID",
+ "name": "userID",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "Created",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "$ref": "#/definitions/models.User"
}
},
+ "400": {
+ "description": "Bad Request",
+ "schema": {}
+ },
+ "401": {
+ "description": "Unauthorized",
+ "schema": {}
+ },
+ "404": {
+ "description": "Not Found",
+ "schema": {}
+ },
"500": {
"description": "Internal Server Error",
+ "schema": {}
+ }
+ }
+ },
+ "delete": {
+ "description": "Deletes a member associated with a club",
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "club-member"
+ ],
+ "summary": "Delete a member from a club",
+ "operationId": "delete-member-from-club",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "Club ID",
+ "name": "clubID",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "User ID",
+ "name": "userID",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "No Content",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "$ref": "#/definitions/models.User"
}
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {}
+ },
+ "401": {
+ "description": "Unauthorized",
+ "schema": {}
+ },
+ "404": {
+ "description": "Not Found",
+ "schema": {}
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {}
}
}
}
@@ -1407,27 +1435,19 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -1471,27 +1491,19 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
@@ -1527,21 +1539,15 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
@@ -1583,27 +1589,19 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -1640,21 +1638,15 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -1695,21 +1687,15 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -1746,21 +1732,15 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
@@ -1791,7 +1771,7 @@
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.CreateClubTagsRequestBody"
+ "$ref": "#/definitions/tags.CreateClubTagsRequestBody"
}
}
],
@@ -1807,27 +1787,19 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -1868,27 +1840,19 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
@@ -2086,45 +2050,135 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
+ "schema": {}
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {}
+ }
+ }
+ }
+ },
+ "/events/{eventID}/": {
+ "get": {
+ "description": "Retrieves an event",
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "event"
+ ],
+ "summary": "Retrieve an event",
+ "operationId": "get-event",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "Event ID",
+ "name": "eventID",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "$ref": "#/definitions/models.Event"
}
},
+ "400": {
+ "description": "Bad Request",
+ "schema": {}
+ },
+ "404": {
+ "description": "Not Found",
+ "schema": {}
+ },
"500": {
"description": "Internal Server Error",
+ "schema": {}
+ }
+ }
+ }
+ },
+ "/files/": {
+ "get": {
+ "description": "Retrieves all files",
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "file"
+ ],
+ "summary": "Retrieve all files",
+ "operationId": "get-files",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "Limit",
+ "name": "limit",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "Page",
+ "name": "page",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/models.File"
+ }
}
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {}
+ },
+ "401": {
+ "description": "Unauthorized",
+ "schema": {}
+ },
+ "404": {
+ "description": "Not Found",
+ "schema": {}
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {}
}
}
},
"post": {
- "description": "Creates an event",
+ "description": "Creates a file",
"consumes": [
- "application/json"
+ "multipart/form-data"
],
"produces": [
"application/json"
],
"tags": [
- "event"
+ "file"
],
- "summary": "Create an event",
- "operationId": "create-event",
+ "summary": "Create a file",
+ "operationId": "create-file",
"parameters": [
{
- "description": "Event Body",
- "name": "event",
+ "description": "File",
+ "name": "file",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.CreateEventRequestBody"
+ "$ref": "#/definitions/base.CreateFileRequestBody"
}
}
],
@@ -2132,52 +2186,44 @@
"201": {
"description": "Created",
"schema": {
- "$ref": "#/definitions/models.Event"
+ "$ref": "#/definitions/models.File"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
},
- "/events/{eventID}/": {
+ "/files/:fileID": {
"get": {
- "description": "Retrieves an event",
+ "description": "Retrieves a file",
"produces": [
"application/json"
],
"tags": [
- "event"
+ "file"
],
- "summary": "Retrieve an event",
- "operationId": "get-event",
+ "summary": "Retrieve a file",
+ "operationId": "get-file",
"parameters": [
{
"type": "string",
- "description": "Event ID",
- "name": "eventID",
+ "description": "File ID",
+ "name": "fileID",
"in": "path",
"required": true
}
@@ -2186,100 +2232,95 @@
"200": {
"description": "OK",
"schema": {
- "$ref": "#/definitions/models.Event"
+ "$ref": "#/definitions/models.File"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
+ },
+ "401": {
+ "description": "Unauthorized",
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
"delete": {
- "description": "Deletes an event",
+ "description": "Deletes a file",
"produces": [
"application/json"
],
"tags": [
- "event"
+ "file"
],
- "summary": "Delete an event",
- "operationId": "delete-event",
+ "summary": "Delete a file",
+ "operationId": "delete-file",
"parameters": [
{
"type": "string",
- "description": "Event ID",
- "name": "eventID",
+ "description": "File ID",
+ "name": "fileID",
"in": "path",
"required": true
}
],
"responses": {
- "204": {
- "description": "No Content",
+ "201": {
+ "description": "Created",
"schema": {
- "type": "string"
+ "$ref": "#/definitions/models.File"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
},
- "/events/{eventID}/hosts": {
+ "/pocs/": {
"get": {
- "description": "Retrieves all hosts associated with an event",
+ "description": "Retrieves all point of contacts",
"produces": [
"application/json"
],
"tags": [
- "event"
+ "point of contact"
],
- "summary": "Retrieve all hosts by event",
- "operationId": "get-hosts-by-event",
+ "summary": "Retrieve all point of contacts",
+ "operationId": "get-point-of-contacts",
"parameters": [
{
- "type": "string",
- "description": "Event ID",
- "name": "eventID",
- "in": "path",
- "required": true
+ "type": "integer",
+ "description": "Limit",
+ "name": "limit",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "Page",
+ "name": "page",
+ "in": "query"
}
],
"responses": {
@@ -2288,47 +2329,47 @@
"schema": {
"type": "array",
"items": {
- "$ref": "#/definitions/models.Club"
+ "$ref": "#/definitions/models.PointOfContact"
}
}
},
"400": {
"description": "Bad Request",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "type": "string"
}
},
"404": {
"description": "Not Found",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "type": "string"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "type": "string"
}
}
}
}
},
- "/events/{eventID}/series/": {
+ "/pocs/{pocID}/": {
"get": {
- "description": "Retrieves all series associated with an event",
+ "description": "Retrieves a point of contact by id",
"produces": [
"application/json"
],
"tags": [
- "event"
+ "point of contact"
],
- "summary": "Retrieve all series by event",
- "operationId": "get-series-by-event",
+ "summary": "Retrieves a point of contact",
+ "operationId": "get-point-of-contact",
"parameters": [
{
"type": "string",
- "description": "Event ID",
- "name": "eventID",
+ "description": "Point of Contact ID",
+ "name": "pocID",
"in": "path",
"required": true
}
@@ -2337,86 +2378,83 @@
"200": {
"description": "OK",
"schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/models.Series"
- }
+ "$ref": "#/definitions/models.PointOfContact"
}
},
"400": {
"description": "Bad Request",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "type": "string"
}
},
"404": {
"description": "Not Found",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "type": "string"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
- "$ref": "#/definitions/errors.Error"
+ "type": "string"
}
}
}
- },
- "delete": {
- "description": "Deletes all series associated with an event",
+ }
+ },
+ "/tags": {
+ "get": {
+ "description": "Retrieves all tags",
"produces": [
"application/json"
],
"tags": [
- "event"
+ "tag"
],
- "summary": "Delete all series by event",
- "operationId": "delete-series-by-event",
+ "summary": "Retrieve all tags",
+ "operationId": "get-all-tags",
"parameters": [
{
- "type": "string",
- "description": "Event ID",
- "name": "eventID",
- "in": "path",
- "required": true
+ "type": "integer",
+ "description": "Limit",
+ "name": "limit",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "Page",
+ "name": "page",
+ "in": "query"
}
],
"responses": {
- "204": {
- "description": "No Content",
+ "200": {
+ "description": "OK",
"schema": {
- "type": "string"
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/models.Tag"
+ }
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
- },
- "patch": {
- "description": "Creates a series",
+ }
+ },
+ "/tags/": {
+ "post": {
+ "description": "Creates a tag",
"consumes": [
"application/json"
],
@@ -2424,25 +2462,18 @@
"application/json"
],
"tags": [
- "event"
+ "tag"
],
- "summary": "Create a series",
- "operationId": "create-series",
+ "summary": "Create a tag",
+ "operationId": "create-tag",
"parameters": [
{
- "type": "string",
- "description": "Event ID",
- "name": "eventID",
- "in": "path",
- "required": true
- },
- {
- "description": "Series Body",
- "name": "seriesBody",
+ "description": "Tag Body",
+ "name": "tagBody",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.UpdateEventRequestBody"
+ "$ref": "#/definitions/base.CreateTagRequestBody"
}
}
],
@@ -2450,59 +2481,44 @@
"201": {
"description": "Created",
"schema": {
- "$ref": "#/definitions/models.Series"
+ "$ref": "#/definitions/models.Tag"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
},
- "/events/{eventID}/series/{seriesID}/": {
+ "/tags/{tagID}/": {
"get": {
- "description": "Retrieves a series by ID",
+ "description": "Retrieves a tag",
"produces": [
"application/json"
],
"tags": [
- "event"
+ "tag"
],
- "summary": "Retrieve a series by ID",
- "operationId": "get-series-by-id",
+ "summary": "Retrieve a tag",
+ "operationId": "get-tag",
"parameters": [
{
"type": "string",
- "description": "Event ID",
- "name": "eventID",
- "in": "path",
- "required": true
- },
- {
- "type": "string",
- "description": "Series ID",
- "name": "seriesID",
+ "description": "Tag ID",
+ "name": "tagID",
"in": "path",
"required": true
}
@@ -2511,51 +2527,38 @@
"200": {
"description": "OK",
"schema": {
- "$ref": "#/definitions/models.Series"
+ "$ref": "#/definitions/models.Tag"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
"delete": {
- "description": "Deletes a series by ID",
+ "description": "Deletes a tag",
"produces": [
"application/json"
],
"tags": [
- "event"
+ "tag"
],
- "summary": "Delete a series by ID",
- "operationId": "delete-series-by-id",
+ "summary": "Delete a tag",
+ "operationId": "delete-tag",
"parameters": [
{
"type": "string",
- "description": "Event ID",
- "name": "eventID",
- "in": "path",
- "required": true
- },
- {
- "type": "string",
- "description": "Series ID",
- "name": "seriesID",
+ "description": "Tag ID",
+ "name": "tagID",
"in": "path",
"required": true
}
@@ -2569,32 +2572,24 @@
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
"patch": {
- "description": "Updates a series by event ID",
+ "description": "Updates a tag",
"consumes": [
"application/json"
],
@@ -2602,25 +2597,25 @@
"application/json"
],
"tags": [
- "event"
+ "tag"
],
- "summary": "Update a series by event ID",
- "operationId": "update-series-by-event-id",
+ "summary": "Update a tag",
+ "operationId": "update-tag",
"parameters": [
{
"type": "string",
- "description": "Event ID",
- "name": "eventID",
+ "description": "Tag ID",
+ "name": "tagID",
"in": "path",
"required": true
},
{
- "description": "Series Body",
- "name": "seriesBody",
+ "description": "Tag",
+ "name": "tag",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.UpdateSeriesRequestBody"
+ "$ref": "#/definitions/base.UpdateTagRequestBody"
}
}
],
@@ -2628,54 +2623,51 @@
"200": {
"description": "OK",
"schema": {
- "$ref": "#/definitions/models.Series"
+ "$ref": "#/definitions/models.Tag"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
},
- "/events/{eventID}/tags": {
+ "/users/": {
"get": {
- "description": "Retrieves all tags associated with an event",
+ "description": "Retrieves all users",
"produces": [
"application/json"
],
"tags": [
- "event"
+ "user"
],
- "summary": "Retrieve all tags by event",
- "operationId": "get-tags-by-event",
+ "summary": "Retrieve all users",
+ "operationId": "get-users",
"parameters": [
{
- "type": "string",
- "description": "Event ID",
- "name": "eventID",
- "in": "path",
- "required": true
+ "type": "integer",
+ "description": "Limit",
+ "name": "limit",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "Page",
+ "name": "page",
+ "in": "query"
}
],
"responses": {
@@ -2684,383 +2676,340 @@
"schema": {
"type": "array",
"items": {
- "$ref": "#/definitions/models.Tag"
+ "$ref": "#/definitions/models.User"
}
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "401": {
+ "description": "Unauthorized",
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
},
- "/files/": {
+ "/users/{userID}/": {
"get": {
- "description": "Retrieves all files",
+ "description": "Retrieves a user",
"produces": [
"application/json"
],
"tags": [
- "file"
+ "user"
],
- "summary": "Retrieve all files",
- "operationId": "get-files",
+ "summary": "Retrieve a user",
+ "operationId": "get-user",
"parameters": [
{
- "type": "integer",
- "description": "Limit",
- "name": "limit",
- "in": "query"
- },
- {
- "type": "integer",
- "description": "Page",
- "name": "page",
- "in": "query"
+ "type": "string",
+ "description": "User ID",
+ "name": "userID",
+ "in": "path",
+ "required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/models.File"
- }
+ "$ref": "#/definitions/models.User"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
- "post": {
- "description": "Creates a file",
- "consumes": [
- "multipart/form-data"
- ],
+ "delete": {
+ "description": "Deletes a user",
"produces": [
"application/json"
],
"tags": [
- "file"
+ "user"
],
- "summary": "Create a file",
- "operationId": "create-file",
+ "summary": "Delete a user",
+ "operationId": "delete-user",
"parameters": [
{
- "description": "File",
- "name": "file",
- "in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/models.CreateFileRequestBody"
- }
+ "type": "string",
+ "description": "User ID",
+ "name": "userID",
+ "in": "path",
+ "required": true
}
],
"responses": {
- "201": {
- "description": "Created",
+ "204": {
+ "description": "No Content",
"schema": {
- "$ref": "#/definitions/models.File"
+ "type": "string"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
- }
- },
- "/files/:fileID": {
- "get": {
- "description": "Retrieves a file",
+ },
+ "patch": {
+ "description": "Updates a user",
+ "consumes": [
+ "application/json"
+ ],
"produces": [
"application/json"
],
"tags": [
- "file"
+ "user"
],
- "summary": "Retrieve a file",
- "operationId": "get-file",
+ "summary": "Update a user",
+ "operationId": "update-user",
"parameters": [
{
"type": "string",
- "description": "File ID",
- "name": "fileID",
+ "description": "User ID",
+ "name": "userID",
"in": "path",
"required": true
+ },
+ {
+ "description": "User Body",
+ "name": "userBody",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/base.UpdateUserRequestBody"
+ }
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
- "$ref": "#/definitions/models.File"
+ "$ref": "#/definitions/models.User"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
- },
- "delete": {
- "description": "Deletes a file",
+ }
+ },
+ "/users/{userID}/follower/": {
+ "get": {
+ "description": "Retrieves all clubs a user is following",
"produces": [
"application/json"
],
"tags": [
- "file"
+ "user-follower"
],
- "summary": "Delete a file",
- "operationId": "delete-file",
+ "summary": "Retrieve all clubs a user is following",
+ "operationId": "get-following",
"parameters": [
{
"type": "string",
- "description": "File ID",
- "name": "fileID",
+ "description": "User ID",
+ "name": "userID",
"in": "path",
"required": true
}
],
"responses": {
- "201": {
- "description": "Created",
+ "200": {
+ "description": "OK",
"schema": {
- "$ref": "#/definitions/models.File"
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/models.Club"
+ }
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
},
- "/pocs/": {
- "get": {
- "description": "Retrieves all point of contacts",
+ "/users/{userID}/follower/{clubID}/": {
+ "post": {
+ "description": "Follow a club",
+ "consumes": [
+ "application/json"
+ ],
"produces": [
"application/json"
],
"tags": [
- "point of contact"
+ "user-follower"
],
- "summary": "Retrieve all point of contacts",
- "operationId": "get-point-of-contacts",
+ "summary": "Follow a club",
+ "operationId": "create-following",
"parameters": [
{
- "type": "integer",
- "description": "Limit",
- "name": "limit",
- "in": "query"
+ "type": "string",
+ "description": "User ID",
+ "name": "userID",
+ "in": "path",
+ "required": true
},
{
- "type": "integer",
- "description": "Page",
- "name": "page",
- "in": "query"
+ "type": "string",
+ "description": "Club ID",
+ "name": "clubID",
+ "in": "path",
+ "required": true
}
],
"responses": {
- "200": {
- "description": "OK",
+ "201": {
+ "description": "Created",
"schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/models.PointOfContact"
- }
+ "$ref": "#/definitions/utilities.SuccessResponse"
}
},
- "400": {
- "description": "Bad Request",
- "schema": {
- "type": "string"
- }
+ "401": {
+ "description": "Unauthorized",
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "type": "string"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "type": "string"
- }
+ "schema": {}
}
}
- }
- },
- "/pocs/{pocID}/": {
- "get": {
- "description": "Retrieves a point of contact by id",
+ },
+ "delete": {
+ "description": "Unfollow a club",
+ "consumes": [
+ "application/json"
+ ],
"produces": [
"application/json"
],
"tags": [
- "point of contact"
+ "user-follower"
],
- "summary": "Retrieves a point of contact",
- "operationId": "get-point-of-contact",
+ "summary": "Unfollow a club",
+ "operationId": "delete-following",
"parameters": [
{
"type": "string",
- "description": "Point of Contact ID",
- "name": "pocID",
+ "description": "User ID",
+ "name": "userID",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "Club ID",
+ "name": "clubID",
"in": "path",
"required": true
}
],
"responses": {
- "200": {
- "description": "OK",
+ "204": {
+ "description": "No Content",
"schema": {
- "$ref": "#/definitions/models.PointOfContact"
+ "$ref": "#/definitions/utilities.SuccessResponse"
}
},
- "400": {
- "description": "Bad Request",
- "schema": {
- "type": "string"
- }
+ "401": {
+ "description": "Unauthorized",
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "type": "string"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "type": "string"
- }
+ "schema": {}
}
}
}
},
- "/tags": {
+ "/users/{userID}/member/": {
"get": {
- "description": "Retrieves all tags",
+ "description": "Retrieves all clubs a user is a member of",
"produces": [
"application/json"
],
"tags": [
- "tag"
+ "user-member"
],
- "summary": "Retrieve all tags",
- "operationId": "get-all-tags",
+ "summary": "Retrieve all clubs a user is a member of",
+ "operationId": "get-membership",
"parameters": [
{
- "type": "integer",
- "description": "Limit",
- "name": "limit",
- "in": "query"
- },
- {
- "type": "integer",
- "description": "Page",
- "name": "page",
- "in": "query"
+ "type": "string",
+ "description": "User ID",
+ "name": "userID",
+ "in": "path",
+ "required": true
}
],
"responses": {
@@ -3069,34 +3018,32 @@
"schema": {
"type": "array",
"items": {
- "$ref": "#/definitions/models.Tag"
+ "$ref": "#/definitions/models.Club"
}
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
+ },
+ "401": {
+ "description": "Unauthorized",
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
},
- "/tags/": {
- "post": {
- "description": "Creates a tag",
+ "/users/{userID}/password": {
+ "patch": {
+ "description": "Updates a user's password",
"consumes": [
"application/json"
],
@@ -3104,71 +3051,70 @@
"application/json"
],
"tags": [
- "tag"
+ "user"
],
- "summary": "Create a tag",
- "operationId": "create-tag",
+ "summary": "Update a user's password",
+ "operationId": "update-password",
"parameters": [
{
- "description": "Tag Body",
- "name": "tagBody",
+ "type": "string",
+ "description": "User ID",
+ "name": "userID",
+ "in": "path",
+ "required": true
+ },
+ {
+ "description": "Password Body",
+ "name": "passwordBody",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.CreateTagRequestBody"
+ "$ref": "#/definitions/auth.UpdatePasswordRequestBody"
}
}
],
"responses": {
- "201": {
- "description": "Created",
+ "200": {
+ "description": "OK",
"schema": {
- "$ref": "#/definitions/models.Tag"
+ "type": "string"
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
}
},
- "/tags/{tagID}/": {
+ "/users/{userID}/tags/": {
"get": {
- "description": "Retrieves a tag",
+ "description": "Retrieves all tags associated with a user",
"produces": [
"application/json"
],
"tags": [
- "tag"
+ "user-tag"
],
- "summary": "Retrieve a tag",
- "operationId": "get-tag",
+ "summary": "Retrieve all tags for a user",
+ "operationId": "get-tags-by-user",
"parameters": [
{
"type": "string",
- "description": "Tag ID",
- "name": "tagID",
+ "description": "User ID",
+ "name": "userID",
"in": "path",
"required": true
}
@@ -3177,83 +3123,32 @@
"200": {
"description": "OK",
"schema": {
- "$ref": "#/definitions/models.Tag"
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/models.Tag"
+ }
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
+ },
+ "401": {
+ "description": "Unauthorized",
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
- }
- },
- "delete": {
- "description": "Deletes a tag",
- "produces": [
- "application/json"
- ],
- "tags": [
- "tag"
- ],
- "summary": "Delete a tag",
- "operationId": "delete-tag",
- "parameters": [
- {
- "type": "string",
- "description": "Tag ID",
- "name": "tagID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "204": {
- "description": "No Content",
- "schema": {
- "type": "string"
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
- "patch": {
- "description": "Updates a tag",
+ "post": {
+ "description": "Creates tags for a user",
"consumes": [
"application/json"
],
@@ -3261,119 +3156,58 @@
"application/json"
],
"tags": [
- "tag"
+ "user-tag"
],
- "summary": "Update a tag",
- "operationId": "update-tag",
+ "summary": "Create user tags",
+ "operationId": "create-user-tags",
"parameters": [
{
"type": "string",
- "description": "Tag ID",
- "name": "tagID",
+ "description": "User ID",
+ "name": "userID",
"in": "path",
"required": true
},
{
- "description": "Tag",
- "name": "tag",
+ "description": "User Tags Body",
+ "name": "userTagsBody",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/models.UpdateTagRequestBody"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "$ref": "#/definitions/models.Tag"
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
+ "$ref": "#/definitions/tags.CreateUserTagsBody"
}
}
- }
- }
- },
- "/users/": {
- "get": {
- "description": "Retrieves all users",
- "produces": [
- "application/json"
- ],
- "tags": [
- "user"
- ],
- "summary": "Retrieve all users",
- "operationId": "get-users",
- "parameters": [
- {
- "type": "integer",
- "description": "Limit",
- "name": "limit",
- "in": "query"
- },
- {
- "type": "integer",
- "description": "Page",
- "name": "page",
- "in": "query"
- }
],
"responses": {
- "200": {
- "description": "OK",
+ "201": {
+ "description": "Created",
"schema": {
"type": "array",
"items": {
- "$ref": "#/definitions/models.User"
+ "$ref": "#/definitions/models.Tag"
}
}
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
+ },
+ "404": {
+ "description": "Not Found",
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
},
- "post": {
- "description": "Creates a user",
+ "delete": {
+ "description": "Creates tags for a user",
"consumes": [
"application/json"
],
@@ -3381,72 +3215,10 @@
"application/json"
],
"tags": [
- "user"
- ],
- "summary": "Create a user",
- "operationId": "create-user",
- "parameters": [
- {
- "description": "User Body",
- "name": "userBody",
- "in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/models.CreateUserRequestBody"
- }
- }
- ],
- "responses": {
- "201": {
- "description": "Created",
- "schema": {
- "$ref": "#/definitions/models.User"
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "409": {
- "description": "Conflict",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
- }
- }
- },
- "/users/{userID}/": {
- "get": {
- "description": "Retrieves a user",
- "produces": [
- "application/json"
- ],
- "tags": [
- "user"
+ "user-tag"
],
- "summary": "Retrieve a user",
- "operationId": "get-user",
+ "summary": "Create user tags",
+ "operationId": "create-user-tags",
"parameters": [
{
"type": "string",
@@ -3457,1254 +3229,801 @@
}
],
"responses": {
- "200": {
- "description": "OK",
- "schema": {
- "$ref": "#/definitions/models.User"
- }
+ "201": {
+ "description": "Created"
},
"400": {
"description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"401": {
"description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"404": {
"description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
},
"500": {
"description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
+ "schema": {}
}
}
- },
- "delete": {
- "description": "Deletes a user",
- "produces": [
- "application/json"
- ],
- "tags": [
- "user"
- ],
- "summary": "Delete a user",
- "operationId": "delete-user",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "204": {
- "description": "No Content",
- "schema": {
- "type": "string"
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
+ }
+ }
+ },
+ "definitions": {
+ "auth.LoginResponseBody": {
+ "type": "object",
+ "required": [
+ "email",
+ "password"
+ ],
+ "properties": {
+ "email": {
+ "type": "string"
+ },
+ "password": {
+ "description": "MARK: must be validated manually",
+ "type": "string",
+ "maxLength": 255
}
- },
- "patch": {
- "description": "Updates a user",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "user"
- ],
- "summary": "Update a user",
- "operationId": "update-user",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- },
- {
- "description": "User Body",
- "name": "userBody",
- "in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/models.UpdateUserRequestBody"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "$ref": "#/definitions/models.User"
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
+ }
+ },
+ "auth.UpdatePasswordRequestBody": {
+ "type": "object",
+ "required": [
+ "new_password",
+ "old_password"
+ ],
+ "properties": {
+ "new_password": {
+ "description": "MARK: must be validated manually",
+ "type": "string",
+ "maxLength": 255
+ },
+ "old_password": {
+ "description": "MARK: must be validated manually",
+ "type": "string",
+ "maxLength": 255
}
}
},
- "/users/{userID}/follower/": {
- "get": {
- "description": "Retrieves all clubs a user is following",
- "produces": [
- "application/json"
- ],
- "tags": [
- "user-follower"
- ],
- "summary": "Retrieve all clubs a user is following",
- "operationId": "get-following",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/models.Club"
- }
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
+ "base.CreateClubRequestBody": {
+ "type": "object",
+ "required": [
+ "application_link",
+ "description",
+ "is_recruiting",
+ "name",
+ "preview",
+ "recruitment_cycle",
+ "recruitment_type",
+ "user_id"
+ ],
+ "properties": {
+ "application_link": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "is_recruiting": {
+ "type": "boolean"
+ },
+ "logo": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "one_word_to_describe_us": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "preview": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "recruitment_cycle": {
+ "maxLength": 255,
+ "enum": [
+ "fall",
+ "spring",
+ "fallSpring",
+ "always"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.RecruitmentCycle"
}
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
+ ]
+ },
+ "recruitment_type": {
+ "maxLength": 255,
+ "enum": [
+ "unrestricted",
+ "tryout",
+ "application"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.RecruitmentType"
}
- }
+ ]
+ },
+ "user_id": {
+ "type": "string"
+ },
+ "weekly_time_commitment": {
+ "type": "integer",
+ "minimum": 1
}
}
},
- "/users/{userID}/follower/{clubID}/": {
- "post": {
- "description": "Follow a club",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "user-follower"
- ],
- "summary": "Follow a club",
- "operationId": "create-following",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- },
- {
- "type": "string",
- "description": "Club ID",
- "name": "clubID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "201": {
- "description": "Created",
- "schema": {
- "$ref": "#/definitions/utilities.SuccessResponse"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
- }
- },
- "delete": {
- "description": "Unfollow a club",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "user-follower"
- ],
- "summary": "Unfollow a club",
- "operationId": "delete-following",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- },
- {
- "type": "string",
- "description": "Club ID",
- "name": "clubID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "204": {
- "description": "No Content",
- "schema": {
- "$ref": "#/definitions/utilities.SuccessResponse"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
+ "base.CreateFileRequestBody": {
+ "type": "object",
+ "required": [
+ "owner_id",
+ "owner_type"
+ ],
+ "properties": {
+ "owner_id": {
+ "type": "string"
+ },
+ "owner_type": {
+ "type": "string",
+ "maxLength": 255
}
}
},
- "/users/{userID}/member/": {
- "get": {
- "description": "Retrieves all clubs a user is a member of",
- "produces": [
- "application/json"
- ],
- "tags": [
- "user-member"
- ],
- "summary": "Retrieve all clubs a user is a member of",
- "operationId": "get-membership",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/models.Club"
- }
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
+ "base.CreateTagRequestBody": {
+ "type": "object",
+ "required": [
+ "category_id",
+ "name"
+ ],
+ "properties": {
+ "category_id": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255
}
}
},
- "/users/{userID}/member/{clubID}/": {
- "post": {
- "description": "Join a club",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "user-member"
- ],
- "summary": "Join a club",
- "operationId": "create-membership",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- },
- {
- "type": "string",
- "description": "Club ID",
- "name": "clubID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "201": {
- "description": "Created",
- "schema": {
- "$ref": "#/definitions/utilities.SuccessResponse"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
+ "base.CreateUserRequestBody": {
+ "type": "object",
+ "required": [
+ "email",
+ "first_name",
+ "last_name",
+ "password"
+ ],
+ "properties": {
+ "college": {
+ "enum": [
+ "CAMD",
+ "DMSB",
+ "KCCS",
+ "CE",
+ "BCHS",
+ "SL",
+ "CPS",
+ "CS",
+ "CSSH"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.College"
}
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
+ ]
+ },
+ "email": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "first_name": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "graduation_cycle": {
+ "maxLength": 255,
+ "enum": [
+ "december",
+ "may"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.GraduationCycle"
}
- }
- }
- },
- "delete": {
- "description": "Leave a club",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "user-member"
- ],
- "summary": "Leave a club",
- "operationId": "delete-membership",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- },
- {
- "type": "string",
- "description": "Club ID",
- "name": "clubID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "204": {
- "description": "No Content",
- "schema": {
- "$ref": "#/definitions/utilities.SuccessResponse"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
+ ]
+ },
+ "graduation_year": {
+ "type": "integer"
+ },
+ "last_name": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "major0": {
+ "description": "Optional fields",
+ "maxLength": 255,
+ "enum": [
+ "africanaStudies",
+ "americanSignLanguage",
+ "americanSignLanguage-EnglishInterpreting",
+ "appliedPhysics",
+ "architecturalStudies",
+ "architecture",
+ "art:ArtVisualStudies",
+ "behavioralNeuroscience",
+ "biochemistry",
+ "bioengineering",
+ "biology",
+ "biomedicalPhysics",
+ "businessAdministration",
+ "businessAdministration:Accounting",
+ "businessAdministration:AccountingAndAdvisoryServices",
+ "businessAdministration:BrandManagement",
+ "businessAdministration:BusinessAnalytics",
+ "businessAdministration:CorporateInnovation",
+ "businessAdministration:EntrepreneurialStartups",
+ "businessAdministration:FamilyBusiness",
+ "businessAdministration:Finance",
+ "businessAdministration:Fintech",
+ "businessAdministration:HealthcareManagementAndConsulting",
+ "businessAdministration:Management",
+ "businessAdministration:ManagementInformationSystems",
+ "businessAdministration:Marketing",
+ "businessAdministration:MarketingAnalytics",
+ "businessAdministration:SocialInnovationAndEntrepreneurship",
+ "businessAdministration:SupplyChainManagement",
+ "cellAndMolecularBiology",
+ "chemicalEngineering",
+ "chemistry",
+ "civilEngineering",
+ "communicationStudies",
+ "computerEngineering",
+ "computerScience",
+ "computingAndLaw",
+ "criminologyAndCriminalJustice",
+ "culturalAnthropology",
+ "cybersecurity",
+ "dataScience",
+ "design",
+ "economics",
+ "electricalEngineering",
+ "english",
+ "environmentalAndSustainabilityStudies",
+ "environmentalEngineering",
+ "environmentalScience",
+ "environmentalStudies",
+ "gameArtAndAnimation",
+ "gameDesign",
+ "globalAsianStudies",
+ "healthScience",
+ "history",
+ "historyCultureAndLaw",
+ "humanServices",
+ "industrialEngineering",
+ "internationalAffairs",
+ "internationalBusiness",
+ "internationalBusiness:Accounting",
+ "internationalBusiness:AccountingAndAdvisoryServices",
+ "internationalBusiness:BrandManagement",
+ "internationalBusiness:BusinessAnalytics",
+ "internationalBusiness:CorporateInnovation",
+ "internationalBusiness:EntrepreneurialStartups",
+ "internationalBusiness:FamilyBusiness",
+ "internationalBusiness:Finance",
+ "internationalBusiness:Fintech",
+ "internationalBusiness:HealthcareManagementAndConsulting",
+ "internationalBusiness:Management",
+ "internationalBusiness:ManagementInformationSystems",
+ "internationalBusiness:Marketing",
+ "internationalBusiness:MarketingAnalytics",
+ "internationalBusiness:SocialInnovationAndEntrepreneurship",
+ "internationalBusiness:SupplyChainManagement",
+ "journalism",
+ "landscapeArchitecture",
+ "linguistics",
+ "marineBiology",
+ "mathematics",
+ "mechanicalEngineering",
+ "mediaAndScreenStudies",
+ "mediaArts",
+ "music",
+ "musicTechnology",
+ "nursing",
+ "pharmaceuticalSciences",
+ "pharmacy(PharmD)",
+ "philosophy",
+ "physics",
+ "politicalScience",
+ "politicsPhilosophyEconomics",
+ "psychology",
+ "publicHealth",
+ "publicRelations",
+ "religiousStudies",
+ "sociology",
+ "spanish",
+ "speechLanguagePathologyAndAudiology",
+ "theatre"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.Major"
}
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
+ ]
+ },
+ "major1": {
+ "maxLength": 255,
+ "enum": [
+ "africanaStudies",
+ "americanSignLanguage",
+ "americanSignLanguage-EnglishInterpreting",
+ "appliedPhysics",
+ "architecturalStudies",
+ "architecture",
+ "art:ArtVisualStudies",
+ "behavioralNeuroscience",
+ "biochemistry",
+ "bioengineering",
+ "biology",
+ "biomedicalPhysics",
+ "businessAdministration",
+ "businessAdministration:Accounting",
+ "businessAdministration:AccountingAndAdvisoryServices",
+ "businessAdministration:BrandManagement",
+ "businessAdministration:BusinessAnalytics",
+ "businessAdministration:CorporateInnovation",
+ "businessAdministration:EntrepreneurialStartups",
+ "businessAdministration:FamilyBusiness",
+ "businessAdministration:Finance",
+ "businessAdministration:Fintech",
+ "businessAdministration:HealthcareManagementAndConsulting",
+ "businessAdministration:Management",
+ "businessAdministration:ManagementInformationSystems",
+ "businessAdministration:Marketing",
+ "businessAdministration:MarketingAnalytics",
+ "businessAdministration:SocialInnovationAndEntrepreneurship",
+ "businessAdministration:SupplyChainManagement",
+ "cellAndMolecularBiology",
+ "chemicalEngineering",
+ "chemistry",
+ "civilEngineering",
+ "communicationStudies",
+ "computerEngineering",
+ "computerScience",
+ "computingAndLaw",
+ "criminologyAndCriminalJustice",
+ "culturalAnthropology",
+ "cybersecurity",
+ "dataScience",
+ "design",
+ "economics",
+ "electricalEngineering",
+ "english",
+ "environmentalAndSustainabilityStudies",
+ "environmentalEngineering",
+ "environmentalScience",
+ "environmentalStudies",
+ "gameArtAndAnimation",
+ "gameDesign",
+ "globalAsianStudies",
+ "healthScience",
+ "history",
+ "historyCultureAndLaw",
+ "humanServices",
+ "industrialEngineering",
+ "internationalAffairs",
+ "internationalBusiness",
+ "internationalBusiness:Accounting",
+ "internationalBusiness:AccountingAndAdvisoryServices",
+ "internationalBusiness:BrandManagement",
+ "internationalBusiness:BusinessAnalytics",
+ "internationalBusiness:CorporateInnovation",
+ "internationalBusiness:EntrepreneurialStartups",
+ "internationalBusiness:FamilyBusiness",
+ "internationalBusiness:Finance",
+ "internationalBusiness:Fintech",
+ "internationalBusiness:HealthcareManagementAndConsulting",
+ "internationalBusiness:Management",
+ "internationalBusiness:ManagementInformationSystems",
+ "internationalBusiness:Marketing",
+ "internationalBusiness:MarketingAnalytics",
+ "internationalBusiness:SocialInnovationAndEntrepreneurship",
+ "internationalBusiness:SupplyChainManagement",
+ "journalism",
+ "landscapeArchitecture",
+ "linguistics",
+ "marineBiology",
+ "mathematics",
+ "mechanicalEngineering",
+ "mediaAndScreenStudies",
+ "mediaArts",
+ "music",
+ "musicTechnology",
+ "nursing",
+ "pharmaceuticalSciences",
+ "pharmacy(PharmD)",
+ "philosophy",
+ "physics",
+ "politicalScience",
+ "politicsPhilosophyEconomics",
+ "psychology",
+ "publicHealth",
+ "publicRelations",
+ "religiousStudies",
+ "sociology",
+ "spanish",
+ "speechLanguagePathologyAndAudiology",
+ "theatre"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.Major"
}
- }
- }
- }
- },
- "/users/{userID}/password": {
- "patch": {
- "description": "Updates a user's password",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "user"
- ],
- "summary": "Update a user's password",
- "operationId": "update-password",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- },
- {
- "description": "Password Body",
- "name": "passwordBody",
- "in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/models.UpdatePasswordRequestBody"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "type": "string"
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
+ ]
+ },
+ "major2": {
+ "maxLength": 255,
+ "enum": [
+ "africanaStudies",
+ "americanSignLanguage",
+ "americanSignLanguage-EnglishInterpreting",
+ "appliedPhysics",
+ "architecturalStudies",
+ "architecture",
+ "art:ArtVisualStudies",
+ "behavioralNeuroscience",
+ "biochemistry",
+ "bioengineering",
+ "biology",
+ "biomedicalPhysics",
+ "businessAdministration",
+ "businessAdministration:Accounting",
+ "businessAdministration:AccountingAndAdvisoryServices",
+ "businessAdministration:BrandManagement",
+ "businessAdministration:BusinessAnalytics",
+ "businessAdministration:CorporateInnovation",
+ "businessAdministration:EntrepreneurialStartups",
+ "businessAdministration:FamilyBusiness",
+ "businessAdministration:Finance",
+ "businessAdministration:Fintech",
+ "businessAdministration:HealthcareManagementAndConsulting",
+ "businessAdministration:Management",
+ "businessAdministration:ManagementInformationSystems",
+ "businessAdministration:Marketing",
+ "businessAdministration:MarketingAnalytics",
+ "businessAdministration:SocialInnovationAndEntrepreneurship",
+ "businessAdministration:SupplyChainManagement",
+ "cellAndMolecularBiology",
+ "chemicalEngineering",
+ "chemistry",
+ "civilEngineering",
+ "communicationStudies",
+ "computerEngineering",
+ "computerScience",
+ "computingAndLaw",
+ "criminologyAndCriminalJustice",
+ "culturalAnthropology",
+ "cybersecurity",
+ "dataScience",
+ "design",
+ "economics",
+ "electricalEngineering",
+ "english",
+ "environmentalAndSustainabilityStudies",
+ "environmentalEngineering",
+ "environmentalScience",
+ "environmentalStudies",
+ "gameArtAndAnimation",
+ "gameDesign",
+ "globalAsianStudies",
+ "healthScience",
+ "history",
+ "historyCultureAndLaw",
+ "humanServices",
+ "industrialEngineering",
+ "internationalAffairs",
+ "internationalBusiness",
+ "internationalBusiness:Accounting",
+ "internationalBusiness:AccountingAndAdvisoryServices",
+ "internationalBusiness:BrandManagement",
+ "internationalBusiness:BusinessAnalytics",
+ "internationalBusiness:CorporateInnovation",
+ "internationalBusiness:EntrepreneurialStartups",
+ "internationalBusiness:FamilyBusiness",
+ "internationalBusiness:Finance",
+ "internationalBusiness:Fintech",
+ "internationalBusiness:HealthcareManagementAndConsulting",
+ "internationalBusiness:Management",
+ "internationalBusiness:ManagementInformationSystems",
+ "internationalBusiness:Marketing",
+ "internationalBusiness:MarketingAnalytics",
+ "internationalBusiness:SocialInnovationAndEntrepreneurship",
+ "internationalBusiness:SupplyChainManagement",
+ "journalism",
+ "landscapeArchitecture",
+ "linguistics",
+ "marineBiology",
+ "mathematics",
+ "mechanicalEngineering",
+ "mediaAndScreenStudies",
+ "mediaArts",
+ "music",
+ "musicTechnology",
+ "nursing",
+ "pharmaceuticalSciences",
+ "pharmacy(PharmD)",
+ "philosophy",
+ "physics",
+ "politicalScience",
+ "politicsPhilosophyEconomics",
+ "psychology",
+ "publicHealth",
+ "publicRelations",
+ "religiousStudies",
+ "sociology",
+ "spanish",
+ "speechLanguagePathologyAndAudiology",
+ "theatre"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.Major"
}
- }
+ ]
+ },
+ "password": {
+ "description": "MARK: must be validated manually",
+ "type": "string",
+ "maxLength": 255
}
}
},
- "/users/{userID}/tags/": {
- "get": {
- "description": "Retrieves all tags associated with a user",
- "produces": [
- "application/json"
- ],
- "tags": [
- "user-tag"
- ],
- "summary": "Retrieve all tags for a user",
- "operationId": "get-tags-by-user",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "200": {
- "description": "OK",
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/models.Tag"
- }
+ "base.UpdateClubRequestBody": {
+ "type": "object",
+ "required": [
+ "application_link",
+ "recruitment_cycle",
+ "recruitment_type"
+ ],
+ "properties": {
+ "application_link": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "is_recruiting": {
+ "type": "boolean"
+ },
+ "logo": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "one_word_to_describe_us": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "preview": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "recruitment_cycle": {
+ "maxLength": 255,
+ "enum": [
+ "fall",
+ "spring",
+ "fallSpring",
+ "always"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.RecruitmentCycle"
}
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
+ ]
+ },
+ "recruitment_type": {
+ "maxLength": 255,
+ "enum": [
+ "unrestricted",
+ "tryout",
+ "application"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.RecruitmentType"
}
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
- }
- },
- "post": {
- "description": "Creates tags for a user",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "user-tag"
- ],
- "summary": "Create user tags",
- "operationId": "create-user-tags",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- },
- {
- "description": "User Tags Body",
- "name": "userTagsBody",
- "in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/tag.CreateUserTagsBody"
- }
- }
- ],
- "responses": {
- "201": {
- "description": "Created",
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/models.Tag"
- }
- }
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
- }
- },
- "delete": {
- "description": "Creates tags for a user",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "user-tag"
- ],
- "summary": "Create user tags",
- "operationId": "create-user-tags",
- "parameters": [
- {
- "type": "string",
- "description": "User ID",
- "name": "userID",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "201": {
- "description": "Created"
- },
- "400": {
- "description": "Bad Request",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "401": {
- "description": "Unauthorized",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "404": {
- "description": "Not Found",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- },
- "500": {
- "description": "Internal Server Error",
- "schema": {
- "$ref": "#/definitions/errors.Error"
- }
- }
- }
- }
- }
- },
- "definitions": {
- "errors.Error": {
- "type": "object",
- "properties": {
- "message": {
- "type": "string"
+ ]
},
- "statusCode": {
- "type": "integer"
+ "weekly_time_commitment": {
+ "type": "integer",
+ "minimum": 1
}
}
},
- "models.Category": {
+ "base.UpdateTagRequestBody": {
"type": "object",
- "required": [
- "name"
- ],
"properties": {
- "created_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- },
- "id": {
- "type": "string",
- "example": "123e4567-e89b-12d3-a456-426614174000"
- },
- "name": {
- "type": "string",
- "maxLength": 255
+ "category_id": {
+ "type": "string"
},
- "updated_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- }
- }
- },
- "models.CategoryRequestBody": {
- "type": "object",
- "required": [
- "name"
- ],
- "properties": {
"name": {
"type": "string",
"maxLength": 255
}
}
},
- "models.Club": {
+ "base.UpdateUserRequestBody": {
"type": "object",
- "required": [
- "application_link",
- "description",
- "is_recruiting",
- "name",
- "num_members",
- "preview",
- "recruitment_cycle",
- "recruitment_type"
- ],
"properties": {
- "application_link": {
- "type": "string",
- "maxLength": 255
- },
- "created_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- },
- "description": {
- "type": "string",
- "maxLength": 255
- },
- "id": {
- "type": "string",
- "example": "123e4567-e89b-12d3-a456-426614174000"
- },
- "is_recruiting": {
- "type": "boolean"
- },
- "logo": {
- "type": "string",
- "maxLength": 255
- },
- "name": {
- "type": "string",
- "maxLength": 255
- },
- "num_members": {
- "type": "integer",
- "minimum": 1
- },
- "one_word_to_describe_us": {
- "type": "string",
- "maxLength": 255
- },
- "preview": {
- "type": "string",
- "maxLength": 255
- },
- "recruitment_cycle": {
- "maxLength": 255,
+ "college": {
"enum": [
- "fall",
- "spring",
- "fallSpring",
- "always"
+ "CAMD",
+ "DMSB",
+ "KCCS",
+ "CE",
+ "BCHS",
+ "SL",
+ "CPS",
+ "CS",
+ "CSSH"
],
"allOf": [
{
- "$ref": "#/definitions/models.RecruitmentCycle"
+ "$ref": "#/definitions/models.College"
}
]
},
- "recruitment_type": {
+ "first_name": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "graduation_cycle": {
"maxLength": 255,
"enum": [
- "unrestricted",
- "tryout",
- "application"
+ "december",
+ "may"
],
"allOf": [
{
- "$ref": "#/definitions/models.RecruitmentType"
+ "$ref": "#/definitions/models.GraduationCycle"
}
]
},
- "updated_at": {
+ "graduation_year": {
+ "type": "integer"
+ },
+ "last_name": {
"type": "string",
- "example": "2023-09-20T16:34:50Z"
+ "maxLength": 255
},
- "weekly_time_commitment": {
- "type": "integer",
- "minimum": 1
- }
- }
- },
- "models.College": {
- "type": "string",
- "enum": [
- "CAMD",
- "DMSB",
- "KCCS",
- "CE",
- "BCHS",
- "SL",
- "CPS",
- "CS",
- "CSSH"
- ],
- "x-enum-comments": {
- "BCHS": "Bouvé College of Health Sciences",
- "CAMD": "College of Arts, Media and Design",
- "CE": "College of Engineering",
- "CPS": "College of Professional Studies",
- "CS": "College of Science",
- "CSSH": "College of Social Sciences and Humanities",
- "DMSB": "D'Amore-McKim School of Business",
- "KCCS": "Khoury College of Computer Sciences",
- "SL": "School of Law"
- },
- "x-enum-varnames": [
- "CAMD",
- "DMSB",
- "KCCS",
- "CE",
- "BCHS",
- "SL",
- "CPS",
- "CS",
- "CSSH"
- ]
- },
- "models.Contact": {
- "type": "object",
- "required": [
- "content",
- "type"
- ],
- "properties": {
- "content": {
- "type": "string",
- "maxLength": 255
- },
- "created_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- },
- "id": {
- "type": "string",
- "example": "123e4567-e89b-12d3-a456-426614174000"
- },
- "type": {
+ "major0": {
"maxLength": 255,
"enum": [
- "facebook",
- "instagram",
- "x",
- "linkedin",
- "youtube",
- "github",
- "slack",
- "discord",
- "email",
- "customSite"
+ "africanaStudies",
+ "americanSignLanguage",
+ "americanSignLanguage-EnglishInterpreting",
+ "appliedPhysics",
+ "architecturalStudies",
+ "architecture",
+ "art:ArtVisualStudies",
+ "behavioralNeuroscience",
+ "biochemistry",
+ "bioengineering",
+ "biology",
+ "biomedicalPhysics",
+ "businessAdministration",
+ "businessAdministration:Accounting",
+ "businessAdministration:AccountingAndAdvisoryServices",
+ "businessAdministration:BrandManagement",
+ "businessAdministration:BusinessAnalytics",
+ "businessAdministration:CorporateInnovation",
+ "businessAdministration:EntrepreneurialStartups",
+ "businessAdministration:FamilyBusiness",
+ "businessAdministration:Finance",
+ "businessAdministration:Fintech",
+ "businessAdministration:HealthcareManagementAndConsulting",
+ "businessAdministration:Management",
+ "businessAdministration:ManagementInformationSystems",
+ "businessAdministration:Marketing",
+ "businessAdministration:MarketingAnalytics",
+ "businessAdministration:SocialInnovationAndEntrepreneurship",
+ "businessAdministration:SupplyChainManagement",
+ "cellAndMolecularBiology",
+ "chemicalEngineering",
+ "chemistry",
+ "civilEngineering",
+ "communicationStudies",
+ "computerEngineering",
+ "computerScience",
+ "computingAndLaw",
+ "criminologyAndCriminalJustice",
+ "culturalAnthropology",
+ "cybersecurity",
+ "dataScience",
+ "design",
+ "economics",
+ "electricalEngineering",
+ "english",
+ "environmentalAndSustainabilityStudies",
+ "environmentalEngineering",
+ "environmentalScience",
+ "environmentalStudies",
+ "gameArtAndAnimation",
+ "gameDesign",
+ "globalAsianStudies",
+ "healthScience",
+ "history",
+ "historyCultureAndLaw",
+ "humanServices",
+ "industrialEngineering",
+ "internationalAffairs",
+ "internationalBusiness",
+ "internationalBusiness:Accounting",
+ "internationalBusiness:AccountingAndAdvisoryServices",
+ "internationalBusiness:BrandManagement",
+ "internationalBusiness:BusinessAnalytics",
+ "internationalBusiness:CorporateInnovation",
+ "internationalBusiness:EntrepreneurialStartups",
+ "internationalBusiness:FamilyBusiness",
+ "internationalBusiness:Finance",
+ "internationalBusiness:Fintech",
+ "internationalBusiness:HealthcareManagementAndConsulting",
+ "internationalBusiness:Management",
+ "internationalBusiness:ManagementInformationSystems",
+ "internationalBusiness:Marketing",
+ "internationalBusiness:MarketingAnalytics",
+ "internationalBusiness:SocialInnovationAndEntrepreneurship",
+ "internationalBusiness:SupplyChainManagement",
+ "journalism",
+ "landscapeArchitecture",
+ "linguistics",
+ "marineBiology",
+ "mathematics",
+ "mechanicalEngineering",
+ "mediaAndScreenStudies",
+ "mediaArts",
+ "music",
+ "musicTechnology",
+ "nursing",
+ "pharmaceuticalSciences",
+ "pharmacy(PharmD)",
+ "philosophy",
+ "physics",
+ "politicalScience",
+ "politicsPhilosophyEconomics",
+ "psychology",
+ "publicHealth",
+ "publicRelations",
+ "religiousStudies",
+ "sociology",
+ "spanish",
+ "speechLanguagePathologyAndAudiology",
+ "theatre"
],
"allOf": [
{
- "$ref": "#/definitions/models.ContactType"
+ "$ref": "#/definitions/models.Major"
}
]
},
- "updated_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- }
- }
- },
- "models.ContactType": {
- "type": "string",
- "enum": [
- "facebook",
- "instagram",
- "x",
- "linkedin",
- "youtube",
- "github",
- "slack",
- "discord",
- "email",
- "customSite"
- ],
- "x-enum-varnames": [
- "Facebook",
- "Instagram",
- "X",
- "LinkedIn",
- "YouTube",
- "GitHub",
- "Slack",
- "Discord",
- "Email",
- "CustomSite"
- ]
- },
- "models.CreateClubRequestBody": {
- "type": "object",
- "required": [
- "application_link",
- "description",
- "is_recruiting",
- "name",
- "preview",
- "recruitment_cycle",
- "recruitment_type",
- "user_id"
- ],
- "properties": {
- "application_link": {
- "type": "string",
- "maxLength": 255
- },
- "description": {
- "type": "string",
- "maxLength": 255
- },
- "is_recruiting": {
- "type": "boolean"
- },
- "logo": {
- "type": "string",
- "maxLength": 255
- },
- "name": {
- "type": "string",
- "maxLength": 255
- },
- "one_word_to_describe_us": {
- "type": "string",
- "maxLength": 255
- },
- "preview": {
- "type": "string",
- "maxLength": 255
- },
- "recruitment_cycle": {
- "maxLength": 255,
- "enum": [
- "fall",
- "spring",
- "fallSpring",
- "always"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.RecruitmentCycle"
- }
- ]
- },
- "recruitment_type": {
- "maxLength": 255,
- "enum": [
- "unrestricted",
- "tryout",
- "application"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.RecruitmentType"
- }
- ]
- },
- "user_id": {
- "type": "string"
- },
- "weekly_time_commitment": {
- "type": "integer",
- "minimum": 1
- }
- }
- },
- "models.CreateClubTagsRequestBody": {
- "type": "object",
- "required": [
- "tags"
- ],
- "properties": {
- "tags": {
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- }
- },
- "models.CreateEventRequestBody": {
- "type": "object",
- "required": [
- "content",
- "end_time",
- "event_type",
- "host",
- "is_recurring",
- "location",
- "name",
- "preview",
- "start_time"
- ],
- "properties": {
- "content": {
- "type": "string",
- "maxLength": 255
- },
- "end_time": {
- "type": "string"
- },
- "event_type": {
- "maxLength": 255,
- "enum": [
- "open",
- "membersOnly"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.EventType"
- }
- ]
- },
- "host": {
- "description": "TODO club/tag/notification logic",
- "type": "string"
- },
- "is_recurring": {
- "type": "boolean"
- },
- "location": {
- "type": "string",
- "maxLength": 255
- },
- "name": {
- "type": "string",
- "maxLength": 255
- },
- "preview": {
- "type": "string",
- "maxLength": 255
- },
- "series": {
- "description": "TODO validate if isRecurring, then series is required",
- "allOf": [
- {
- "$ref": "#/definitions/models.CreateSeriesRequestBody"
- }
- ]
- },
- "start_time": {
- "type": "string"
- }
- }
- },
- "models.CreateFileRequestBody": {
- "type": "object",
- "required": [
- "owner_id",
- "owner_type"
- ],
- "properties": {
- "owner_id": {
- "type": "string"
- },
- "owner_type": {
- "type": "string",
- "maxLength": 255
- }
- }
- },
- "models.CreateSeriesRequestBody": {
- "type": "object",
- "required": [
- "max_occurrences",
- "recurring_type"
- ],
- "properties": {
- "max_occurrences": {
- "type": "integer",
- "minimum": 2
- },
- "recurring_type": {
- "maxLength": 255,
- "enum": [
- "daily",
- "weekly",
- "monthly"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.RecurringType"
- }
- ]
- }
- }
- },
- "models.CreateTagRequestBody": {
- "type": "object",
- "required": [
- "category_id",
- "name"
- ],
- "properties": {
- "category_id": {
- "type": "string"
- },
- "name": {
- "type": "string",
- "maxLength": 255
- }
- }
- },
- "models.CreateUserRequestBody": {
- "type": "object",
- "required": [
- "email",
- "first_name",
- "last_name",
- "password"
- ],
- "properties": {
- "college": {
- "enum": [
- "CAMD",
- "DMSB",
- "KCCS",
- "CE",
- "BCHS",
- "SL",
- "CPS",
- "CS",
- "CSSH"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.College"
- }
- ]
- },
- "email": {
- "type": "string",
- "maxLength": 255
- },
- "first_name": {
- "type": "string",
- "maxLength": 255
- },
- "graduation_cycle": {
- "maxLength": 255,
- "enum": [
- "december",
- "may"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.GraduationCycle"
- }
- ]
- },
- "graduation_year": {
- "type": "integer"
- },
- "last_name": {
- "type": "string",
- "maxLength": 255
- },
- "major0": {
- "description": "Optional fields",
+ "major1": {
"maxLength": 255,
"enum": [
"africanaStudies",
@@ -4814,7 +4133,7 @@
}
]
},
- "major1": {
+ "major2": {
"maxLength": 255,
"enum": [
"africanaStudies",
@@ -4923,241 +4242,212 @@
"$ref": "#/definitions/models.Major"
}
]
+ }
+ }
+ },
+ "base.VerifyEmailRequestBody": {
+ "type": "object",
+ "required": [
+ "email",
+ "token"
+ ],
+ "properties": {
+ "email": {
+ "type": "string"
},
- "major2": {
+ "token": {
+ "type": "string"
+ }
+ }
+ },
+ "base.VerifyPasswordResetTokenRequestBody": {
+ "type": "object",
+ "required": [
+ "new_password",
+ "token",
+ "verify_new_password"
+ ],
+ "properties": {
+ "new_password": {
+ "type": "string",
+ "minLength": 8
+ },
+ "token": {
+ "type": "string"
+ },
+ "verify_new_password": {
+ "type": "string",
+ "minLength": 8
+ }
+ }
+ },
+ "categories.CategoryRequestBody": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "maxLength": 255
+ }
+ }
+ },
+ "contacts.PutContactRequestBody": {
+ "type": "object",
+ "required": [
+ "content",
+ "type"
+ ],
+ "properties": {
+ "content": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "type": {
"maxLength": 255,
"enum": [
- "africanaStudies",
- "americanSignLanguage",
- "americanSignLanguage-EnglishInterpreting",
- "appliedPhysics",
- "architecturalStudies",
- "architecture",
- "art:ArtVisualStudies",
- "behavioralNeuroscience",
- "biochemistry",
- "bioengineering",
- "biology",
- "biomedicalPhysics",
- "businessAdministration",
- "businessAdministration:Accounting",
- "businessAdministration:AccountingAndAdvisoryServices",
- "businessAdministration:BrandManagement",
- "businessAdministration:BusinessAnalytics",
- "businessAdministration:CorporateInnovation",
- "businessAdministration:EntrepreneurialStartups",
- "businessAdministration:FamilyBusiness",
- "businessAdministration:Finance",
- "businessAdministration:Fintech",
- "businessAdministration:HealthcareManagementAndConsulting",
- "businessAdministration:Management",
- "businessAdministration:ManagementInformationSystems",
- "businessAdministration:Marketing",
- "businessAdministration:MarketingAnalytics",
- "businessAdministration:SocialInnovationAndEntrepreneurship",
- "businessAdministration:SupplyChainManagement",
- "cellAndMolecularBiology",
- "chemicalEngineering",
- "chemistry",
- "civilEngineering",
- "communicationStudies",
- "computerEngineering",
- "computerScience",
- "computingAndLaw",
- "criminologyAndCriminalJustice",
- "culturalAnthropology",
- "cybersecurity",
- "dataScience",
- "design",
- "economics",
- "electricalEngineering",
- "english",
- "environmentalAndSustainabilityStudies",
- "environmentalEngineering",
- "environmentalScience",
- "environmentalStudies",
- "gameArtAndAnimation",
- "gameDesign",
- "globalAsianStudies",
- "healthScience",
- "history",
- "historyCultureAndLaw",
- "humanServices",
- "industrialEngineering",
- "internationalAffairs",
- "internationalBusiness",
- "internationalBusiness:Accounting",
- "internationalBusiness:AccountingAndAdvisoryServices",
- "internationalBusiness:BrandManagement",
- "internationalBusiness:BusinessAnalytics",
- "internationalBusiness:CorporateInnovation",
- "internationalBusiness:EntrepreneurialStartups",
- "internationalBusiness:FamilyBusiness",
- "internationalBusiness:Finance",
- "internationalBusiness:Fintech",
- "internationalBusiness:HealthcareManagementAndConsulting",
- "internationalBusiness:Management",
- "internationalBusiness:ManagementInformationSystems",
- "internationalBusiness:Marketing",
- "internationalBusiness:MarketingAnalytics",
- "internationalBusiness:SocialInnovationAndEntrepreneurship",
- "internationalBusiness:SupplyChainManagement",
- "journalism",
- "landscapeArchitecture",
- "linguistics",
- "marineBiology",
- "mathematics",
- "mechanicalEngineering",
- "mediaAndScreenStudies",
- "mediaArts",
- "music",
- "musicTechnology",
- "nursing",
- "pharmaceuticalSciences",
- "pharmacy(PharmD)",
- "philosophy",
- "physics",
- "politicalScience",
- "politicsPhilosophyEconomics",
- "psychology",
- "publicHealth",
- "publicRelations",
- "religiousStudies",
- "sociology",
- "spanish",
- "speechLanguagePathologyAndAudiology",
- "theatre"
+ "facebook",
+ "instagram",
+ "x",
+ "linkedin",
+ "youtube",
+ "github",
+ "slack",
+ "discord",
+ "email",
+ "customSite"
],
"allOf": [
{
- "$ref": "#/definitions/models.Major"
+ "$ref": "#/definitions/models.ContactType"
}
]
- },
- "password": {
- "description": "MARK: must be validated manually",
- "type": "string",
- "maxLength": 255
}
}
},
- "models.Event": {
+ "models.Category": {
"type": "object",
- "required": [
- "content",
- "end_time",
- "event_type",
- "location",
- "name",
- "preview",
- "start_time"
- ],
"properties": {
- "content": {
- "type": "string",
- "maxLength": 255
- },
"created_at": {
"type": "string",
"example": "2023-09-20T16:34:50Z"
},
- "end_time": {
+ "id": {
+ "type": "string",
+ "example": "123e4567-e89b-12d3-a456-426614174000"
+ },
+ "name": {
"type": "string"
},
- "event_type": {
- "maxLength": 255,
- "enum": [
- "open",
- "membersOnly"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.EventType"
- }
- ]
+ "updated_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
+ }
+ }
+ },
+ "models.Club": {
+ "type": "object",
+ "properties": {
+ "application_link": {
+ "type": "string"
},
- "host": {
+ "created_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
+ },
+ "description": {
"type": "string"
},
"id": {
"type": "string",
"example": "123e4567-e89b-12d3-a456-426614174000"
},
- "is_recurring": {
+ "is_recruiting": {
"type": "boolean"
},
- "location": {
- "type": "string",
- "maxLength": 255
- },
- "meeting_link": {
+ "logo": {
"type": "string"
},
"name": {
- "type": "string",
- "maxLength": 255
+ "type": "string"
},
- "preview": {
- "type": "string",
- "maxLength": 255
+ "num_members": {
+ "type": "integer"
},
- "start_time": {
+ "one_word_to_describe_us": {
+ "type": "string"
+ },
+ "preview": {
"type": "string"
},
+ "recruitment_cycle": {
+ "$ref": "#/definitions/models.RecruitmentCycle"
+ },
+ "recruitment_type": {
+ "$ref": "#/definitions/models.RecruitmentType"
+ },
"updated_at": {
"type": "string",
"example": "2023-09-20T16:34:50Z"
+ },
+ "weekly_time_commitment": {
+ "type": "integer"
}
}
},
- "models.EventType": {
+ "models.College": {
"type": "string",
"enum": [
- "open",
- "membersOnly"
+ "CAMD",
+ "DMSB",
+ "KCCS",
+ "CE",
+ "BCHS",
+ "SL",
+ "CPS",
+ "CS",
+ "CSSH"
],
+ "x-enum-comments": {
+ "BCHS": "Bouvé College of Health Sciences",
+ "CAMD": "College of Arts, Media and Design",
+ "CE": "College of Engineering",
+ "CPS": "College of Professional Studies",
+ "CS": "College of Science",
+ "CSSH": "College of Social Sciences and Humanities",
+ "DMSB": "D'Amore-McKim School of Business",
+ "KCCS": "Khoury College of Computer Sciences",
+ "SL": "School of Law"
+ },
"x-enum-varnames": [
- "Open",
- "MembersOnly"
+ "CAMD",
+ "DMSB",
+ "KCCS",
+ "CE",
+ "BCHS",
+ "SL",
+ "CPS",
+ "CS",
+ "CSSH"
]
},
- "models.File": {
+ "models.Contact": {
"type": "object",
- "required": [
- "file_name",
- "file_size",
- "file_type",
- "file_url",
- "object_key"
- ],
"properties": {
+ "content": {
+ "type": "string"
+ },
"created_at": {
"type": "string",
"example": "2023-09-20T16:34:50Z"
},
- "file_name": {
- "type": "string",
- "maxLength": 255
- },
- "file_size": {
- "type": "integer",
- "minimum": 1
- },
- "file_type": {
- "type": "string",
- "maxLength": 255
- },
- "file_url": {
- "type": "string",
- "maxLength": 255
- },
"id": {
"type": "string",
"example": "123e4567-e89b-12d3-a456-426614174000"
},
- "object_key": {
- "type": "string",
- "maxLength": 255
+ "type": {
+ "$ref": "#/definitions/models.ContactType"
},
"updated_at": {
"type": "string",
@@ -5165,34 +4455,150 @@
}
}
},
- "models.GraduationCycle": {
+ "models.ContactType": {
"type": "string",
"enum": [
- "december",
- "may"
+ "facebook",
+ "instagram",
+ "x",
+ "linkedin",
+ "youtube",
+ "github",
+ "slack",
+ "discord",
+ "email",
+ "customSite"
],
"x-enum-varnames": [
- "December",
- "May"
+ "Facebook",
+ "Instagram",
+ "X",
+ "LinkedIn",
+ "YouTube",
+ "GitHub",
+ "Slack",
+ "Discord",
+ "Email",
+ "CustomSite"
]
},
- "models.LoginUserResponseBody": {
+ "models.Event": {
"type": "object",
- "required": [
- "email",
- "password"
+ "properties": {
+ "created_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
+ },
+ "description": {
+ "type": "string"
+ },
+ "end_time": {
+ "type": "string"
+ },
+ "event_type": {
+ "description": "geoshi",
+ "allOf": [
+ {
+ "$ref": "#/definitions/models.EventType"
+ }
+ ]
+ },
+ "host": {
+ "type": "string"
+ },
+ "id": {
+ "type": "string",
+ "example": "123e4567-e89b-12d3-a456-426614174000"
+ },
+ "is_archived": {
+ "type": "boolean"
+ },
+ "is_draft": {
+ "type": "boolean"
+ },
+ "is_public": {
+ "description": "internal housekeeping states",
+ "type": "boolean"
+ },
+ "link": {
+ "type": "string"
+ },
+ "location": {
+ "type": "string"
+ },
+ "name": {
+ "description": "details",
+ "type": "string"
+ },
+ "preview": {
+ "type": "string"
+ },
+ "start_time": {
+ "description": "timing",
+ "type": "string"
+ },
+ "updated_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
+ }
+ }
+ },
+ "models.EventType": {
+ "type": "string",
+ "enum": [
+ "hybrid",
+ "in_person",
+ "virtual"
],
+ "x-enum-varnames": [
+ "Hybrid",
+ "InPerson",
+ "Virtual"
+ ]
+ },
+ "models.File": {
+ "type": "object",
"properties": {
- "email": {
+ "created_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
+ },
+ "file_name": {
"type": "string"
},
- "password": {
- "description": "MARK: must be validated manually",
+ "file_size": {
+ "type": "integer"
+ },
+ "file_type": {
+ "type": "string"
+ },
+ "file_url": {
+ "type": "string"
+ },
+ "id": {
"type": "string",
- "maxLength": 255
+ "example": "123e4567-e89b-12d3-a456-426614174000"
+ },
+ "object_key": {
+ "type": "string"
+ },
+ "updated_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
}
}
},
+ "models.GraduationCycle": {
+ "type": "string",
+ "enum": [
+ "december",
+ "may"
+ ],
+ "x-enum-varnames": [
+ "December",
+ "May"
+ ]
+ },
"models.Major": {
"type": "string",
"enum": [
@@ -5382,1135 +4788,46 @@
"MediaAndScreenStudies",
"MediaArts",
"Music",
- "MusicTechnology",
- "Nursing",
- "PharmaceuticalSciences",
- "PharmacyPharmD",
- "Philosophy",
- "Physics",
- "PoliticalScience",
- "PoliticsPhilosophyEconomics",
- "Psychology",
- "PublicHealth",
- "PublicRelations",
- "ReligiousStudies",
- "Sociology",
- "Spanish",
- "SpeechLanguagePathologyAndAudiology",
- "Theatre"
- ]
- },
- "models.PointOfContact": {
- "type": "object",
- "required": [
- "email",
- "name",
- "position"
- ],
- "properties": {
- "created_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- },
- "email": {
- "type": "string",
- "maxLength": 255
- },
- "id": {
- "type": "string",
- "example": "123e4567-e89b-12d3-a456-426614174000"
- },
- "name": {
- "type": "string",
- "maxLength": 255
- },
- "photo_file": {
- "$ref": "#/definitions/models.File"
- },
- "position": {
- "type": "string",
- "maxLength": 255
- },
- "updated_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- }
- }
- },
- "models.PutContactRequestBody": {
- "type": "object",
- "required": [
- "content",
- "type"
- ],
- "properties": {
- "content": {
- "type": "string",
- "maxLength": 255
- },
- "type": {
- "maxLength": 255,
- "enum": [
- "facebook",
- "instagram",
- "x",
- "linkedin",
- "youtube",
- "github",
- "slack",
- "discord",
- "email",
- "customSite"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.ContactType"
- }
- ]
- }
- }
- },
- "models.RecruitmentCycle": {
- "type": "string",
- "enum": [
- "fall",
- "spring",
- "fallSpring",
- "always"
- ],
- "x-enum-varnames": [
- "Fall",
- "Spring",
- "FallSpring",
- "Always"
- ]
- },
- "models.RecruitmentType": {
- "type": "string",
- "enum": [
- "unrestricted",
- "tryout",
- "application"
- ],
- "x-enum-varnames": [
- "Unrestricted",
- "Tryout",
- "Application"
- ]
- },
- "models.RecurringType": {
- "type": "string",
- "enum": [
- "daily",
- "weekly",
- "monthly"
- ],
- "x-enum-varnames": [
- "Daily",
- "Weekly",
- "Monthly"
- ]
- },
- "models.Series": {
- "type": "object",
- "properties": {
- "created_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- },
- "events": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/models.Event"
- }
- },
- "id": {
- "type": "string",
- "example": "123e4567-e89b-12d3-a456-426614174000"
- },
- "max_occurrences": {
- "type": "integer",
- "minimum": 1
- },
- "recurring_type": {
- "maxLength": 255,
- "allOf": [
- {
- "$ref": "#/definitions/models.RecurringType"
- }
- ]
- },
- "updated_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- }
- }
- },
- "models.Tag": {
- "type": "object",
- "required": [
- "category_id",
- "name"
- ],
- "properties": {
- "category_id": {
- "type": "string"
- },
- "created_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- },
- "id": {
- "type": "string",
- "example": "123e4567-e89b-12d3-a456-426614174000"
- },
- "name": {
- "type": "string",
- "maxLength": 255
- },
- "updated_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- }
- }
- },
- "models.UpdateClubRequestBody": {
- "type": "object",
- "required": [
- "application_link",
- "recruitment_cycle",
- "recruitment_type"
- ],
- "properties": {
- "application_link": {
- "type": "string",
- "maxLength": 255
- },
- "description": {
- "type": "string",
- "maxLength": 255
- },
- "is_recruiting": {
- "type": "boolean"
- },
- "logo": {
- "type": "string",
- "maxLength": 255
- },
- "name": {
- "type": "string",
- "maxLength": 255
- },
- "one_word_to_describe_us": {
- "type": "string",
- "maxLength": 255
- },
- "preview": {
- "type": "string",
- "maxLength": 255
- },
- "recruitment_cycle": {
- "maxLength": 255,
- "enum": [
- "fall",
- "spring",
- "fallSpring",
- "always"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.RecruitmentCycle"
- }
- ]
- },
- "recruitment_type": {
- "maxLength": 255,
- "enum": [
- "unrestricted",
- "tryout",
- "application"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.RecruitmentType"
- }
- ]
- },
- "weekly_time_commitment": {
- "type": "integer",
- "minimum": 1
- }
- }
- },
- "models.UpdateEventRequestBody": {
- "type": "object",
- "properties": {
- "content": {
- "type": "string",
- "maxLength": 255
- },
- "end_time": {
- "type": "string"
- },
- "event_type": {
- "maxLength": 255,
- "enum": [
- "open",
- "membersOnly"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.EventType"
- }
- ]
- },
- "host": {
- "type": "string"
- },
- "location": {
- "type": "string",
- "maxLength": 255
- },
- "name": {
- "type": "string",
- "maxLength": 255
- },
- "preview": {
- "type": "string",
- "maxLength": 255
- },
- "start_time": {
- "type": "string"
- }
- }
- },
- "models.UpdatePasswordRequestBody": {
- "type": "object",
- "required": [
- "new_password",
- "old_password"
- ],
- "properties": {
- "new_password": {
- "description": "MARK: must be validated manually",
- "type": "string",
- "maxLength": 255
- },
- "old_password": {
- "description": "MARK: must be validated manually",
- "type": "string",
- "maxLength": 255
- }
- }
- },
- "models.UpdateSeriesRequestBody": {
- "type": "object",
- "properties": {
- "event_details": {
- "$ref": "#/definitions/models.UpdateEventRequestBody"
- },
- "max_occurrences": {
- "type": "integer",
- "minimum": 2
- },
- "recurring_type": {
- "maxLength": 255,
- "enum": [
- "daily",
- "weekly",
- "monthly"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.RecurringType"
- }
- ]
- }
- }
- },
- "models.UpdateTagRequestBody": {
- "type": "object",
- "properties": {
- "category_id": {
- "type": "string"
- },
- "name": {
- "type": "string",
- "maxLength": 255
- }
- }
- },
- "models.UpdateUserRequestBody": {
- "type": "object",
- "properties": {
- "college": {
- "enum": [
- "CAMD",
- "DMSB",
- "KCCS",
- "CE",
- "BCHS",
- "SL",
- "CPS",
- "CS",
- "CSSH"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.College"
- }
- ]
- },
- "first_name": {
- "type": "string",
- "maxLength": 255
- },
- "graduation_cycle": {
- "maxLength": 255,
- "enum": [
- "december",
- "may"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.GraduationCycle"
- }
- ]
- },
- "graduation_year": {
- "type": "integer"
- },
- "last_name": {
- "type": "string",
- "maxLength": 255
- },
- "major0": {
- "maxLength": 255,
- "enum": [
- "africanaStudies",
- "americanSignLanguage",
- "americanSignLanguage-EnglishInterpreting",
- "appliedPhysics",
- "architecturalStudies",
- "architecture",
- "art:ArtVisualStudies",
- "behavioralNeuroscience",
- "biochemistry",
- "bioengineering",
- "biology",
- "biomedicalPhysics",
- "businessAdministration",
- "businessAdministration:Accounting",
- "businessAdministration:AccountingAndAdvisoryServices",
- "businessAdministration:BrandManagement",
- "businessAdministration:BusinessAnalytics",
- "businessAdministration:CorporateInnovation",
- "businessAdministration:EntrepreneurialStartups",
- "businessAdministration:FamilyBusiness",
- "businessAdministration:Finance",
- "businessAdministration:Fintech",
- "businessAdministration:HealthcareManagementAndConsulting",
- "businessAdministration:Management",
- "businessAdministration:ManagementInformationSystems",
- "businessAdministration:Marketing",
- "businessAdministration:MarketingAnalytics",
- "businessAdministration:SocialInnovationAndEntrepreneurship",
- "businessAdministration:SupplyChainManagement",
- "cellAndMolecularBiology",
- "chemicalEngineering",
- "chemistry",
- "civilEngineering",
- "communicationStudies",
- "computerEngineering",
- "computerScience",
- "computingAndLaw",
- "criminologyAndCriminalJustice",
- "culturalAnthropology",
- "cybersecurity",
- "dataScience",
- "design",
- "economics",
- "electricalEngineering",
- "english",
- "environmentalAndSustainabilityStudies",
- "environmentalEngineering",
- "environmentalScience",
- "environmentalStudies",
- "gameArtAndAnimation",
- "gameDesign",
- "globalAsianStudies",
- "healthScience",
- "history",
- "historyCultureAndLaw",
- "humanServices",
- "industrialEngineering",
- "internationalAffairs",
- "internationalBusiness",
- "internationalBusiness:Accounting",
- "internationalBusiness:AccountingAndAdvisoryServices",
- "internationalBusiness:BrandManagement",
- "internationalBusiness:BusinessAnalytics",
- "internationalBusiness:CorporateInnovation",
- "internationalBusiness:EntrepreneurialStartups",
- "internationalBusiness:FamilyBusiness",
- "internationalBusiness:Finance",
- "internationalBusiness:Fintech",
- "internationalBusiness:HealthcareManagementAndConsulting",
- "internationalBusiness:Management",
- "internationalBusiness:ManagementInformationSystems",
- "internationalBusiness:Marketing",
- "internationalBusiness:MarketingAnalytics",
- "internationalBusiness:SocialInnovationAndEntrepreneurship",
- "internationalBusiness:SupplyChainManagement",
- "journalism",
- "landscapeArchitecture",
- "linguistics",
- "marineBiology",
- "mathematics",
- "mechanicalEngineering",
- "mediaAndScreenStudies",
- "mediaArts",
- "music",
- "musicTechnology",
- "nursing",
- "pharmaceuticalSciences",
- "pharmacy(PharmD)",
- "philosophy",
- "physics",
- "politicalScience",
- "politicsPhilosophyEconomics",
- "psychology",
- "publicHealth",
- "publicRelations",
- "religiousStudies",
- "sociology",
- "spanish",
- "speechLanguagePathologyAndAudiology",
- "theatre"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.Major"
- }
- ]
- },
- "major1": {
- "maxLength": 255,
- "enum": [
- "africanaStudies",
- "americanSignLanguage",
- "americanSignLanguage-EnglishInterpreting",
- "appliedPhysics",
- "architecturalStudies",
- "architecture",
- "art:ArtVisualStudies",
- "behavioralNeuroscience",
- "biochemistry",
- "bioengineering",
- "biology",
- "biomedicalPhysics",
- "businessAdministration",
- "businessAdministration:Accounting",
- "businessAdministration:AccountingAndAdvisoryServices",
- "businessAdministration:BrandManagement",
- "businessAdministration:BusinessAnalytics",
- "businessAdministration:CorporateInnovation",
- "businessAdministration:EntrepreneurialStartups",
- "businessAdministration:FamilyBusiness",
- "businessAdministration:Finance",
- "businessAdministration:Fintech",
- "businessAdministration:HealthcareManagementAndConsulting",
- "businessAdministration:Management",
- "businessAdministration:ManagementInformationSystems",
- "businessAdministration:Marketing",
- "businessAdministration:MarketingAnalytics",
- "businessAdministration:SocialInnovationAndEntrepreneurship",
- "businessAdministration:SupplyChainManagement",
- "cellAndMolecularBiology",
- "chemicalEngineering",
- "chemistry",
- "civilEngineering",
- "communicationStudies",
- "computerEngineering",
- "computerScience",
- "computingAndLaw",
- "criminologyAndCriminalJustice",
- "culturalAnthropology",
- "cybersecurity",
- "dataScience",
- "design",
- "economics",
- "electricalEngineering",
- "english",
- "environmentalAndSustainabilityStudies",
- "environmentalEngineering",
- "environmentalScience",
- "environmentalStudies",
- "gameArtAndAnimation",
- "gameDesign",
- "globalAsianStudies",
- "healthScience",
- "history",
- "historyCultureAndLaw",
- "humanServices",
- "industrialEngineering",
- "internationalAffairs",
- "internationalBusiness",
- "internationalBusiness:Accounting",
- "internationalBusiness:AccountingAndAdvisoryServices",
- "internationalBusiness:BrandManagement",
- "internationalBusiness:BusinessAnalytics",
- "internationalBusiness:CorporateInnovation",
- "internationalBusiness:EntrepreneurialStartups",
- "internationalBusiness:FamilyBusiness",
- "internationalBusiness:Finance",
- "internationalBusiness:Fintech",
- "internationalBusiness:HealthcareManagementAndConsulting",
- "internationalBusiness:Management",
- "internationalBusiness:ManagementInformationSystems",
- "internationalBusiness:Marketing",
- "internationalBusiness:MarketingAnalytics",
- "internationalBusiness:SocialInnovationAndEntrepreneurship",
- "internationalBusiness:SupplyChainManagement",
- "journalism",
- "landscapeArchitecture",
- "linguistics",
- "marineBiology",
- "mathematics",
- "mechanicalEngineering",
- "mediaAndScreenStudies",
- "mediaArts",
- "music",
- "musicTechnology",
- "nursing",
- "pharmaceuticalSciences",
- "pharmacy(PharmD)",
- "philosophy",
- "physics",
- "politicalScience",
- "politicsPhilosophyEconomics",
- "psychology",
- "publicHealth",
- "publicRelations",
- "religiousStudies",
- "sociology",
- "spanish",
- "speechLanguagePathologyAndAudiology",
- "theatre"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.Major"
- }
- ]
- },
- "major2": {
- "maxLength": 255,
- "enum": [
- "africanaStudies",
- "americanSignLanguage",
- "americanSignLanguage-EnglishInterpreting",
- "appliedPhysics",
- "architecturalStudies",
- "architecture",
- "art:ArtVisualStudies",
- "behavioralNeuroscience",
- "biochemistry",
- "bioengineering",
- "biology",
- "biomedicalPhysics",
- "businessAdministration",
- "businessAdministration:Accounting",
- "businessAdministration:AccountingAndAdvisoryServices",
- "businessAdministration:BrandManagement",
- "businessAdministration:BusinessAnalytics",
- "businessAdministration:CorporateInnovation",
- "businessAdministration:EntrepreneurialStartups",
- "businessAdministration:FamilyBusiness",
- "businessAdministration:Finance",
- "businessAdministration:Fintech",
- "businessAdministration:HealthcareManagementAndConsulting",
- "businessAdministration:Management",
- "businessAdministration:ManagementInformationSystems",
- "businessAdministration:Marketing",
- "businessAdministration:MarketingAnalytics",
- "businessAdministration:SocialInnovationAndEntrepreneurship",
- "businessAdministration:SupplyChainManagement",
- "cellAndMolecularBiology",
- "chemicalEngineering",
- "chemistry",
- "civilEngineering",
- "communicationStudies",
- "computerEngineering",
- "computerScience",
- "computingAndLaw",
- "criminologyAndCriminalJustice",
- "culturalAnthropology",
- "cybersecurity",
- "dataScience",
- "design",
- "economics",
- "electricalEngineering",
- "english",
- "environmentalAndSustainabilityStudies",
- "environmentalEngineering",
- "environmentalScience",
- "environmentalStudies",
- "gameArtAndAnimation",
- "gameDesign",
- "globalAsianStudies",
- "healthScience",
- "history",
- "historyCultureAndLaw",
- "humanServices",
- "industrialEngineering",
- "internationalAffairs",
- "internationalBusiness",
- "internationalBusiness:Accounting",
- "internationalBusiness:AccountingAndAdvisoryServices",
- "internationalBusiness:BrandManagement",
- "internationalBusiness:BusinessAnalytics",
- "internationalBusiness:CorporateInnovation",
- "internationalBusiness:EntrepreneurialStartups",
- "internationalBusiness:FamilyBusiness",
- "internationalBusiness:Finance",
- "internationalBusiness:Fintech",
- "internationalBusiness:HealthcareManagementAndConsulting",
- "internationalBusiness:Management",
- "internationalBusiness:ManagementInformationSystems",
- "internationalBusiness:Marketing",
- "internationalBusiness:MarketingAnalytics",
- "internationalBusiness:SocialInnovationAndEntrepreneurship",
- "internationalBusiness:SupplyChainManagement",
- "journalism",
- "landscapeArchitecture",
- "linguistics",
- "marineBiology",
- "mathematics",
- "mechanicalEngineering",
- "mediaAndScreenStudies",
- "mediaArts",
- "music",
- "musicTechnology",
- "nursing",
- "pharmaceuticalSciences",
- "pharmacy(PharmD)",
- "philosophy",
- "physics",
- "politicalScience",
- "politicsPhilosophyEconomics",
- "psychology",
- "publicHealth",
- "publicRelations",
- "religiousStudies",
- "sociology",
- "spanish",
- "speechLanguagePathologyAndAudiology",
- "theatre"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.Major"
- }
- ]
- }
- }
- },
- "models.User": {
- "type": "object",
- "required": [
- "college",
- "email",
- "first_name",
- "graduation_cycle",
- "graduation_year",
- "last_name",
- "major0",
- "role"
- ],
- "properties": {
- "college": {
- "maxLength": 255,
- "allOf": [
- {
- "$ref": "#/definitions/models.College"
- }
- ]
- },
- "created_at": {
- "type": "string",
- "example": "2023-09-20T16:34:50Z"
- },
- "email": {
- "type": "string",
- "maxLength": 255
- },
- "first_name": {
- "type": "string",
- "maxLength": 255
- },
- "graduation_cycle": {
- "maxLength": 255,
- "enum": [
- "december",
- "may"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.GraduationCycle"
- }
- ]
- },
- "graduation_year": {
- "type": "integer"
- },
- "id": {
- "type": "string",
- "example": "123e4567-e89b-12d3-a456-426614174000"
- },
- "is_verified": {
- "type": "boolean"
- },
- "last_name": {
- "type": "string",
- "maxLength": 255
- },
- "major0": {
- "maxLength": 255,
- "enum": [
- "africanaStudies",
- "americanSignLanguage",
- "americanSignLanguage-EnglishInterpreting",
- "appliedPhysics",
- "architecturalStudies",
- "architecture",
- "art:ArtVisualStudies",
- "behavioralNeuroscience",
- "biochemistry",
- "bioengineering",
- "biology",
- "biomedicalPhysics",
- "businessAdministration",
- "businessAdministration:Accounting",
- "businessAdministration:AccountingAndAdvisoryServices",
- "businessAdministration:BrandManagement",
- "businessAdministration:BusinessAnalytics",
- "businessAdministration:CorporateInnovation",
- "businessAdministration:EntrepreneurialStartups",
- "businessAdministration:FamilyBusiness",
- "businessAdministration:Finance",
- "businessAdministration:Fintech",
- "businessAdministration:HealthcareManagementAndConsulting",
- "businessAdministration:Management",
- "businessAdministration:ManagementInformationSystems",
- "businessAdministration:Marketing",
- "businessAdministration:MarketingAnalytics",
- "businessAdministration:SocialInnovationAndEntrepreneurship",
- "businessAdministration:SupplyChainManagement",
- "cellAndMolecularBiology",
- "chemicalEngineering",
- "chemistry",
- "civilEngineering",
- "communicationStudies",
- "computerEngineering",
- "computerScience",
- "computingAndLaw",
- "criminologyAndCriminalJustice",
- "culturalAnthropology",
- "cybersecurity",
- "dataScience",
- "design",
- "economics",
- "electricalEngineering",
- "english",
- "environmentalAndSustainabilityStudies",
- "environmentalEngineering",
- "environmentalScience",
- "environmentalStudies",
- "gameArtAndAnimation",
- "gameDesign",
- "globalAsianStudies",
- "healthScience",
- "history",
- "historyCultureAndLaw",
- "humanServices",
- "industrialEngineering",
- "internationalAffairs",
- "internationalBusiness",
- "internationalBusiness:Accounting",
- "internationalBusiness:AccountingAndAdvisoryServices",
- "internationalBusiness:BrandManagement",
- "internationalBusiness:BusinessAnalytics",
- "internationalBusiness:CorporateInnovation",
- "internationalBusiness:EntrepreneurialStartups",
- "internationalBusiness:FamilyBusiness",
- "internationalBusiness:Finance",
- "internationalBusiness:Fintech",
- "internationalBusiness:HealthcareManagementAndConsulting",
- "internationalBusiness:Management",
- "internationalBusiness:ManagementInformationSystems",
- "internationalBusiness:Marketing",
- "internationalBusiness:MarketingAnalytics",
- "internationalBusiness:SocialInnovationAndEntrepreneurship",
- "internationalBusiness:SupplyChainManagement",
- "journalism",
- "landscapeArchitecture",
- "linguistics",
- "marineBiology",
- "mathematics",
- "mechanicalEngineering",
- "mediaAndScreenStudies",
- "mediaArts",
- "music",
- "musicTechnology",
- "nursing",
- "pharmaceuticalSciences",
- "pharmacy(PharmD)",
- "philosophy",
- "physics",
- "politicalScience",
- "politicsPhilosophyEconomics",
- "psychology",
- "publicHealth",
- "publicRelations",
- "religiousStudies",
- "sociology",
- "spanish",
- "speechLanguagePathologyAndAudiology",
- "theatre"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.Major"
- }
- ]
- },
- "major1": {
- "maxLength": 255,
- "enum": [
- "africanaStudies",
- "americanSignLanguage",
- "americanSignLanguage-EnglishInterpreting",
- "appliedPhysics",
- "architecturalStudies",
- "architecture",
- "art:ArtVisualStudies",
- "behavioralNeuroscience",
- "biochemistry",
- "bioengineering",
- "biology",
- "biomedicalPhysics",
- "businessAdministration",
- "businessAdministration:Accounting",
- "businessAdministration:AccountingAndAdvisoryServices",
- "businessAdministration:BrandManagement",
- "businessAdministration:BusinessAnalytics",
- "businessAdministration:CorporateInnovation",
- "businessAdministration:EntrepreneurialStartups",
- "businessAdministration:FamilyBusiness",
- "businessAdministration:Finance",
- "businessAdministration:Fintech",
- "businessAdministration:HealthcareManagementAndConsulting",
- "businessAdministration:Management",
- "businessAdministration:ManagementInformationSystems",
- "businessAdministration:Marketing",
- "businessAdministration:MarketingAnalytics",
- "businessAdministration:SocialInnovationAndEntrepreneurship",
- "businessAdministration:SupplyChainManagement",
- "cellAndMolecularBiology",
- "chemicalEngineering",
- "chemistry",
- "civilEngineering",
- "communicationStudies",
- "computerEngineering",
- "computerScience",
- "computingAndLaw",
- "criminologyAndCriminalJustice",
- "culturalAnthropology",
- "cybersecurity",
- "dataScience",
- "design",
- "economics",
- "electricalEngineering",
- "english",
- "environmentalAndSustainabilityStudies",
- "environmentalEngineering",
- "environmentalScience",
- "environmentalStudies",
- "gameArtAndAnimation",
- "gameDesign",
- "globalAsianStudies",
- "healthScience",
- "history",
- "historyCultureAndLaw",
- "humanServices",
- "industrialEngineering",
- "internationalAffairs",
- "internationalBusiness",
- "internationalBusiness:Accounting",
- "internationalBusiness:AccountingAndAdvisoryServices",
- "internationalBusiness:BrandManagement",
- "internationalBusiness:BusinessAnalytics",
- "internationalBusiness:CorporateInnovation",
- "internationalBusiness:EntrepreneurialStartups",
- "internationalBusiness:FamilyBusiness",
- "internationalBusiness:Finance",
- "internationalBusiness:Fintech",
- "internationalBusiness:HealthcareManagementAndConsulting",
- "internationalBusiness:Management",
- "internationalBusiness:ManagementInformationSystems",
- "internationalBusiness:Marketing",
- "internationalBusiness:MarketingAnalytics",
- "internationalBusiness:SocialInnovationAndEntrepreneurship",
- "internationalBusiness:SupplyChainManagement",
- "journalism",
- "landscapeArchitecture",
- "linguistics",
- "marineBiology",
- "mathematics",
- "mechanicalEngineering",
- "mediaAndScreenStudies",
- "mediaArts",
- "music",
- "musicTechnology",
- "nursing",
- "pharmaceuticalSciences",
- "pharmacy(PharmD)",
- "philosophy",
- "physics",
- "politicalScience",
- "politicsPhilosophyEconomics",
- "psychology",
- "publicHealth",
- "publicRelations",
- "religiousStudies",
- "sociology",
- "spanish",
- "speechLanguagePathologyAndAudiology",
- "theatre"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.Major"
- }
- ]
+ "MusicTechnology",
+ "Nursing",
+ "PharmaceuticalSciences",
+ "PharmacyPharmD",
+ "Philosophy",
+ "Physics",
+ "PoliticalScience",
+ "PoliticsPhilosophyEconomics",
+ "Psychology",
+ "PublicHealth",
+ "PublicRelations",
+ "ReligiousStudies",
+ "Sociology",
+ "Spanish",
+ "SpeechLanguagePathologyAndAudiology",
+ "Theatre"
+ ]
+ },
+ "models.PointOfContact": {
+ "type": "object",
+ "properties": {
+ "created_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
},
- "major2": {
- "maxLength": 255,
- "enum": [
- "africanaStudies",
- "americanSignLanguage",
- "americanSignLanguage-EnglishInterpreting",
- "appliedPhysics",
- "architecturalStudies",
- "architecture",
- "art:ArtVisualStudies",
- "behavioralNeuroscience",
- "biochemistry",
- "bioengineering",
- "biology",
- "biomedicalPhysics",
- "businessAdministration",
- "businessAdministration:Accounting",
- "businessAdministration:AccountingAndAdvisoryServices",
- "businessAdministration:BrandManagement",
- "businessAdministration:BusinessAnalytics",
- "businessAdministration:CorporateInnovation",
- "businessAdministration:EntrepreneurialStartups",
- "businessAdministration:FamilyBusiness",
- "businessAdministration:Finance",
- "businessAdministration:Fintech",
- "businessAdministration:HealthcareManagementAndConsulting",
- "businessAdministration:Management",
- "businessAdministration:ManagementInformationSystems",
- "businessAdministration:Marketing",
- "businessAdministration:MarketingAnalytics",
- "businessAdministration:SocialInnovationAndEntrepreneurship",
- "businessAdministration:SupplyChainManagement",
- "cellAndMolecularBiology",
- "chemicalEngineering",
- "chemistry",
- "civilEngineering",
- "communicationStudies",
- "computerEngineering",
- "computerScience",
- "computingAndLaw",
- "criminologyAndCriminalJustice",
- "culturalAnthropology",
- "cybersecurity",
- "dataScience",
- "design",
- "economics",
- "electricalEngineering",
- "english",
- "environmentalAndSustainabilityStudies",
- "environmentalEngineering",
- "environmentalScience",
- "environmentalStudies",
- "gameArtAndAnimation",
- "gameDesign",
- "globalAsianStudies",
- "healthScience",
- "history",
- "historyCultureAndLaw",
- "humanServices",
- "industrialEngineering",
- "internationalAffairs",
- "internationalBusiness",
- "internationalBusiness:Accounting",
- "internationalBusiness:AccountingAndAdvisoryServices",
- "internationalBusiness:BrandManagement",
- "internationalBusiness:BusinessAnalytics",
- "internationalBusiness:CorporateInnovation",
- "internationalBusiness:EntrepreneurialStartups",
- "internationalBusiness:FamilyBusiness",
- "internationalBusiness:Finance",
- "internationalBusiness:Fintech",
- "internationalBusiness:HealthcareManagementAndConsulting",
- "internationalBusiness:Management",
- "internationalBusiness:ManagementInformationSystems",
- "internationalBusiness:Marketing",
- "internationalBusiness:MarketingAnalytics",
- "internationalBusiness:SocialInnovationAndEntrepreneurship",
- "internationalBusiness:SupplyChainManagement",
- "journalism",
- "landscapeArchitecture",
- "linguistics",
- "marineBiology",
- "mathematics",
- "mechanicalEngineering",
- "mediaAndScreenStudies",
- "mediaArts",
- "music",
- "musicTechnology",
- "nursing",
- "pharmaceuticalSciences",
- "pharmacy(PharmD)",
- "philosophy",
- "physics",
- "politicalScience",
- "politicsPhilosophyEconomics",
- "psychology",
- "publicHealth",
- "publicRelations",
- "religiousStudies",
- "sociology",
- "spanish",
- "speechLanguagePathologyAndAudiology",
- "theatre"
- ],
- "allOf": [
- {
- "$ref": "#/definitions/models.Major"
- }
- ]
+ "email": {
+ "type": "string"
},
- "role": {
+ "id": {
"type": "string",
- "enum": [
- "super",
- "student"
- ]
+ "example": "123e4567-e89b-12d3-a456-426614174000"
+ },
+ "name": {
+ "type": "string"
+ },
+ "photo_file": {
+ "$ref": "#/definitions/models.File"
+ },
+ "position": {
+ "type": "string"
},
"updated_at": {
"type": "string",
@@ -6518,43 +4835,122 @@
}
}
},
- "models.VerifyEmailRequestBody": {
- "type": "object",
- "required": [
- "email",
- "token"
+ "models.RecruitmentCycle": {
+ "type": "string",
+ "enum": [
+ "fall",
+ "spring",
+ "fallSpring",
+ "always"
],
+ "x-enum-varnames": [
+ "Fall",
+ "Spring",
+ "FallSpring",
+ "Always"
+ ]
+ },
+ "models.RecruitmentType": {
+ "type": "string",
+ "enum": [
+ "unrestricted",
+ "tryout",
+ "application"
+ ],
+ "x-enum-varnames": [
+ "Unrestricted",
+ "Tryout",
+ "Application"
+ ]
+ },
+ "models.Tag": {
+ "type": "object",
"properties": {
- "email": {
+ "category_id": {
"type": "string"
},
- "token": {
+ "created_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
+ },
+ "id": {
+ "type": "string",
+ "example": "123e4567-e89b-12d3-a456-426614174000"
+ },
+ "name": {
"type": "string"
+ },
+ "updated_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
}
}
},
- "models.VerifyPasswordResetTokenRequestBody": {
+ "models.User": {
"type": "object",
- "required": [
- "new_password",
- "token",
- "verify_new_password"
- ],
"properties": {
- "new_password": {
+ "college": {
+ "$ref": "#/definitions/models.College"
+ },
+ "created_at": {
"type": "string",
- "minLength": 8
+ "example": "2023-09-20T16:34:50Z"
},
- "token": {
+ "email": {
"type": "string"
},
- "verify_new_password": {
+ "first_name": {
+ "type": "string"
+ },
+ "graduation_cycle": {
+ "$ref": "#/definitions/models.GraduationCycle"
+ },
+ "graduation_year": {
+ "type": "integer"
+ },
+ "id": {
"type": "string",
- "minLength": 8
+ "example": "123e4567-e89b-12d3-a456-426614174000"
+ },
+ "is_verified": {
+ "type": "boolean"
+ },
+ "last_name": {
+ "type": "string"
+ },
+ "major0": {
+ "$ref": "#/definitions/models.Major"
+ },
+ "major1": {
+ "$ref": "#/definitions/models.Major"
+ },
+ "major2": {
+ "$ref": "#/definitions/models.Major"
+ },
+ "role": {
+ "type": "string"
+ },
+ "updated_at": {
+ "type": "string",
+ "example": "2023-09-20T16:34:50Z"
+ }
+ }
+ },
+ "tags.CreateClubTagsRequestBody": {
+ "type": "object",
+ "required": [
+ "tags"
+ ],
+ "properties": {
+ "tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
}
}
},
- "tag.CreateUserTagsBody": {
+ "tags.CreateUserTagsBody": {
"type": "object",
"required": [
"tags"
diff --git a/backend/docs/swagger.yaml b/backend/docs/swagger.yaml
index 24d2b66dd..93f68a29c 100644
--- a/backend/docs/swagger.yaml
+++ b/backend/docs/swagger.yaml
@@ -1,190 +1,31 @@
definitions:
- errors.Error:
+ auth.LoginResponseBody:
properties:
- message:
- type: string
- statusCode:
- type: integer
- type: object
- models.Category:
- properties:
- created_at:
- example: "2023-09-20T16:34:50Z"
- type: string
- id:
- example: 123e4567-e89b-12d3-a456-426614174000
- type: string
- name:
- maxLength: 255
- type: string
- updated_at:
- example: "2023-09-20T16:34:50Z"
- type: string
- required:
- - name
- type: object
- models.CategoryRequestBody:
- properties:
- name:
- maxLength: 255
- type: string
- required:
- - name
- type: object
- models.Club:
- properties:
- application_link:
- maxLength: 255
- type: string
- created_at:
- example: "2023-09-20T16:34:50Z"
- type: string
- description:
- maxLength: 255
- type: string
- id:
- example: 123e4567-e89b-12d3-a456-426614174000
- type: string
- is_recruiting:
- type: boolean
- logo:
- maxLength: 255
- type: string
- name:
- maxLength: 255
- type: string
- num_members:
- minimum: 1
- type: integer
- one_word_to_describe_us:
- maxLength: 255
- type: string
- preview:
- maxLength: 255
+ email:
type: string
- recruitment_cycle:
- allOf:
- - $ref: '#/definitions/models.RecruitmentCycle'
- enum:
- - fall
- - spring
- - fallSpring
- - always
- maxLength: 255
- recruitment_type:
- allOf:
- - $ref: '#/definitions/models.RecruitmentType'
- enum:
- - unrestricted
- - tryout
- - application
+ password:
+ description: 'MARK: must be validated manually'
maxLength: 255
- updated_at:
- example: "2023-09-20T16:34:50Z"
type: string
- weekly_time_commitment:
- minimum: 1
- type: integer
required:
- - application_link
- - description
- - is_recruiting
- - name
- - num_members
- - preview
- - recruitment_cycle
- - recruitment_type
+ - email
+ - password
type: object
- models.College:
- enum:
- - CAMD
- - DMSB
- - KCCS
- - CE
- - BCHS
- - SL
- - CPS
- - CS
- - CSSH
- type: string
- x-enum-comments:
- BCHS: Bouvé College of Health Sciences
- CAMD: College of Arts, Media and Design
- CE: College of Engineering
- CPS: College of Professional Studies
- CS: College of Science
- CSSH: College of Social Sciences and Humanities
- DMSB: D'Amore-McKim School of Business
- KCCS: Khoury College of Computer Sciences
- SL: School of Law
- x-enum-varnames:
- - CAMD
- - DMSB
- - KCCS
- - CE
- - BCHS
- - SL
- - CPS
- - CS
- - CSSH
- models.Contact:
+ auth.UpdatePasswordRequestBody:
properties:
- content:
+ new_password:
+ description: 'MARK: must be validated manually'
maxLength: 255
type: string
- created_at:
- example: "2023-09-20T16:34:50Z"
- type: string
- id:
- example: 123e4567-e89b-12d3-a456-426614174000
- type: string
- type:
- allOf:
- - $ref: '#/definitions/models.ContactType'
- enum:
- - facebook
- - instagram
- - x
- - linkedin
- - youtube
- - github
- - slack
- - discord
- - email
- - customSite
+ old_password:
+ description: 'MARK: must be validated manually'
maxLength: 255
- updated_at:
- example: "2023-09-20T16:34:50Z"
type: string
required:
- - content
- - type
+ - new_password
+ - old_password
type: object
- models.ContactType:
- enum:
- - facebook
- - instagram
- - x
- - linkedin
- - youtube
- - github
- - slack
- - discord
- - email
- - customSite
- type: string
- x-enum-varnames:
- - Facebook
- - Instagram
- - X
- - LinkedIn
- - YouTube
- - GitHub
- - Slack
- - Discord
- - Email
- - CustomSite
- models.CreateClubRequestBody:
+ base.CreateClubRequestBody:
properties:
application_link:
maxLength: 255
@@ -238,61 +79,7 @@ definitions:
- recruitment_type
- user_id
type: object
- models.CreateClubTagsRequestBody:
- properties:
- tags:
- items:
- type: string
- type: array
- required:
- - tags
- type: object
- models.CreateEventRequestBody:
- properties:
- content:
- maxLength: 255
- type: string
- end_time:
- type: string
- event_type:
- allOf:
- - $ref: '#/definitions/models.EventType'
- enum:
- - open
- - membersOnly
- maxLength: 255
- host:
- description: TODO club/tag/notification logic
- type: string
- is_recurring:
- type: boolean
- location:
- maxLength: 255
- type: string
- name:
- maxLength: 255
- type: string
- preview:
- maxLength: 255
- type: string
- series:
- allOf:
- - $ref: '#/definitions/models.CreateSeriesRequestBody'
- description: TODO validate if isRecurring, then series is required
- start_time:
- type: string
- required:
- - content
- - end_time
- - event_type
- - host
- - is_recurring
- - location
- - name
- - preview
- - start_time
- type: object
- models.CreateFileRequestBody:
+ base.CreateFileRequestBody:
properties:
owner_id:
type: string
@@ -303,24 +90,7 @@ definitions:
- owner_id
- owner_type
type: object
- models.CreateSeriesRequestBody:
- properties:
- max_occurrences:
- minimum: 2
- type: integer
- recurring_type:
- allOf:
- - $ref: '#/definitions/models.RecurringType'
- enum:
- - daily
- - weekly
- - monthly
- maxLength: 255
- required:
- - max_occurrences
- - recurring_type
- type: object
- models.CreateTagRequestBody:
+ base.CreateTagRequestBody:
properties:
category_id:
type: string
@@ -331,7 +101,7 @@ definitions:
- category_id
- name
type: object
- models.CreateUserRequestBody:
+ base.CreateUserRequestBody:
properties:
college:
allOf:
@@ -690,695 +460,197 @@ definitions:
- last_name
- password
type: object
- models.Event:
+ base.UpdateClubRequestBody:
properties:
- content:
+ application_link:
maxLength: 255
type: string
- created_at:
- example: "2023-09-20T16:34:50Z"
- type: string
- end_time:
- type: string
- event_type:
- allOf:
- - $ref: '#/definitions/models.EventType'
- enum:
- - open
- - membersOnly
+ description:
maxLength: 255
- host:
- type: string
- id:
- example: 123e4567-e89b-12d3-a456-426614174000
type: string
- is_recurring:
+ is_recruiting:
type: boolean
- location:
+ logo:
maxLength: 255
type: string
- meeting_link:
- type: string
name:
maxLength: 255
type: string
- preview:
+ one_word_to_describe_us:
maxLength: 255
type: string
- start_time:
- type: string
- updated_at:
- example: "2023-09-20T16:34:50Z"
+ preview:
+ maxLength: 255
type: string
- required:
- - content
- - end_time
- - event_type
- - location
- - name
- - preview
- - start_time
- type: object
- models.EventType:
- enum:
- - open
- - membersOnly
- type: string
- x-enum-varnames:
- - Open
- - MembersOnly
- models.File:
- properties:
- created_at:
- example: "2023-09-20T16:34:50Z"
- type: string
- file_name:
+ recruitment_cycle:
+ allOf:
+ - $ref: '#/definitions/models.RecruitmentCycle'
+ enum:
+ - fall
+ - spring
+ - fallSpring
+ - always
maxLength: 255
- type: string
- file_size:
+ recruitment_type:
+ allOf:
+ - $ref: '#/definitions/models.RecruitmentType'
+ enum:
+ - unrestricted
+ - tryout
+ - application
+ maxLength: 255
+ weekly_time_commitment:
minimum: 1
type: integer
- file_type:
- maxLength: 255
- type: string
- file_url:
- maxLength: 255
- type: string
- id:
- example: 123e4567-e89b-12d3-a456-426614174000
+ required:
+ - application_link
+ - recruitment_cycle
+ - recruitment_type
+ type: object
+ base.UpdateTagRequestBody:
+ properties:
+ category_id:
type: string
- object_key:
+ name:
maxLength: 255
type: string
- updated_at:
- example: "2023-09-20T16:34:50Z"
- type: string
- required:
- - file_name
- - file_size
- - file_type
- - file_url
- - object_key
type: object
- models.GraduationCycle:
- enum:
- - december
- - may
- type: string
- x-enum-varnames:
- - December
- - May
- models.LoginUserResponseBody:
+ base.UpdateUserRequestBody:
properties:
- email:
+ college:
+ allOf:
+ - $ref: '#/definitions/models.College'
+ enum:
+ - CAMD
+ - DMSB
+ - KCCS
+ - CE
+ - BCHS
+ - SL
+ - CPS
+ - CS
+ - CSSH
+ first_name:
+ maxLength: 255
type: string
- password:
- description: 'MARK: must be validated manually'
+ graduation_cycle:
+ allOf:
+ - $ref: '#/definitions/models.GraduationCycle'
+ enum:
+ - december
+ - may
+ maxLength: 255
+ graduation_year:
+ type: integer
+ last_name:
maxLength: 255
type: string
- required:
- - email
- - password
- type: object
- models.Major:
- enum:
- - africanaStudies
- - americanSignLanguage
- - americanSignLanguage-EnglishInterpreting
- - appliedPhysics
- - architecturalStudies
- - architecture
- - art:ArtVisualStudies
- - behavioralNeuroscience
- - biochemistry
- - bioengineering
- - biology
- - biomedicalPhysics
- - businessAdministration
- - businessAdministration:Accounting
- - businessAdministration:AccountingAndAdvisoryServices
- - businessAdministration:BrandManagement
- - businessAdministration:BusinessAnalytics
- - businessAdministration:CorporateInnovation
- - businessAdministration:EntrepreneurialStartups
- - businessAdministration:FamilyBusiness
- - businessAdministration:Finance
- - businessAdministration:Fintech
- - businessAdministration:HealthcareManagementAndConsulting
- - businessAdministration:Management
- - businessAdministration:ManagementInformationSystems
- - businessAdministration:Marketing
- - businessAdministration:MarketingAnalytics
- - businessAdministration:SocialInnovationAndEntrepreneurship
- - businessAdministration:SupplyChainManagement
- - cellAndMolecularBiology
- - chemicalEngineering
- - chemistry
- - civilEngineering
- - communicationStudies
- - computerEngineering
- - computerScience
- - computingAndLaw
- - criminologyAndCriminalJustice
- - culturalAnthropology
- - cybersecurity
- - dataScience
- - design
- - economics
- - electricalEngineering
- - english
- - environmentalAndSustainabilityStudies
- - environmentalEngineering
- - environmentalScience
- - environmentalStudies
- - gameArtAndAnimation
- - gameDesign
- - globalAsianStudies
- - healthScience
- - history
- - historyCultureAndLaw
- - humanServices
- - industrialEngineering
- - internationalAffairs
- - internationalBusiness
- - internationalBusiness:Accounting
- - internationalBusiness:AccountingAndAdvisoryServices
- - internationalBusiness:BrandManagement
- - internationalBusiness:BusinessAnalytics
- - internationalBusiness:CorporateInnovation
- - internationalBusiness:EntrepreneurialStartups
- - internationalBusiness:FamilyBusiness
- - internationalBusiness:Finance
- - internationalBusiness:Fintech
- - internationalBusiness:HealthcareManagementAndConsulting
- - internationalBusiness:Management
- - internationalBusiness:ManagementInformationSystems
- - internationalBusiness:Marketing
- - internationalBusiness:MarketingAnalytics
- - internationalBusiness:SocialInnovationAndEntrepreneurship
- - internationalBusiness:SupplyChainManagement
- - journalism
- - landscapeArchitecture
- - linguistics
- - marineBiology
- - mathematics
- - mechanicalEngineering
- - mediaAndScreenStudies
- - mediaArts
- - music
- - musicTechnology
- - nursing
- - pharmaceuticalSciences
- - pharmacy(PharmD)
- - philosophy
- - physics
- - politicalScience
- - politicsPhilosophyEconomics
- - psychology
- - publicHealth
- - publicRelations
- - religiousStudies
- - sociology
- - spanish
- - speechLanguagePathologyAndAudiology
- - theatre
- type: string
- x-enum-varnames:
- - AfricanaStudies
- - AmericanSignLanguage
- - AmericanSignLanguageEnglishInterpreting
- - AppliedPhysics
- - ArchitecturalStudies
- - Architecture
- - ArtArtVisualStudies
- - BehavioralNeuroscience
- - Biochemistry
- - Bioengineering
- - Biology
- - BiomedicalPhysics
- - BusinessAdministration
- - BusinessAdministrationAccounting
- - BusinessAdministrationAccountingAndAdvisoryServices
- - BusinessAdministrationBrandManagement
- - BusinessAdministrationBusinessAnalytics
- - BusinessAdministrationCorporateInnovation
- - BusinessAdministrationEntrepreneurialStartups
- - BusinessAdministrationFamilyBusiness
- - BusinessAdministrationFinance
- - BusinessAdministrationFintech
- - BusinessAdministrationHealthcareManagementAndConsulting
- - BusinessAdministrationManagement
- - BusinessAdministrationManagementInformationSystems
- - BusinessAdministrationMarketing
- - BusinessAdministrationMarketingAnalytics
- - BusinessAdministrationSocialInnovationAndEntrepreneurship
- - BusinessAdministrationSupplyChainManagement
- - CellAndMolecularBiology
- - ChemicalEngineering
- - Chemistry
- - CivilEngineering
- - CommunicationStudies
- - ComputerEngineering
- - ComputerScience
- - ComputingAndLaw
- - CriminologyAndCriminalJustice
- - CulturalAnthropology
- - Cybersecurity
- - DataScience
- - Design
- - Economics
- - ElectricalEngineering
- - English
- - EnvironmentalAndSustainabilityStudies
- - EnvironmentalEngineering
- - EnvironmentalScience
- - EnvironmentalStudies
- - GameArtAndAnimation
- - GameDesign
- - GlobalAsianStudies
- - HealthScience
- - History
- - HistoryCultureAndLaw
- - HumanServices
- - IndustrialEngineering
- - InternationalAffairs
- - InternationalBusiness
- - InternationalBusinessAccounting
- - InternationalBusinessAccountingAndAdvisoryServices
- - InternationalBusinessBrandManagement
- - InternationalBusinessBusinessAnalytics
- - InternationalBusinessCorporateInnovation
- - InternationalBusinessEntrepreneurialStartups
- - InternationalBusinessFamilyBusiness
- - InternationalBusinessFinance
- - InternationalBusinessFintech
- - InternationalBusinessHealthcareManagementAndConsulting
- - InternationalBusinessManagement
- - InternationalBusinessManagementInformationSystems
- - InternationalBusinessMarketing
- - InternationalBusinessMarketingAnalytics
- - InternationalBusinessSocialInnovationAndEntrepreneurship
- - InternationalBusinessSupplyChainManagement
- - Journalism
- - LandscapeArchitecture
- - Linguistics
- - MarineBiology
- - Mathematics
- - MechanicalEngineering
- - MediaAndScreenStudies
- - MediaArts
- - Music
- - MusicTechnology
- - Nursing
- - PharmaceuticalSciences
- - PharmacyPharmD
- - Philosophy
- - Physics
- - PoliticalScience
- - PoliticsPhilosophyEconomics
- - Psychology
- - PublicHealth
- - PublicRelations
- - ReligiousStudies
- - Sociology
- - Spanish
- - SpeechLanguagePathologyAndAudiology
- - Theatre
- models.PointOfContact:
- properties:
- created_at:
- example: "2023-09-20T16:34:50Z"
- type: string
- email:
- maxLength: 255
- type: string
- id:
- example: 123e4567-e89b-12d3-a456-426614174000
- type: string
- name:
- maxLength: 255
- type: string
- photo_file:
- $ref: '#/definitions/models.File'
- position:
- maxLength: 255
- type: string
- updated_at:
- example: "2023-09-20T16:34:50Z"
- type: string
- required:
- - email
- - name
- - position
- type: object
- models.PutContactRequestBody:
- properties:
- content:
- maxLength: 255
- type: string
- type:
+ major0:
allOf:
- - $ref: '#/definitions/models.ContactType'
+ - $ref: '#/definitions/models.Major'
enum:
- - facebook
- - instagram
- - x
- - linkedin
- - youtube
- - github
- - slack
- - discord
- - email
- - customSite
+ - africanaStudies
+ - americanSignLanguage
+ - americanSignLanguage-EnglishInterpreting
+ - appliedPhysics
+ - architecturalStudies
+ - architecture
+ - art:ArtVisualStudies
+ - behavioralNeuroscience
+ - biochemistry
+ - bioengineering
+ - biology
+ - biomedicalPhysics
+ - businessAdministration
+ - businessAdministration:Accounting
+ - businessAdministration:AccountingAndAdvisoryServices
+ - businessAdministration:BrandManagement
+ - businessAdministration:BusinessAnalytics
+ - businessAdministration:CorporateInnovation
+ - businessAdministration:EntrepreneurialStartups
+ - businessAdministration:FamilyBusiness
+ - businessAdministration:Finance
+ - businessAdministration:Fintech
+ - businessAdministration:HealthcareManagementAndConsulting
+ - businessAdministration:Management
+ - businessAdministration:ManagementInformationSystems
+ - businessAdministration:Marketing
+ - businessAdministration:MarketingAnalytics
+ - businessAdministration:SocialInnovationAndEntrepreneurship
+ - businessAdministration:SupplyChainManagement
+ - cellAndMolecularBiology
+ - chemicalEngineering
+ - chemistry
+ - civilEngineering
+ - communicationStudies
+ - computerEngineering
+ - computerScience
+ - computingAndLaw
+ - criminologyAndCriminalJustice
+ - culturalAnthropology
+ - cybersecurity
+ - dataScience
+ - design
+ - economics
+ - electricalEngineering
+ - english
+ - environmentalAndSustainabilityStudies
+ - environmentalEngineering
+ - environmentalScience
+ - environmentalStudies
+ - gameArtAndAnimation
+ - gameDesign
+ - globalAsianStudies
+ - healthScience
+ - history
+ - historyCultureAndLaw
+ - humanServices
+ - industrialEngineering
+ - internationalAffairs
+ - internationalBusiness
+ - internationalBusiness:Accounting
+ - internationalBusiness:AccountingAndAdvisoryServices
+ - internationalBusiness:BrandManagement
+ - internationalBusiness:BusinessAnalytics
+ - internationalBusiness:CorporateInnovation
+ - internationalBusiness:EntrepreneurialStartups
+ - internationalBusiness:FamilyBusiness
+ - internationalBusiness:Finance
+ - internationalBusiness:Fintech
+ - internationalBusiness:HealthcareManagementAndConsulting
+ - internationalBusiness:Management
+ - internationalBusiness:ManagementInformationSystems
+ - internationalBusiness:Marketing
+ - internationalBusiness:MarketingAnalytics
+ - internationalBusiness:SocialInnovationAndEntrepreneurship
+ - internationalBusiness:SupplyChainManagement
+ - journalism
+ - landscapeArchitecture
+ - linguistics
+ - marineBiology
+ - mathematics
+ - mechanicalEngineering
+ - mediaAndScreenStudies
+ - mediaArts
+ - music
+ - musicTechnology
+ - nursing
+ - pharmaceuticalSciences
+ - pharmacy(PharmD)
+ - philosophy
+ - physics
+ - politicalScience
+ - politicsPhilosophyEconomics
+ - psychology
+ - publicHealth
+ - publicRelations
+ - religiousStudies
+ - sociology
+ - spanish
+ - speechLanguagePathologyAndAudiology
+ - theatre
maxLength: 255
- required:
- - content
- - type
- type: object
- models.RecruitmentCycle:
- enum:
- - fall
- - spring
- - fallSpring
- - always
- type: string
- x-enum-varnames:
- - Fall
- - Spring
- - FallSpring
- - Always
- models.RecruitmentType:
- enum:
- - unrestricted
- - tryout
- - application
- type: string
- x-enum-varnames:
- - Unrestricted
- - Tryout
- - Application
- models.RecurringType:
- enum:
- - daily
- - weekly
- - monthly
- type: string
- x-enum-varnames:
- - Daily
- - Weekly
- - Monthly
- models.Series:
- properties:
- created_at:
- example: "2023-09-20T16:34:50Z"
- type: string
- events:
- items:
- $ref: '#/definitions/models.Event'
- type: array
- id:
- example: 123e4567-e89b-12d3-a456-426614174000
- type: string
- max_occurrences:
- minimum: 1
- type: integer
- recurring_type:
- allOf:
- - $ref: '#/definitions/models.RecurringType'
- maxLength: 255
- updated_at:
- example: "2023-09-20T16:34:50Z"
- type: string
- type: object
- models.Tag:
- properties:
- category_id:
- type: string
- created_at:
- example: "2023-09-20T16:34:50Z"
- type: string
- id:
- example: 123e4567-e89b-12d3-a456-426614174000
- type: string
- name:
- maxLength: 255
- type: string
- updated_at:
- example: "2023-09-20T16:34:50Z"
- type: string
- required:
- - category_id
- - name
- type: object
- models.UpdateClubRequestBody:
- properties:
- application_link:
- maxLength: 255
- type: string
- description:
- maxLength: 255
- type: string
- is_recruiting:
- type: boolean
- logo:
- maxLength: 255
- type: string
- name:
- maxLength: 255
- type: string
- one_word_to_describe_us:
- maxLength: 255
- type: string
- preview:
- maxLength: 255
- type: string
- recruitment_cycle:
- allOf:
- - $ref: '#/definitions/models.RecruitmentCycle'
- enum:
- - fall
- - spring
- - fallSpring
- - always
- maxLength: 255
- recruitment_type:
- allOf:
- - $ref: '#/definitions/models.RecruitmentType'
- enum:
- - unrestricted
- - tryout
- - application
- maxLength: 255
- weekly_time_commitment:
- minimum: 1
- type: integer
- required:
- - application_link
- - recruitment_cycle
- - recruitment_type
- type: object
- models.UpdateEventRequestBody:
- properties:
- content:
- maxLength: 255
- type: string
- end_time:
- type: string
- event_type:
- allOf:
- - $ref: '#/definitions/models.EventType'
- enum:
- - open
- - membersOnly
- maxLength: 255
- host:
- type: string
- location:
- maxLength: 255
- type: string
- name:
- maxLength: 255
- type: string
- preview:
- maxLength: 255
- type: string
- start_time:
- type: string
- type: object
- models.UpdatePasswordRequestBody:
- properties:
- new_password:
- description: 'MARK: must be validated manually'
- maxLength: 255
- type: string
- old_password:
- description: 'MARK: must be validated manually'
- maxLength: 255
- type: string
- required:
- - new_password
- - old_password
- type: object
- models.UpdateSeriesRequestBody:
- properties:
- event_details:
- $ref: '#/definitions/models.UpdateEventRequestBody'
- max_occurrences:
- minimum: 2
- type: integer
- recurring_type:
- allOf:
- - $ref: '#/definitions/models.RecurringType'
- enum:
- - daily
- - weekly
- - monthly
- maxLength: 255
- type: object
- models.UpdateTagRequestBody:
- properties:
- category_id:
- type: string
- name:
- maxLength: 255
- type: string
- type: object
- models.UpdateUserRequestBody:
- properties:
- college:
- allOf:
- - $ref: '#/definitions/models.College'
- enum:
- - CAMD
- - DMSB
- - KCCS
- - CE
- - BCHS
- - SL
- - CPS
- - CS
- - CSSH
- first_name:
- maxLength: 255
- type: string
- graduation_cycle:
- allOf:
- - $ref: '#/definitions/models.GraduationCycle'
- enum:
- - december
- - may
- maxLength: 255
- graduation_year:
- type: integer
- last_name:
- maxLength: 255
- type: string
- major0:
- allOf:
- - $ref: '#/definitions/models.Major'
- enum:
- - africanaStudies
- - americanSignLanguage
- - americanSignLanguage-EnglishInterpreting
- - appliedPhysics
- - architecturalStudies
- - architecture
- - art:ArtVisualStudies
- - behavioralNeuroscience
- - biochemistry
- - bioengineering
- - biology
- - biomedicalPhysics
- - businessAdministration
- - businessAdministration:Accounting
- - businessAdministration:AccountingAndAdvisoryServices
- - businessAdministration:BrandManagement
- - businessAdministration:BusinessAnalytics
- - businessAdministration:CorporateInnovation
- - businessAdministration:EntrepreneurialStartups
- - businessAdministration:FamilyBusiness
- - businessAdministration:Finance
- - businessAdministration:Fintech
- - businessAdministration:HealthcareManagementAndConsulting
- - businessAdministration:Management
- - businessAdministration:ManagementInformationSystems
- - businessAdministration:Marketing
- - businessAdministration:MarketingAnalytics
- - businessAdministration:SocialInnovationAndEntrepreneurship
- - businessAdministration:SupplyChainManagement
- - cellAndMolecularBiology
- - chemicalEngineering
- - chemistry
- - civilEngineering
- - communicationStudies
- - computerEngineering
- - computerScience
- - computingAndLaw
- - criminologyAndCriminalJustice
- - culturalAnthropology
- - cybersecurity
- - dataScience
- - design
- - economics
- - electricalEngineering
- - english
- - environmentalAndSustainabilityStudies
- - environmentalEngineering
- - environmentalScience
- - environmentalStudies
- - gameArtAndAnimation
- - gameDesign
- - globalAsianStudies
- - healthScience
- - history
- - historyCultureAndLaw
- - humanServices
- - industrialEngineering
- - internationalAffairs
- - internationalBusiness
- - internationalBusiness:Accounting
- - internationalBusiness:AccountingAndAdvisoryServices
- - internationalBusiness:BrandManagement
- - internationalBusiness:BusinessAnalytics
- - internationalBusiness:CorporateInnovation
- - internationalBusiness:EntrepreneurialStartups
- - internationalBusiness:FamilyBusiness
- - internationalBusiness:Finance
- - internationalBusiness:Fintech
- - internationalBusiness:HealthcareManagementAndConsulting
- - internationalBusiness:Management
- - internationalBusiness:ManagementInformationSystems
- - internationalBusiness:Marketing
- - internationalBusiness:MarketingAnalytics
- - internationalBusiness:SocialInnovationAndEntrepreneurship
- - internationalBusiness:SupplyChainManagement
- - journalism
- - landscapeArchitecture
- - linguistics
- - marineBiology
- - mathematics
- - mechanicalEngineering
- - mediaAndScreenStudies
- - mediaArts
- - music
- - musicTechnology
- - nursing
- - pharmaceuticalSciences
- - pharmacy(PharmD)
- - philosophy
- - physics
- - politicalScience
- - politicsPhilosophyEconomics
- - psychology
- - publicHealth
- - publicRelations
- - religiousStudies
- - sociology
- - spanish
- - speechLanguagePathologyAndAudiology
- - theatre
- maxLength: 255
- major1:
+ major1:
allOf:
- $ref: '#/definitions/models.Major'
enum:
@@ -1589,397 +861,570 @@ definitions:
- theatre
maxLength: 255
type: object
- models.User:
+ base.VerifyEmailRequestBody:
properties:
- college:
- allOf:
- - $ref: '#/definitions/models.College'
- maxLength: 255
- created_at:
- example: "2023-09-20T16:34:50Z"
- type: string
email:
- maxLength: 255
- type: string
- first_name:
- maxLength: 255
type: string
- graduation_cycle:
- allOf:
- - $ref: '#/definitions/models.GraduationCycle'
- enum:
- - december
- - may
- maxLength: 255
- graduation_year:
- type: integer
- id:
- example: 123e4567-e89b-12d3-a456-426614174000
+ token:
type: string
- is_verified:
- type: boolean
- last_name:
- maxLength: 255
+ required:
+ - email
+ - token
+ type: object
+ base.VerifyPasswordResetTokenRequestBody:
+ properties:
+ new_password:
+ minLength: 8
type: string
- major0:
- allOf:
- - $ref: '#/definitions/models.Major'
- enum:
- - africanaStudies
- - americanSignLanguage
- - americanSignLanguage-EnglishInterpreting
- - appliedPhysics
- - architecturalStudies
- - architecture
- - art:ArtVisualStudies
- - behavioralNeuroscience
- - biochemistry
- - bioengineering
- - biology
- - biomedicalPhysics
- - businessAdministration
- - businessAdministration:Accounting
- - businessAdministration:AccountingAndAdvisoryServices
- - businessAdministration:BrandManagement
- - businessAdministration:BusinessAnalytics
- - businessAdministration:CorporateInnovation
- - businessAdministration:EntrepreneurialStartups
- - businessAdministration:FamilyBusiness
- - businessAdministration:Finance
- - businessAdministration:Fintech
- - businessAdministration:HealthcareManagementAndConsulting
- - businessAdministration:Management
- - businessAdministration:ManagementInformationSystems
- - businessAdministration:Marketing
- - businessAdministration:MarketingAnalytics
- - businessAdministration:SocialInnovationAndEntrepreneurship
- - businessAdministration:SupplyChainManagement
- - cellAndMolecularBiology
- - chemicalEngineering
- - chemistry
- - civilEngineering
- - communicationStudies
- - computerEngineering
- - computerScience
- - computingAndLaw
- - criminologyAndCriminalJustice
- - culturalAnthropology
- - cybersecurity
- - dataScience
- - design
- - economics
- - electricalEngineering
- - english
- - environmentalAndSustainabilityStudies
- - environmentalEngineering
- - environmentalScience
- - environmentalStudies
- - gameArtAndAnimation
- - gameDesign
- - globalAsianStudies
- - healthScience
- - history
- - historyCultureAndLaw
- - humanServices
- - industrialEngineering
- - internationalAffairs
- - internationalBusiness
- - internationalBusiness:Accounting
- - internationalBusiness:AccountingAndAdvisoryServices
- - internationalBusiness:BrandManagement
- - internationalBusiness:BusinessAnalytics
- - internationalBusiness:CorporateInnovation
- - internationalBusiness:EntrepreneurialStartups
- - internationalBusiness:FamilyBusiness
- - internationalBusiness:Finance
- - internationalBusiness:Fintech
- - internationalBusiness:HealthcareManagementAndConsulting
- - internationalBusiness:Management
- - internationalBusiness:ManagementInformationSystems
- - internationalBusiness:Marketing
- - internationalBusiness:MarketingAnalytics
- - internationalBusiness:SocialInnovationAndEntrepreneurship
- - internationalBusiness:SupplyChainManagement
- - journalism
- - landscapeArchitecture
- - linguistics
- - marineBiology
- - mathematics
- - mechanicalEngineering
- - mediaAndScreenStudies
- - mediaArts
- - music
- - musicTechnology
- - nursing
- - pharmaceuticalSciences
- - pharmacy(PharmD)
- - philosophy
- - physics
- - politicalScience
- - politicsPhilosophyEconomics
- - psychology
- - publicHealth
- - publicRelations
- - religiousStudies
- - sociology
- - spanish
- - speechLanguagePathologyAndAudiology
- - theatre
+ token:
+ type: string
+ verify_new_password:
+ minLength: 8
+ type: string
+ required:
+ - new_password
+ - token
+ - verify_new_password
+ type: object
+ categories.CategoryRequestBody:
+ properties:
+ name:
maxLength: 255
- major1:
- allOf:
- - $ref: '#/definitions/models.Major'
- enum:
- - africanaStudies
- - americanSignLanguage
- - americanSignLanguage-EnglishInterpreting
- - appliedPhysics
- - architecturalStudies
- - architecture
- - art:ArtVisualStudies
- - behavioralNeuroscience
- - biochemistry
- - bioengineering
- - biology
- - biomedicalPhysics
- - businessAdministration
- - businessAdministration:Accounting
- - businessAdministration:AccountingAndAdvisoryServices
- - businessAdministration:BrandManagement
- - businessAdministration:BusinessAnalytics
- - businessAdministration:CorporateInnovation
- - businessAdministration:EntrepreneurialStartups
- - businessAdministration:FamilyBusiness
- - businessAdministration:Finance
- - businessAdministration:Fintech
- - businessAdministration:HealthcareManagementAndConsulting
- - businessAdministration:Management
- - businessAdministration:ManagementInformationSystems
- - businessAdministration:Marketing
- - businessAdministration:MarketingAnalytics
- - businessAdministration:SocialInnovationAndEntrepreneurship
- - businessAdministration:SupplyChainManagement
- - cellAndMolecularBiology
- - chemicalEngineering
- - chemistry
- - civilEngineering
- - communicationStudies
- - computerEngineering
- - computerScience
- - computingAndLaw
- - criminologyAndCriminalJustice
- - culturalAnthropology
- - cybersecurity
- - dataScience
- - design
- - economics
- - electricalEngineering
- - english
- - environmentalAndSustainabilityStudies
- - environmentalEngineering
- - environmentalScience
- - environmentalStudies
- - gameArtAndAnimation
- - gameDesign
- - globalAsianStudies
- - healthScience
- - history
- - historyCultureAndLaw
- - humanServices
- - industrialEngineering
- - internationalAffairs
- - internationalBusiness
- - internationalBusiness:Accounting
- - internationalBusiness:AccountingAndAdvisoryServices
- - internationalBusiness:BrandManagement
- - internationalBusiness:BusinessAnalytics
- - internationalBusiness:CorporateInnovation
- - internationalBusiness:EntrepreneurialStartups
- - internationalBusiness:FamilyBusiness
- - internationalBusiness:Finance
- - internationalBusiness:Fintech
- - internationalBusiness:HealthcareManagementAndConsulting
- - internationalBusiness:Management
- - internationalBusiness:ManagementInformationSystems
- - internationalBusiness:Marketing
- - internationalBusiness:MarketingAnalytics
- - internationalBusiness:SocialInnovationAndEntrepreneurship
- - internationalBusiness:SupplyChainManagement
- - journalism
- - landscapeArchitecture
- - linguistics
- - marineBiology
- - mathematics
- - mechanicalEngineering
- - mediaAndScreenStudies
- - mediaArts
- - music
- - musicTechnology
- - nursing
- - pharmaceuticalSciences
- - pharmacy(PharmD)
- - philosophy
- - physics
- - politicalScience
- - politicsPhilosophyEconomics
- - psychology
- - publicHealth
- - publicRelations
- - religiousStudies
- - sociology
- - spanish
- - speechLanguagePathologyAndAudiology
- - theatre
+ type: string
+ required:
+ - name
+ type: object
+ contacts.PutContactRequestBody:
+ properties:
+ content:
maxLength: 255
- major2:
+ type: string
+ type:
allOf:
- - $ref: '#/definitions/models.Major'
+ - $ref: '#/definitions/models.ContactType'
enum:
- - africanaStudies
- - americanSignLanguage
- - americanSignLanguage-EnglishInterpreting
- - appliedPhysics
- - architecturalStudies
- - architecture
- - art:ArtVisualStudies
- - behavioralNeuroscience
- - biochemistry
- - bioengineering
- - biology
- - biomedicalPhysics
- - businessAdministration
- - businessAdministration:Accounting
- - businessAdministration:AccountingAndAdvisoryServices
- - businessAdministration:BrandManagement
- - businessAdministration:BusinessAnalytics
- - businessAdministration:CorporateInnovation
- - businessAdministration:EntrepreneurialStartups
- - businessAdministration:FamilyBusiness
- - businessAdministration:Finance
- - businessAdministration:Fintech
- - businessAdministration:HealthcareManagementAndConsulting
- - businessAdministration:Management
- - businessAdministration:ManagementInformationSystems
- - businessAdministration:Marketing
- - businessAdministration:MarketingAnalytics
- - businessAdministration:SocialInnovationAndEntrepreneurship
- - businessAdministration:SupplyChainManagement
- - cellAndMolecularBiology
- - chemicalEngineering
- - chemistry
- - civilEngineering
- - communicationStudies
- - computerEngineering
- - computerScience
- - computingAndLaw
- - criminologyAndCriminalJustice
- - culturalAnthropology
- - cybersecurity
- - dataScience
- - design
- - economics
- - electricalEngineering
- - english
- - environmentalAndSustainabilityStudies
- - environmentalEngineering
- - environmentalScience
- - environmentalStudies
- - gameArtAndAnimation
- - gameDesign
- - globalAsianStudies
- - healthScience
- - history
- - historyCultureAndLaw
- - humanServices
- - industrialEngineering
- - internationalAffairs
- - internationalBusiness
- - internationalBusiness:Accounting
- - internationalBusiness:AccountingAndAdvisoryServices
- - internationalBusiness:BrandManagement
- - internationalBusiness:BusinessAnalytics
- - internationalBusiness:CorporateInnovation
- - internationalBusiness:EntrepreneurialStartups
- - internationalBusiness:FamilyBusiness
- - internationalBusiness:Finance
- - internationalBusiness:Fintech
- - internationalBusiness:HealthcareManagementAndConsulting
- - internationalBusiness:Management
- - internationalBusiness:ManagementInformationSystems
- - internationalBusiness:Marketing
- - internationalBusiness:MarketingAnalytics
- - internationalBusiness:SocialInnovationAndEntrepreneurship
- - internationalBusiness:SupplyChainManagement
- - journalism
- - landscapeArchitecture
- - linguistics
- - marineBiology
- - mathematics
- - mechanicalEngineering
- - mediaAndScreenStudies
- - mediaArts
- - music
- - musicTechnology
- - nursing
- - pharmaceuticalSciences
- - pharmacy(PharmD)
- - philosophy
- - physics
- - politicalScience
- - politicsPhilosophyEconomics
- - psychology
- - publicHealth
- - publicRelations
- - religiousStudies
- - sociology
- - spanish
- - speechLanguagePathologyAndAudiology
- - theatre
+ - facebook
+ - instagram
+ - x
+ - linkedin
+ - youtube
+ - github
+ - slack
+ - discord
+ - email
+ - customSite
maxLength: 255
- role:
- enum:
- - super
- - student
+ required:
+ - content
+ - type
+ type: object
+ models.Category:
+ properties:
+ created_at:
+ example: "2023-09-20T16:34:50Z"
+ type: string
+ id:
+ example: 123e4567-e89b-12d3-a456-426614174000
+ type: string
+ name:
+ type: string
+ updated_at:
+ example: "2023-09-20T16:34:50Z"
+ type: string
+ type: object
+ models.Club:
+ properties:
+ application_link:
+ type: string
+ created_at:
+ example: "2023-09-20T16:34:50Z"
+ type: string
+ description:
+ type: string
+ id:
+ example: 123e4567-e89b-12d3-a456-426614174000
+ type: string
+ is_recruiting:
+ type: boolean
+ logo:
+ type: string
+ name:
+ type: string
+ num_members:
+ type: integer
+ one_word_to_describe_us:
+ type: string
+ preview:
+ type: string
+ recruitment_cycle:
+ $ref: '#/definitions/models.RecruitmentCycle'
+ recruitment_type:
+ $ref: '#/definitions/models.RecruitmentType'
+ updated_at:
+ example: "2023-09-20T16:34:50Z"
+ type: string
+ weekly_time_commitment:
+ type: integer
+ type: object
+ models.College:
+ enum:
+ - CAMD
+ - DMSB
+ - KCCS
+ - CE
+ - BCHS
+ - SL
+ - CPS
+ - CS
+ - CSSH
+ type: string
+ x-enum-comments:
+ BCHS: Bouvé College of Health Sciences
+ CAMD: College of Arts, Media and Design
+ CE: College of Engineering
+ CPS: College of Professional Studies
+ CS: College of Science
+ CSSH: College of Social Sciences and Humanities
+ DMSB: D'Amore-McKim School of Business
+ KCCS: Khoury College of Computer Sciences
+ SL: School of Law
+ x-enum-varnames:
+ - CAMD
+ - DMSB
+ - KCCS
+ - CE
+ - BCHS
+ - SL
+ - CPS
+ - CS
+ - CSSH
+ models.Contact:
+ properties:
+ content:
+ type: string
+ created_at:
+ example: "2023-09-20T16:34:50Z"
+ type: string
+ id:
+ example: 123e4567-e89b-12d3-a456-426614174000
+ type: string
+ type:
+ $ref: '#/definitions/models.ContactType'
+ updated_at:
+ example: "2023-09-20T16:34:50Z"
+ type: string
+ type: object
+ models.ContactType:
+ enum:
+ - facebook
+ - instagram
+ - x
+ - linkedin
+ - youtube
+ - github
+ - slack
+ - discord
+ - email
+ - customSite
+ type: string
+ x-enum-varnames:
+ - Facebook
+ - Instagram
+ - X
+ - LinkedIn
+ - YouTube
+ - GitHub
+ - Slack
+ - Discord
+ - Email
+ - CustomSite
+ models.Event:
+ properties:
+ created_at:
+ example: "2023-09-20T16:34:50Z"
+ type: string
+ description:
+ type: string
+ end_time:
+ type: string
+ event_type:
+ allOf:
+ - $ref: '#/definitions/models.EventType'
+ description: geoshi
+ host:
+ type: string
+ id:
+ example: 123e4567-e89b-12d3-a456-426614174000
+ type: string
+ is_archived:
+ type: boolean
+ is_draft:
+ type: boolean
+ is_public:
+ description: internal housekeeping states
+ type: boolean
+ link:
+ type: string
+ location:
+ type: string
+ name:
+ description: details
+ type: string
+ preview:
+ type: string
+ start_time:
+ description: timing
+ type: string
+ updated_at:
+ example: "2023-09-20T16:34:50Z"
+ type: string
+ type: object
+ models.EventType:
+ enum:
+ - hybrid
+ - in_person
+ - virtual
+ type: string
+ x-enum-varnames:
+ - Hybrid
+ - InPerson
+ - Virtual
+ models.File:
+ properties:
+ created_at:
+ example: "2023-09-20T16:34:50Z"
+ type: string
+ file_name:
+ type: string
+ file_size:
+ type: integer
+ file_type:
+ type: string
+ file_url:
+ type: string
+ id:
+ example: 123e4567-e89b-12d3-a456-426614174000
+ type: string
+ object_key:
+ type: string
+ updated_at:
+ example: "2023-09-20T16:34:50Z"
+ type: string
+ type: object
+ models.GraduationCycle:
+ enum:
+ - december
+ - may
+ type: string
+ x-enum-varnames:
+ - December
+ - May
+ models.Major:
+ enum:
+ - africanaStudies
+ - americanSignLanguage
+ - americanSignLanguage-EnglishInterpreting
+ - appliedPhysics
+ - architecturalStudies
+ - architecture
+ - art:ArtVisualStudies
+ - behavioralNeuroscience
+ - biochemistry
+ - bioengineering
+ - biology
+ - biomedicalPhysics
+ - businessAdministration
+ - businessAdministration:Accounting
+ - businessAdministration:AccountingAndAdvisoryServices
+ - businessAdministration:BrandManagement
+ - businessAdministration:BusinessAnalytics
+ - businessAdministration:CorporateInnovation
+ - businessAdministration:EntrepreneurialStartups
+ - businessAdministration:FamilyBusiness
+ - businessAdministration:Finance
+ - businessAdministration:Fintech
+ - businessAdministration:HealthcareManagementAndConsulting
+ - businessAdministration:Management
+ - businessAdministration:ManagementInformationSystems
+ - businessAdministration:Marketing
+ - businessAdministration:MarketingAnalytics
+ - businessAdministration:SocialInnovationAndEntrepreneurship
+ - businessAdministration:SupplyChainManagement
+ - cellAndMolecularBiology
+ - chemicalEngineering
+ - chemistry
+ - civilEngineering
+ - communicationStudies
+ - computerEngineering
+ - computerScience
+ - computingAndLaw
+ - criminologyAndCriminalJustice
+ - culturalAnthropology
+ - cybersecurity
+ - dataScience
+ - design
+ - economics
+ - electricalEngineering
+ - english
+ - environmentalAndSustainabilityStudies
+ - environmentalEngineering
+ - environmentalScience
+ - environmentalStudies
+ - gameArtAndAnimation
+ - gameDesign
+ - globalAsianStudies
+ - healthScience
+ - history
+ - historyCultureAndLaw
+ - humanServices
+ - industrialEngineering
+ - internationalAffairs
+ - internationalBusiness
+ - internationalBusiness:Accounting
+ - internationalBusiness:AccountingAndAdvisoryServices
+ - internationalBusiness:BrandManagement
+ - internationalBusiness:BusinessAnalytics
+ - internationalBusiness:CorporateInnovation
+ - internationalBusiness:EntrepreneurialStartups
+ - internationalBusiness:FamilyBusiness
+ - internationalBusiness:Finance
+ - internationalBusiness:Fintech
+ - internationalBusiness:HealthcareManagementAndConsulting
+ - internationalBusiness:Management
+ - internationalBusiness:ManagementInformationSystems
+ - internationalBusiness:Marketing
+ - internationalBusiness:MarketingAnalytics
+ - internationalBusiness:SocialInnovationAndEntrepreneurship
+ - internationalBusiness:SupplyChainManagement
+ - journalism
+ - landscapeArchitecture
+ - linguistics
+ - marineBiology
+ - mathematics
+ - mechanicalEngineering
+ - mediaAndScreenStudies
+ - mediaArts
+ - music
+ - musicTechnology
+ - nursing
+ - pharmaceuticalSciences
+ - pharmacy(PharmD)
+ - philosophy
+ - physics
+ - politicalScience
+ - politicsPhilosophyEconomics
+ - psychology
+ - publicHealth
+ - publicRelations
+ - religiousStudies
+ - sociology
+ - spanish
+ - speechLanguagePathologyAndAudiology
+ - theatre
+ type: string
+ x-enum-varnames:
+ - AfricanaStudies
+ - AmericanSignLanguage
+ - AmericanSignLanguageEnglishInterpreting
+ - AppliedPhysics
+ - ArchitecturalStudies
+ - Architecture
+ - ArtArtVisualStudies
+ - BehavioralNeuroscience
+ - Biochemistry
+ - Bioengineering
+ - Biology
+ - BiomedicalPhysics
+ - BusinessAdministration
+ - BusinessAdministrationAccounting
+ - BusinessAdministrationAccountingAndAdvisoryServices
+ - BusinessAdministrationBrandManagement
+ - BusinessAdministrationBusinessAnalytics
+ - BusinessAdministrationCorporateInnovation
+ - BusinessAdministrationEntrepreneurialStartups
+ - BusinessAdministrationFamilyBusiness
+ - BusinessAdministrationFinance
+ - BusinessAdministrationFintech
+ - BusinessAdministrationHealthcareManagementAndConsulting
+ - BusinessAdministrationManagement
+ - BusinessAdministrationManagementInformationSystems
+ - BusinessAdministrationMarketing
+ - BusinessAdministrationMarketingAnalytics
+ - BusinessAdministrationSocialInnovationAndEntrepreneurship
+ - BusinessAdministrationSupplyChainManagement
+ - CellAndMolecularBiology
+ - ChemicalEngineering
+ - Chemistry
+ - CivilEngineering
+ - CommunicationStudies
+ - ComputerEngineering
+ - ComputerScience
+ - ComputingAndLaw
+ - CriminologyAndCriminalJustice
+ - CulturalAnthropology
+ - Cybersecurity
+ - DataScience
+ - Design
+ - Economics
+ - ElectricalEngineering
+ - English
+ - EnvironmentalAndSustainabilityStudies
+ - EnvironmentalEngineering
+ - EnvironmentalScience
+ - EnvironmentalStudies
+ - GameArtAndAnimation
+ - GameDesign
+ - GlobalAsianStudies
+ - HealthScience
+ - History
+ - HistoryCultureAndLaw
+ - HumanServices
+ - IndustrialEngineering
+ - InternationalAffairs
+ - InternationalBusiness
+ - InternationalBusinessAccounting
+ - InternationalBusinessAccountingAndAdvisoryServices
+ - InternationalBusinessBrandManagement
+ - InternationalBusinessBusinessAnalytics
+ - InternationalBusinessCorporateInnovation
+ - InternationalBusinessEntrepreneurialStartups
+ - InternationalBusinessFamilyBusiness
+ - InternationalBusinessFinance
+ - InternationalBusinessFintech
+ - InternationalBusinessHealthcareManagementAndConsulting
+ - InternationalBusinessManagement
+ - InternationalBusinessManagementInformationSystems
+ - InternationalBusinessMarketing
+ - InternationalBusinessMarketingAnalytics
+ - InternationalBusinessSocialInnovationAndEntrepreneurship
+ - InternationalBusinessSupplyChainManagement
+ - Journalism
+ - LandscapeArchitecture
+ - Linguistics
+ - MarineBiology
+ - Mathematics
+ - MechanicalEngineering
+ - MediaAndScreenStudies
+ - MediaArts
+ - Music
+ - MusicTechnology
+ - Nursing
+ - PharmaceuticalSciences
+ - PharmacyPharmD
+ - Philosophy
+ - Physics
+ - PoliticalScience
+ - PoliticsPhilosophyEconomics
+ - Psychology
+ - PublicHealth
+ - PublicRelations
+ - ReligiousStudies
+ - Sociology
+ - Spanish
+ - SpeechLanguagePathologyAndAudiology
+ - Theatre
+ models.PointOfContact:
+ properties:
+ created_at:
+ example: "2023-09-20T16:34:50Z"
+ type: string
+ email:
+ type: string
+ id:
+ example: 123e4567-e89b-12d3-a456-426614174000
+ type: string
+ name:
+ type: string
+ photo_file:
+ $ref: '#/definitions/models.File'
+ position:
type: string
updated_at:
example: "2023-09-20T16:34:50Z"
type: string
- required:
- - college
- - email
- - first_name
- - graduation_cycle
- - graduation_year
- - last_name
- - major0
- - role
type: object
- models.VerifyEmailRequestBody:
+ models.RecruitmentCycle:
+ enum:
+ - fall
+ - spring
+ - fallSpring
+ - always
+ type: string
+ x-enum-varnames:
+ - Fall
+ - Spring
+ - FallSpring
+ - Always
+ models.RecruitmentType:
+ enum:
+ - unrestricted
+ - tryout
+ - application
+ type: string
+ x-enum-varnames:
+ - Unrestricted
+ - Tryout
+ - Application
+ models.Tag:
properties:
- email:
+ category_id:
type: string
- token:
+ created_at:
+ example: "2023-09-20T16:34:50Z"
+ type: string
+ id:
+ example: 123e4567-e89b-12d3-a456-426614174000
+ type: string
+ name:
+ type: string
+ updated_at:
+ example: "2023-09-20T16:34:50Z"
type: string
- required:
- - email
- - token
type: object
- models.VerifyPasswordResetTokenRequestBody:
+ models.User:
properties:
- new_password:
- minLength: 8
+ college:
+ $ref: '#/definitions/models.College'
+ created_at:
+ example: "2023-09-20T16:34:50Z"
type: string
- token:
+ email:
type: string
- verify_new_password:
- minLength: 8
+ first_name:
+ type: string
+ graduation_cycle:
+ $ref: '#/definitions/models.GraduationCycle'
+ graduation_year:
+ type: integer
+ id:
+ example: 123e4567-e89b-12d3-a456-426614174000
+ type: string
+ is_verified:
+ type: boolean
+ last_name:
+ type: string
+ major0:
+ $ref: '#/definitions/models.Major'
+ major1:
+ $ref: '#/definitions/models.Major'
+ major2:
+ $ref: '#/definitions/models.Major'
+ role:
+ type: string
+ updated_at:
+ example: "2023-09-20T16:34:50Z"
type: string
+ type: object
+ tags.CreateClubTagsRequestBody:
+ properties:
+ tags:
+ items:
+ type: string
+ type: array
required:
- - new_password
- - token
- - verify_new_password
+ - tags
type: object
- tag.CreateUserTagsBody:
+ tags.CreateUserTagsBody:
properties:
tags:
items:
@@ -2018,16 +1463,13 @@ paths:
$ref: '#/definitions/utilities.SuccessResponse'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"429":
description: Too Many Requests
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Generates a password reset token
tags:
- auth
@@ -2043,7 +1485,7 @@ paths:
name: loginBody
required: true
schema:
- $ref: '#/definitions/models.LoginUserResponseBody'
+ $ref: '#/definitions/auth.LoginResponseBody'
produces:
- application/json
responses:
@@ -2053,16 +1495,13 @@ paths:
$ref: '#/definitions/models.User'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Logs in a user
tags:
- auth
@@ -2097,20 +1536,16 @@ paths:
$ref: '#/definitions/models.User'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
security:
- Bearer: []
summary: Retrieves the currently authenticated user
@@ -2128,401 +1563,153 @@ paths:
"200":
description: OK
schema:
- $ref: '#/definitions/utilities.SuccessResponse'
- "400":
- description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
- "404":
- description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
- "500":
- description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Refreshes a user's access token
- tags:
- - auth
- /auth/send-code:
- post:
- consumes:
- - application/json
- description: Sends a verification code
- operationId: send-verification-code
- parameters:
- - description: Email
- in: body
- name: email
- required: true
- schema:
- type: string
- produces:
- - application/json
- responses:
- "200":
- description: OK
- schema:
- $ref: '#/definitions/utilities.SuccessResponse'
- "400":
- description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
- "429":
- description: Too Many Requests
- schema:
- $ref: '#/definitions/errors.Error'
- "500":
- description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Sends a verification code
- tags:
- - auth
- /auth/verify-email:
- post:
- consumes:
- - application/json
- description: Verifies an email
- operationId: verify-email
- parameters:
- - description: Email Verification Token Body
- in: body
- name: tokenBody
- required: true
- schema:
- $ref: '#/definitions/models.VerifyEmailRequestBody'
- produces:
- - application/json
- responses:
- "200":
- description: OK
- schema:
- $ref: '#/definitions/utilities.SuccessResponse'
- "400":
- description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
- "429":
- description: Too Many Requests
- schema:
- $ref: '#/definitions/errors.Error'
- "500":
- description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Verifies an email
- tags:
- - auth
- /auth/verify-reset:
- post:
- consumes:
- - application/json
- description: Verifies a password reset token
- operationId: verify-password-reset-token
- parameters:
- - description: Password Reset Token Body
- in: body
- name: tokenBody
- required: true
- schema:
- $ref: '#/definitions/models.VerifyPasswordResetTokenRequestBody'
- produces:
- - application/json
- responses:
- "200":
- description: OK
- schema:
- $ref: '#/definitions/utilities.SuccessResponse'
- "400":
- description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
- "429":
- description: Too Many Requests
- schema:
- $ref: '#/definitions/errors.Error'
- "500":
- description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- security:
- - Bearer: []
- summary: Verifies a password reset token
- tags:
- - auth
- /categories/:
- get:
- description: Retrieves all categories
- operationId: get-categories
- parameters:
- - description: Limit
- in: query
- name: limit
- type: integer
- - description: Page
- in: query
- name: page
- type: integer
- produces:
- - application/json
- responses:
- "200":
- description: OK
- schema:
- items:
- $ref: '#/definitions/models.Category'
- type: array
- "400":
- description: Bad Request
- schema:
- type: string
- "404":
- description: Not Found
- schema:
- type: string
- "500":
- description: Internal Server Error
- schema:
- type: string
- summary: Retrieve all categories
- tags:
- - category
- post:
- consumes:
- - application/json
- description: Creates a category
- operationId: create-category
- parameters:
- - description: Category Body
- in: body
- name: categoryBody
- required: true
- schema:
- $ref: '#/definitions/models.CategoryRequestBody'
- produces:
- - application/json
- responses:
- "201":
- description: Created
- schema:
- $ref: '#/definitions/models.Category'
- "400":
- description: Bad Request
- schema:
- type: string
- "401":
- description: Unauthorized
- schema:
- type: string
- "404":
- description: Not Found
- schema:
- type: string
- "409":
- description: Conflict
- schema:
- type: string
- "500":
- description: Internal Server Error
- schema:
- type: string
- summary: Creates a category
- tags:
- - category
- /categories/{categoryID}/:
- delete:
- description: Deletes a category
- operationId: delete-category
- parameters:
- - description: Category ID
- in: path
- name: categoryID
- required: true
- type: string
- produces:
- - application/json
- responses:
- "204":
- description: No Content
- schema:
- type: string
- "400":
- description: Bad Request
- schema:
- type: string
- "401":
- description: Unauthorized
- schema:
- type: string
- "404":
- description: Not Found
- schema:
- type: string
- "500":
- description: Internal Server Error
- schema:
- type: string
- summary: Deletes a category
- tags:
- - category
- get:
- description: Retrieves a category
- operationId: get-category
- parameters:
- - description: Category ID
- in: path
- name: categoryID
- required: true
- type: string
- produces:
- - application/json
- responses:
- "200":
- description: OK
- schema:
- $ref: '#/definitions/models.Category'
+ $ref: '#/definitions/utilities.SuccessResponse'
"400":
description: Bad Request
- schema:
- type: string
+ schema: {}
"404":
description: Not Found
- schema:
- type: string
+ schema: {}
"500":
description: Internal Server Error
- schema:
- type: string
- summary: Retrieve a category
+ schema: {}
+ summary: Refreshes a user's access token
tags:
- - category
- patch:
+ - auth
+ /auth/register:
+ post:
consumes:
- application/json
- description: Updates a category
- operationId: update-category
+ description: Registers a user
+ operationId: register-user
parameters:
- - description: Category ID
- in: path
- name: categoryID
- required: true
- type: string
- - description: Category Body
+ - description: User Body
in: body
- name: categoryBody
+ name: userBody
required: true
schema:
- $ref: '#/definitions/models.CategoryRequestBody'
+ $ref: '#/definitions/base.CreateUserRequestBody'
produces:
- application/json
responses:
- "200":
- description: OK
+ "201":
+ description: Created
schema:
- $ref: '#/definitions/models.Category'
+ $ref: '#/definitions/models.User'
"400":
description: Bad Request
- schema:
- type: string
- "401":
- description: Unauthorized
- schema:
- type: string
+ schema: {}
"404":
description: Not Found
- schema:
- type: string
+ schema: {}
"500":
description: Internal Server Error
- schema:
- type: string
- summary: Updates a category
+ schema: {}
+ summary: Registers a user
tags:
- - category
- /categories/{categoryID}/tags/:
- get:
- description: Retrieves all tags associated with a category
- operationId: get-tags-by-category
+ - auth
+ /auth/send-code:
+ post:
+ consumes:
+ - application/json
+ description: Sends a verification code
+ operationId: send-verification-code
parameters:
- - description: Category ID
- in: path
- name: categoryID
+ - description: Email
+ in: body
+ name: email
required: true
- type: string
- - description: Limit
- in: query
- name: limit
- type: integer
- - description: Page
- in: query
- name: page
- type: integer
+ schema:
+ type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
- items:
- $ref: '#/definitions/models.Tag'
- type: array
+ $ref: '#/definitions/utilities.SuccessResponse'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
- "404":
- description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
+ "429":
+ description: Too Many Requests
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Retrieve all tags by category
+ schema: {}
+ summary: Sends a verification code
tags:
- - category-tag
- /categories/{categoryID}/tags/{tagID}/:
- get:
- description: Retrieves a tag associated with a category
- operationId: get-tag-by-category
+ - auth
+ /auth/verify-email:
+ post:
+ consumes:
+ - application/json
+ description: Verifies an email
+ operationId: verify-email
parameters:
- - description: Category ID
- in: path
- name: categoryID
- required: true
- type: string
- - description: Tag ID
- in: path
- name: tagID
+ - description: Email Verification Token Body
+ in: body
+ name: tokenBody
required: true
- type: string
+ schema:
+ $ref: '#/definitions/base.VerifyEmailRequestBody'
produces:
- application/json
responses:
"200":
description: OK
schema:
- $ref: '#/definitions/models.Tag'
+ $ref: '#/definitions/utilities.SuccessResponse'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
- "404":
- description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
+ "429":
+ description: Too Many Requests
+ schema: {}
"500":
description: Internal Server Error
+ schema: {}
+ summary: Verifies an email
+ tags:
+ - auth
+ /auth/verify-reset:
+ post:
+ consumes:
+ - application/json
+ description: Verifies a password reset token
+ operationId: verify-password-reset-token
+ parameters:
+ - description: Password Reset Token Body
+ in: body
+ name: tokenBody
+ required: true
+ schema:
+ $ref: '#/definitions/base.VerifyPasswordResetTokenRequestBody'
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
schema:
- $ref: '#/definitions/errors.Error'
- summary: Retrieve a tag by category
+ $ref: '#/definitions/utilities.SuccessResponse'
+ "400":
+ description: Bad Request
+ schema: {}
+ "429":
+ description: Too Many Requests
+ schema: {}
+ "500":
+ description: Internal Server Error
+ schema: {}
+ security:
+ - Bearer: []
+ summary: Verifies a password reset token
tags:
- - category-tag
- /clubs/:
+ - auth
+ /categories/:
get:
- description: Retrieves all clubs
- operationId: get-all-clubs
+ description: Retrieves all categories
+ operationId: get-categories
parameters:
- description: Limit
in: query
@@ -2539,175 +1726,108 @@ paths:
description: OK
schema:
items:
- $ref: '#/definitions/models.Club'
+ $ref: '#/definitions/models.Category'
type: array
"400":
description: Bad Request
schema:
- $ref: '#/definitions/errors.Error'
+ type: string
+ "404":
+ description: Not Found
+ schema:
+ type: string
"500":
description: Internal Server Error
schema:
- $ref: '#/definitions/errors.Error'
- summary: Retrieve all clubs
+ type: string
+ summary: Retrieve all categories
tags:
- - club
+ - category
post:
consumes:
- application/json
- description: Creates a club
- operationId: create-club
+ description: Creates a category
+ operationId: create-category
parameters:
- - description: Club
+ - description: Category Body
in: body
- name: club
+ name: categoryBody
required: true
schema:
- $ref: '#/definitions/models.CreateClubRequestBody'
+ $ref: '#/definitions/categories.CategoryRequestBody'
produces:
- application/json
responses:
"201":
description: Created
schema:
- $ref: '#/definitions/models.Club'
+ $ref: '#/definitions/models.Category'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
- "401":
- description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
- "404":
- description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
- "500":
- description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Create a club
- tags:
- - club
- /clubs/{clubID}/:
- delete:
- description: Deletes a club
- operationId: delete-club
- parameters:
- - description: Club ID
- in: path
- name: clubID
- required: true
- type: string
- produces:
- - application/json
- responses:
- "204":
- description: No Content
schema:
type: string
- "400":
- description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
"401":
description: Unauthorized
schema:
- $ref: '#/definitions/errors.Error'
+ type: string
"404":
description: Not Found
schema:
- $ref: '#/definitions/errors.Error'
- "500":
- description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Delete a club
- tags:
- - club
- get:
- description: Retrieves a club
- operationId: get-club
- parameters:
- - description: Club ID
- in: path
- name: clubID
- required: true
- type: string
- produces:
- - application/json
- responses:
- "200":
- description: OK
- schema:
- $ref: '#/definitions/models.Club'
- "400":
- description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
- "404":
- description: Not Found
+ type: string
+ "409":
+ description: Conflict
schema:
- $ref: '#/definitions/errors.Error'
+ type: string
"500":
description: Internal Server Error
schema:
- $ref: '#/definitions/errors.Error'
- summary: Retrieve a club
+ type: string
+ summary: Creates a category
tags:
- - club
- patch:
- consumes:
- - application/json
- description: Updates a club
- operationId: update-club
+ - category
+ /categories/{categoryID}/:
+ delete:
+ description: Deletes a category
+ operationId: delete-category
parameters:
- - description: Club ID
+ - description: Category ID
in: path
- name: clubID
+ name: categoryID
required: true
type: string
- - description: Club
- in: body
- name: club
- required: true
- schema:
- $ref: '#/definitions/models.UpdateClubRequestBody'
produces:
- application/json
responses:
- "200":
- description: OK
+ "204":
+ description: No Content
schema:
- $ref: '#/definitions/models.Club'
+ type: string
"400":
description: Bad Request
schema:
- $ref: '#/definitions/errors.Error'
+ type: string
"401":
description: Unauthorized
schema:
- $ref: '#/definitions/errors.Error'
+ type: string
"404":
description: Not Found
schema:
- $ref: '#/definitions/errors.Error'
+ type: string
"500":
description: Internal Server Error
schema:
- $ref: '#/definitions/errors.Error'
- summary: Update a club
+ type: string
+ summary: Deletes a category
tags:
- - club
- /clubs/{clubID}/contacts/:
+ - category
get:
- description: Retrieves all contacts associated with a club
- operationId: get-contacts-by-club
+ description: Retrieves a category
+ operationId: get-category
parameters:
- - description: Club ID
+ - description: Category ID
in: path
- name: clubID
+ name: categoryID
required: true
type: string
produces:
@@ -2716,75 +1836,73 @@ paths:
"200":
description: OK
schema:
- items:
- $ref: '#/definitions/models.Contact'
- type: array
+ $ref: '#/definitions/models.Category'
"400":
description: Bad Request
schema:
- $ref: '#/definitions/errors.Error'
+ type: string
"404":
description: Not Found
schema:
- $ref: '#/definitions/errors.Error'
+ type: string
"500":
description: Internal Server Error
schema:
- $ref: '#/definitions/errors.Error'
- summary: Retrieve all contacts for a club
+ type: string
+ summary: Retrieve a category
tags:
- - club-contact
- put:
+ - category
+ patch:
consumes:
- application/json
- description: Creates a contact
- operationId: put-contact
+ description: Updates a category
+ operationId: update-category
parameters:
- - description: Club ID
+ - description: Category ID
in: path
- name: clubID
+ name: categoryID
required: true
type: string
- - description: Contact Body
+ - description: Category Body
in: body
- name: contactBody
+ name: categoryBody
required: true
schema:
- $ref: '#/definitions/models.PutContactRequestBody'
+ $ref: '#/definitions/categories.CategoryRequestBody'
produces:
- application/json
responses:
- "201":
- description: Created
+ "200":
+ description: OK
schema:
- $ref: '#/definitions/models.Contact'
+ $ref: '#/definitions/models.Category'
"400":
description: Bad Request
schema:
- $ref: '#/definitions/errors.Error'
+ type: string
"401":
description: Unauthorized
schema:
- $ref: '#/definitions/errors.Error'
+ type: string
"404":
description: Not Found
schema:
- $ref: '#/definitions/errors.Error'
+ type: string
"500":
description: Internal Server Error
schema:
- $ref: '#/definitions/errors.Error'
- summary: Creates a contact
+ type: string
+ summary: Updates a category
tags:
- - club-contact
- /clubs/{clubID}/events/:
+ - category
+ /categories/{categoryID}/tags/:
get:
- description: Retrieves all events associated with a club
- operationId: get-events-by-club
+ description: Retrieves all tags associated with a category
+ operationId: get-tags-by-category
parameters:
- - description: Club ID
+ - description: Category ID
in: path
- name: clubID
+ name: categoryID
required: true
type: string
- description: Limit
@@ -2802,75 +1920,59 @@ paths:
description: OK
schema:
items:
- $ref: '#/definitions/models.Event'
+ $ref: '#/definitions/models.Tag'
type: array
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Retrieve all events for a club
+ schema: {}
+ summary: Retrieve all tags by category
tags:
- - club-event
- /clubs/{clubID}/followers/:
+ - category-tag
+ /categories/{categoryID}/tags/{tagID}/:
get:
- description: Retrieves all followers associated with a club
- operationId: get-followers-by-club
+ description: Retrieves a tag associated with a category
+ operationId: get-tag-by-category
parameters:
- - description: Club ID
+ - description: Category ID
in: path
- name: clubID
+ name: categoryID
+ required: true
+ type: string
+ - description: Tag ID
+ in: path
+ name: tagID
required: true
type: string
- - description: Limit
- in: query
- name: limit
- type: integer
- - description: Page
- in: query
- name: page
- type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
- items:
- $ref: '#/definitions/models.User'
- type: array
+ $ref: '#/definitions/models.Tag'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Retrieve all followers for a club
+ schema: {}
+ summary: Retrieve a tag by category
tags:
- - club-follower
- /clubs/{clubID}/members/:
+ - category-tag
+ /clubs/:
get:
- description: Retrieves all members associated with a club
- operationId: get-members-by-club
+ description: Retrieves all clubs
+ operationId: get-all-clubs
parameters:
- - description: Club ID
- in: path
- name: clubID
- required: true
- type: string
- description: Limit
in: query
name: limit
@@ -2886,188 +1988,86 @@ paths:
description: OK
schema:
items:
- $ref: '#/definitions/models.User'
+ $ref: '#/definitions/models.Club'
type: array
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
- "401":
- description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
- "404":
- description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Retrieve all members for a club
+ schema: {}
+ summary: Retrieve all clubs
tags:
- - club-member
- /clubs/{clubID}/poc/:
+ - club
post:
consumes:
- - multipart/form-data
- description: Creates a point of contact associated with a club
- operationId: create-point-of-contact-by-club
+ - application/json
+ description: Creates a club
+ operationId: create-club
parameters:
- - description: Club ID
- in: path
- name: clubID
+ - description: Club
+ in: body
+ name: club
required: true
- type: string
+ schema:
+ $ref: '#/definitions/base.CreateClubRequestBody'
produces:
- application/json
responses:
"201":
description: Created
schema:
- $ref: '#/definitions/models.PointOfContact'
+ $ref: '#/definitions/models.Club'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Create a point of contact for a club
+ schema: {}
+ summary: Create a club
tags:
- - club-point-of-contact
- /clubs/{clubID}/poc/{pocID}:
+ - club
+ /clubs/{clubID}/:
delete:
- description: Delete a point of contact associated with a club
- operationId: delete-point-of-contact-by-club
+ description: Deletes a club
+ operationId: delete-club
parameters:
- description: Club ID
in: path
name: clubID
required: true
type: string
- - description: Point of Contact ID
- in: path
- name: pocID
- required: true
- type: string
produces:
- application/json
responses:
"204":
description: No Content
- "400":
- description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
- "404":
- description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
- "500":
- description: Internal Server Error
schema:
- $ref: '#/definitions/errors.Error'
- summary: Delete a point of contact for a club
- tags:
- - club-point-of-contact
- patch:
- consumes:
- - multipart/form-data
- description: Updates a point of contact photo associated with a club
- operationId: update-point-of-contact-photo-by-club
- parameters:
- - description: Club ID
- in: path
- name: clubID
- required: true
- type: string
- - description: Point of Contact ID
- in: path
- name: pocID
- required: true
- type: string
- produces:
- - application/json
- responses:
- "200":
- description: OK
- schema:
- $ref: '#/definitions/models.PointOfContact'
- "400":
- description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
- "401":
- description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
- "404":
- description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
- "500":
- description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Update a point of contact photo for a club
- tags:
- - club-point-of-contact
- put:
- consumes:
- - application/json
- description: Updates a point of contact associated with a club
- operationId: update-point-of-contact-by-club
- parameters:
- - description: Club ID
- in: path
- name: clubID
- required: true
- type: string
- - description: Point of Contact ID
- in: path
- name: pocID
- required: true
- type: string
- produces:
- - application/json
- responses:
- "200":
- description: OK
- schema:
- $ref: '#/definitions/models.PointOfContact'
+ type: string
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Update a point of contact for a club
+ schema: {}
+ summary: Delete a club
tags:
- - club-point-of-contact
- /clubs/{clubID}/pocs/:
+ - club
get:
- description: Retrieves all point of contacts associated with a club
- operationId: get-point-of-contacts-by-club
+ description: Retrieves a club
+ operationId: get-club
parameters:
- description: Club ID
in: path
@@ -3080,65 +2080,62 @@ paths:
"200":
description: OK
schema:
- items:
- $ref: '#/definitions/models.PointOfContact'
- type: array
+ $ref: '#/definitions/models.Club'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Retrieve all point of contacts for a club
+ schema: {}
+ summary: Retrieve a club
tags:
- - club-point-of-contact
- /clubs/{clubID}/pocs/{pocID}:
- get:
- description: Retrieves a point of contact associated with a club
- operationId: get-point-of-contact-by-club
+ - club
+ patch:
+ consumes:
+ - application/json
+ description: Updates a club
+ operationId: update-club
parameters:
- description: Club ID
in: path
name: clubID
required: true
type: string
- - description: Point of Contact ID
- in: path
- name: pocID
+ - description: Club
+ in: body
+ name: club
required: true
- type: string
+ schema:
+ $ref: '#/definitions/base.UpdateClubRequestBody'
produces:
- application/json
responses:
"200":
description: OK
schema:
- $ref: '#/definitions/models.PointOfContact'
+ $ref: '#/definitions/models.Club'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
+ "401":
+ description: Unauthorized
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Retrieve a point of contact for a club
+ schema: {}
+ summary: Update a club
tags:
- - club-point-of-contact
- /clubs/{clubID}/tags/:
+ - club
+ /clubs/{clubID}/contacts/:
get:
- description: Retrieves all tags associated with a club
- operationId: get-tags-by-club
+ description: Retrieves all contacts associated with a club
+ operationId: get-contacts-by-club
parameters:
- description: Club ID
in: path
@@ -3152,114 +2149,108 @@ paths:
description: OK
schema:
items:
- $ref: '#/definitions/models.Tag'
+ $ref: '#/definitions/models.Contact'
type: array
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Retrieve all tags for a club
+ schema: {}
+ summary: Retrieve all contacts for a club
tags:
- - club-tag
- post:
+ - club-contact
+ put:
consumes:
- application/json
- description: Creates tags for a club
- operationId: create-club-tags
+ description: Creates a contact
+ operationId: put-contact
parameters:
- description: Club ID
in: path
name: clubID
required: true
type: string
- - description: Club Tags Body
+ - description: Contact Body
in: body
- name: clubTagsBody
+ name: contactBody
required: true
schema:
- $ref: '#/definitions/models.CreateClubTagsRequestBody'
+ $ref: '#/definitions/contacts.PutContactRequestBody'
produces:
- application/json
responses:
"201":
description: Created
schema:
- items:
- $ref: '#/definitions/models.Tag'
- type: array
+ $ref: '#/definitions/models.Contact'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Create club tags
+ schema: {}
+ summary: Creates a contact
tags:
- - club-tag
- /clubs/{clubID}/tags/{tagID}/:
- delete:
- description: Deletes a tag associated with a club
- operationId: delete-tag-by-club
+ - club-contact
+ /clubs/{clubID}/events/:
+ get:
+ description: Retrieves all events associated with a club
+ operationId: get-events-by-club
parameters:
- description: Club ID
in: path
name: clubID
required: true
type: string
- - description: Tag ID
- in: path
- name: tagID
- required: true
- type: string
+ - description: Limit
+ in: query
+ name: limit
+ type: integer
+ - description: Page
+ in: query
+ name: page
+ type: integer
produces:
- application/json
responses:
- "204":
- description: No Content
+ "200":
+ description: OK
schema:
- type: string
+ items:
+ $ref: '#/definitions/models.Event'
+ type: array
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
- "401":
- description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Delete a tag for a club
+ schema: {}
+ summary: Retrieve all events for a club
tags:
- - club-tag
- /contacts/:
+ - club-event
+ /clubs/{clubID}/followers/:
get:
- description: Retrieves all contacts
- operationId: get-contacts
+ description: Retrieves all followers associated with a club
+ operationId: get-followers-by-club
parameters:
+ - description: Club ID
+ in: path
+ name: clubID
+ required: true
+ type: string
- description: Limit
in: query
name: limit
@@ -3275,95 +2266,66 @@ paths:
description: OK
schema:
items:
- $ref: '#/definitions/models.Contact'
+ $ref: '#/definitions/models.User'
type: array
"400":
description: Bad Request
- schema:
- type: string
+ schema: {}
"404":
description: Not Found
- schema:
- type: string
+ schema: {}
"500":
description: Internal Server Error
- schema:
- type: string
- summary: Retrieve all contacts
+ schema: {}
+ summary: Retrieve all followers for a club
tags:
- - contact
- /contacts/{contactID}/:
+ - club-follower
+ /clubs/{clubID}/members/:
delete:
- consumes:
- - application/json
- description: Deletes a contact
- operationId: delete-contact
+ description: Deletes a member associated with a club
+ operationId: delete-member-from-club
parameters:
- - description: Contact ID
+ - description: Club ID
in: path
- name: contactID
+ name: clubID
required: true
type: string
- produces:
- - application/json
- responses:
- "201":
- description: Created
- schema:
- $ref: '#/definitions/models.Contact'
- "400":
- description: Bad Request
- schema:
- type: string
- "404":
- description: Not Found
- schema:
- type: string
- "500":
- description: Internal Server Error
- schema:
- type: string
- summary: Deletes a contact
- tags:
- - contact
- get:
- consumes:
- - application/json
- description: Retrieves a contact by id
- operationId: get-contact
- parameters:
- - description: Contact ID
+ - description: User ID
in: path
- name: contactID
+ name: userID
required: true
type: string
produces:
- application/json
responses:
- "201":
- description: Created
+ "204":
+ description: No Content
schema:
- $ref: '#/definitions/models.Contact'
+ $ref: '#/definitions/models.User'
"400":
description: Bad Request
- schema:
- type: string
+ schema: {}
+ "401":
+ description: Unauthorized
+ schema: {}
"404":
description: Not Found
- schema:
- type: string
+ schema: {}
"500":
description: Internal Server Error
- schema:
- type: string
- summary: Retrieves a contact
+ schema: {}
+ summary: Delete a member from a club
tags:
- - contact
- /events/:
+ - club-member
get:
- description: Retrieves all events
- operationId: get-all-events
+ description: Retrieves all members associated with a club
+ operationId: get-members-by-club
parameters:
+ - description: Club ID
+ in: path
+ name: clubID
+ required: true
+ type: string
- description: Limit
in: query
name: limit
@@ -3379,69 +2341,108 @@ paths:
description: OK
schema:
items:
- $ref: '#/definitions/models.Event'
+ $ref: '#/definitions/models.User'
type: array
"400":
description: Bad Request
+ schema: {}
+ "401":
+ description: Unauthorized
+ schema: {}
+ "404":
+ description: Not Found
+ schema: {}
+ "500":
+ description: Internal Server Error
+ schema: {}
+ summary: Retrieve all members for a club
+ tags:
+ - club-member
+ post:
+ consumes:
+ - application/json
+ description: Creates a new member associated with a club
+ operationId: create-member-for-club
+ parameters:
+ - description: Club ID
+ in: path
+ name: clubID
+ required: true
+ type: string
+ - description: User ID
+ in: path
+ name: userID
+ required: true
+ type: string
+ produces:
+ - application/json
+ responses:
+ "201":
+ description: Created
schema:
- $ref: '#/definitions/errors.Error'
+ $ref: '#/definitions/models.User'
+ "400":
+ description: Bad Request
+ schema: {}
+ "401":
+ description: Unauthorized
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Retrieve all events
+ schema: {}
+ summary: Create a new member for a club
tags:
- - event
+ - club-member
+ /clubs/{clubID}/poc/:
post:
consumes:
- - application/json
- description: Creates an event
- operationId: create-event
+ - multipart/form-data
+ description: Creates a point of contact associated with a club
+ operationId: create-point-of-contact-by-club
parameters:
- - description: Event Body
- in: body
- name: event
+ - description: Club ID
+ in: path
+ name: clubID
required: true
- schema:
- $ref: '#/definitions/models.CreateEventRequestBody'
+ type: string
produces:
- application/json
responses:
"201":
description: Created
schema:
- $ref: '#/definitions/models.Event'
+ $ref: '#/definitions/models.PointOfContact'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Create an event
+ schema: {}
+ summary: Create a point of contact for a club
tags:
- - event
- /events/{eventID}/:
+ - club-point-of-contact
+ /clubs/{clubID}/poc/{pocID}:
delete:
- description: Deletes an event
- operationId: delete-event
+ description: Delete a point of contact associated with a club
+ operationId: delete-point-of-contact-by-club
parameters:
- - description: Event ID
+ - description: Club ID
in: path
- name: eventID
+ name: clubID
+ required: true
+ type: string
+ - description: Point of Contact ID
+ in: path
+ name: pocID
required: true
type: string
produces:
@@ -3449,34 +2450,70 @@ paths:
responses:
"204":
description: No Content
- schema:
- type: string
"400":
description: Bad Request
+ schema: {}
+ "404":
+ description: Not Found
+ schema: {}
+ "500":
+ description: Internal Server Error
+ schema: {}
+ summary: Delete a point of contact for a club
+ tags:
+ - club-point-of-contact
+ patch:
+ consumes:
+ - multipart/form-data
+ description: Updates a point of contact photo associated with a club
+ operationId: update-point-of-contact-photo-by-club
+ parameters:
+ - description: Club ID
+ in: path
+ name: clubID
+ required: true
+ type: string
+ - description: Point of Contact ID
+ in: path
+ name: pocID
+ required: true
+ type: string
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
schema:
- $ref: '#/definitions/errors.Error'
+ $ref: '#/definitions/models.PointOfContact'
+ "400":
+ description: Bad Request
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Delete an event
+ schema: {}
+ summary: Update a point of contact photo for a club
tags:
- - event
- get:
- description: Retrieves an event
- operationId: get-event
+ - club-point-of-contact
+ put:
+ consumes:
+ - application/json
+ description: Updates a point of contact associated with a club
+ operationId: update-point-of-contact-by-club
parameters:
- - description: Event ID
+ - description: Club ID
in: path
- name: eventID
+ name: clubID
+ required: true
+ type: string
+ - description: Point of Contact ID
+ in: path
+ name: pocID
required: true
type: string
produces:
@@ -3485,30 +2522,30 @@ paths:
"200":
description: OK
schema:
- $ref: '#/definitions/models.Event'
+ $ref: '#/definitions/models.PointOfContact'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
+ "401":
+ description: Unauthorized
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Retrieve an event
+ schema: {}
+ summary: Update a point of contact for a club
tags:
- - event
- /events/{eventID}/hosts:
+ - club-point-of-contact
+ /clubs/{clubID}/pocs/:
get:
- description: Retrieves all hosts associated with an event
- operationId: get-hosts-by-event
+ description: Retrieves all point of contacts associated with a club
+ operationId: get-point-of-contacts-by-club
parameters:
- - description: Event ID
+ - description: Club ID
in: path
- name: eventID
+ name: clubID
required: true
type: string
produces:
@@ -3518,66 +2555,62 @@ paths:
description: OK
schema:
items:
- $ref: '#/definitions/models.Club'
+ $ref: '#/definitions/models.PointOfContact'
type: array
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Retrieve all hosts by event
+ schema: {}
+ summary: Retrieve all point of contacts for a club
tags:
- - event
- /events/{eventID}/series/:
- delete:
- description: Deletes all series associated with an event
- operationId: delete-series-by-event
+ - club-point-of-contact
+ /clubs/{clubID}/pocs/{pocID}:
+ get:
+ description: Retrieves a point of contact associated with a club
+ operationId: get-point-of-contact-by-club
parameters:
- - description: Event ID
+ - description: Club ID
in: path
- name: eventID
+ name: clubID
+ required: true
+ type: string
+ - description: Point of Contact ID
+ in: path
+ name: pocID
required: true
type: string
produces:
- application/json
responses:
- "204":
- description: No Content
+ "200":
+ description: OK
schema:
- type: string
+ $ref: '#/definitions/models.PointOfContact'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
- "401":
- description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Delete all series by event
+ schema: {}
+ summary: Retrieve a point of contact for a club
tags:
- - event
+ - club-point-of-contact
+ /clubs/{clubID}/tags/:
get:
- description: Retrieves all series associated with an event
- operationId: get-series-by-event
+ description: Retrieves all tags associated with a club
+ operationId: get-tags-by-club
parameters:
- - description: Event ID
+ - description: Club ID
in: path
- name: eventID
+ name: clubID
required: true
type: string
produces:
@@ -3587,79 +2620,74 @@ paths:
description: OK
schema:
items:
- $ref: '#/definitions/models.Series'
+ $ref: '#/definitions/models.Tag'
type: array
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Retrieve all series by event
+ schema: {}
+ summary: Retrieve all tags for a club
tags:
- - event
- patch:
+ - club-tag
+ post:
consumes:
- application/json
- description: Creates a series
- operationId: create-series
+ description: Creates tags for a club
+ operationId: create-club-tags
parameters:
- - description: Event ID
+ - description: Club ID
in: path
- name: eventID
+ name: clubID
required: true
type: string
- - description: Series Body
+ - description: Club Tags Body
in: body
- name: seriesBody
+ name: clubTagsBody
required: true
schema:
- $ref: '#/definitions/models.UpdateEventRequestBody'
+ $ref: '#/definitions/tags.CreateClubTagsRequestBody'
produces:
- application/json
responses:
"201":
description: Created
schema:
- $ref: '#/definitions/models.Series'
+ items:
+ $ref: '#/definitions/models.Tag'
+ type: array
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Create a series
+ schema: {}
+ summary: Create club tags
tags:
- - event
- /events/{eventID}/series/{seriesID}/:
+ - club-tag
+ /clubs/{clubID}/tags/{tagID}/:
delete:
- description: Deletes a series by ID
- operationId: delete-series-by-id
+ description: Deletes a tag associated with a club
+ operationId: delete-tag-by-club
parameters:
- - description: Event ID
+ - description: Club ID
in: path
- name: eventID
+ name: clubID
required: true
type: string
- - description: Series ID
+ - description: Tag ID
in: path
- name: seriesID
+ name: tagID
required: true
type: string
produces:
@@ -3668,109 +2696,164 @@ paths:
"204":
description: No Content
schema:
- type: string
+ type: string
+ "400":
+ description: Bad Request
+ schema: {}
+ "401":
+ description: Unauthorized
+ schema: {}
+ "404":
+ description: Not Found
+ schema: {}
+ "500":
+ description: Internal Server Error
+ schema: {}
+ summary: Delete a tag for a club
+ tags:
+ - club-tag
+ /contacts/:
+ get:
+ description: Retrieves all contacts
+ operationId: get-contacts
+ parameters:
+ - description: Limit
+ in: query
+ name: limit
+ type: integer
+ - description: Page
+ in: query
+ name: page
+ type: integer
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ items:
+ $ref: '#/definitions/models.Contact'
+ type: array
+ "400":
+ description: Bad Request
+ schema:
+ type: string
+ "404":
+ description: Not Found
+ schema:
+ type: string
+ "500":
+ description: Internal Server Error
+ schema:
+ type: string
+ summary: Retrieve all contacts
+ tags:
+ - contact
+ /contacts/{contactID}/:
+ delete:
+ consumes:
+ - application/json
+ description: Deletes a contact
+ operationId: delete-contact
+ parameters:
+ - description: Contact ID
+ in: path
+ name: contactID
+ required: true
+ type: string
+ produces:
+ - application/json
+ responses:
+ "201":
+ description: Created
+ schema:
+ $ref: '#/definitions/models.Contact'
"400":
description: Bad Request
schema:
- $ref: '#/definitions/errors.Error'
- "401":
- description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ type: string
"404":
description: Not Found
schema:
- $ref: '#/definitions/errors.Error'
+ type: string
"500":
description: Internal Server Error
schema:
- $ref: '#/definitions/errors.Error'
- summary: Delete a series by ID
+ type: string
+ summary: Deletes a contact
tags:
- - event
+ - contact
get:
- description: Retrieves a series by ID
- operationId: get-series-by-id
+ consumes:
+ - application/json
+ description: Retrieves a contact by id
+ operationId: get-contact
parameters:
- - description: Event ID
- in: path
- name: eventID
- required: true
- type: string
- - description: Series ID
+ - description: Contact ID
in: path
- name: seriesID
+ name: contactID
required: true
type: string
produces:
- application/json
responses:
- "200":
- description: OK
+ "201":
+ description: Created
schema:
- $ref: '#/definitions/models.Series'
+ $ref: '#/definitions/models.Contact'
"400":
description: Bad Request
schema:
- $ref: '#/definitions/errors.Error'
+ type: string
"404":
description: Not Found
schema:
- $ref: '#/definitions/errors.Error'
+ type: string
"500":
description: Internal Server Error
schema:
- $ref: '#/definitions/errors.Error'
- summary: Retrieve a series by ID
+ type: string
+ summary: Retrieves a contact
tags:
- - event
- patch:
- consumes:
- - application/json
- description: Updates a series by event ID
- operationId: update-series-by-event-id
+ - contact
+ /events/:
+ get:
+ description: Retrieves all events
+ operationId: get-all-events
parameters:
- - description: Event ID
- in: path
- name: eventID
- required: true
- type: string
- - description: Series Body
- in: body
- name: seriesBody
- required: true
- schema:
- $ref: '#/definitions/models.UpdateSeriesRequestBody'
+ - description: Limit
+ in: query
+ name: limit
+ type: integer
+ - description: Page
+ in: query
+ name: page
+ type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
- $ref: '#/definitions/models.Series'
+ items:
+ $ref: '#/definitions/models.Event'
+ type: array
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
- "401":
- description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Update a series by event ID
+ schema: {}
+ summary: Retrieve all events
tags:
- event
- /events/{eventID}/tags:
+ /events/{eventID}/:
get:
- description: Retrieves all tags associated with an event
- operationId: get-tags-by-event
+ description: Retrieves an event
+ operationId: get-event
parameters:
- description: Event ID
in: path
@@ -3783,22 +2866,17 @@ paths:
"200":
description: OK
schema:
- items:
- $ref: '#/definitions/models.Tag'
- type: array
+ $ref: '#/definitions/models.Event'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Retrieve all tags by event
+ schema: {}
+ summary: Retrieve an event
tags:
- event
/files/:
@@ -3825,20 +2903,16 @@ paths:
type: array
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Retrieve all files
tags:
- file
@@ -3853,7 +2927,7 @@ paths:
name: file
required: true
schema:
- $ref: '#/definitions/models.CreateFileRequestBody'
+ $ref: '#/definitions/base.CreateFileRequestBody'
produces:
- application/json
responses:
@@ -3863,20 +2937,16 @@ paths:
$ref: '#/definitions/models.File'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Create a file
tags:
- file
@@ -3899,20 +2969,16 @@ paths:
$ref: '#/definitions/models.File'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Delete a file
tags:
- file
@@ -3934,20 +3000,16 @@ paths:
$ref: '#/definitions/models.File'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Retrieve a file
tags:
- file
@@ -4044,16 +3106,13 @@ paths:
type: array
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Retrieve all tags
tags:
- tag
@@ -4069,7 +3128,7 @@ paths:
name: tagBody
required: true
schema:
- $ref: '#/definitions/models.CreateTagRequestBody'
+ $ref: '#/definitions/base.CreateTagRequestBody'
produces:
- application/json
responses:
@@ -4079,20 +3138,16 @@ paths:
$ref: '#/definitions/models.Tag'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Create a tag
tags:
- tag
@@ -4115,20 +3170,16 @@ paths:
type: string
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Delete a tag
tags:
- tag
@@ -4150,16 +3201,13 @@ paths:
$ref: '#/definitions/models.Tag'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Retrieve a tag
tags:
- tag
@@ -4179,7 +3227,7 @@ paths:
name: tag
required: true
schema:
- $ref: '#/definitions/models.UpdateTagRequestBody'
+ $ref: '#/definitions/base.UpdateTagRequestBody'
produces:
- application/json
responses:
@@ -4189,20 +3237,16 @@ paths:
$ref: '#/definitions/models.Tag'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Update a tag
tags:
- tag
@@ -4230,61 +3274,16 @@ paths:
type: array
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Retrieve all users
tags:
- user
- post:
- consumes:
- - application/json
- description: Creates a user
- operationId: create-user
- parameters:
- - description: User Body
- in: body
- name: userBody
- required: true
- schema:
- $ref: '#/definitions/models.CreateUserRequestBody'
- produces:
- - application/json
- responses:
- "201":
- description: Created
- schema:
- $ref: '#/definitions/models.User'
- "400":
- description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
- "401":
- description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
- "404":
- description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
- "409":
- description: Conflict
- schema:
- $ref: '#/definitions/errors.Error'
- "500":
- description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Create a user
- tags:
- - user
/users/{userID}/:
delete:
description: Deletes a user
@@ -4304,20 +3303,16 @@ paths:
type: string
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Delete a user
tags:
- user
@@ -4339,20 +3334,16 @@ paths:
$ref: '#/definitions/models.User'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Retrieve a user
tags:
- user
@@ -4372,7 +3363,7 @@ paths:
name: userBody
required: true
schema:
- $ref: '#/definitions/models.UpdateUserRequestBody'
+ $ref: '#/definitions/base.UpdateUserRequestBody'
produces:
- application/json
responses:
@@ -4382,20 +3373,16 @@ paths:
$ref: '#/definitions/models.User'
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Update a user
tags:
- user
@@ -4420,20 +3407,16 @@ paths:
type: array
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Retrieve all clubs a user is following
tags:
- user-follower
@@ -4463,16 +3446,13 @@ paths:
$ref: '#/definitions/utilities.SuccessResponse'
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Unfollow a club
tags:
- user-follower
@@ -4501,16 +3481,13 @@ paths:
$ref: '#/definitions/utilities.SuccessResponse'
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Follow a club
tags:
- user-follower
@@ -4535,100 +3512,19 @@ paths:
type: array
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Retrieve all clubs a user is a member of
tags:
- user-member
- /users/{userID}/member/{clubID}/:
- delete:
- consumes:
- - application/json
- description: Leave a club
- operationId: delete-membership
- parameters:
- - description: User ID
- in: path
- name: userID
- required: true
- type: string
- - description: Club ID
- in: path
- name: clubID
- required: true
- type: string
- produces:
- - application/json
- responses:
- "204":
- description: No Content
- schema:
- $ref: '#/definitions/utilities.SuccessResponse'
- "401":
- description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
- "404":
- description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
- "500":
- description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Leave a club
- tags:
- - user-member
- post:
- consumes:
- - application/json
- description: Join a club
- operationId: create-membership
- parameters:
- - description: User ID
- in: path
- name: userID
- required: true
- type: string
- - description: Club ID
- in: path
- name: clubID
- required: true
- type: string
- produces:
- - application/json
- responses:
- "201":
- description: Created
- schema:
- $ref: '#/definitions/utilities.SuccessResponse'
- "401":
- description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
- "404":
- description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
- "500":
- description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
- summary: Join a club
- tags:
- - user-member
/users/{userID}/password:
patch:
consumes:
@@ -4646,7 +3542,7 @@ paths:
name: passwordBody
required: true
schema:
- $ref: '#/definitions/models.UpdatePasswordRequestBody'
+ $ref: '#/definitions/auth.UpdatePasswordRequestBody'
produces:
- application/json
responses:
@@ -4656,20 +3552,16 @@ paths:
type: string
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Update a user's password
tags:
- user
@@ -4692,20 +3584,16 @@ paths:
description: Created
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Create user tags
tags:
- user-tag
@@ -4729,20 +3617,16 @@ paths:
type: array
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Retrieve all tags for a user
tags:
- user-tag
@@ -4762,7 +3646,7 @@ paths:
name: userTagsBody
required: true
schema:
- $ref: '#/definitions/tag.CreateUserTagsBody'
+ $ref: '#/definitions/tags.CreateUserTagsBody'
produces:
- application/json
responses:
@@ -4774,20 +3658,16 @@ paths:
type: array
"400":
description: Bad Request
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"401":
description: Unauthorized
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"404":
description: Not Found
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
"500":
description: Internal Server Error
- schema:
- $ref: '#/definitions/errors.Error'
+ schema: {}
summary: Create user tags
tags:
- user-tag
diff --git a/backend/entities/auth/base/controller.go b/backend/entities/auth/base/controller.go
index 52594fce9..48396131e 100644
--- a/backend/entities/auth/base/controller.go
+++ b/backend/entities/auth/base/controller.go
@@ -1,9 +1,11 @@
package base
import (
+ "net/http"
+
"github.com/GenerateNU/sac/backend/auth"
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+ authEntities "github.com/GenerateNU/sac/backend/entities/auth"
+ users "github.com/GenerateNU/sac/backend/entities/users/base"
"github.com/GenerateNU/sac/backend/utilities"
"github.com/gofiber/fiber/v2"
)
@@ -24,63 +26,97 @@ func NewAuthController(authService AuthServiceInterface) *AuthController {
// @Tags auth
// @Accept json
// @Produce json
-// @Param loginBody body models.LoginUserResponseBody true "Login Body"
+// @Param loginBody body authEntities.LoginResponseBody true "Login Body"
// @Success 200 {object} models.User
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /auth/login [post]
func (a *AuthController) Login(c *fiber.Ctx) error {
- var userBody models.LoginUserResponseBody
+ var userBody authEntities.LoginResponseBody
if err := c.BodyParser(&userBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ return utilities.InvalidJSON()
}
user, tokens, err := a.authService.Login(userBody)
if err != nil {
- return err.FiberError(c)
+ return err
+ }
+
+ err = auth.SetResponseTokens(c, tokens)
+ if err != nil {
+ return err
+ }
+
+ return c.Status(http.StatusOK).JSON(user)
+}
+
+// Register godoc
+//
+// @Summary Registers a user
+// @Description Registers a user
+// @ID register-user
+// @Tags auth
+// @Accept json
+// @Produce json
+// @Param userBody body CreateUserRequestBody true "User Body"
+// @Success 201 {object} models.User
+// @Failure 400 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
+// @Router /auth/register [post]
+func (a *AuthController) Register(c *fiber.Ctx) error {
+ var userBody users.CreateUserRequestBody
+
+ if err := c.BodyParser(&userBody); err != nil {
+ return utilities.InvalidJSON()
+ }
+
+ user, tokens, err := a.authService.Register(userBody)
+ if err != nil {
+ return err
}
err = auth.SetResponseTokens(c, tokens)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(user)
+ return c.Status(http.StatusCreated).JSON(user)
}
// Refresh godoc
//
-// @Summary Refreshes a user's access token
-// @Description Refreshes a user's access token
+// @Summary Refreshes a user's access token and returns a new pair of tokens
+// @Description Refreshes a user's access token and returns a new pair of tokens
// @ID refresh-user
// @Tags auth
// @Accept json
// @Produce json
// @Success 200 {object} utilities.SuccessResponse
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /auth/refresh [post]
func (a *AuthController) Refresh(c *fiber.Ctx) error {
- var refreshBody models.RefreshTokenRequestBody
+ var refreshBody RefreshTokenCookieBody
- if err := c.BodyParser(&refreshBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ if err := c.CookieParser(&refreshBody); err != nil {
+ return utilities.InvalidJSON()
}
tokens, err := a.authService.Refresh(refreshBody.RefreshToken)
if err != nil {
- return err.FiberError(c)
+ return err
}
err = auth.SetResponseTokens(c, tokens)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return utilities.FiberMessage(c, fiber.StatusOK, "success")
+ return utilities.FiberMessage(c, http.StatusOK, "success")
}
// Logout godoc
@@ -96,10 +132,10 @@ func (a *AuthController) Refresh(c *fiber.Ctx) error {
func (a *AuthController) Logout(c *fiber.Ctx) error {
err := a.authService.Logout(c)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return utilities.FiberMessage(c, fiber.StatusOK, "success")
+ return utilities.FiberMessage(c, http.StatusOK, "success")
}
// ForgotPassword godoc
@@ -112,22 +148,22 @@ func (a *AuthController) Logout(c *fiber.Ctx) error {
// @Produce json
// @Param email body string true "Email"
// @Success 200 {object} utilities.SuccessResponse
-// @Failure 400 {object} errors.Error
-// @Failure 429 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 429 {object} error
+// @Failure 500 {object} error
// @Router /auth/forgot-password [post]
func (a *AuthController) ForgotPassword(c *fiber.Ctx) error {
- var emailBody models.EmailRequestBody
+ var emailBody EmailRequestBody
if err := c.BodyParser(&emailBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ return utilities.InvalidJSON()
}
if err := a.authService.ForgotPassword(emailBody.Email); err != nil {
- return err.FiberError(c)
+ return err
}
- return utilities.FiberMessage(c, fiber.StatusOK, "success")
+ return utilities.FiberMessage(c, http.StatusOK, "success")
}
// VerifyPasswordResetToken godoc
@@ -138,25 +174,25 @@ func (a *AuthController) ForgotPassword(c *fiber.Ctx) error {
// @Tags auth
// @Accept json
// @Produce json
-// @Param tokenBody body models.VerifyPasswordResetTokenRequestBody true "Password Reset Token Body"
+// @Param tokenBody body VerifyPasswordResetTokenRequestBody true "Password Reset Token Body"
// @Security Bearer
// @Success 200 {object} utilities.SuccessResponse
-// @Failure 400 {object} errors.Error
-// @Failure 429 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 429 {object} error
+// @Failure 500 {object} error
// @Router /auth/verify-reset [post]
func (a *AuthController) VerifyPasswordResetToken(c *fiber.Ctx) error {
- var tokenBody models.VerifyPasswordResetTokenRequestBody
+ var tokenBody VerifyPasswordResetTokenRequestBody
if err := c.BodyParser(&tokenBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ return utilities.InvalidJSON()
}
if err := a.authService.VerifyPasswordResetToken(tokenBody); err != nil {
- return err.FiberError(c)
+ return err
}
- return utilities.FiberMessage(c, fiber.StatusOK, "success")
+ return utilities.FiberMessage(c, http.StatusOK, "success")
}
// SendCode godoc
@@ -169,22 +205,22 @@ func (a *AuthController) VerifyPasswordResetToken(c *fiber.Ctx) error {
// @Produce json
// @Param email body string true "Email"
// @Success 200 {object} utilities.SuccessResponse
-// @Failure 400 {object} errors.Error
-// @Failure 429 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 429 {object} error
+// @Failure 500 {object} error
// @Router /auth/send-code [post]
func (a *AuthController) SendCode(c *fiber.Ctx) error {
- var emailBody models.EmailRequestBody
+ var emailBody EmailRequestBody
if err := c.BodyParser(&emailBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ return utilities.InvalidJSON()
}
if err := a.authService.SendCode(emailBody.Email); err != nil {
- return err.FiberError(c)
+ return err
}
- return utilities.FiberMessage(c, fiber.StatusOK, "success")
+ return utilities.FiberMessage(c, http.StatusOK, "success")
}
// VerifyEmail godoc
@@ -195,22 +231,22 @@ func (a *AuthController) SendCode(c *fiber.Ctx) error {
// @Tags auth
// @Accept json
// @Produce json
-// @Param tokenBody body models.VerifyEmailRequestBody true "Email Verification Token Body"
+// @Param tokenBody body VerifyEmailRequestBody true "Email Verification Token Body"
// @Success 200 {object} utilities.SuccessResponse
-// @Failure 400 {object} errors.Error
-// @Failure 429 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 429 {object} error
+// @Failure 500 {object} error
// @Router /auth/verify-email [post]
func (a *AuthController) VerifyEmail(c *fiber.Ctx) error {
- var tokenBody models.VerifyEmailRequestBody
+ var tokenBody VerifyEmailRequestBody
if err := c.BodyParser(&tokenBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ return utilities.InvalidJSON()
}
if err := a.authService.VerifyEmail(tokenBody); err != nil {
- return err.FiberError(c)
+ return err
}
- return utilities.FiberMessage(c, fiber.StatusOK, "success")
+ return utilities.FiberMessage(c, http.StatusOK, "success")
}
diff --git a/backend/entities/auth/base/models.go b/backend/entities/auth/base/models.go
new file mode 100644
index 000000000..a15a48349
--- /dev/null
+++ b/backend/entities/auth/base/models.go
@@ -0,0 +1,20 @@
+package base
+
+type VerifyEmailRequestBody struct {
+ Email string `json:"email" validate:"required,email"`
+ Token string `json:"token" validate:"required,len=6"`
+}
+
+type VerifyPasswordResetTokenRequestBody struct {
+ Token string `json:"token" validate:"required"`
+ NewPassword string `json:"new_password" validate:"required,min=8,password"`
+ VerifyNewPassword string `json:"verify_new_password" validate:"required,min=8,password,eqfield=NewPassword"`
+}
+
+type EmailRequestBody struct {
+ Email string `json:"email" validate:"required,email"`
+}
+
+type RefreshTokenCookieBody struct {
+ RefreshToken string `cookie:"refresh_token" validate:"required"`
+}
diff --git a/backend/entities/auth/base/routes.go b/backend/entities/auth/base/routes.go
index 5000e1f5e..b79cbd818 100644
--- a/backend/entities/auth/base/routes.go
+++ b/backend/entities/auth/base/routes.go
@@ -10,6 +10,7 @@ func Auth(params types.RouteParams) {
// api/v1/auth/*
auth := params.Router.Group("/auth")
+ auth.Post("/register", authController.Register)
auth.Post("/logout", authController.Logout)
auth.Post("/login", authController.Login)
auth.Post("/refresh", authController.Refresh)
diff --git a/backend/entities/auth/base/service.go b/backend/entities/auth/base/service.go
index bc68504e6..c2ebc4371 100644
--- a/backend/entities/auth/base/service.go
+++ b/backend/entities/auth/base/service.go
@@ -1,12 +1,17 @@
package base
import (
+ "errors"
+ "fmt"
+ "log/slog"
"time"
"github.com/GenerateNU/sac/backend/auth"
+ authEntities "github.com/GenerateNU/sac/backend/entities/auth"
"github.com/GenerateNU/sac/backend/entities/models"
"github.com/GenerateNU/sac/backend/entities/users"
- "github.com/GenerateNU/sac/backend/errors"
+ usersEntities "github.com/GenerateNU/sac/backend/entities/users/base"
+
"github.com/GenerateNU/sac/backend/types"
"github.com/GenerateNU/sac/backend/utilities"
@@ -16,16 +21,17 @@ import (
)
type AuthServiceInterface interface {
- GetRole(id string) (*models.UserRole, *errors.Error)
- Login(userBody models.LoginUserResponseBody) (*models.User, *auth.Token, *errors.Error)
- Refresh(refreshToken string) (*auth.Token, *errors.Error)
- Logout(c *fiber.Ctx) *errors.Error
+ GetRole(id string) (*models.UserRole, error)
+ Register(userBody usersEntities.CreateUserRequestBody) (*models.User, *auth.Token, error)
+ Login(userBody authEntities.LoginResponseBody) (*models.User, *auth.Token, error)
+ Refresh(refreshToken string) (*auth.Token, error)
+ Logout(c *fiber.Ctx) error
- SendCode(email string) *errors.Error
- VerifyEmail(emailBody models.VerifyEmailRequestBody) *errors.Error
+ SendCode(email string) error
+ VerifyEmail(emailBody VerifyEmailRequestBody) error
- ForgotPassword(email string) *errors.Error
- VerifyPasswordResetToken(passwordBody models.VerifyPasswordResetTokenRequestBody) *errors.Error
+ ForgotPassword(email string) error
+ VerifyPasswordResetToken(passwordBody VerifyPasswordResetTokenRequestBody) error
}
type AuthService struct {
@@ -36,23 +42,19 @@ func NewAuthService(serviceParams types.ServiceParams) AuthServiceInterface {
return &AuthService{serviceParams}
}
-func (a *AuthService) Login(loginBody models.LoginUserResponseBody) (*models.User, *auth.Token, *errors.Error) {
- if err := a.Validate.Struct(loginBody); err != nil {
- return nil, nil, &errors.FailedToValidateUser
- }
-
- if pwordValErr := auth.ValidatePassword(loginBody.Password); pwordValErr != nil {
- return nil, nil, pwordValErr
+func (a *AuthService) Login(loginBody authEntities.LoginResponseBody) (*models.User, *auth.Token, error) {
+ if err := utilities.Validate(a.Validate, loginBody, *utilities.NewMaybeError("password", auth.ValidatePassword(loginBody.Password))); err != nil {
+ return nil, nil, err
}
- user, getUserByEmailErr := users.GetUserByEmail(a.DB, loginBody.Email)
- if getUserByEmailErr != nil {
- return nil, nil, getUserByEmailErr
+ user, err := users.GetUserByEmail(a.DB, loginBody.Email)
+ if err != nil {
+ return nil, nil, err
}
- correct, passwordErr := auth.CompareHash(loginBody.Password, user.PasswordHash)
- if passwordErr != nil || !correct {
- return nil, nil, &errors.FailedToValidateUser
+ correct, err := auth.CompareHash(loginBody.Password, user.PasswordHash)
+ if err != nil || !correct {
+ return nil, nil, err
}
tokens, err := a.JWT.GenerateTokenPair(auth.Claims{
@@ -70,21 +72,62 @@ func (a *AuthService) Login(loginBody models.LoginUserResponseBody) (*models.Use
},
})
if err != nil {
- return nil, nil, &errors.FailedToGenerateToken
+ return nil, nil, err
+ }
+
+ return user, tokens, nil
+}
+
+func (a *AuthService) Register(userBody usersEntities.CreateUserRequestBody) (*models.User, *auth.Token, error) {
+ if err := utilities.Validate(a.Validate, userBody, *utilities.NewMaybeError("password", auth.ValidatePassword(userBody.Password))); err != nil {
+ return nil, nil, err
+ }
+
+ user, err := utilities.MapJsonTags(userBody, &models.User{})
+ if err != nil {
+ return nil, nil, err
+ }
+
+ user.Role = models.Student
+
+ passwordHash, err := auth.ComputeHash(userBody.Password)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ user.Email = utilities.NormalizeEmail(userBody.Email)
+ user.PasswordHash = *passwordHash
+
+ if err := a.Integrations.Email.SendWelcomeEmail(fmt.Sprintf("%s %s", user.FirstName, user.LastName), user.Email); err != nil {
+ return nil, nil, fmt.Errorf("failed to send welcome email: %w", err)
+ }
+
+ user, err = CreateUser(a.DB, user)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ if err := a.SendCode(user.Email); err != nil {
+ return nil, nil, err
+ }
+
+ _, tokens, err := a.Login(authEntities.LoginResponseBody{Email: user.Email, Password: userBody.Password})
+ if err != nil {
+ return nil, nil, err
}
return user, tokens, nil
}
-func (a *AuthService) Refresh(refreshToken string) (*auth.Token, *errors.Error) {
+func (a *AuthService) Refresh(refreshToken string) (*auth.Token, error) {
claims, err := a.JWT.ExtractClaims(refreshToken, auth.RefreshToken)
if err != nil {
- return nil, &errors.FailedToExtractClaims
+ return nil, err
}
- role, roleErr := a.GetRole(claims["iss"].(string))
- if roleErr != nil {
- return nil, roleErr
+ role, err := a.GetRole(claims["iss"].(string))
+ if err != nil {
+ return nil, err
}
tokens, err := a.JWT.GenerateTokenPair(auth.Claims{
@@ -102,16 +145,16 @@ func (a *AuthService) Refresh(refreshToken string) (*auth.Token, *errors.Error)
},
})
if err != nil {
- return nil, &errors.FailedToGenerateToken
+ return nil, err
}
return tokens, nil
}
-func (a *AuthService) GetRole(id string) (*models.UserRole, *errors.Error) {
- idAsUUID, idErr := utilities.ValidateID(id)
- if idErr != nil {
- return nil, idErr
+func (a *AuthService) GetRole(id string) (*models.UserRole, error) {
+ idAsUUID, err := utilities.ValidateID(id)
+ if err != nil {
+ return nil, err
}
user, err := users.GetUser(a.DB, *idAsUUID)
@@ -122,63 +165,61 @@ func (a *AuthService) GetRole(id string) (*models.UserRole, *errors.Error) {
return &user.Role, nil
}
-func (a *AuthService) ForgotPassword(email string) *errors.Error {
+func (a *AuthService) ForgotPassword(email string) error {
user, err := users.GetUserByEmail(a.DB, email)
if err != nil {
return nil
}
- activeToken, tokenErr := GetActiveTokenByUserID(a.DB, user.ID, models.PasswordResetType)
- if tokenErr != nil {
- if tokenErr != &errors.TokenNotFound {
- return tokenErr
+ activeToken, err := GetActiveTokenByUserID(a.DB, user.ID, models.PasswordResetType)
+ if err != nil {
+ if !utilities.IsNotFound(err) {
+ return err
}
}
if activeToken != nil {
- sendErr := a.Integrations.Email.SendPasswordResetEmail(user.FirstName, user.Email, activeToken.Token)
- if sendErr != nil {
- return &errors.FailedToSendEmail
+ err := a.Integrations.Email.SendPasswordResetEmail(user.FirstName, user.Email, activeToken.Token)
+ if err != nil {
+ return err
}
return nil
}
- token, generateErr := auth.GenerateURLSafeToken(64)
- if generateErr != nil {
- return &errors.FailedToGenerateToken
+ token, err := auth.GenerateURLSafeToken(64)
+ if err != nil {
+ return err
}
- saveErr := SaveToken(a.DB, user.ID, *token, models.PasswordResetType, time.Now().Add(time.Hour*24).UTC())
- if saveErr != nil {
- return saveErr
+ if err := SaveToken(a.DB, user.ID, *token, models.PasswordResetType, time.Now().Add(time.Hour*24).UTC()); err != nil {
+ return err
}
- sendErr := a.Integrations.Email.SendPasswordResetEmail(user.FirstName, user.Email, *token)
- if sendErr != nil {
- return sendErr
+ if err := a.Integrations.Email.SendPasswordResetEmail(user.FirstName, user.Email, *token); err != nil {
+ return err
}
return nil
}
-func (a *AuthService) VerifyPasswordResetToken(passwordBody models.VerifyPasswordResetTokenRequestBody) *errors.Error {
- if err := a.Validate.Struct(passwordBody); err != nil {
- return &errors.FailedToValidateUser
+func (a *AuthService) VerifyPasswordResetToken(passwordBody VerifyPasswordResetTokenRequestBody) error {
+ if err := utilities.Validate(a.Validate, passwordBody); err != nil {
+ return err
}
- token, tokenErr := GetToken(a.DB, passwordBody.Token, models.PasswordResetType)
- if tokenErr != nil {
- return tokenErr
+ token, err := GetToken(a.DB, passwordBody.Token, models.PasswordResetType)
+ if err != nil {
+ return err
}
if token.ExpiresAt.Before(time.Now().UTC()) {
- return &errors.TokenExpired
+ return utilities.Unauthorized()
}
- hash, hashErr := auth.ComputeHash(passwordBody.NewPassword)
- if hashErr != nil {
- return &errors.FailedToValidateUser
+ hash, err := auth.ComputeHash(passwordBody.NewPassword)
+ if err != nil {
+ return fmt.Errorf("failed to hash password: %w", err)
}
tx := a.DB.Begin()
@@ -188,73 +229,68 @@ func (a *AuthService) VerifyPasswordResetToken(passwordBody models.VerifyPasswor
}
}()
- updateErr := users.UpdatePassword(tx, token.UserID, *hash)
- if updateErr != nil {
+ if err := users.UpdatePassword(tx, token.UserID, *hash); err != nil {
tx.Rollback()
- return updateErr
+ return err
}
- deleteErr := DeleteToken(tx, passwordBody.Token, models.PasswordResetType)
- if deleteErr != nil {
+ if err := DeleteToken(tx, passwordBody.Token, models.PasswordResetType); err != nil {
tx.Rollback()
- return deleteErr
+ return err
}
if err := tx.Commit().Error; err != nil {
tx.Rollback()
- return &errors.FailedToUpdatePassword
+ return err
}
return nil
}
-func (a *AuthService) SendCode(email string) *errors.Error {
+func (a *AuthService) SendCode(email string) error {
user, err := users.GetUserByEmail(a.DB, email)
if err != nil {
return err
}
if user.IsVerified {
- return &errors.EmailAlreadyVerified
+ return fmt.Errorf("user is already verified")
}
- activeOTP, tokenErr := GetActiveTokenByUserID(a.DB, user.ID, models.EmailVerificationType)
- if tokenErr != nil {
- if tokenErr != &errors.TokenNotFound {
- return tokenErr
+ activeOTP, err := GetActiveTokenByUserID(a.DB, user.ID, models.EmailVerificationType)
+ if err != nil {
+ if !utilities.IsNotFound(err) {
+ return err
}
}
if activeOTP != nil {
- sendErr := a.Integrations.Email.SendEmailVerification(user.Email, activeOTP.Token)
- if sendErr != nil {
- return &errors.FailedToSendEmail
+ if err := a.Integrations.Email.SendEmailVerification(user.Email, activeOTP.Token); err != nil {
+ return err
}
return nil
}
- otp, otpErr := auth.GenerateOTP(6)
- if otpErr != nil {
- return &errors.FailedToGenerateOTP
+ otp, err := auth.GenerateOTP(6)
+ if err != nil {
+ return fmt.Errorf("failed to generate OTP: %w", err)
}
- saveErr := SaveToken(a.DB, user.ID, *otp, models.EmailVerificationType, time.Now().Add(time.Minute*5).UTC())
- if saveErr != nil {
- return saveErr
+ if err := SaveToken(a.DB, user.ID, *otp, models.EmailVerificationType, time.Now().Add(time.Minute*5).UTC()); err != nil {
+ return err
}
- sendErr := a.Integrations.Email.SendEmailVerification(user.Email, *otp)
- if sendErr != nil {
- return &errors.FailedToSendEmail
+ if err := a.Integrations.Email.SendEmailVerification(user.Email, *otp); err != nil {
+ return err
}
return nil
}
-func verifyEmailHelper(user *models.User, token string, db *gorm.DB) *errors.Error {
+func verifyEmailHelper(user *models.User, token string, db *gorm.DB) error {
if user.IsVerified {
- return &errors.EmailAlreadyVerified
+ return fmt.Errorf("user is already verified")
}
otp, otpErr := GetToken(db, token, models.EmailVerificationType)
@@ -263,19 +299,20 @@ func verifyEmailHelper(user *models.User, token string, db *gorm.DB) *errors.Err
}
if otp.Token != token {
- return &errors.InvalidOTP
+ slog.Error("invalid otp", "otp", otp.Token, "token", token)
+ return utilities.BadRequest(errors.New("invalid otp"))
}
if otp.ExpiresAt.Before(time.Now().UTC()) {
- return &errors.OTPExpired
+ return utilities.BadRequest(errors.New("otp expired"))
}
return nil
}
-func (a *AuthService) VerifyEmail(emailBody models.VerifyEmailRequestBody) *errors.Error {
- if err := a.Validate.Struct(emailBody); err != nil {
- return &errors.FailedToValidateUser
+func (a *AuthService) VerifyEmail(emailBody VerifyEmailRequestBody) error {
+ if err := utilities.Validate(a.Validate, emailBody); err != nil {
+ return err
}
user, err := users.GetUserByEmail(a.DB, emailBody.Email)
@@ -283,9 +320,8 @@ func (a *AuthService) VerifyEmail(emailBody models.VerifyEmailRequestBody) *erro
return err
}
- verifyErr := verifyEmailHelper(user, emailBody.Token, a.DB)
- if verifyErr != nil {
- return verifyErr
+ if err := verifyEmailHelper(user, emailBody.Token, a.DB); err != nil {
+ return err
}
tx := a.DB.Begin()
@@ -295,27 +331,25 @@ func (a *AuthService) VerifyEmail(emailBody models.VerifyEmailRequestBody) *erro
}
}()
- updateErr := users.UpdateEmailVerification(tx, user.ID)
- if updateErr != nil {
+ if err := users.UpdateEmailVerification(tx, user.ID); err != nil {
tx.Rollback()
- return updateErr
+ return err
}
- deleteErr := DeleteToken(tx, emailBody.Token, models.EmailVerificationType)
- if deleteErr != nil {
+ if err := DeleteToken(tx, emailBody.Token, models.EmailVerificationType); err != nil {
tx.Rollback()
- return deleteErr
+ return err
}
if err := tx.Commit().Error; err != nil {
tx.Rollback()
- return &errors.FailedToUpdateEmailVerification
+ return err
}
return nil
}
-func (a *AuthService) Logout(c *fiber.Ctx) *errors.Error {
+func (a *AuthService) Logout(c *fiber.Ctx) error {
c.Cookie(&fiber.Cookie{
Name: "refresh_token",
Value: "",
diff --git a/backend/entities/auth/base/transactions.go b/backend/entities/auth/base/transactions.go
index 4749ea05a..a8812c280 100644
--- a/backend/entities/auth/base/transactions.go
+++ b/backend/entities/auth/base/transactions.go
@@ -1,47 +1,59 @@
package base
import (
+ "errors"
"time"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+ "github.com/GenerateNU/sac/backend/utilities"
"github.com/google/uuid"
"gorm.io/gorm"
)
-func GetToken(db *gorm.DB, token string, tokenType models.VerificationType) (*models.Verification, *errors.Error) {
+func CreateUser(db *gorm.DB, user *models.User) (*models.User, error) {
+ if err := db.Create(user).Error; err != nil {
+ if errors.Is(err, gorm.ErrDuplicatedKey) {
+ return nil, utilities.ErrDuplicate
+ }
+ return nil, err
+ }
+
+ return user, nil
+}
+
+func GetToken(db *gorm.DB, token string, tokenType models.VerificationType) (*models.Verification, error) {
tokenModel := models.Verification{}
if err := db.Where("token = ? AND type = ?", token, tokenType).First(&tokenModel).Error; err != nil {
- if err == gorm.ErrRecordNotFound {
- return nil, &errors.TokenNotFound
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
}
- return nil, &errors.FailedToGetToken
+ return nil, err
}
return &tokenModel, nil
}
-func GetActiveTokenByUserID(db *gorm.DB, userID uuid.UUID, tokenType models.VerificationType) (*models.Verification, *errors.Error) {
+func GetActiveTokenByUserID(db *gorm.DB, userID uuid.UUID, tokenType models.VerificationType) (*models.Verification, error) {
token := models.Verification{}
if err := db.Where("user_id = ? AND expires_at > ? AND type = ?", userID, time.Now().UTC(), tokenType).First(&token).Error; err != nil {
- if err == gorm.ErrRecordNotFound {
- return nil, &errors.TokenNotFound
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
}
- return nil, &errors.FailedToGetToken
+ return nil, err
}
return &token, nil
}
-func DeleteToken(db *gorm.DB, token string, tokenType models.VerificationType) *errors.Error {
+func DeleteToken(db *gorm.DB, token string, tokenType models.VerificationType) error {
if err := db.Where("token = ? AND type = ?", token, tokenType).Delete(&models.Verification{}).Error; err != nil {
- return &errors.FailedToDeleteToken
+ return err
}
return nil
}
-func SaveToken(db *gorm.DB, userID uuid.UUID, token string, tokenType models.VerificationType, expiry time.Time) *errors.Error {
+func SaveToken(db *gorm.DB, userID uuid.UUID, token string, tokenType models.VerificationType, expiry time.Time) error {
tokenModel := models.Verification{
UserID: userID,
Token: token,
@@ -50,7 +62,7 @@ func SaveToken(db *gorm.DB, userID uuid.UUID, token string, tokenType models.Ver
}
if err := db.Create(&tokenModel).Error; err != nil {
- return &errors.FailedToSaveToken
+ return err
}
return nil
diff --git a/backend/entities/auth/models.go b/backend/entities/auth/models.go
new file mode 100644
index 000000000..7272b50d8
--- /dev/null
+++ b/backend/entities/auth/models.go
@@ -0,0 +1,15 @@
+package auth
+
+type LoginResponseBody struct {
+ Email string `json:"email" validate:"required,email"`
+ Password string `json:"password" validate:"required,max=255"` // MARK: must be validated manually
+}
+
+type UpdatePasswordRequestBody struct {
+ OldPassword string `json:"old_password" validate:"required,max=255"` // MARK: must be validated manually
+ NewPassword string `json:"new_password" validate:"required,not_equal_if_not_empty=OldPassword,max=255"` // MARK: must be validated manually
+}
+
+type RefreshTokenRequestBody struct {
+ RefreshToken string `json:"refresh_token" validate:"required"`
+}
diff --git a/backend/entities/categories/base/controller.go b/backend/entities/categories/base/controller.go
index 7ac6e2a7e..2ec179336 100644
--- a/backend/entities/categories/base/controller.go
+++ b/backend/entities/categories/base/controller.go
@@ -1,9 +1,12 @@
package base
import (
- "github.com/GenerateNU/sac/backend/constants"
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+ "net/http"
+
+ "github.com/GenerateNU/sac/backend/entities/categories"
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
+
"github.com/gofiber/fiber/v2"
)
@@ -23,27 +26,27 @@ func NewCategoryController(categoryService CategoryServiceInterface) *CategoryCo
// @Tags category
// @Accept json
// @Produce json
-// @Param categoryBody body models.CategoryRequestBody true "Category Body"
+// @Param categoryBody body categories.CategoryRequestBody true "Category Body"
// @Success 201 {object} models.Category
-// @Failure 400 {string} errors.Error
-// @Failure 401 {string} errors.Error
-// @Failure 404 {string} errors.Error
-// @Failure 409 {string} errors.Error
-// @Failure 500 {string} errors.Error
+// @Failure 400 {string} error
+// @Failure 401 {string} error
+// @Failure 404 {string} error
+// @Failure 409 {string} error
+// @Failure 500 {string} error
// @Router /categories/ [post]
func (cat *CategoryController) CreateCategory(c *fiber.Ctx) error {
- var categoryBody models.CategoryRequestBody
+ var categoryBody categories.CategoryRequestBody
if err := c.BodyParser(&categoryBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ return utilities.InvalidJSON()
}
newCategory, err := cat.categoryService.CreateCategory(categoryBody)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusCreated).JSON(newCategory)
+ return c.Status(http.StatusCreated).JSON(newCategory)
}
// GetCategories godoc
@@ -56,17 +59,22 @@ func (cat *CategoryController) CreateCategory(c *fiber.Ctx) error {
// @Param limit query int false "Limit"
// @Param page query int false "Page"
// @Success 200 {object} []models.Category
-// @Failure 400 {string} errors.Error
-// @Failure 404 {string} errors.Error
-// @Failure 500 {string} errors.Error
+// @Failure 400 {string} error
+// @Failure 404 {string} error
+// @Failure 500 {string} error
// @Router /categories/ [get]
func (cat *CategoryController) GetCategories(c *fiber.Ctx) error {
- categories, err := cat.categoryService.GetCategories(c.Query("limit", constants.DEFAULT_LIMIT_STRING), c.Query("page", constants.DEFAULT_PAGE_STRING))
+ pagination, ok := fiberpaginate.FromContext(c)
+ if !ok {
+ return utilities.ErrExpectedPagination
+ }
+
+ categories, err := cat.categoryService.GetCategories(*pagination)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(&categories)
+ return c.Status(http.StatusOK).JSON(&categories)
}
// GetCategory godoc
@@ -78,17 +86,17 @@ func (cat *CategoryController) GetCategories(c *fiber.Ctx) error {
// @Produce json
// @Param categoryID path string true "Category ID"
// @Success 200 {object} models.Category
-// @Failure 400 {string} errors.Error
-// @Failure 404 {string} errors.Error
-// @Failure 500 {string} errors.Error
+// @Failure 400 {string} error
+// @Failure 404 {string} error
+// @Failure 500 {string} error
// @Router /categories/{categoryID}/ [get]
func (cat *CategoryController) GetCategory(c *fiber.Ctx) error {
category, err := cat.categoryService.GetCategory(c.Params("categoryID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(&category)
+ return c.Status(http.StatusOK).JSON(&category)
}
// DeleteCategory godoc
@@ -100,17 +108,17 @@ func (cat *CategoryController) GetCategory(c *fiber.Ctx) error {
// @Produce json
// @Param categoryID path string true "Category ID"
// @Success 204 {string} utilities.SuccessResponse
-// @Failure 400 {string} errors.Error
-// @Failure 401 {string} errors.Error
-// @Failure 404 {string} errors.Error
-// @Failure 500 {string} errors.Error
+// @Failure 400 {string} error
+// @Failure 401 {string} error
+// @Failure 404 {string} error
+// @Failure 500 {string} error
// @Router /categories/{categoryID}/ [delete]
func (cat *CategoryController) DeleteCategory(c *fiber.Ctx) error {
if err := cat.categoryService.DeleteCategory(c.Params("categoryID")); err != nil {
- return err.FiberError(c)
+ return err
}
- return c.SendStatus(fiber.StatusNoContent)
+ return c.SendStatus(http.StatusNoContent)
}
// UpdateCategory godoc
@@ -122,24 +130,23 @@ func (cat *CategoryController) DeleteCategory(c *fiber.Ctx) error {
// @Accept json
// @Produce json
// @Param categoryID path string true "Category ID"
-// @Param categoryBody body models.CategoryRequestBody true "Category Body"
+// @Param categoryBody body categories.CategoryRequestBody true "Category Body"
// @Success 200 {object} models.Category
-// @Failure 400 {string} errors.Error
-// @Failure 401 {string} errors.Error
-// @Failure 404 {string} errors.Error
-// @Failure 500 {string} errors.Error
+// @Failure 400 {string} error
+// @Failure 401 {string} error
+// @Failure 404 {string} error
+// @Failure 500 {string} error
// @Router /categories/{categoryID}/ [patch]
func (cat *CategoryController) UpdateCategory(c *fiber.Ctx) error {
- var category models.CategoryRequestBody
-
+ var category categories.CategoryRequestBody
if err := c.BodyParser(&category); err != nil {
- return errors.FailedToValidateCategory.FiberError(c)
+ return utilities.InvalidJSON()
}
updatedCategory, err := cat.categoryService.UpdateCategory(c.Params("categoryID"), category)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(updatedCategory)
+ return c.Status(http.StatusOK).JSON(updatedCategory)
}
diff --git a/backend/entities/categories/base/routes.go b/backend/entities/categories/base/routes.go
index 87ab9e30f..f41980ee0 100644
--- a/backend/entities/categories/base/routes.go
+++ b/backend/entities/categories/base/routes.go
@@ -2,7 +2,7 @@ package base
import (
"github.com/GenerateNU/sac/backend/auth"
- "github.com/GenerateNU/sac/backend/entities/categories/tag"
+ "github.com/GenerateNU/sac/backend/entities/categories/tags"
"github.com/GenerateNU/sac/backend/types"
"github.com/gofiber/fiber/v2"
)
@@ -13,7 +13,7 @@ func CategoryRoutes(categoryParams types.RouteParams) {
// update the router in params
categoryParams.Router = categoryIDRoute
- tag.CategoryTag(categoryParams)
+ tags.CategoryTag(categoryParams)
}
func Category(categoryParams types.RouteParams) fiber.Router {
@@ -23,7 +23,7 @@ func Category(categoryParams types.RouteParams) fiber.Router {
categories := categoryParams.Router.Group("/categories")
categories.Post("/", categoryParams.AuthMiddleware.Authorize(auth.CreateAll), categoryController.CreateCategory)
- categories.Get("/", categoryController.GetCategories)
+ categories.Get("/", categoryParams.UtilityMiddleware.Paginator, categoryController.GetCategories)
// api/v1/categories/:categoryID/*
categoryID := categories.Group("/:categoryID")
diff --git a/backend/entities/categories/base/service.go b/backend/entities/categories/base/service.go
index c41ab6252..47d13cdaa 100644
--- a/backend/entities/categories/base/service.go
+++ b/backend/entities/categories/base/service.go
@@ -1,21 +1,22 @@
package base
import (
+ "github.com/GenerateNU/sac/backend/entities/categories"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/types"
"github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
type CategoryServiceInterface interface {
- CreateCategory(categoryBody models.CategoryRequestBody) (*models.Category, *errors.Error)
- GetCategories(limit string, page string) ([]models.Category, *errors.Error)
- GetCategory(id string) (*models.Category, *errors.Error)
- UpdateCategory(id string, params models.CategoryRequestBody) (*models.Category, *errors.Error)
- DeleteCategory(id string) *errors.Error
+ CreateCategory(categoryBody categories.CategoryRequestBody) (*models.Category, error)
+ GetCategories(pageInfo fiberpaginate.PageInfo) ([]models.Category, error)
+ GetCategory(id string) (*models.Category, error)
+ UpdateCategory(id string, params categories.CategoryRequestBody) (*models.Category, error)
+ DeleteCategory(id string) error
}
type CategoryService struct {
@@ -26,14 +27,14 @@ func NewCategoryService(params types.ServiceParams) CategoryServiceInterface {
return &CategoryService{params}
}
-func (c *CategoryService) CreateCategory(categoryBody models.CategoryRequestBody) (*models.Category, *errors.Error) {
- if err := c.Validate.Struct(categoryBody); err != nil {
- return nil, &errors.FailedToValidateCategory
+func (c *CategoryService) CreateCategory(categoryBody categories.CategoryRequestBody) (*models.Category, error) {
+ if err := utilities.Validate(c.Validate, categoryBody); err != nil {
+ return nil, err
}
- category, err := utilities.MapRequestToModel(categoryBody, &models.Category{})
+ category, err := utilities.MapJsonTags(categoryBody, &models.Category{})
if err != nil {
- return nil, &errors.FailedToMapRequestToModel
+ return nil, err
}
category.Name = cases.Title(language.English).String(category.Name)
@@ -41,21 +42,11 @@ func (c *CategoryService) CreateCategory(categoryBody models.CategoryRequestBody
return CreateCategory(c.DB, *category)
}
-func (c *CategoryService) GetCategories(limit string, page string) ([]models.Category, *errors.Error) {
- limitAsInt, err := utilities.ValidateNonNegative(limit)
- if err != nil {
- return nil, &errors.FailedToValidateLimit
- }
-
- pageAsInt, err := utilities.ValidateNonNegative(page)
- if err != nil {
- return nil, &errors.FailedToValidatePage
- }
-
- return GetCategories(c.DB, *limitAsInt, *pageAsInt)
+func (c *CategoryService) GetCategories(pageInfo fiberpaginate.PageInfo) ([]models.Category, error) {
+ return GetCategories(c.DB, pageInfo)
}
-func (c *CategoryService) GetCategory(id string) (*models.Category, *errors.Error) {
+func (c *CategoryService) GetCategory(id string) (*models.Category, error) {
idAsUUID, err := utilities.ValidateID(id)
if err != nil {
return nil, err
@@ -64,19 +55,19 @@ func (c *CategoryService) GetCategory(id string) (*models.Category, *errors.Erro
return GetCategory(c.DB, *idAsUUID)
}
-func (c *CategoryService) UpdateCategory(id string, categoryBody models.CategoryRequestBody) (*models.Category, *errors.Error) {
- idAsUUID, idErr := utilities.ValidateID(id)
- if idErr != nil {
- return nil, idErr
+func (c *CategoryService) UpdateCategory(id string, categoryBody categories.CategoryRequestBody) (*models.Category, error) {
+ idAsUUID, err := utilities.ValidateID(id)
+ if err != nil {
+ return nil, err
}
- if err := c.Validate.Struct(categoryBody); err != nil {
- return nil, &errors.FailedToValidateTag
+ if err := utilities.Validate(c.Validate, categoryBody); err != nil {
+ return nil, err
}
- category, err := utilities.MapRequestToModel(categoryBody, &models.Category{})
+ category, err := utilities.MapJsonTags(categoryBody, &models.Category{})
if err != nil {
- return nil, &errors.FailedToMapRequestToModel
+ return nil, err
}
category.Name = cases.Title(language.English).String(category.Name)
@@ -84,7 +75,7 @@ func (c *CategoryService) UpdateCategory(id string, categoryBody models.Category
return UpdateCategory(c.DB, *idAsUUID, *category)
}
-func (c *CategoryService) DeleteCategory(id string) *errors.Error {
+func (c *CategoryService) DeleteCategory(id string) error {
idAsUUID, err := utilities.ValidateID(id)
if err != nil {
return err
diff --git a/backend/entities/categories/base/transactions.go b/backend/entities/categories/base/transactions.go
index a753bc780..6e981f10e 100644
--- a/backend/entities/categories/base/transactions.go
+++ b/backend/entities/categories/base/transactions.go
@@ -1,73 +1,70 @@
package base
import (
- stdliberrors "errors"
+ "errors"
- "github.com/GenerateNU/sac/backend/errors"
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
"github.com/google/uuid"
"github.com/GenerateNU/sac/backend/entities/models"
"gorm.io/gorm"
+ "gorm.io/gorm/clause"
)
-func CreateCategory(db *gorm.DB, category models.Category) (*models.Category, *errors.Error) {
+func CreateCategory(db *gorm.DB, category models.Category) (*models.Category, error) {
if err := db.Create(&category).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrDuplicatedKey) {
- return nil, &errors.CategoryAlreadyExists
- } else {
- return nil, &errors.FailedToCreateCategory
+ if errors.Is(err, gorm.ErrDuplicatedKey) {
+ return nil, utilities.ErrDuplicate
}
+ return nil, err
}
return &category, nil
}
-func GetCategories(db *gorm.DB, limit int, page int) ([]models.Category, *errors.Error) {
+func GetCategories(db *gorm.DB, pageInfo fiberpaginate.PageInfo) ([]models.Category, error) {
var categories []models.Category
- offset := (page - 1) * limit
-
- if err := db.Limit(limit).Offset(offset).Find(&categories).Error; err != nil {
- return nil, &errors.FailedToGetCategories
+ if err := db.Scopes(utilities.IntoScope(pageInfo, db)).Find(&categories).Error; err != nil {
+ return nil, err
}
return categories, nil
}
-func GetCategory(db *gorm.DB, id uuid.UUID) (*models.Category, *errors.Error) {
+func GetCategory(db *gorm.DB, id uuid.UUID) (*models.Category, error) {
var category models.Category
if err := db.First(&category, id).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.CategoryNotFound
- } else {
- return nil, &errors.FailedToGetCategory
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
}
+ return nil, err
}
return &category, nil
}
-func UpdateCategory(db *gorm.DB, id uuid.UUID, category models.Category) (*models.Category, *errors.Error) {
- if err := db.Model(&models.Category{}).Where("id = ?", id).Updates(category).First(&category, id).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.TagNotFound
- } else {
- return nil, &errors.FailedToUpdateTag
+func UpdateCategory(db *gorm.DB, id uuid.UUID, category models.Category) (*models.Category, error) {
+ var resultingCategory models.Category
+ if err := db.Model(&resultingCategory).Clauses(clause.Returning{}).Where("id = ?", id).Updates(category).First(&category, id).Error; err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
}
+ return nil, err
}
- return &category, nil
+ return &resultingCategory, nil
}
-func DeleteCategory(db *gorm.DB, id uuid.UUID) *errors.Error {
+func DeleteCategory(db *gorm.DB, id uuid.UUID) error {
if result := db.Delete(&models.Category{}, id); result.RowsAffected == 0 {
if result.Error == nil {
- return &errors.CategoryNotFound
- } else {
- return &errors.FailedToDeleteCategory
+ return utilities.ErrNotFound
}
+ return result.Error
}
return nil
diff --git a/backend/entities/categories/models.go b/backend/entities/categories/models.go
new file mode 100644
index 000000000..18285b996
--- /dev/null
+++ b/backend/entities/categories/models.go
@@ -0,0 +1,5 @@
+package categories
+
+type CategoryRequestBody struct {
+ Name string `json:"name" validate:"required,max=255"`
+}
diff --git a/backend/entities/categories/tag/transactions.go b/backend/entities/categories/tag/transactions.go
deleted file mode 100644
index 9f6741d12..000000000
--- a/backend/entities/categories/tag/transactions.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package tag
-
-import (
- stdliberrors "errors"
-
- "github.com/GenerateNU/sac/backend/errors"
- "github.com/google/uuid"
-
- "github.com/GenerateNU/sac/backend/entities/models"
-
- "gorm.io/gorm"
-)
-
-func GetTagsByCategory(db *gorm.DB, categoryID uuid.UUID, limit int, page int) ([]models.Tag, *errors.Error) {
- var category models.Category
-
- if err := db.Where("id = ?", categoryID).First(&category).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.CategoryNotFound
- }
- return nil, &errors.FailedToGetCategory
- }
-
- var tags []models.Tag
-
- offset := (page - 1) * limit
-
- if err := db.Where("category_id = ?", categoryID).Limit(limit).Offset(offset).Find(&tags).Error; err != nil {
- return nil, &errors.FailedToGetTags
- }
-
- return tags, nil
-}
-
-func GetTagByCategory(db *gorm.DB, categoryID uuid.UUID, tagID uuid.UUID) (*models.Tag, *errors.Error) {
- var tag models.Tag
- if err := db.Where("category_id = ? AND id = ?", categoryID, tagID).First(&tag).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.TagNotFound
- } else {
- return nil, &errors.FailedToGetTag
- }
- }
-
- return &tag, nil
-}
diff --git a/backend/entities/categories/tag/controller.go b/backend/entities/categories/tags/controller.go
similarity index 71%
rename from backend/entities/categories/tag/controller.go
rename to backend/entities/categories/tags/controller.go
index c6db327f2..8fb211b12 100644
--- a/backend/entities/categories/tag/controller.go
+++ b/backend/entities/categories/tags/controller.go
@@ -1,8 +1,10 @@
-package tag
+package tags
import (
- "github.com/GenerateNU/sac/backend/constants"
+ "net/http"
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
"github.com/gofiber/fiber/v2"
)
@@ -25,17 +27,22 @@ func NewCategoryTagController(categoryTagService CategoryTagServiceInterface) *C
// @Param limit query int false "Limit"
// @Param page query int false "Page"
// @Success 200 {object} []models.Tag
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /categories/{categoryID}/tags/ [get]
func (ct *CategoryTagController) GetTagsByCategory(c *fiber.Ctx) error {
- tags, err := ct.categoryTagService.GetTagsByCategory(c.Params("categoryID"), c.Query("limit", constants.DEFAULT_LIMIT_STRING), c.Query("page", constants.DEFAULT_PAGE_STRING))
+ pagination, ok := fiberpaginate.FromContext(c)
+ if !ok {
+ return utilities.ErrExpectedPagination
+ }
+
+ tags, err := ct.categoryTagService.GetTagsByCategory(c.Params("categoryID"), *pagination)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(&tags)
+ return c.Status(http.StatusOK).JSON(&tags)
}
// GetTagByCategory godoc
@@ -48,15 +55,15 @@ func (ct *CategoryTagController) GetTagsByCategory(c *fiber.Ctx) error {
// @Param categoryID path string true "Category ID"
// @Param tagID path string true "Tag ID"
// @Success 200 {object} models.Tag
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /categories/{categoryID}/tags/{tagID}/ [get]
func (ct *CategoryTagController) GetTagByCategory(c *fiber.Ctx) error {
tag, err := ct.categoryTagService.GetTagByCategory(c.Params("categoryID"), c.Params("tagID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(&tag)
+ return c.Status(http.StatusOK).JSON(&tag)
}
diff --git a/backend/entities/categories/tag/routes.go b/backend/entities/categories/tags/routes.go
similarity index 75%
rename from backend/entities/categories/tag/routes.go
rename to backend/entities/categories/tags/routes.go
index e3b46347e..f4a0d4cb4 100644
--- a/backend/entities/categories/tag/routes.go
+++ b/backend/entities/categories/tags/routes.go
@@ -1,4 +1,4 @@
-package tag
+package tags
import (
"github.com/GenerateNU/sac/backend/types"
@@ -10,6 +10,6 @@ func CategoryTag(categoryParams types.RouteParams) {
// api/v1/categories/:categoryID/tags/*
categoryTags := categoryParams.Router.Group("/tags")
- categoryTags.Get("/", categoryTagController.GetTagsByCategory)
+ categoryTags.Get("/", categoryParams.UtilityMiddleware.Paginator, categoryTagController.GetTagsByCategory)
categoryTags.Get("/:tagID", categoryTagController.GetTagByCategory)
}
diff --git a/backend/entities/categories/tag/service.go b/backend/entities/categories/tags/service.go
similarity index 61%
rename from backend/entities/categories/tag/service.go
rename to backend/entities/categories/tags/service.go
index 90db3286e..7f3dfd63e 100644
--- a/backend/entities/categories/tag/service.go
+++ b/backend/entities/categories/tags/service.go
@@ -1,15 +1,15 @@
-package tag
+package tags
import (
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/types"
"github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
)
type CategoryTagServiceInterface interface {
- GetTagsByCategory(categoryID string, limit string, page string) ([]models.Tag, *errors.Error)
- GetTagByCategory(categoryID string, tagID string) (*models.Tag, *errors.Error)
+ GetTagsByCategory(categoryID string, pageInfo fiberpaginate.PageInfo) ([]models.Tag, error)
+ GetTagByCategory(categoryID string, tagID string) (*models.Tag, error)
}
type CategoryTagService struct {
@@ -20,26 +20,16 @@ func NewCategoryTagService(params types.ServiceParams) CategoryTagServiceInterfa
return &CategoryTagService{params}
}
-func (t *CategoryTagService) GetTagsByCategory(categoryID string, limit string, page string) ([]models.Tag, *errors.Error) {
+func (t *CategoryTagService) GetTagsByCategory(categoryID string, pageInfo fiberpaginate.PageInfo) ([]models.Tag, error) {
categoryIDAsUUID, err := utilities.ValidateID(categoryID)
if err != nil {
return nil, err
}
- limitAsInt, err := utilities.ValidateNonNegative(limit)
- if err != nil {
- return nil, &errors.FailedToValidateLimit
- }
-
- pageAsInt, err := utilities.ValidateNonNegative(page)
- if err != nil {
- return nil, &errors.FailedToValidatePage
- }
-
- return GetTagsByCategory(t.DB, *categoryIDAsUUID, *limitAsInt, *pageAsInt)
+ return GetTagsByCategory(t.DB, *categoryIDAsUUID, pageInfo)
}
-func (t *CategoryTagService) GetTagByCategory(categoryID string, tagID string) (*models.Tag, *errors.Error) {
+func (t *CategoryTagService) GetTagByCategory(categoryID string, tagID string) (*models.Tag, error) {
categoryIDAsUUID, idErr := utilities.ValidateID(categoryID)
if idErr != nil {
diff --git a/backend/entities/categories/tags/transactions.go b/backend/entities/categories/tags/transactions.go
new file mode 100644
index 000000000..817bcedef
--- /dev/null
+++ b/backend/entities/categories/tags/transactions.go
@@ -0,0 +1,44 @@
+package tags
+
+import (
+ "errors"
+
+ "github.com/garrettladley/fiberpaginate"
+ "github.com/google/uuid"
+
+ "github.com/GenerateNU/sac/backend/entities/models"
+ "github.com/GenerateNU/sac/backend/utilities"
+
+ "gorm.io/gorm"
+)
+
+func GetTagsByCategory(db *gorm.DB, categoryID uuid.UUID, pageInfo fiberpaginate.PageInfo) ([]models.Tag, error) {
+ var category models.Category
+
+ if err := db.Where("id = ?", categoryID).First(&category).Error; err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
+ }
+ return nil, err
+ }
+
+ var tags []models.Tag
+
+ if err := db.Where("category_id = ?", categoryID).Scopes(utilities.IntoScope(pageInfo, db)).Find(&tags).Error; err != nil {
+ return nil, err
+ }
+
+ return tags, nil
+}
+
+func GetTagByCategory(db *gorm.DB, categoryID uuid.UUID, tagID uuid.UUID) (*models.Tag, error) {
+ var tag models.Tag
+ if err := db.Where("category_id = ? AND id = ?", categoryID, tagID).First(&tag).Error; err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
+ }
+ return nil, err
+ }
+
+ return &tag, nil
+}
diff --git a/backend/entities/clubs/base/controller.go b/backend/entities/clubs/base/controller.go
index f4b09e857..add4ae5b5 100644
--- a/backend/entities/clubs/base/controller.go
+++ b/backend/entities/clubs/base/controller.go
@@ -1,9 +1,11 @@
package base
import (
- "github.com/GenerateNU/sac/backend/constants"
+ "net/http"
+
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
"github.com/gofiber/fiber/v2"
)
@@ -25,25 +27,26 @@ func NewClubController(clubService ClubServiceInterface) *ClubController {
// @Param limit query int false "Limit"
// @Param page query int false "Page"
// @Success 200 {object} []models.Club
-// @Failure 400 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 500 {object} error
// @Router /clubs/ [get]
func (cl *ClubController) GetClubs(c *fiber.Ctx) error {
var queryParams models.ClubQueryParams
-
- queryParams.Limit = constants.DEFAULT_LIMIT
- queryParams.Page = constants.DEFAULT_PAGE
-
if err := c.QueryParser(&queryParams); err != nil {
- return errors.FailedtoParseQueryParams.FiberError(c)
+ return err
+ }
+
+ pagination, ok := fiberpaginate.FromContext(c)
+ if !ok {
+ return utilities.ErrExpectedPagination
}
- clubs, err := cl.clubService.GetClubs(&queryParams)
+ clubs, err := cl.clubService.GetClubs(&queryParams, *pagination)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(clubs)
+ return c.Status(http.StatusOK).JSON(clubs)
}
// CreateClub godoc
@@ -54,26 +57,26 @@ func (cl *ClubController) GetClubs(c *fiber.Ctx) error {
// @Tags club
// @Accept json
// @Produce json
-// @Param club body models.CreateClubRequestBody true "Club"
+// @Param club body CreateClubRequestBody true "Club"
// @Success 201 {object} models.Club
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /clubs/ [post]
func (cl *ClubController) CreateClub(c *fiber.Ctx) error {
- var clubBody models.CreateClubRequestBody
+ var clubBody CreateClubRequestBody
if err := c.BodyParser(&clubBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ return utilities.InvalidJSON()
}
club, err := cl.clubService.CreateClub(clubBody)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusCreated).JSON(club)
+ return c.Status(http.StatusCreated).JSON(club)
}
// GetClub godoc
@@ -85,17 +88,17 @@ func (cl *ClubController) CreateClub(c *fiber.Ctx) error {
// @Produce json
// @Param clubID path string true "Club ID"
// @Success 200 {object} models.Club
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /clubs/{clubID}/ [get]
func (cl *ClubController) GetClub(c *fiber.Ctx) error {
club, err := cl.clubService.GetClub(c.Params("clubID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(club)
+ return c.Status(http.StatusOK).JSON(club)
}
// UpdateClub godoc
@@ -107,26 +110,26 @@ func (cl *ClubController) GetClub(c *fiber.Ctx) error {
// @Accept json
// @Produce json
// @Param clubID path string true "Club ID"
-// @Param club body models.UpdateClubRequestBody true "Club"
+// @Param club body UpdateClubRequestBody true "Club"
// @Success 200 {object} models.Club
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /clubs/{clubID}/ [patch]
func (cl *ClubController) UpdateClub(c *fiber.Ctx) error {
- var clubBody models.UpdateClubRequestBody
+ var clubBody UpdateClubRequestBody
if err := c.BodyParser(&clubBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ return utilities.InvalidJSON()
}
updatedClub, err := cl.clubService.UpdateClub(c.Params("clubID"), clubBody)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(updatedClub)
+ return c.Status(http.StatusOK).JSON(updatedClub)
}
// DeleteClub godoc
@@ -138,15 +141,15 @@ func (cl *ClubController) UpdateClub(c *fiber.Ctx) error {
// @Produce json
// @Param clubID path string true "Club ID"
// @Success 204 {string} utilities.SuccessResponse
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /clubs/{clubID}/ [delete]
func (cl *ClubController) DeleteClub(c *fiber.Ctx) error {
err := cl.clubService.DeleteClub(c.Params("clubID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.SendStatus(fiber.StatusNoContent)
+ return c.SendStatus(http.StatusNoContent)
}
diff --git a/backend/entities/clubs/base/models.go b/backend/entities/clubs/base/models.go
new file mode 100644
index 000000000..e0a6b63f1
--- /dev/null
+++ b/backend/entities/clubs/base/models.go
@@ -0,0 +1,33 @@
+package base
+
+import (
+ "github.com/GenerateNU/sac/backend/entities/models"
+ "github.com/google/uuid"
+)
+
+type CreateClubRequestBody struct {
+ UserID uuid.UUID `json:"user_id" validate:"required,uuid4"`
+ Name string `json:"name" validate:"required,max=255"`
+ Preview string `json:"preview" validate:"required,max=255"`
+ Description string `json:"description" validate:"required,http_url,s3_url,max=255"`
+ IsRecruiting bool `json:"is_recruiting" validate:"required"`
+ RecruitmentCycle models.RecruitmentCycle `json:"recruitment_cycle" validate:"required,max=255,oneof=fall spring fallSpring always"`
+ RecruitmentType models.RecruitmentType `json:"recruitment_type" validate:"required,max=255,oneof=unrestricted tryout application"`
+ WeeklyTimeCommitment *int `json:"weekly_time_commitment" validate:"omitempty,min=1"`
+ OneWordToDescribeUs string `json:"one_word_to_describe_us" validate:"omitempty,max=255"`
+ ApplicationLink string `json:"application_link" validate:"required,max=255,http_url"`
+ Logo string `json:"logo" validate:"omitempty,http_url,s3_url,max=255"`
+}
+
+type UpdateClubRequestBody struct {
+ Name string `json:"name" validate:"omitempty,max=255"`
+ Preview string `json:"preview" validate:"omitempty,max=255"`
+ Description string `json:"description" validate:"omitempty,http_url,s3_url,max=255"`
+ IsRecruiting bool `json:"is_recruiting" validate:"omitempty"`
+ RecruitmentCycle models.RecruitmentCycle `json:"recruitment_cycle" validate:"required,max=255,oneof=fall spring fallSpring always"`
+ RecruitmentType models.RecruitmentType `json:"recruitment_type" validate:"required,max=255,oneof=unrestricted tryout application"`
+ WeeklyTimeCommitment *int `json:"weekly_time_commitment" validate:"omitempty,min=1"`
+ OneWordToDescribeUs string `json:"one_word_to_describe_us" validate:"omitempty,max=255"`
+ ApplicationLink string `json:"application_link" validate:"omitempty,required,max=255,http_url"`
+ Logo string `json:"logo" validate:"omitempty,s3_url,max=255,http_url"`
+}
diff --git a/backend/entities/clubs/base/routes.go b/backend/entities/clubs/base/routes.go
index 0af04c27c..7633698b2 100644
--- a/backend/entities/clubs/base/routes.go
+++ b/backend/entities/clubs/base/routes.go
@@ -2,29 +2,27 @@ package base
import (
p "github.com/GenerateNU/sac/backend/auth"
- "github.com/GenerateNU/sac/backend/entities/clubs/contact"
- "github.com/GenerateNU/sac/backend/entities/clubs/event"
- "github.com/GenerateNU/sac/backend/entities/clubs/follower"
- "github.com/GenerateNU/sac/backend/entities/clubs/member"
- "github.com/GenerateNU/sac/backend/entities/clubs/poc"
- "github.com/GenerateNU/sac/backend/entities/clubs/tag"
+ "github.com/GenerateNU/sac/backend/entities/clubs/contacts"
+ "github.com/GenerateNU/sac/backend/entities/clubs/events"
+ "github.com/GenerateNU/sac/backend/entities/clubs/followers"
+ "github.com/GenerateNU/sac/backend/entities/clubs/members"
+ "github.com/GenerateNU/sac/backend/entities/clubs/pocs"
+ "github.com/GenerateNU/sac/backend/entities/clubs/tags"
+ authMiddleware "github.com/GenerateNU/sac/backend/middleware/auth"
"github.com/GenerateNU/sac/backend/types"
"github.com/gofiber/fiber/v2"
)
func ClubRoutes(clubParams types.RouteParams) {
- clubIDRouter := ClubRouter(clubParams)
-
- // update the router in params
- clubParams.Router = clubIDRouter
-
- tag.ClubTag(clubParams)
- follower.ClubFollower(clubParams)
- member.ClubMember(clubParams)
- contact.ClubContact(clubParams)
- event.ClubEvent(clubParams)
- poc.ClubPointOfContact(clubParams)
+ clubParams.Router = ClubRouter(clubParams)
+
+ tags.ClubTag(clubParams)
+ followers.ClubFollower(clubParams)
+ members.ClubMember(clubParams)
+ contacts.ClubContact(clubParams)
+ events.ClubEvent(clubParams)
+ pocs.ClubPointOfContact(clubParams)
}
func ClubRouter(clubParams types.RouteParams) fiber.Router {
@@ -33,14 +31,18 @@ func ClubRouter(clubParams types.RouteParams) fiber.Router {
// api/v1/clubs/*
clubs := clubParams.Router.Group("/clubs")
- clubs.Get("/", clubController.GetClubs)
+ clubs.Get("/", clubParams.UtilityMiddleware.Paginator, clubController.GetClubs)
clubs.Post("/", clubParams.AuthMiddleware.Authorize(p.CreateAll), clubController.CreateClub)
// api/v1/clubs/:clubID/*
clubID := clubs.Group("/:clubID")
clubID.Get("/", clubController.GetClub)
- clubID.Patch("/", clubParams.AuthMiddleware.ClubAuthorizeById, clubController.UpdateClub)
+ clubID.Patch(
+ "/",
+ authMiddleware.AttachExtractor(clubParams.AuthMiddleware.ClubAuthorizeById, authMiddleware.ExtractFromParams("clubID")),
+ clubController.UpdateClub,
+ )
clubID.Delete("/", clubParams.AuthMiddleware.Authorize(p.DeleteAll), clubController.DeleteClub)
return clubID
diff --git a/backend/entities/clubs/base/service.go b/backend/entities/clubs/base/service.go
index 7d3e60280..6891aeb1d 100644
--- a/backend/entities/clubs/base/service.go
+++ b/backend/entities/clubs/base/service.go
@@ -1,19 +1,21 @@
package base
import (
+ "fmt"
+
"github.com/GenerateNU/sac/backend/entities/clubs"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/types"
"github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
)
type ClubServiceInterface interface {
- GetClubs(queryParams *models.ClubQueryParams) ([]models.Club, *errors.Error)
- GetClub(id string) (*models.Club, *errors.Error)
- CreateClub(clubBody models.CreateClubRequestBody) (*models.Club, *errors.Error)
- UpdateClub(id string, clubBody models.UpdateClubRequestBody) (*models.Club, *errors.Error)
- DeleteClub(id string) *errors.Error
+ GetClubs(queryParams *models.ClubQueryParams, pageInfo fiberpaginate.PageInfo) ([]models.Club, error)
+ GetClub(id string) (*models.Club, error)
+ CreateClub(clubBody CreateClubRequestBody) (*models.Club, error)
+ UpdateClub(id string, clubBody UpdateClubRequestBody) (*models.Club, error)
+ DeleteClub(id string) error
}
type ClubService struct {
@@ -24,66 +26,58 @@ func NewClubService(serviceParams types.ServiceParams) ClubServiceInterface {
return &ClubService{serviceParams}
}
-func (c *ClubService) GetClubs(queryParams *models.ClubQueryParams) ([]models.Club, *errors.Error) {
- if queryParams.Limit < 0 {
- return nil, &errors.FailedToValidateLimit
- }
-
- if queryParams.Page < 0 {
- return nil, &errors.FailedToValidatePage
- }
-
- return GetClubs(c.DB, c.Integrations.Search, queryParams)
+func (c *ClubService) GetClubs(queryParams *models.ClubQueryParams, pageInfo fiberpaginate.PageInfo) ([]models.Club, error) {
+ return GetClubs(c.DB, c.Integrations.Search, queryParams, pageInfo)
}
-func (c *ClubService) CreateClub(clubBody models.CreateClubRequestBody) (*models.Club, *errors.Error) {
- if err := c.Validate.Struct(clubBody); err != nil {
- return nil, &errors.FailedToValidateClub
+func (c *ClubService) CreateClub(clubBody CreateClubRequestBody) (*models.Club, error) {
+ if err := utilities.Validate(c.Validate, clubBody); err != nil {
+ return nil, err
}
- club, err := utilities.MapRequestToModel(clubBody, &models.Club{})
+ club, err := utilities.MapJsonTags(clubBody, &models.Club{})
if err != nil {
- return nil, &errors.FailedToMapRequestToModel
+ return nil, err
}
return CreateClub(c.DB, c.Integrations.Search, clubBody.UserID, *club)
}
-func (c *ClubService) GetClub(id string) (*models.Club, *errors.Error) {
+func (c *ClubService) GetClub(id string) (*models.Club, error) {
idAsUUID, err := utilities.ValidateID(id)
if err != nil {
- return nil, &errors.FailedToValidateID
+ return nil, err
}
return clubs.GetClub(c.DB, *idAsUUID)
}
-func (c *ClubService) UpdateClub(id string, clubBody models.UpdateClubRequestBody) (*models.Club, *errors.Error) {
- idAsUUID, idErr := utilities.ValidateID(id)
- if idErr != nil {
- return nil, idErr
+func (c *ClubService) UpdateClub(id string, clubBody UpdateClubRequestBody) (*models.Club, error) {
+ idAsUUID, err := utilities.ValidateID(id)
+ if err != nil {
+ return nil, err
}
- if utilities.AtLeastOne(clubBody, models.UpdateClubRequestBody{}) {
- return nil, &errors.FailedToValidateClub
+ if utilities.AtLeastOne(clubBody, UpdateClubRequestBody{}) {
+ return nil, fmt.Errorf("at least one field must be present")
}
- if err := c.Validate.Struct(clubBody); err != nil {
- return nil, &errors.FailedToValidateClub
+ if err := utilities.Validate(c.Validate, clubBody); err != nil {
+ return nil, err
}
- club, err := utilities.MapRequestToModel(clubBody, &models.Club{})
+ club, err := utilities.MapJsonTags(clubBody, &models.Club{})
if err != nil {
- return nil, &errors.FailedToMapRequestToModel
+ return nil, err
}
return UpdateClub(c.DB, c.Integrations.Search, *idAsUUID, *club)
}
-func (c *ClubService) DeleteClub(id string) *errors.Error {
+func (c *ClubService) DeleteClub(id string) error {
idAsUUID, err := utilities.ValidateID(id)
if err != nil {
- return &errors.FailedToValidateID
+ return err
}
return DeleteClub(c.DB, c.Integrations.Search, *idAsUUID)
diff --git a/backend/entities/clubs/base/transactions.go b/backend/entities/clubs/base/transactions.go
index 1d4055f9b..c1352a5b8 100644
--- a/backend/entities/clubs/base/transactions.go
+++ b/backend/entities/clubs/base/transactions.go
@@ -1,19 +1,22 @@
package base
import (
- stdliberrors "errors"
+ "errors"
"github.com/GenerateNU/sac/backend/integrations/search"
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
"github.com/sahilm/fuzzy"
"github.com/GenerateNU/sac/backend/entities/models"
"github.com/GenerateNU/sac/backend/entities/users"
- "github.com/GenerateNU/sac/backend/errors"
+
"github.com/google/uuid"
"gorm.io/gorm"
+ "gorm.io/gorm/clause"
)
-func GetClubs(db *gorm.DB, pinecone search.SearchClientInterface, queryParams *models.ClubQueryParams) ([]models.Club, *errors.Error) {
+func GetClubs(db *gorm.DB, pinecone search.SearchClientInterface, queryParams *models.ClubQueryParams, pageInfo fiberpaginate.PageInfo) ([]models.Club, error) {
query := db.Model(&models.Club{})
if queryParams.Tags != nil && len(queryParams.Tags) > 0 {
@@ -43,7 +46,7 @@ func GetClubs(db *gorm.DB, pinecone search.SearchClientInterface, queryParams *m
if queryParams.Search != "" {
if err := query.Find(&clubs).Error; err != nil {
- return nil, &errors.FailedToGetClubs
+ return nil, err
}
// len(matches) <= len(clubs), because it discardss results that don't fuzz at all.
@@ -70,29 +73,35 @@ func GetClubs(db *gorm.DB, pinecone search.SearchClientInterface, queryParams *m
return clubsSorted, nil
}
- offset := (queryParams.Page - 1) * queryParams.Limit
-
- result := query.Limit(queryParams.Limit).Offset(offset).Find(&clubs)
- if result.Error != nil {
- return nil, &errors.FailedToGetClubs
+ if err := query.Scopes(utilities.IntoScope(pageInfo, query)).Find(&clubs).Error; err != nil {
+ return nil, err
}
return clubs, nil
}
-func CreateClub(db *gorm.DB, pinecone search.SearchClientInterface, userId uuid.UUID, club models.Club) (*models.Club, *errors.Error) {
+func CreateClub(db *gorm.DB, pinecone search.SearchClientInterface, userId uuid.UUID, club models.Club) (*models.Club, error) {
user, err := users.GetUser(db, userId)
if err != nil {
return nil, err
}
tx := db.Begin()
+ defer func() {
+ if r := recover(); r != nil {
+ tx.Rollback()
+ }
+ }()
+
+ if err := tx.Error; err != nil {
+ return nil, err
+ }
club.NumMembers = 1
if err := tx.Create(&club).Error; err != nil {
tx.Rollback()
- return nil, &errors.FailedToCreateClub
+ return nil, err
}
membership := models.Membership{
@@ -103,89 +112,83 @@ func CreateClub(db *gorm.DB, pinecone search.SearchClientInterface, userId uuid.
if err := tx.Create(&membership).Error; err != nil {
tx.Rollback()
- return nil, &errors.FailedToCreateClub
+ return nil, err
}
if err := tx.Model(&user).Association("Follower").Append(&club); err != nil {
tx.Rollback()
- return nil, &errors.FailedToCreateClub
+ return nil, err
}
if err := pinecone.Upsert([]search.Searchable{&club}); err != nil {
tx.Rollback()
- return nil, &errors.FailedToCreateClub
- }
-
- if err := tx.Commit().Error; err != nil {
- tx.Rollback()
- return nil, &errors.FailedToCreateClub
+ return nil, err
}
- return &club, nil
+ return &club, tx.Commit().Error
}
-func UpdateClub(db *gorm.DB, pinecone search.SearchClientInterface, id uuid.UUID, club models.Club) (*models.Club, *errors.Error) {
+func UpdateClub(db *gorm.DB, pinecone search.SearchClientInterface, id uuid.UUID, club models.Club) (*models.Club, error) {
tx := db.Begin()
+ defer func() {
+ if r := recover(); r != nil {
+ tx.Rollback()
+ }
+ }()
var existingClub models.Club
-
err := tx.First(&existingClub, id).Error
if err != nil {
tx.Rollback()
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.ClubNotFound
- } else {
- return nil, &errors.FailedToCreateClub
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
}
+ return nil, err
}
- if err := tx.Model(&existingClub).Updates(&club).Error; err != nil {
+ if err := tx.Model(&existingClub).Clauses(clause.Returning{}).Updates(&club).Error; err != nil {
tx.Rollback()
- return nil, &errors.FailedToUpdateUser
+ return nil, err
}
if pinecone.Upsert([]search.Searchable{&existingClub}) != nil {
tx.Rollback()
- return nil, &errors.FailedToUpsertToPinecone
- }
-
- if err := tx.Commit().Error; err != nil {
- tx.Rollback()
- return nil, &errors.FailedToUpdateClub
+ return nil, err
}
- return &existingClub, nil
+ return &existingClub, tx.Commit().Error
}
-func DeleteClub(db *gorm.DB, pinecone search.SearchClientInterface, id uuid.UUID) *errors.Error {
+func DeleteClub(db *gorm.DB, pinecone search.SearchClientInterface, id uuid.UUID) error {
tx := db.Begin()
+ defer func() {
+ if r := recover(); r != nil {
+ tx.Rollback()
+ }
+ }()
var existingClub models.Club
err := tx.First(&existingClub, id).Error
if err != nil {
tx.Rollback()
- return &errors.ClubNotFound
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return utilities.ErrNotFound
+ }
+ return err
}
- pineconeErr := pinecone.Delete([]search.Searchable{&existingClub})
- if pineconeErr != nil {
+ if err := pinecone.Delete([]search.Searchable{&existingClub}); err != nil {
tx.Rollback()
- return &errors.FailedToDeleteClub
+ return err
}
if result := tx.Delete(&models.Club{}, id); result.RowsAffected == 0 {
tx.Rollback()
if result.Error == nil {
- return &errors.ClubNotFound
- } else {
- return &errors.FailedToDeleteClub
+ return utilities.ErrNotFound
}
+ return result.Error
}
- if err := tx.Commit().Error; err != nil {
- tx.Rollback()
- return &errors.FailedToDeleteClub
- }
-
- return nil
+ return tx.Commit().Error
}
diff --git a/backend/entities/clubs/contact/controller.go b/backend/entities/clubs/contacts/controller.go
similarity index 63%
rename from backend/entities/clubs/contact/controller.go
rename to backend/entities/clubs/contacts/controller.go
index c2c170b8a..ac0bb51b9 100644
--- a/backend/entities/clubs/contact/controller.go
+++ b/backend/entities/clubs/contacts/controller.go
@@ -1,8 +1,9 @@
-package contact
+package contacts
import (
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+ "net/http"
+
+ "github.com/GenerateNU/sac/backend/utilities"
"github.com/gofiber/fiber/v2"
)
@@ -23,17 +24,17 @@ func NewClubContactController(clubContactService ClubContactServiceInterface) *C
// @Produce json
// @Param clubID path string true "Club ID"
// @Success 200 {object} []models.Contact
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /clubs/{clubID}/contacts/ [get]
func (cc *ClubContactController) GetClubContacts(c *fiber.Ctx) error {
contacts, err := cc.clubContactService.GetClubContacts(c.Params("clubID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(contacts)
+ return c.Status(http.StatusOK).JSON(contacts)
}
// PutContact godoc
@@ -45,24 +46,24 @@ func (cc *ClubContactController) GetClubContacts(c *fiber.Ctx) error {
// @Accept json
// @Produce json
// @Param clubID path string true "Club ID"
-// @Param contactBody body models.PutContactRequestBody true "Contact Body"
+// @Param contactBody body PutContactRequestBody true "Contact Body"
// @Success 201 {object} models.Contact
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /clubs/{clubID}/contacts/ [put]
func (cc *ClubContactController) PutContact(c *fiber.Ctx) error {
- var contactBody models.PutContactRequestBody
+ var contactBody PutContactRequestBody
if err := c.BodyParser(&contactBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ return utilities.InvalidJSON()
}
contact, err := cc.clubContactService.PutClubContact(c.Params("clubID"), contactBody)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(contact)
+ return c.Status(http.StatusOK).JSON(contact)
}
diff --git a/backend/entities/clubs/contacts/models.go b/backend/entities/clubs/contacts/models.go
new file mode 100644
index 000000000..26c5cf1dd
--- /dev/null
+++ b/backend/entities/clubs/contacts/models.go
@@ -0,0 +1,8 @@
+package contacts
+
+import "github.com/GenerateNU/sac/backend/entities/models"
+
+type PutContactRequestBody struct {
+ Type models.ContactType `json:"type" validate:"required,max=255,oneof=facebook instagram x linkedin youtube github slack discord email customSite"`
+ Content string `json:"content" validate:"required,contact_pointer,max=255"`
+}
diff --git a/backend/entities/clubs/contact/routes.go b/backend/entities/clubs/contacts/routes.go
similarity index 56%
rename from backend/entities/clubs/contact/routes.go
rename to backend/entities/clubs/contacts/routes.go
index 883f2b63d..252fcfe52 100644
--- a/backend/entities/clubs/contact/routes.go
+++ b/backend/entities/clubs/contacts/routes.go
@@ -1,6 +1,7 @@
-package contact
+package contacts
import (
+ authMiddleware "github.com/GenerateNU/sac/backend/middleware/auth"
"github.com/GenerateNU/sac/backend/types"
)
@@ -11,5 +12,9 @@ func ClubContact(clubParams types.RouteParams) {
// api/v1/clubs/:clubID/contacts/*
clubContacts.Get("/", clubContactController.GetClubContacts)
- clubContacts.Put("/", clubParams.AuthMiddleware.ClubAuthorizeById, clubContactController.PutContact)
+ clubContacts.Put(
+ "/",
+ authMiddleware.AttachExtractor(clubParams.AuthMiddleware.ClubAuthorizeById, authMiddleware.ExtractFromParams("clubID")),
+ clubContactController.PutContact,
+ )
}
diff --git a/backend/entities/clubs/contact/service.go b/backend/entities/clubs/contacts/service.go
similarity index 51%
rename from backend/entities/clubs/contact/service.go
rename to backend/entities/clubs/contacts/service.go
index 455ac4c47..5c12bd409 100644
--- a/backend/entities/clubs/contact/service.go
+++ b/backend/entities/clubs/contacts/service.go
@@ -1,15 +1,14 @@
-package contact
+package contacts
import (
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/types"
"github.com/GenerateNU/sac/backend/utilities"
)
type ClubContactServiceInterface interface {
- GetClubContacts(clubID string) ([]models.Contact, *errors.Error)
- PutClubContact(clubID string, contactBody models.PutContactRequestBody) (*models.Contact, *errors.Error)
+ GetClubContacts(clubID string) ([]models.Contact, error)
+ PutClubContact(clubID string, contactBody PutContactRequestBody) (*models.Contact, error)
}
type ClubContactService struct {
@@ -20,28 +19,28 @@ func NewClubContactService(params types.ServiceParams) ClubContactServiceInterfa
return &ClubContactService{params}
}
-func (c *ClubContactService) GetClubContacts(clubID string) ([]models.Contact, *errors.Error) {
+func (c *ClubContactService) GetClubContacts(clubID string) ([]models.Contact, error) {
idAsUUID, err := utilities.ValidateID(clubID)
if err != nil {
- return nil, &errors.FailedToValidateID
+ return nil, err
}
return GetClubContacts(c.DB, *idAsUUID)
}
-func (c *ClubContactService) PutClubContact(clubID string, contactBody models.PutContactRequestBody) (*models.Contact, *errors.Error) {
- idAsUUID, idErr := utilities.ValidateID(clubID)
- if idErr != nil {
- return nil, idErr
+func (c *ClubContactService) PutClubContact(clubID string, contactBody PutContactRequestBody) (*models.Contact, error) {
+ idAsUUID, err := utilities.ValidateID(clubID)
+ if err != nil {
+ return nil, err
}
- if err := c.Validate.Struct(contactBody); err != nil {
- return nil, &errors.FailedToValidateContact
+ if err := utilities.Validate(c.Validate, contactBody); err != nil {
+ return nil, err
}
- contact, err := utilities.MapRequestToModel(contactBody, &models.Contact{})
+ contact, err := utilities.MapJsonTags(contactBody, &models.Contact{})
if err != nil {
- return nil, &errors.FailedToMapRequestToModel
+ return nil, err
}
contact.ClubID = *idAsUUID
diff --git a/backend/entities/clubs/contact/transactions.go b/backend/entities/clubs/contacts/transactions.go
similarity index 56%
rename from backend/entities/clubs/contact/transactions.go
rename to backend/entities/clubs/contacts/transactions.go
index 5db842e1e..5c8ce2bd1 100644
--- a/backend/entities/clubs/contact/transactions.go
+++ b/backend/entities/clubs/contacts/transactions.go
@@ -1,43 +1,43 @@
-package contact
+package contacts
import (
- stdliberrors "errors"
+ "errors"
+ "fmt"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+
+ "github.com/GenerateNU/sac/backend/utilities"
"github.com/google/uuid"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
-func PutClubContact(db *gorm.DB, contact models.Contact) (*models.Contact, *errors.Error) {
+func PutClubContact(db *gorm.DB, contact models.Contact) (*models.Contact, error) {
err := db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "club_id"}, {Name: "type"}},
DoUpdates: clause.AssignmentColumns([]string{"content"}),
}).Create(&contact).Error
if err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) || stdliberrors.Is(err, gorm.ErrForeignKeyViolated) {
- return nil, &errors.ClubNotFound
- } else {
- return nil, &errors.FailedToPutContact
+ if errors.Is(err, gorm.ErrRecordNotFound) || errors.Is(err, gorm.ErrForeignKeyViolated) {
+ return nil, utilities.ErrNotFound
}
+ return nil, err
}
return &contact, nil
}
-func GetClubContacts(db *gorm.DB, clubID uuid.UUID) ([]models.Contact, *errors.Error) {
+func GetClubContacts(db *gorm.DB, clubID uuid.UUID) ([]models.Contact, error) {
var club models.Club
if err := db.Preload("Contact").First(&club, clubID).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.ClubNotFound
- } else {
- return nil, &errors.FailedToGetContacts
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
}
+ return nil, err
}
if club.Contact == nil {
- return nil, &errors.FailedToGetContacts
+ return nil, fmt.Errorf("club with ID %s has no contacts", clubID)
}
return club.Contact, nil
diff --git a/backend/entities/clubs/event/service.go b/backend/entities/clubs/event/service.go
deleted file mode 100644
index d918ec5e2..000000000
--- a/backend/entities/clubs/event/service.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package event
-
-import (
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
- "github.com/GenerateNU/sac/backend/types"
- "github.com/GenerateNU/sac/backend/utilities"
-)
-
-type ClubEventServiceInterface interface {
- GetClubEvents(clubID string, limit string, page string) ([]models.Event, *errors.Error)
-}
-
-type ClubEventService struct {
- types.ServiceParams
-}
-
-func NewClubEventService(params types.ServiceParams) ClubEventServiceInterface {
- return &ClubEventService{params}
-}
-
-func (c *ClubEventService) GetClubEvents(clubID string, limit string, page string) ([]models.Event, *errors.Error) {
- idAsUUID, err := utilities.ValidateID(clubID)
- if err != nil {
- return nil, &errors.FailedToValidateID
- }
-
- limitAsInt, err := utilities.ValidateNonNegative(limit)
- if err != nil {
- return nil, &errors.FailedToValidateLimit
- }
-
- pageAsInt, err := utilities.ValidateNonNegative(page)
- if err != nil {
- return nil, &errors.FailedToValidatePage
- }
-
- return GetClubEvents(c.DB, *idAsUUID, *limitAsInt, *pageAsInt)
-}
diff --git a/backend/entities/clubs/event/transactions.go b/backend/entities/clubs/event/transactions.go
deleted file mode 100644
index 99b946063..000000000
--- a/backend/entities/clubs/event/transactions.go
+++ /dev/null
@@ -1,20 +0,0 @@
-package event
-
-import (
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
- "github.com/google/uuid"
- "gorm.io/gorm"
-)
-
-func GetClubEvents(db *gorm.DB, clubID uuid.UUID, limit int, page int) ([]models.Event, *errors.Error) {
- var events []models.Event
-
- offset := (page - 1) * limit
-
- if err := db.Where("club_id = ?", clubID).Limit(limit).Offset(offset).Find(&events).Error; err != nil {
- return nil, &errors.FailedToGetEvents
- }
-
- return events, nil
-}
diff --git a/backend/entities/clubs/event/controller.go b/backend/entities/clubs/events/controller.go
similarity index 66%
rename from backend/entities/clubs/event/controller.go
rename to backend/entities/clubs/events/controller.go
index 8e7c677aa..9f0235657 100644
--- a/backend/entities/clubs/event/controller.go
+++ b/backend/entities/clubs/events/controller.go
@@ -1,7 +1,10 @@
-package event
+package events
import (
- "github.com/GenerateNU/sac/backend/constants"
+ "net/http"
+
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
"github.com/gofiber/fiber/v2"
)
@@ -24,14 +27,19 @@ func NewClubEventController(clubEventService ClubEventServiceInterface) *ClubEve
// @Param limit query int false "Limit"
// @Param page query int false "Page"
// @Success 200 {object} []models.Event
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /clubs/{clubID}/events/ [get]
func (cl *ClubEventController) GetClubEvents(c *fiber.Ctx) error {
- if events, err := cl.clubEventService.GetClubEvents(c.Params("clubID"), c.Query("limit", constants.DEFAULT_LIMIT_STRING), c.Query("page", constants.DEFAULT_PAGE_STRING)); err != nil {
- return err.FiberError(c)
+ pagination, ok := fiberpaginate.FromContext(c)
+ if !ok {
+ return utilities.ErrExpectedPagination
+ }
+
+ if events, err := cl.clubEventService.GetClubEvents(c.Params("clubID"), *pagination); err != nil {
+ return err
} else {
- return c.Status(fiber.StatusOK).JSON(events)
+ return c.Status(http.StatusOK).JSON(events)
}
}
diff --git a/backend/entities/clubs/event/routes.go b/backend/entities/clubs/events/routes.go
similarity index 72%
rename from backend/entities/clubs/event/routes.go
rename to backend/entities/clubs/events/routes.go
index e18221b62..1a0bd42dd 100644
--- a/backend/entities/clubs/event/routes.go
+++ b/backend/entities/clubs/events/routes.go
@@ -1,4 +1,4 @@
-package event
+package events
import (
"github.com/GenerateNU/sac/backend/types"
@@ -10,5 +10,5 @@ func ClubEvent(clubParams types.RouteParams) {
// api/v1/clubs/:clubID/events/*
events := clubParams.Router.Group("/events")
- events.Get("/", clubEventController.GetClubEvents)
+ events.Get("/", clubParams.UtilityMiddleware.Paginator, clubEventController.GetClubEvents)
}
diff --git a/backend/entities/clubs/events/service.go b/backend/entities/clubs/events/service.go
new file mode 100644
index 000000000..4f11880f2
--- /dev/null
+++ b/backend/entities/clubs/events/service.go
@@ -0,0 +1,29 @@
+package events
+
+import (
+ "github.com/GenerateNU/sac/backend/entities/models"
+ "github.com/GenerateNU/sac/backend/types"
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
+)
+
+type ClubEventServiceInterface interface {
+ GetClubEvents(clubID string, pageInfo fiberpaginate.PageInfo) ([]models.Event, error)
+}
+
+type ClubEventService struct {
+ types.ServiceParams
+}
+
+func NewClubEventService(params types.ServiceParams) ClubEventServiceInterface {
+ return &ClubEventService{params}
+}
+
+func (c *ClubEventService) GetClubEvents(clubID string, pageInfo fiberpaginate.PageInfo) ([]models.Event, error) {
+ idAsUUID, err := utilities.ValidateID(clubID)
+ if err != nil {
+ return nil, err
+ }
+
+ return GetClubEvents(c.DB, *idAsUUID, pageInfo)
+}
diff --git a/backend/entities/clubs/events/transactions.go b/backend/entities/clubs/events/transactions.go
new file mode 100644
index 000000000..f8e681715
--- /dev/null
+++ b/backend/entities/clubs/events/transactions.go
@@ -0,0 +1,20 @@
+package events
+
+import (
+ "github.com/GenerateNU/sac/backend/entities/models"
+ "github.com/GenerateNU/sac/backend/utilities"
+
+ "github.com/garrettladley/fiberpaginate"
+ "github.com/google/uuid"
+ "gorm.io/gorm"
+)
+
+func GetClubEvents(db *gorm.DB, clubID uuid.UUID, pageInfo fiberpaginate.PageInfo) ([]models.Event, error) {
+ var events []models.Event
+
+ if err := db.Where("club_id = ?", clubID).Scopes(utilities.IntoScope(pageInfo, db)).Find(&events).Error; err != nil {
+ return nil, err
+ }
+
+ return events, nil
+}
diff --git a/backend/entities/clubs/follower/service.go b/backend/entities/clubs/follower/service.go
deleted file mode 100644
index ec63940f2..000000000
--- a/backend/entities/clubs/follower/service.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package follower
-
-import (
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
- "github.com/GenerateNU/sac/backend/types"
- "github.com/GenerateNU/sac/backend/utilities"
-)
-
-type ClubFollowerServiceInterface interface {
- GetClubFollowers(clubID string, limit string, page string) ([]models.User, *errors.Error)
-}
-
-type ClubFollowerService struct {
- types.ServiceParams
-}
-
-func NewClubFollowerService(params types.ServiceParams) ClubFollowerServiceInterface {
- return &ClubFollowerService{params}
-}
-
-func (cf *ClubFollowerService) GetClubFollowers(clubID string, limit string, page string) ([]models.User, *errors.Error) {
- idAsUUID, err := utilities.ValidateID(clubID)
- if err != nil {
- return nil, &errors.FailedToValidateID
- }
-
- limitAsInt, err := utilities.ValidateNonNegative(limit)
- if err != nil {
- return nil, &errors.FailedToValidateLimit
- }
-
- pageAsInt, err := utilities.ValidateNonNegative(page)
- if err != nil {
- return nil, &errors.FailedToValidatePage
- }
-
- return GetClubFollowers(cf.DB, *idAsUUID, *limitAsInt, *pageAsInt)
-}
diff --git a/backend/entities/clubs/follower/transactions.go b/backend/entities/clubs/follower/transactions.go
deleted file mode 100644
index 929f1202f..000000000
--- a/backend/entities/clubs/follower/transactions.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package follower
-
-import (
- "github.com/GenerateNU/sac/backend/entities/clubs"
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
- "github.com/google/uuid"
- "gorm.io/gorm"
-)
-
-func GetClubFollowers(db *gorm.DB, clubID uuid.UUID, limit int, page int) ([]models.User, *errors.Error) {
- club, err := clubs.GetClub(db, clubID)
- if err != nil {
- return nil, err
- }
-
- var users []models.User
-
- offset := (page - 1) * limit
-
- if err := db.Limit(limit).Offset(offset).Model(&club).Association("Follower").Find(&users); err != nil {
- return nil, &errors.FailedToGetClubFollowers
- }
-
- return users, nil
-}
diff --git a/backend/entities/clubs/follower/controller.go b/backend/entities/clubs/followers/controller.go
similarity index 67%
rename from backend/entities/clubs/follower/controller.go
rename to backend/entities/clubs/followers/controller.go
index 7e56d3516..45f8b9217 100644
--- a/backend/entities/clubs/follower/controller.go
+++ b/backend/entities/clubs/followers/controller.go
@@ -1,7 +1,10 @@
-package follower
+package followers
import (
- "github.com/GenerateNU/sac/backend/constants"
+ "net/http"
+
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
"github.com/gofiber/fiber/v2"
)
@@ -24,15 +27,20 @@ func NewClubFollowerController(clubFollowerService ClubFollowerServiceInterface)
// @Param limit query int false "Limit"
// @Param page query int false "Page"
// @Success 200 {object} []models.User
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /clubs/{clubID}/followers/ [get]
func (cf *ClubFollowerController) GetClubFollowers(c *fiber.Ctx) error {
- followers, err := cf.clubFollowerService.GetClubFollowers(c.Params("clubID"), c.Query("limit", constants.DEFAULT_LIMIT_STRING), c.Query("page", constants.DEFAULT_PAGE_STRING))
+ pagination, ok := fiberpaginate.FromContext(c)
+ if !ok {
+ return utilities.ErrExpectedPagination
+ }
+
+ followers, err := cf.clubFollowerService.GetClubFollowers(c.Params("clubID"), *pagination)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(followers)
+ return c.Status(http.StatusOK).JSON(followers)
}
diff --git a/backend/entities/clubs/follower/routes.go b/backend/entities/clubs/followers/routes.go
similarity index 71%
rename from backend/entities/clubs/follower/routes.go
rename to backend/entities/clubs/followers/routes.go
index 294f735e8..81f9e3a61 100644
--- a/backend/entities/clubs/follower/routes.go
+++ b/backend/entities/clubs/followers/routes.go
@@ -1,4 +1,4 @@
-package follower
+package followers
import (
"github.com/GenerateNU/sac/backend/types"
@@ -10,5 +10,5 @@ func ClubFollower(clubParams types.RouteParams) {
clubFollowers := clubParams.Router.Group("/followers")
// api/clubs/:clubID/followers/*
- clubFollowers.Get("/", clubFollowerController.GetClubFollowers)
+ clubFollowers.Get("/", clubParams.UtilityMiddleware.Paginator, clubFollowerController.GetClubFollowers)
}
diff --git a/backend/entities/clubs/followers/service.go b/backend/entities/clubs/followers/service.go
new file mode 100644
index 000000000..e1fced5c2
--- /dev/null
+++ b/backend/entities/clubs/followers/service.go
@@ -0,0 +1,29 @@
+package followers
+
+import (
+ "github.com/GenerateNU/sac/backend/entities/models"
+ "github.com/GenerateNU/sac/backend/types"
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
+)
+
+type ClubFollowerServiceInterface interface {
+ GetClubFollowers(clubID string, pageInfo fiberpaginate.PageInfo) ([]models.User, error)
+}
+
+type ClubFollowerService struct {
+ types.ServiceParams
+}
+
+func NewClubFollowerService(params types.ServiceParams) ClubFollowerServiceInterface {
+ return &ClubFollowerService{params}
+}
+
+func (cf *ClubFollowerService) GetClubFollowers(clubID string, pageInfo fiberpaginate.PageInfo) ([]models.User, error) {
+ idAsUUID, err := utilities.ValidateID(clubID)
+ if err != nil {
+ return nil, err
+ }
+
+ return GetClubFollowers(cf.DB, *idAsUUID, pageInfo)
+}
diff --git a/backend/entities/clubs/followers/transactions.go b/backend/entities/clubs/followers/transactions.go
new file mode 100644
index 000000000..8a98f8d2e
--- /dev/null
+++ b/backend/entities/clubs/followers/transactions.go
@@ -0,0 +1,24 @@
+package followers
+
+import (
+ "github.com/GenerateNU/sac/backend/entities/clubs"
+ "github.com/GenerateNU/sac/backend/entities/models"
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
+ "github.com/google/uuid"
+ "gorm.io/gorm"
+)
+
+func GetClubFollowers(db *gorm.DB, clubID uuid.UUID, pageInfo fiberpaginate.PageInfo) ([]models.User, error) {
+ club, err := clubs.GetClub(db, clubID)
+ if err != nil {
+ return nil, err
+ }
+
+ var users []models.User
+ if err := db.Scopes(utilities.IntoScope(pageInfo, db)).Model(&club).Association("Follower").Find(&users); err != nil {
+ return nil, err
+ }
+
+ return users, nil
+}
diff --git a/backend/entities/clubs/member/controller.go b/backend/entities/clubs/member/controller.go
deleted file mode 100644
index 3e241ff64..000000000
--- a/backend/entities/clubs/member/controller.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package member
-
-import (
- "github.com/GenerateNU/sac/backend/constants"
- "github.com/gofiber/fiber/v2"
-)
-
-type ClubMemberController struct {
- clubMemberService ClubMemberServiceInterface
-}
-
-func NewClubMemberController(clubMemberService ClubMemberServiceInterface) *ClubMemberController {
- return &ClubMemberController{clubMemberService: clubMemberService}
-}
-
-// GetClubMembers godoc
-//
-// @Summary Retrieve all members for a club
-// @Description Retrieves all members associated with a club
-// @ID get-members-by-club
-// @Tags club-member
-// @Produce json
-// @Param clubID path string true "Club ID"
-// @Param limit query int false "Limit"
-// @Param page query int false "Page"
-// @Success 200 {object} []models.User
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
-// @Router /clubs/{clubID}/members/ [get]
-func (cm *ClubMemberController) GetClubMembers(c *fiber.Ctx) error {
- followers, err := cm.clubMemberService.GetClubMembers(c.Params("clubID"), c.Query("limit", constants.DEFAULT_LIMIT_STRING), c.Query("page", constants.DEFAULT_PAGE_STRING))
- if err != nil {
- return err.FiberError(c)
- }
-
- return c.Status(fiber.StatusOK).JSON(followers)
-}
diff --git a/backend/entities/clubs/member/routes.go b/backend/entities/clubs/member/routes.go
deleted file mode 100644
index a7cdfb093..000000000
--- a/backend/entities/clubs/member/routes.go
+++ /dev/null
@@ -1,14 +0,0 @@
-package member
-
-import (
- "github.com/GenerateNU/sac/backend/types"
-)
-
-func ClubMember(clubParams types.RouteParams) {
- clubMemberController := NewClubMemberController(NewClubMemberService(clubParams.ServiceParams))
-
- clubMembers := clubParams.Router.Group("/members")
-
- // api/v1/clubs/:clubID/members/*
- clubMembers.Get("/", clubMemberController.GetClubMembers)
-}
diff --git a/backend/entities/clubs/member/service.go b/backend/entities/clubs/member/service.go
deleted file mode 100644
index 88549c794..000000000
--- a/backend/entities/clubs/member/service.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package member
-
-import (
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
- "github.com/GenerateNU/sac/backend/types"
- "github.com/GenerateNU/sac/backend/utilities"
-)
-
-type ClubMemberServiceInterface interface {
- GetClubMembers(clubID string, limit string, page string) ([]models.User, *errors.Error)
-}
-
-type ClubMemberService struct {
- types.ServiceParams
-}
-
-func NewClubMemberService(params types.ServiceParams) ClubMemberServiceInterface {
- return &ClubMemberService{params}
-}
-
-func (cms *ClubMemberService) GetClubMembers(clubID string, limit string, page string) ([]models.User, *errors.Error) {
- idAsUUID, err := utilities.ValidateID(clubID)
- if err != nil {
- return nil, &errors.FailedToValidateID
- }
-
- limitAsInt, err := utilities.ValidateNonNegative(limit)
- if err != nil {
- return nil, &errors.FailedToValidateLimit
- }
-
- pageAsInt, err := utilities.ValidateNonNegative(page)
- if err != nil {
- return nil, &errors.FailedToValidatePage
- }
-
- return GetClubMembers(cms.DB, *idAsUUID, *limitAsInt, *pageAsInt)
-}
diff --git a/backend/entities/clubs/member/transactions.go b/backend/entities/clubs/member/transactions.go
deleted file mode 100644
index 6d5308d1b..000000000
--- a/backend/entities/clubs/member/transactions.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package member
-
-import (
- "github.com/GenerateNU/sac/backend/entities/clubs"
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
-
- "github.com/google/uuid"
- "gorm.io/gorm"
-)
-
-func GetClubMembers(db *gorm.DB, clubID uuid.UUID, limit int, page int) ([]models.User, *errors.Error) {
- club, err := clubs.GetClub(db, clubID)
- if err != nil {
- return nil, err
- }
-
- var users []models.User
-
- offset := (page - 1) * limit
-
- if err := db.Limit(limit).Offset(offset).Model(&club).Association("Member").Find(&users); err != nil {
- return nil, &errors.FailedToGetClubMembers
- }
-
- return users, nil
-}
diff --git a/backend/entities/clubs/members/controller.go b/backend/entities/clubs/members/controller.go
new file mode 100644
index 000000000..b5c899bee
--- /dev/null
+++ b/backend/entities/clubs/members/controller.go
@@ -0,0 +1,96 @@
+package members
+
+import (
+ "net/http"
+
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
+ "github.com/gofiber/fiber/v2"
+)
+
+type ClubMemberController struct {
+ clubMemberService ClubMemberServiceInterface
+}
+
+func NewClubMemberController(clubMemberService ClubMemberServiceInterface) *ClubMemberController {
+ return &ClubMemberController{clubMemberService: clubMemberService}
+}
+
+// GetClubMembers godoc
+//
+// @Summary Retrieve all members for a club
+// @Description Retrieves all members associated with a club
+// @ID get-members-by-club
+// @Tags club-member
+// @Produce json
+// @Param clubID path string true "Club ID"
+// @Param limit query int false "Limit"
+// @Param page query int false "Page"
+// @Success 200 {object} []models.User
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
+// @Router /clubs/{clubID}/members/ [get]
+func (cm *ClubMemberController) GetClubMembers(c *fiber.Ctx) error {
+ pagination, ok := fiberpaginate.FromContext(c)
+ if !ok {
+ return utilities.ErrExpectedPagination
+ }
+
+ followers, err := cm.clubMemberService.GetClubMembers(c.Params("clubID"), *pagination)
+ if err != nil {
+ return err
+ }
+
+ return c.Status(http.StatusOK).JSON(followers)
+}
+
+// CreateClubMember godoc
+//
+// @Summary Create a new member for a club
+// @Description Creates a new member associated with a club
+// @ID create-member-for-club
+// @Tags club-member
+// @Accept json
+// @Produce json
+// @Param clubID path string true "Club ID"
+// @Param userID path string true "User ID"
+// @Success 201 {object} models.User
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
+// @Router /clubs/{clubID}/members/ [post]
+func (cm *ClubMemberController) CreateClubMember(c *fiber.Ctx) error {
+ err := cm.clubMemberService.CreateClubMember(c.Params("clubID"), c.Params("userID"))
+ if err != nil {
+ return err
+ }
+
+ return c.SendStatus(http.StatusCreated)
+}
+
+// DeleteClubMember godoc
+//
+// @Summary Delete a member from a club
+// @Description Deletes a member associated with a club
+// @ID delete-member-from-club
+// @Tags club-member
+// @Produce json
+// @Param clubID path string true "Club ID"
+// @Param userID path string true "User ID"
+// @Success 204 {object} models.User
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
+// @Router /clubs/{clubID}/members/ [delete]
+func (cm *ClubMemberController) DeleteClubMember(c *fiber.Ctx) error {
+ err := cm.clubMemberService.DeleteClubMember(c.Params("clubID"), c.Params("userID"))
+ if err != nil {
+ return err
+ }
+
+ return c.SendStatus(http.StatusNoContent)
+}
diff --git a/backend/entities/clubs/members/routes.go b/backend/entities/clubs/members/routes.go
new file mode 100644
index 000000000..660a83db8
--- /dev/null
+++ b/backend/entities/clubs/members/routes.go
@@ -0,0 +1,25 @@
+package members
+
+import (
+ authMiddleware "github.com/GenerateNU/sac/backend/middleware/auth"
+ "github.com/GenerateNU/sac/backend/types"
+)
+
+func ClubMember(clubParams types.RouteParams) {
+ clubMemberController := NewClubMemberController(NewClubMemberService(clubParams.ServiceParams))
+
+ clubMembers := clubParams.Router.Group("/members")
+
+ // api/v1/clubs/:clubID/members/*
+ clubMembers.Get("/", clubParams.UtilityMiddleware.Paginator, clubMemberController.GetClubMembers)
+ clubMembers.Post(
+ "/:userID",
+ authMiddleware.AttachExtractor(clubParams.AuthMiddleware.ClubAuthorizeById, authMiddleware.ExtractFromParams("clubID")),
+ clubMemberController.CreateClubMember,
+ )
+ clubMembers.Delete(
+ "/:userID",
+ authMiddleware.AttachExtractor(clubParams.AuthMiddleware.ClubAuthorizeById, authMiddleware.ExtractFromParams("clubID")),
+ clubMemberController.DeleteClubMember,
+ )
+}
diff --git a/backend/entities/clubs/members/service.go b/backend/entities/clubs/members/service.go
new file mode 100644
index 000000000..4e23be332
--- /dev/null
+++ b/backend/entities/clubs/members/service.go
@@ -0,0 +1,59 @@
+package members
+
+import (
+ "github.com/GenerateNU/sac/backend/entities/models"
+ "github.com/GenerateNU/sac/backend/types"
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
+)
+
+type ClubMemberServiceInterface interface {
+ GetClubMembers(clubID string, pageInfo fiberpaginate.PageInfo) ([]models.User, error)
+ CreateClubMember(clubID string, userID string) error
+ DeleteClubMember(clubID string, userID string) error
+}
+
+type ClubMemberService struct {
+ types.ServiceParams
+}
+
+func NewClubMemberService(params types.ServiceParams) ClubMemberServiceInterface {
+ return &ClubMemberService{params}
+}
+
+func (cms *ClubMemberService) GetClubMembers(clubID string, pageInfo fiberpaginate.PageInfo) ([]models.User, error) {
+ clubIDAsUUID, err := utilities.ValidateID(clubID)
+ if err != nil {
+ return nil, err
+ }
+
+ return GetClubMembers(cms.DB, *clubIDAsUUID, pageInfo)
+}
+
+func (cms *ClubMemberService) CreateClubMember(clubID string, userID string) error {
+ clubIDAsUUID, err := utilities.ValidateID(clubID)
+ if err != nil {
+ return err
+ }
+
+ userIDAsUUID, err := utilities.ValidateID(userID)
+ if err != nil {
+ return err
+ }
+
+ return CreateClubMember(cms.DB, *clubIDAsUUID, *userIDAsUUID)
+}
+
+func (cms *ClubMemberService) DeleteClubMember(clubID string, userID string) error {
+ clubIDAsUUID, err := utilities.ValidateID(clubID)
+ if err != nil {
+ return err
+ }
+
+ userIDAsUUID, err := utilities.ValidateID(userID)
+ if err != nil {
+ return err
+ }
+
+ return DeleteClubMember(cms.DB, *clubIDAsUUID, *userIDAsUUID)
+}
diff --git a/backend/entities/users/member/transactions.go b/backend/entities/clubs/members/transactions.go
similarity index 53%
rename from backend/entities/users/member/transactions.go
rename to backend/entities/clubs/members/transactions.go
index 6d03ce77a..8a0fd1f62 100644
--- a/backend/entities/users/member/transactions.go
+++ b/backend/entities/clubs/members/transactions.go
@@ -1,17 +1,32 @@
-package member
+package members
import (
"github.com/GenerateNU/sac/backend/entities/clubs"
"github.com/GenerateNU/sac/backend/entities/models"
"github.com/GenerateNU/sac/backend/entities/users"
- "github.com/GenerateNU/sac/backend/entities/users/follower"
- "github.com/GenerateNU/sac/backend/errors"
+ "github.com/GenerateNU/sac/backend/entities/users/followers"
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
"github.com/google/uuid"
"gorm.io/gorm"
)
-func CreateMember(db *gorm.DB, userID uuid.UUID, clubID uuid.UUID) *errors.Error {
+func GetClubMembers(db *gorm.DB, clubID uuid.UUID, pageInfo fiberpaginate.PageInfo) ([]models.User, error) {
+ club, err := clubs.GetClub(db, clubID)
+ if err != nil {
+ return nil, err
+ }
+
+ var users []models.User
+ if err := db.Scopes(utilities.IntoScope(pageInfo, db)).Model(&club).Association("Member").Find(&users); err != nil {
+ return nil, err
+ }
+
+ return users, nil
+}
+
+func CreateClubMember(db *gorm.DB, clubID uuid.UUID, userID uuid.UUID) error {
user, err := users.GetUser(db, userID)
if err != nil {
return err
@@ -23,10 +38,15 @@ func CreateMember(db *gorm.DB, userID uuid.UUID, clubID uuid.UUID) *errors.Error
}
tx := db.Begin()
+ defer func() {
+ if r := recover(); r != nil {
+ tx.Rollback()
+ }
+ }()
var count int64
if err := tx.Model(&models.Membership{}).Where("user_id = ? AND club_id = ?", userID, clubID).Count(&count).Error; err != nil {
- return &errors.FailedToGetUserMemberships
+ return err
}
if count > 0 {
@@ -35,27 +55,23 @@ func CreateMember(db *gorm.DB, userID uuid.UUID, clubID uuid.UUID) *errors.Error
if err := tx.Model(&user).Association("Member").Append(club); err != nil {
tx.Rollback()
- return &errors.FailedToUpdateUser
+ return err
}
- if err := follower.CreateFollowing(tx, userID, clubID); err != nil {
+ if err := followers.CreateFollowing(tx, userID, clubID); err != nil {
tx.Rollback()
return err
}
if err := tx.Model(&club).Update("num_members", gorm.Expr("num_members + 1")).Error; err != nil {
tx.Rollback()
- return &errors.FailedToUpdateUser
- }
-
- if err := tx.Commit().Error; err != nil {
- return &errors.FailedToUpdateUser
+ return err
}
- return nil
+ return tx.Commit().Error
}
-func DeleteMember(db *gorm.DB, userID uuid.UUID, clubID uuid.UUID) *errors.Error {
+func DeleteClubMember(db *gorm.DB, clubID uuid.UUID, userID uuid.UUID) error {
user, err := users.GetUser(db, userID)
if err != nil {
return err
@@ -67,40 +83,26 @@ func DeleteMember(db *gorm.DB, userID uuid.UUID, clubID uuid.UUID) *errors.Error
}
tx := db.Begin()
+ defer func() {
+ if r := recover(); r != nil {
+ tx.Rollback()
+ }
+ }()
if err := tx.Model(&user).Association("Member").Delete(club); err != nil {
tx.Rollback()
- return &errors.FailedToUpdateUser
+ return err
}
- if err := follower.DeleteFollowing(tx, userID, clubID); err != nil {
+ if err := followers.DeleteFollowing(tx, userID, clubID); err != nil {
tx.Rollback()
return err
}
if err := tx.Model(&club).Update("num_members", gorm.Expr("num_members - 1")).Error; err != nil {
tx.Rollback()
- return &errors.FailedToUpdateUser
- }
-
- if err := tx.Commit().Error; err != nil {
- return &errors.FailedToUpdateUser
- }
-
- return nil
-}
-
-func GetClubMembership(db *gorm.DB, userID uuid.UUID) ([]models.Club, *errors.Error) {
- var clubs []models.Club
-
- user, err := users.GetUser(db, userID)
- if err != nil {
- return nil, err
- }
-
- if err := db.Model(&user).Association("Member").Find(&clubs); err != nil {
- return nil, &errors.FailedToGetUserMemberships
+ return err
}
- return clubs, nil
+ return tx.Commit().Error
}
diff --git a/backend/entities/clubs/poc/routes.go b/backend/entities/clubs/poc/routes.go
deleted file mode 100644
index 135f72a8e..000000000
--- a/backend/entities/clubs/poc/routes.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package poc
-
-import (
- "github.com/GenerateNU/sac/backend/types"
-)
-
-func ClubPointOfContact(clubParams types.RouteParams) {
- clubPointOfContactController := NewClubPointOfContactController(NewClubPointOfContactService(clubParams.ServiceParams))
-
- clubPointOfContacts := clubParams.Router.Group("/pocs")
-
- // api/v1/clubs/:clubID/pocs/*
- clubPointOfContacts.Get("/", clubPointOfContactController.GetClubPointOfContacts)
- clubPointOfContacts.Get("/:pocID", clubPointOfContactController.GetClubPointOfContact)
- clubPointOfContacts.Post("/", clubParams.AuthMiddleware.ClubAuthorizeById, clubPointOfContactController.CreateClubPointOfContact)
- clubPointOfContacts.Patch("/:pocID", clubParams.AuthMiddleware.ClubAuthorizeById, clubPointOfContactController.UpdateClubPointOfContact)
- clubPointOfContacts.Patch("/:pocID/photo", clubParams.AuthMiddleware.ClubAuthorizeById, clubPointOfContactController.UpdateClubPointOfContactPhoto)
- clubPointOfContacts.Delete("/:pocID", clubParams.AuthMiddleware.ClubAuthorizeById, clubPointOfContactController.DeleteClubPointOfContact)
-}
diff --git a/backend/entities/clubs/poc/controller.go b/backend/entities/clubs/pocs/controller.go
similarity index 66%
rename from backend/entities/clubs/poc/controller.go
rename to backend/entities/clubs/pocs/controller.go
index 58214b04c..8d9de7e6f 100644
--- a/backend/entities/clubs/poc/controller.go
+++ b/backend/entities/clubs/pocs/controller.go
@@ -1,8 +1,9 @@
-package poc
+package pocs
import (
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+ "net/http"
+
+ "github.com/GenerateNU/sac/backend/utilities"
"github.com/gofiber/fiber/v2"
)
@@ -23,17 +24,17 @@ func NewClubPointOfContactController(clubPointOfContactService ClubPointOfContac
// @Produce json
// @Param clubID path string true "Club ID"
// @Success 200 {object} []models.PointOfContact
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /clubs/{clubID}/pocs/ [get]
func (cpoc *ClubPointOfContactController) GetClubPointOfContacts(c *fiber.Ctx) error {
pointOfContact, err := cpoc.clubPointOfContactService.GetClubPointOfContacts(c.Params("clubID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(pointOfContact)
+ return c.Status(http.StatusOK).JSON(pointOfContact)
}
// GetClubPointOfContact godoc
@@ -46,17 +47,17 @@ func (cpoc *ClubPointOfContactController) GetClubPointOfContacts(c *fiber.Ctx) e
// @Param clubID path string true "Club ID"
// @Param pocID path string true "Point of Contact ID"
// @Success 200 {object} models.PointOfContact
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /clubs/{clubID}/pocs/{pocID} [get]
func (cpoc *ClubPointOfContactController) GetClubPointOfContact(c *fiber.Ctx) error {
pointOfContact, err := cpoc.clubPointOfContactService.GetClubPointOfContact(c.Params("clubID"), c.Params("pocID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(pointOfContact)
+ return c.Status(http.StatusOK).JSON(pointOfContact)
}
// UpdateClubPointOfContactPhoto godoc
@@ -70,23 +71,23 @@ func (cpoc *ClubPointOfContactController) GetClubPointOfContact(c *fiber.Ctx) er
// @Param clubID path string true "Club ID"
// @Param pocID path string true "Point of Contact ID"
// @Success 200 {object} models.PointOfContact
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /clubs/{clubID}/poc/{pocID} [patch]
func (cpoc *ClubPointOfContactController) UpdateClubPointOfContactPhoto(c *fiber.Ctx) error {
- formFile, parseErr := c.FormFile("file")
- if parseErr != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ formFile, err := c.FormFile("file")
+ if err != nil {
+ return err
}
pointOfContact, err := cpoc.clubPointOfContactService.UpdateClubPointOfContactPhoto(c.Params("clubID"), c.Params("pocID"), formFile)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(pointOfContact)
+ return c.Status(http.StatusOK).JSON(pointOfContact)
}
// UpdateClubPointOfContact godoc
@@ -100,24 +101,24 @@ func (cpoc *ClubPointOfContactController) UpdateClubPointOfContactPhoto(c *fiber
// @Param clubID path string true "Club ID"
// @Param pocID path string true "Point of Contact ID"
// @Success 200 {object} models.PointOfContact
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /clubs/{clubID}/poc/{pocID} [put]
func (cpoc *ClubPointOfContactController) UpdateClubPointOfContact(c *fiber.Ctx) error {
- var pointOfContactBody models.UpdatePointOfContactBody
+ var pointOfContactBody UpdatePointOfContactBody
- if parseErr := c.BodyParser(&pointOfContactBody); parseErr != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ if err := c.BodyParser(&pointOfContactBody); err != nil {
+ return utilities.InvalidJSON()
}
pointOfContact, err := cpoc.clubPointOfContactService.UpdateClubPointOfContact(c.Params("clubID"), c.Params("pocID"), pointOfContactBody)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(pointOfContact)
+ return c.Status(http.StatusOK).JSON(pointOfContact)
}
// CreateClubPointOfContact godoc
@@ -130,29 +131,29 @@ func (cpoc *ClubPointOfContactController) UpdateClubPointOfContact(c *fiber.Ctx)
// @Produce json
// @Param clubID path string true "Club ID"
// @Success 201 {object} models.PointOfContact
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /clubs/{clubID}/poc/ [post]
func (cpoc *ClubPointOfContactController) CreateClubPointOfContact(c *fiber.Ctx) error {
- var pointOfContactBody models.CreatePointOfContactBody
+ var pointOfContactBody CreatePointOfContactBody
- if parseErr := c.BodyParser(&pointOfContactBody); parseErr != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ if err := c.BodyParser(&pointOfContactBody); err != nil {
+ return utilities.InvalidJSON()
}
- formFile, parseErr := c.FormFile("file")
- if parseErr != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ formFile, err := c.FormFile("file")
+ if err != nil {
+ return err
}
pointOfContact, err := cpoc.clubPointOfContactService.CreateClubPointOfContact(c.Params("clubID"), pointOfContactBody, formFile)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusCreated).JSON(pointOfContact)
+ return c.Status(http.StatusCreated).JSON(pointOfContact)
}
// DeleteClubPointOfContact godoc
@@ -165,15 +166,15 @@ func (cpoc *ClubPointOfContactController) CreateClubPointOfContact(c *fiber.Ctx)
// @Param clubID path string true "Club ID"
// @Param pocID path string true "Point of Contact ID"
// @Success 204 {object} nil
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /clubs/{clubID}/poc/{pocID} [delete]
func (cpoc *ClubPointOfContactController) DeleteClubPointOfContact(c *fiber.Ctx) error {
err := cpoc.clubPointOfContactService.DeleteClubPointOfContact(c.Params("clubID"), c.Params("pocID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.SendStatus(fiber.StatusNoContent)
+ return c.SendStatus(http.StatusNoContent)
}
diff --git a/backend/entities/clubs/pocs/models.go b/backend/entities/clubs/pocs/models.go
new file mode 100644
index 000000000..85fa0a9dd
--- /dev/null
+++ b/backend/entities/clubs/pocs/models.go
@@ -0,0 +1,13 @@
+package pocs
+
+type CreatePointOfContactBody struct {
+ Name string `json:"name" validate:"required,max=255"`
+ Email string `json:"email" validate:"required,email,max=255"`
+ Position string `json:"position" validate:"required,max=255"`
+}
+
+type UpdatePointOfContactBody struct {
+ Name string `json:"name" validate:"omitempty,max=255"`
+ Email string `json:"email" validate:"omitempty,email,max=255"`
+ Position string `json:"position" validate:"omitempty,max=255"`
+}
diff --git a/backend/entities/clubs/pocs/routes.go b/backend/entities/clubs/pocs/routes.go
new file mode 100644
index 000000000..bd57f188c
--- /dev/null
+++ b/backend/entities/clubs/pocs/routes.go
@@ -0,0 +1,36 @@
+package pocs
+
+import (
+ authMiddleware "github.com/GenerateNU/sac/backend/middleware/auth"
+ "github.com/GenerateNU/sac/backend/types"
+)
+
+func ClubPointOfContact(clubParams types.RouteParams) {
+ clubPointOfContactController := NewClubPointOfContactController(NewClubPointOfContactService(clubParams.ServiceParams))
+
+ clubPointOfContacts := clubParams.Router.Group("/pocs")
+
+ // api/v1/clubs/:clubID/pocs/*
+ clubPointOfContacts.Get("/", clubPointOfContactController.GetClubPointOfContacts)
+ clubPointOfContacts.Get("/:pocID", clubPointOfContactController.GetClubPointOfContact)
+ clubPointOfContacts.Post(
+ "/",
+ authMiddleware.AttachExtractor(clubParams.AuthMiddleware.ClubAuthorizeById, authMiddleware.ExtractFromParams("clubID")),
+ clubPointOfContactController.CreateClubPointOfContact,
+ )
+ clubPointOfContacts.Patch(
+ "/:pocID",
+ authMiddleware.AttachExtractor(clubParams.AuthMiddleware.ClubAuthorizeById, authMiddleware.ExtractFromParams("clubID")),
+ clubPointOfContactController.UpdateClubPointOfContact,
+ )
+ clubPointOfContacts.Patch(
+ "/:pocID/photo",
+ authMiddleware.AttachExtractor(clubParams.AuthMiddleware.ClubAuthorizeById, authMiddleware.ExtractFromParams("clubID")),
+ clubPointOfContactController.UpdateClubPointOfContactPhoto,
+ )
+ clubPointOfContacts.Delete(
+ "/:pocID",
+ authMiddleware.AttachExtractor(clubParams.AuthMiddleware.ClubAuthorizeById, authMiddleware.ExtractFromParams("clubID")),
+ clubPointOfContactController.DeleteClubPointOfContact,
+ )
+}
diff --git a/backend/entities/clubs/poc/service.go b/backend/entities/clubs/pocs/service.go
similarity index 70%
rename from backend/entities/clubs/poc/service.go
rename to backend/entities/clubs/pocs/service.go
index 2b7fcf7e9..82472507e 100644
--- a/backend/entities/clubs/poc/service.go
+++ b/backend/entities/clubs/pocs/service.go
@@ -1,4 +1,4 @@
-package poc
+package pocs
import (
"mime/multipart"
@@ -6,19 +6,18 @@ import (
"github.com/GenerateNU/sac/backend/entities/files/base"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/integrations/file"
"github.com/GenerateNU/sac/backend/types"
"github.com/GenerateNU/sac/backend/utilities"
)
type ClubPointOfContactServiceInterface interface {
- GetClubPointOfContacts(clubID string) ([]models.PointOfContact, *errors.Error)
- GetClubPointOfContact(clubID, pocID string) (*models.PointOfContact, *errors.Error)
- CreateClubPointOfContact(clubID string, pointOfContactBody models.CreatePointOfContactBody, fileHeader *multipart.FileHeader) (*models.PointOfContact, *errors.Error)
- UpdateClubPointOfContactPhoto(clubID, pocID string, fileHeader *multipart.FileHeader) (*models.PointOfContact, *errors.Error)
- UpdateClubPointOfContact(clubID, pocID string, pointOfContactBody models.UpdatePointOfContactBody) (*models.PointOfContact, *errors.Error)
- DeleteClubPointOfContact(clubID, pocID string) *errors.Error
+ GetClubPointOfContacts(clubID string) ([]models.PointOfContact, error)
+ GetClubPointOfContact(clubID, pocID string) (*models.PointOfContact, error)
+ CreateClubPointOfContact(clubID string, pointOfContactBody CreatePointOfContactBody, fileHeader *multipart.FileHeader) (*models.PointOfContact, error)
+ UpdateClubPointOfContactPhoto(clubID, pocID string, fileHeader *multipart.FileHeader) (*models.PointOfContact, error)
+ UpdateClubPointOfContact(clubID, pocID string, pointOfContactBody UpdatePointOfContactBody) (*models.PointOfContact, error)
+ DeleteClubPointOfContact(clubID, pocID string) error
}
type ClubPointOfContactService struct {
@@ -29,42 +28,42 @@ func NewClubPointOfContactService(serviceParams types.ServiceParams) ClubPointOf
return &ClubPointOfContactService{serviceParams}
}
-func (cpoc *ClubPointOfContactService) GetClubPointOfContacts(clubID string) ([]models.PointOfContact, *errors.Error) {
+func (cpoc *ClubPointOfContactService) GetClubPointOfContacts(clubID string) ([]models.PointOfContact, error) {
clubIdAsUUID, err := utilities.ValidateID(clubID)
if err != nil {
- return nil, &errors.FailedToValidateClub
+ return nil, err
}
return GetClubPointOfContacts(cpoc.DB, *clubIdAsUUID)
}
-func (cpoc *ClubPointOfContactService) GetClubPointOfContact(clubID, pocID string) (*models.PointOfContact, *errors.Error) {
+func (cpoc *ClubPointOfContactService) GetClubPointOfContact(clubID, pocID string) (*models.PointOfContact, error) {
clubIdAsUUID, err := utilities.ValidateID(clubID)
if err != nil {
- return nil, &errors.FailedToValidateClub
+ return nil, err
}
pocIdAsUUID, err := utilities.ValidateID(pocID)
if err != nil {
- return nil, &errors.FailedToValidatePointOfContactId
+ return nil, err
}
return GetClubPointOfContact(cpoc.DB, *clubIdAsUUID, *pocIdAsUUID)
}
-func (cpoc *ClubPointOfContactService) CreateClubPointOfContact(clubID string, pointOfContactBody models.CreatePointOfContactBody, fileHeader *multipart.FileHeader) (*models.PointOfContact, *errors.Error) {
- if err := cpoc.Validate.Struct(pointOfContactBody); err != nil {
- return nil, &errors.FailedToValidatePointOfContact
+func (cpoc *ClubPointOfContactService) CreateClubPointOfContact(clubID string, pointOfContactBody CreatePointOfContactBody, fileHeader *multipart.FileHeader) (*models.PointOfContact, error) {
+ if err := utilities.Validate(cpoc.Validate, pointOfContactBody); err != nil {
+ return nil, err
}
clubIdAsUUID, err := utilities.ValidateID(clubID)
if err != nil {
- return nil, &errors.FailedToValidateClub
+ return nil, err
}
_, err = GetClubPointOfContactByClubIDAndEmail(cpoc.DB, *clubIdAsUUID, pointOfContactBody.Email)
if err == nil {
- return nil, &errors.PointOfContactAlreadyExists
+ return nil, err
}
fileInfo, err := cpoc.Integrations.File.UploadFile("point_of_contacts", fileHeader, []file.FileType{file.IMAGE})
@@ -96,7 +95,7 @@ func (cpoc *ClubPointOfContactService) CreateClubPointOfContact(clubID string, p
return nil, err
}
- return nil, &errors.FailedToCreatePointOfContact
+ return nil, err
}
poc.PhotoFile = *file
@@ -104,15 +103,15 @@ func (cpoc *ClubPointOfContactService) CreateClubPointOfContact(clubID string, p
return poc, nil
}
-func (cpoc *ClubPointOfContactService) UpdateClubPointOfContactPhoto(clubID, pocID string, fileHeader *multipart.FileHeader) (*models.PointOfContact, *errors.Error) {
+func (cpoc *ClubPointOfContactService) UpdateClubPointOfContactPhoto(clubID, pocID string, fileHeader *multipart.FileHeader) (*models.PointOfContact, error) {
clubIdAsUUID, err := utilities.ValidateID(clubID)
if err != nil {
- return nil, &errors.FailedToValidateClub
+ return nil, err
}
pocIdAsUUID, err := utilities.ValidateID(pocID)
if err != nil {
- return nil, &errors.FailedToValidatePointOfContactId
+ return nil, err
}
pointOfContact, err := GetClubPointOfContact(cpoc.DB, *clubIdAsUUID, *pocIdAsUUID)
@@ -139,33 +138,33 @@ func (cpoc *ClubPointOfContactService) UpdateClubPointOfContactPhoto(clubID, poc
return pointOfContact, nil
}
-func (cpoc *ClubPointOfContactService) UpdateClubPointOfContact(clubID, pocID string, pointOfContactBody models.UpdatePointOfContactBody) (*models.PointOfContact, *errors.Error) {
- if err := cpoc.Validate.Struct(pointOfContactBody); err != nil {
- return nil, &errors.FailedToValidatePointOfContact
+func (cpoc *ClubPointOfContactService) UpdateClubPointOfContact(clubID, pocID string, pointOfContactBody UpdatePointOfContactBody) (*models.PointOfContact, error) {
+ if err := utilities.Validate(cpoc.Validate, pointOfContactBody); err != nil {
+ return nil, err
}
clubIdAsUUID, err := utilities.ValidateID(clubID)
if err != nil {
- return nil, &errors.FailedToValidateClub
+ return nil, err
}
pocIdAsUUID, err := utilities.ValidateID(pocID)
if err != nil {
- return nil, &errors.FailedToValidatePointOfContactId
+ return nil, err
}
return UpdateClubPointOfContact(cpoc.DB, *clubIdAsUUID, *pocIdAsUUID, pointOfContactBody)
}
-func (cpoc *ClubPointOfContactService) DeleteClubPointOfContact(clubID, pocID string) *errors.Error {
+func (cpoc *ClubPointOfContactService) DeleteClubPointOfContact(clubID, pocID string) error {
clubIdAsUUID, err := utilities.ValidateID(clubID)
if err != nil {
- return &errors.FailedToValidateClub
+ return err
}
pocIdAsUUID, err := utilities.ValidateID(pocID)
if err != nil {
- return &errors.FailedToValidatePointOfContactId
+ return err
}
pointOfContact, err := GetClubPointOfContact(cpoc.DB, *clubIdAsUUID, *pocIdAsUUID)
@@ -184,7 +183,7 @@ func (cpoc *ClubPointOfContactService) DeleteClubPointOfContact(clubID, pocID st
}
}()
if err := tx.Error; err != nil {
- return &errors.FailedToDeleteClubPointOfContact
+ return err
}
err = base.DeleteFile(tx, pointOfContact.PhotoFile.ID)
@@ -200,7 +199,7 @@ func (cpoc *ClubPointOfContactService) DeleteClubPointOfContact(clubID, pocID st
}
if err := tx.Commit().Error; err != nil {
- return &errors.FailedToDeleteClubPointOfContact
+ return err
}
return nil
diff --git a/backend/entities/clubs/poc/transactions.go b/backend/entities/clubs/pocs/transactions.go
similarity index 59%
rename from backend/entities/clubs/poc/transactions.go
rename to backend/entities/clubs/pocs/transactions.go
index b339a53b9..5233fdfaa 100644
--- a/backend/entities/clubs/poc/transactions.go
+++ b/backend/entities/clubs/pocs/transactions.go
@@ -1,58 +1,57 @@
-package poc
+package pocs
import (
- stdliberrors "errors"
+ "errors"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+
+ "github.com/GenerateNU/sac/backend/utilities"
"github.com/google/uuid"
"gorm.io/gorm"
+ "gorm.io/gorm/clause"
)
-func GetClubPointOfContacts(db *gorm.DB, clubID uuid.UUID) ([]models.PointOfContact, *errors.Error) {
+func GetClubPointOfContacts(db *gorm.DB, clubID uuid.UUID) ([]models.PointOfContact, error) {
var pointOfContacts []models.PointOfContact
result := db.Preload("PhotoFile").Where("club_id = ?", clubID).Find(&pointOfContacts)
if result.Error != nil {
- if stdliberrors.Is(result.Error, gorm.ErrRecordNotFound) {
- return nil, &errors.PointOfContactsNotFound
- } else {
- return nil, &errors.FailedToGetClubPointOfContacts
+ if errors.Is(result.Error, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
}
+ return nil, result.Error
}
return pointOfContacts, nil
}
-func GetClubPointOfContact(db *gorm.DB, clubID uuid.UUID, pocID uuid.UUID) (*models.PointOfContact, *errors.Error) {
+func GetClubPointOfContact(db *gorm.DB, clubID uuid.UUID, pocID uuid.UUID) (*models.PointOfContact, error) {
var pointOfContact models.PointOfContact
if err := db.Preload("PhotoFile").First(&pointOfContact, "id = ? AND club_id = ?", pocID, clubID).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.PointOfContactNotFound
- } else {
- return nil, &errors.FailedToGetClubPointOfContact
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
}
+ return nil, err
}
return &pointOfContact, nil
}
-func GetClubPointOfContactByClubIDAndEmail(db *gorm.DB, clubID uuid.UUID, email string) (*models.PointOfContact, *errors.Error) {
+func GetClubPointOfContactByClubIDAndEmail(db *gorm.DB, clubID uuid.UUID, email string) (*models.PointOfContact, error) {
var pointOfContact models.PointOfContact
if err := db.First(&pointOfContact, "email = ? AND club_id = ?", email, clubID).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.PointOfContactNotFound
- } else {
- return nil, &errors.FailedToGetClubPointOfContact
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
}
+ return nil, err
}
return &pointOfContact, nil
}
-func CreateClubPointOfContact(db *gorm.DB, clubID uuid.UUID, pointOfContactBody models.CreatePointOfContactBody) (*models.PointOfContact, *errors.Error) {
+func CreateClubPointOfContact(db *gorm.DB, clubID uuid.UUID, pointOfContactBody CreatePointOfContactBody) (*models.PointOfContact, error) {
pointOfContact := models.PointOfContact{
Name: pointOfContactBody.Name,
Email: pointOfContactBody.Email,
@@ -61,35 +60,33 @@ func CreateClubPointOfContact(db *gorm.DB, clubID uuid.UUID, pointOfContactBody
}
if err := db.Create(&pointOfContact).Error; err != nil {
- return nil, &errors.FailedToCreatePointOfContact
+ return nil, err
}
return &pointOfContact, nil
}
-func UpdateClubPointOfContact(db *gorm.DB, clubID uuid.UUID, pocID uuid.UUID, pointOfContactBody models.UpdatePointOfContactBody) (*models.PointOfContact, *errors.Error) {
+func UpdateClubPointOfContact(db *gorm.DB, clubID uuid.UUID, pocID uuid.UUID, pointOfContactBody UpdatePointOfContactBody) (*models.PointOfContact, error) {
pointOfContact, err := GetClubPointOfContact(db, clubID, pocID)
if err != nil {
return nil, err
}
-
- if err := db.Model(&pointOfContact).Updates(models.PointOfContact{
+ if err := db.Model(&pointOfContact).Clauses(clause.Returning{}).Updates(models.PointOfContact{
Name: pointOfContactBody.Name,
Email: pointOfContactBody.Email,
Position: pointOfContactBody.Position,
}).Error; err != nil {
- return nil, &errors.FailedToUpdateClubPointOfContact
+ return nil, err
}
return pointOfContact, nil
}
-func DeleteClubPointOfContact(db *gorm.DB, clubID uuid.UUID, pocID uuid.UUID) *errors.Error {
+func DeleteClubPointOfContact(db *gorm.DB, clubID uuid.UUID, pocID uuid.UUID) error {
if result := db.Delete(&models.PointOfContact{}, "id = ? AND club_id = ?", pocID, clubID); result.RowsAffected == 0 {
if result.Error == nil {
- return &errors.PointOfContactNotFound
- } else {
- return &errors.FailedToDeleteClubPointOfContact
+ return utilities.ErrNotFound
}
+ return result.Error
}
return nil
}
diff --git a/backend/entities/clubs/tag/routes.go b/backend/entities/clubs/tag/routes.go
deleted file mode 100644
index 552929089..000000000
--- a/backend/entities/clubs/tag/routes.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package tag
-
-import (
- "github.com/GenerateNU/sac/backend/types"
-)
-
-func ClubTag(clubParams types.RouteParams) {
- clubTagController := NewClubTagController(NewClubTagService(clubParams.ServiceParams))
-
- clubTags := clubParams.Router.Group("/tags")
-
- clubTags.Get("/", clubTagController.GetClubTags)
- clubTags.Post("/", clubParams.AuthMiddleware.ClubAuthorizeById, clubTagController.CreateClubTags)
- clubTags.Delete("/:tagID", clubParams.AuthMiddleware.ClubAuthorizeById, clubTagController.DeleteClubTag)
-}
diff --git a/backend/entities/clubs/tag/controller.go b/backend/entities/clubs/tags/controller.go
similarity index 63%
rename from backend/entities/clubs/tag/controller.go
rename to backend/entities/clubs/tags/controller.go
index 87d0fda92..597bef7a3 100644
--- a/backend/entities/clubs/tag/controller.go
+++ b/backend/entities/clubs/tags/controller.go
@@ -1,8 +1,9 @@
-package tag
+package tags
import (
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+ "net/http"
+
+ "github.com/GenerateNU/sac/backend/utilities"
"github.com/gofiber/fiber/v2"
)
@@ -23,25 +24,25 @@ func NewClubTagController(clubTagService ClubTagServiceInterface) *ClubTagContro
// @Accept json
// @Produce json
// @Param clubID path string true "Club ID"
-// @Param clubTagsBody body models.CreateClubTagsRequestBody true "Club Tags Body"
+// @Param clubTagsBody body CreateClubTagsRequestBody true "Club Tags Body"
// @Success 201 {object} []models.Tag
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /clubs/{clubID}/tags/ [post]
func (l *ClubTagController) CreateClubTags(c *fiber.Ctx) error {
- var clubTagsBody models.CreateClubTagsRequestBody
+ var clubTagsBody CreateClubTagsRequestBody
if err := c.BodyParser(&clubTagsBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ return utilities.InvalidJSON()
}
clubTags, err := l.clubTagService.CreateClubTags(c.Params("clubID"), clubTagsBody)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusCreated).JSON(clubTags)
+ return c.Status(http.StatusCreated).JSON(clubTags)
}
// GetClubTags godoc
@@ -53,17 +54,17 @@ func (l *ClubTagController) CreateClubTags(c *fiber.Ctx) error {
// @Produce json
// @Param clubID path string true "Club ID"
// @Success 200 {object} []models.Tag
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /clubs/{clubID}/tags/ [get]
func (l *ClubTagController) GetClubTags(c *fiber.Ctx) error {
clubTags, err := l.clubTagService.GetClubTags(c.Params("clubID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(clubTags)
+ return c.Status(http.StatusOK).JSON(clubTags)
}
// DeleteClubTag godoc
@@ -76,16 +77,16 @@ func (l *ClubTagController) GetClubTags(c *fiber.Ctx) error {
// @Param clubID path string true "Club ID"
// @Param tagID path string true "Tag ID"
// @Success 204 {string} utilites.SuccessResponse
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /clubs/{clubID}/tags/{tagID}/ [delete]
func (l *ClubTagController) DeleteClubTag(c *fiber.Ctx) error {
err := l.clubTagService.DeleteClubTag(c.Params("clubID"), c.Params("tagID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.SendStatus(fiber.StatusNoContent)
+ return c.SendStatus(http.StatusNoContent)
}
diff --git a/backend/entities/clubs/tags/models.go b/backend/entities/clubs/tags/models.go
new file mode 100644
index 000000000..36f6e0bb8
--- /dev/null
+++ b/backend/entities/clubs/tags/models.go
@@ -0,0 +1,7 @@
+package tags
+
+import "github.com/google/uuid"
+
+type CreateClubTagsRequestBody struct {
+ Tags []uuid.UUID `json:"tags" validate:"required"`
+}
diff --git a/backend/entities/clubs/tags/routes.go b/backend/entities/clubs/tags/routes.go
new file mode 100644
index 000000000..4384d1ee3
--- /dev/null
+++ b/backend/entities/clubs/tags/routes.go
@@ -0,0 +1,25 @@
+package tags
+
+import (
+ authMiddleware "github.com/GenerateNU/sac/backend/middleware/auth"
+ "github.com/GenerateNU/sac/backend/types"
+)
+
+func ClubTag(clubParams types.RouteParams) {
+ clubTagController := NewClubTagController(NewClubTagService(clubParams.ServiceParams))
+
+ clubTags := clubParams.Router.Group("/tags")
+
+ // api/v1/clubs/:clubID/tags/*
+ clubTags.Get("/", clubTagController.GetClubTags)
+ clubTags.Post(
+ "/",
+ authMiddleware.AttachExtractor(clubParams.AuthMiddleware.ClubAuthorizeById, authMiddleware.ExtractFromParams("clubID")),
+ clubTagController.CreateClubTags,
+ )
+ clubTags.Delete(
+ "/:tagID",
+ authMiddleware.AttachExtractor(clubParams.AuthMiddleware.ClubAuthorizeById, authMiddleware.ExtractFromParams("clubID")),
+ clubTagController.DeleteClubTag,
+ )
+}
diff --git a/backend/entities/clubs/tag/service.go b/backend/entities/clubs/tags/service.go
similarity index 62%
rename from backend/entities/clubs/tag/service.go
rename to backend/entities/clubs/tags/service.go
index 9b6b067cc..bff249500 100644
--- a/backend/entities/clubs/tag/service.go
+++ b/backend/entities/clubs/tags/service.go
@@ -1,17 +1,16 @@
-package tag
+package tags
import (
"github.com/GenerateNU/sac/backend/entities/models"
"github.com/GenerateNU/sac/backend/entities/tags"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/types"
"github.com/GenerateNU/sac/backend/utilities"
)
type ClubTagServiceInterface interface {
- CreateClubTags(id string, clubTagsBody models.CreateClubTagsRequestBody) ([]models.Tag, *errors.Error)
- GetClubTags(id string) ([]models.Tag, *errors.Error)
- DeleteClubTag(id string, tagId string) *errors.Error
+ CreateClubTags(id string, clubTagsBody CreateClubTagsRequestBody) ([]models.Tag, error)
+ GetClubTags(id string) ([]models.Tag, error)
+ DeleteClubTag(id string, tagId string) error
}
type ClubTagService struct {
@@ -22,14 +21,14 @@ func NewClubTagService(serviceParams types.ServiceParams) ClubTagServiceInterfac
return &ClubTagService{serviceParams}
}
-func (c *ClubTagService) CreateClubTags(id string, clubTagsBody models.CreateClubTagsRequestBody) ([]models.Tag, *errors.Error) {
+func (c *ClubTagService) CreateClubTags(id string, clubTagsBody CreateClubTagsRequestBody) ([]models.Tag, error) {
idAsUUID, err := utilities.ValidateID(id)
if err != nil {
return nil, err
}
- if err := c.Validate.Struct(clubTagsBody); err != nil {
- return nil, &errors.FailedToValidateClubTags
+ if err := utilities.Validate(c.Validate, clubTagsBody); err != nil {
+ return nil, err
}
tags, err := tags.GetTagsByIDs(c.DB, clubTagsBody.Tags)
@@ -40,24 +39,24 @@ func (c *ClubTagService) CreateClubTags(id string, clubTagsBody models.CreateClu
return CreateClubTags(c.DB, *idAsUUID, tags)
}
-func (c *ClubTagService) GetClubTags(id string) ([]models.Tag, *errors.Error) {
+func (c *ClubTagService) GetClubTags(id string) ([]models.Tag, error) {
idAsUUID, err := utilities.ValidateID(id)
if err != nil {
- return nil, &errors.FailedToValidateID
+ return nil, err
}
return GetClubTags(c.DB, *idAsUUID)
}
-func (c *ClubTagService) DeleteClubTag(id string, tagId string) *errors.Error {
+func (c *ClubTagService) DeleteClubTag(id string, tagId string) error {
idAsUUID, err := utilities.ValidateID(id)
if err != nil {
- return &errors.FailedToValidateID
+ return err
}
tagIdAsUUID, err := utilities.ValidateID(tagId)
if err != nil {
- return &errors.FailedToValidateID
+ return err
}
return DeleteClubTag(c.DB, *idAsUUID, *tagIdAsUUID)
diff --git a/backend/entities/clubs/tag/transactions.go b/backend/entities/clubs/tags/transactions.go
similarity index 57%
rename from backend/entities/clubs/tag/transactions.go
rename to backend/entities/clubs/tags/transactions.go
index 16ec27f28..35d691961 100644
--- a/backend/entities/clubs/tag/transactions.go
+++ b/backend/entities/clubs/tags/transactions.go
@@ -1,45 +1,44 @@
-package tag
+package tags
import (
"github.com/GenerateNU/sac/backend/entities/clubs"
"github.com/GenerateNU/sac/backend/entities/models"
"github.com/GenerateNU/sac/backend/entities/tags"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/transactions"
"github.com/google/uuid"
"gorm.io/gorm"
)
-func CreateClubTags(db *gorm.DB, id uuid.UUID, tags []models.Tag) ([]models.Tag, *errors.Error) {
- user, err := clubs.GetClub(db, id, transactions.PreloadTag())
+func CreateClubTags(db *gorm.DB, id uuid.UUID, tags []models.Tag) ([]models.Tag, error) {
+ club, err := clubs.GetClub(db, id, transactions.PreloadTag())
if err != nil {
return nil, err
}
- if err := db.Model(&user).Association("Tag").Append(tags); err != nil {
- return nil, &errors.FailedToUpdateUser
+ if err := db.Model(&club).Association("Tag").Append(tags); err != nil {
+ return nil, err
}
return tags, nil
}
-func GetClubTags(db *gorm.DB, id uuid.UUID) ([]models.Tag, *errors.Error) {
+func GetClubTags(db *gorm.DB, id uuid.UUID) ([]models.Tag, error) {
var tags []models.Tag
- club, err := clubs.GetClub(db, id)
+ club, err := clubs.GetClub(db, id, transactions.PreloadTag())
if err != nil {
return nil, err
}
if err := db.Model(&club).Association("Tag").Find(&tags); err != nil {
- return nil, &errors.FailedToGetTag
+ return nil, err
}
return tags, nil
}
-func DeleteClubTag(db *gorm.DB, id uuid.UUID, tagID uuid.UUID) *errors.Error {
- club, err := clubs.GetClub(db, id)
+func DeleteClubTag(db *gorm.DB, id uuid.UUID, tagID uuid.UUID) error {
+ club, err := clubs.GetClub(db, id, transactions.PreloadTag())
if err != nil {
return err
}
@@ -50,7 +49,7 @@ func DeleteClubTag(db *gorm.DB, id uuid.UUID, tagID uuid.UUID) *errors.Error {
}
if err := db.Model(&club).Association("Tag").Delete(&tag); err != nil {
- return &errors.FailedToUpdateClub
+ return err
}
return nil
}
diff --git a/backend/entities/clubs/transactions.go b/backend/entities/clubs/transactions.go
index bbe8eeeeb..d501886d4 100644
--- a/backend/entities/clubs/transactions.go
+++ b/backend/entities/clubs/transactions.go
@@ -1,16 +1,16 @@
package clubs
import (
- stdliberrors "errors"
+ "errors"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/transactions"
+ "github.com/GenerateNU/sac/backend/utilities"
"github.com/google/uuid"
"gorm.io/gorm"
)
-func GetClub(db *gorm.DB, id uuid.UUID, preloads ...transactions.OptionalQuery) (*models.Club, *errors.Error) {
+func GetClub(db *gorm.DB, id uuid.UUID, preloads ...transactions.OptionalQuery) (*models.Club, error) {
var club models.Club
query := db
@@ -20,21 +20,20 @@ func GetClub(db *gorm.DB, id uuid.UUID, preloads ...transactions.OptionalQuery)
}
if err := query.First(&club, id).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.ClubNotFound
- } else {
- return nil, &errors.FailedToGetClub
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
}
+ return nil, err
}
return &club, nil
}
-func GetAdminIDs(db *gorm.DB, clubID uuid.UUID) ([]uuid.UUID, *errors.Error) {
+func GetAdminIDs(db *gorm.DB, clubID uuid.UUID) ([]uuid.UUID, error) {
var adminIDs []models.Membership
if err := db.Where("club_id = ? AND membership_type = ?", clubID, models.MembershipTypeAdmin).Find(&adminIDs).Error; err != nil {
- return nil, &errors.FailedtoGetAdminIDs
+ return nil, err
}
adminUUIDs := make([]uuid.UUID, 0)
diff --git a/backend/entities/contacts/base/controller.go b/backend/entities/contacts/base/controller.go
index 434e28f10..46d8b3670 100644
--- a/backend/entities/contacts/base/controller.go
+++ b/backend/entities/contacts/base/controller.go
@@ -1,7 +1,10 @@
package base
import (
- "github.com/GenerateNU/sac/backend/constants"
+ "net/http"
+
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
"github.com/gofiber/fiber/v2"
)
@@ -23,17 +26,17 @@ func NewContactController(contactService ContactServiceInterface) *ContactContro
// @Produce json
// @Param contactID path string true "Contact ID"
// @Success 201 {object} models.Contact
-// @Failure 400 {string} errors.Error
-// @Failure 404 {string} errors.Error
-// @Failure 500 {string} errors.Error
+// @Failure 400 {string} error
+// @Failure 404 {string} error
+// @Failure 500 {string} error
// @Router /contacts/{contactID}/ [get]
func (co *ContactController) GetContact(c *fiber.Ctx) error {
contact, err := co.contactService.GetContact(c.Params("contactID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(contact)
+ return c.Status(http.StatusOK).JSON(contact)
}
// GetContacts godoc
@@ -46,17 +49,22 @@ func (co *ContactController) GetContact(c *fiber.Ctx) error {
// @Param limit query int false "Limit"
// @Param page query int false "Page"
// @Success 200 {object} []models.Contact
-// @Failure 400 {string} errors.Error
-// @Failure 404 {string} errors.Error
-// @Failure 500 {string} errors.Error
+// @Failure 400 {string} error
+// @Failure 404 {string} error
+// @Failure 500 {string} error
// @Router /contacts/ [get]
func (co *ContactController) GetContacts(c *fiber.Ctx) error {
- contacts, err := co.contactService.GetContacts(c.Query("limit", constants.DEFAULT_LIMIT_STRING), c.Query("page", constants.DEFAULT_PAGE_STRING))
+ pagination, ok := fiberpaginate.FromContext(c)
+ if !ok {
+ return utilities.ErrExpectedPagination
+ }
+
+ contacts, err := co.contactService.GetContacts(*pagination)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(contacts)
+ return c.Status(http.StatusOK).JSON(contacts)
}
// DeleteContact godoc
@@ -69,15 +77,15 @@ func (co *ContactController) GetContacts(c *fiber.Ctx) error {
// @Produce json
// @Param contactID path string true "Contact ID"
// @Success 201 {object} models.Contact
-// @Failure 400 {string} errors.Error
-// @Failure 404 {string} errors.Error
-// @Failure 500 {string} errors.Error
+// @Failure 400 {string} error
+// @Failure 404 {string} error
+// @Failure 500 {string} error
// @Router /contacts/{contactID}/ [delete]
func (co *ContactController) DeleteContact(c *fiber.Ctx) error {
err := co.contactService.DeleteContact(c.Params("contactID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.SendStatus(fiber.StatusNoContent)
+ return c.SendStatus(http.StatusNoContent)
}
diff --git a/backend/entities/contacts/base/routes.go b/backend/entities/contacts/base/routes.go
index a44f51206..453705783 100644
--- a/backend/entities/contacts/base/routes.go
+++ b/backend/entities/contacts/base/routes.go
@@ -11,7 +11,7 @@ func Contact(contactParams types.RouteParams) {
// api/v1/contacts/*
contacts := contactParams.Router.Group("/contacts")
- contacts.Get("/", contactController.GetContacts)
+ contacts.Get("/", contactParams.UtilityMiddleware.Paginator, contactController.GetContacts)
contacts.Get("/:contactID", contactController.GetContact)
contacts.Delete("/:contactID", contactParams.AuthMiddleware.Authorize(auth.DeleteAll), contactController.DeleteContact)
}
diff --git a/backend/entities/contacts/base/service.go b/backend/entities/contacts/base/service.go
index 21b41187c..6b5967b2b 100644
--- a/backend/entities/contacts/base/service.go
+++ b/backend/entities/contacts/base/service.go
@@ -2,15 +2,15 @@ package base
import (
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/types"
"github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
)
type ContactServiceInterface interface {
- GetContacts(limit string, page string) ([]models.Contact, *errors.Error)
- GetContact(contactID string) (*models.Contact, *errors.Error)
- DeleteContact(contactID string) *errors.Error
+ GetContacts(pageInfo fiberpaginate.PageInfo) ([]models.Contact, error)
+ GetContact(contactID string) (*models.Contact, error)
+ DeleteContact(contactID string) error
}
type ContactService struct {
@@ -21,33 +21,23 @@ func NewContactService(serviceParams types.ServiceParams) ContactServiceInterfac
return &ContactService{serviceParams}
}
-func (c *ContactService) GetContacts(limit string, page string) ([]models.Contact, *errors.Error) {
- limitAsInt, err := utilities.ValidateNonNegative(limit)
- if err != nil {
- return nil, &errors.FailedToValidateLimit
- }
-
- pageAsInt, err := utilities.ValidateNonNegative(page)
- if err != nil {
- return nil, &errors.FailedToValidatePage
- }
-
- return GetContacts(c.DB, *limitAsInt, *pageAsInt)
+func (c *ContactService) GetContacts(pageInfo fiberpaginate.PageInfo) ([]models.Contact, error) {
+ return GetContacts(c.DB, pageInfo)
}
-func (c *ContactService) GetContact(contactID string) (*models.Contact, *errors.Error) {
+func (c *ContactService) GetContact(contactID string) (*models.Contact, error) {
idAsUUID, err := utilities.ValidateID(contactID)
if err != nil {
- return nil, &errors.FailedToValidateID
+ return nil, err
}
return GetContact(c.DB, *idAsUUID)
}
-func (c *ContactService) DeleteContact(contactID string) *errors.Error {
+func (c *ContactService) DeleteContact(contactID string) error {
idAsUUID, err := utilities.ValidateID(contactID)
if err != nil {
- return &errors.FailedToValidateID
+ return err
}
return DeleteContact(c.DB, *idAsUUID)
diff --git a/backend/entities/contacts/base/transactions.go b/backend/entities/contacts/base/transactions.go
index 9f0c4fe6b..fa21fceab 100644
--- a/backend/entities/contacts/base/transactions.go
+++ b/backend/entities/contacts/base/transactions.go
@@ -1,47 +1,42 @@
package base
import (
- stdliberrors "errors"
+ "errors"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
"github.com/google/uuid"
"gorm.io/gorm"
)
-func GetContacts(db *gorm.DB, limit int, page int) ([]models.Contact, *errors.Error) {
+func GetContacts(db *gorm.DB, pageInfo fiberpaginate.PageInfo) ([]models.Contact, error) {
var contacts []models.Contact
-
- offset := (page - 1) * limit
-
- result := db.Limit(limit).Offset(offset).Find(&contacts)
- if result.Error != nil {
- return nil, &errors.FailedToGetContacts
+ if err := db.Scopes(utilities.IntoScope(pageInfo, db)).Find(&contacts).Error; err != nil {
+ return nil, err
}
return contacts, nil
}
-func GetContact(db *gorm.DB, id uuid.UUID) (*models.Contact, *errors.Error) {
+func GetContact(db *gorm.DB, id uuid.UUID) (*models.Contact, error) {
var contact models.Contact
if err := db.First(&contact, id).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.ContactNotFound
- } else {
- return nil, &errors.FailedToGetContact
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, err
}
+ return nil, err
}
return &contact, nil
}
-func DeleteContact(db *gorm.DB, id uuid.UUID) *errors.Error {
+func DeleteContact(db *gorm.DB, id uuid.UUID) error {
if result := db.Delete(&models.Contact{}, id); result.RowsAffected == 0 {
if result.Error == nil {
- return &errors.ContactNotFound
- } else {
- return &errors.FailedToDeleteContact
+ return utilities.ErrNotFound
}
+ return result.Error
}
return nil
}
diff --git a/backend/entities/events/base/controller.go b/backend/entities/events/base/controller.go
index 326d28a0f..e53934759 100644
--- a/backend/entities/events/base/controller.go
+++ b/backend/entities/events/base/controller.go
@@ -1,9 +1,11 @@
package base
import (
- "github.com/GenerateNU/sac/backend/constants"
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+ "net/http"
+
+ "github.com/GenerateNU/sac/backend/entities/events"
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
"github.com/gofiber/fiber/v2"
)
@@ -25,17 +27,22 @@ func NewEventController(eventService EventServiceInterface) *EventController {
// @Param limit query int false "Limit"
// @Param page query int false "Page"
// @Success 200 {object} []models.Event
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /events/ [get]
func (e *EventController) GetAllEvents(c *fiber.Ctx) error {
- events, err := e.eventService.GetEvents(c.Query("limit", constants.DEFAULT_LIMIT_STRING), c.Query("page", constants.DEFAULT_PAGE_STRING))
+ pagination, ok := fiberpaginate.FromContext(c)
+ if !ok {
+ return utilities.ErrExpectedPagination
+ }
+
+ events, err := e.eventService.GetEvents(*pagination)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(events)
+ return c.Status(http.StatusOK).JSON(events)
}
// GetEvent godoc
@@ -47,293 +54,52 @@ func (e *EventController) GetAllEvents(c *fiber.Ctx) error {
// @Produce json
// @Param eventID path string true "Event ID"
// @Success 200 {object} models.Event
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /events/{eventID}/ [get]
func (e *EventController) GetEvent(c *fiber.Ctx) error {
event, err := e.eventService.GetEvent(c.Params("eventID"))
if err != nil {
- return err.FiberError(c)
- }
-
- return c.Status(fiber.StatusOK).JSON(event)
-}
-
-// GetSeriesByEventID godoc
-//
-// @Summary Retrieve all series by event
-// @Description Retrieves all series associated with an event
-// @ID get-series-by-event
-// @Tags event
-// @Produce json
-// @Param eventID path string true "Event ID"
-// @Success 200 {object} []models.Series
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
-// @Router /events/{eventID}/series/ [get]
-func (e *EventController) GetSeriesByEventID(c *fiber.Ctx) error {
- events, err := e.eventService.GetSeriesByEventID(c.Params("eventID"))
- if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(events)
+ return c.Status(http.StatusOK).JSON(event)
}
-// GetSeriesByID godoc
-//
-// @Summary Retrieve a series by ID
-// @Description Retrieves a series by ID
-// @ID get-series-by-id
-// @Tags event
-// @Produce json
-// @Param eventID path string true "Event ID"
-// @Param seriesID path string true "Series ID"
-// @Success 200 {object} models.Series
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
-// @Router /events/{eventID}/series/{seriesID}/ [get]
-func (e *EventController) GetSeriesByID(c *fiber.Ctx) error {
- events, err := e.eventService.GetSeriesByID(c.Params("seriesID"))
- if err != nil {
- return err.FiberError(c)
- }
-
- return c.Status(fiber.StatusOK).JSON(events)
-}
-
-// CreateEvent godoc
-//
-// @Summary Create an event
-// @Description Creates an event
-// @ID create-event
-// @Tags event
-// @Accept json
-// @Produce json
-// @Param event body models.CreateEventRequestBody true "Event Body"
-// @Success 201 {object} models.Event
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
-// @Router /events/ [post]
func (e *EventController) CreateEvent(c *fiber.Ctx) error {
- var eventBody models.CreateEventRequestBody
- if err := c.BodyParser(&eventBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ var body events.CreateEventRequestBody
+ if err := c.BodyParser(&body); err != nil {
+ return err
}
- event, err := e.eventService.CreateEvent(eventBody)
+ event, err := e.eventService.CreateEvent(body)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusCreated).JSON(event)
+ return c.Status(http.StatusCreated).JSON(event)
}
-// UpdateEvent godoc
-//
-// @Summary Create a series
-// @Description Creates a series
-// @ID create-series
-// @Tags event
-// @Accept json
-// @Produce json
-// @Param eventID path string true "Event ID"
-// @Param seriesBody body models.UpdateEventRequestBody true "Series Body"
-// @Success 201 {object} models.Series
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
-// @Router /events/{eventID}/series/ [patch]
func (e *EventController) UpdateEvent(c *fiber.Ctx) error {
- var eventBody models.UpdateEventRequestBody
- if err := c.BodyParser(&eventBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ var body events.UpdateEventRequestBody
+ if err := c.BodyParser(&body); err != nil {
+ return err
}
- updatedEvent, err := e.eventService.UpdateEvent(c.Params("eventID"), eventBody)
+ event, err := e.eventService.UpdateEvent(c.Params("eventID"), body)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(updatedEvent)
+ return c.Status(http.StatusOK).JSON(event)
}
-// UpdateSeriesByID godoc
-//
-// @Summary Update a series by ID
-// @Description Updates a series by ID. If individual events have been edited prior,
-//
-// this update will override the previous changes
-//
-// @ID update-series-by-id
-// @Tags event
-// @Accept json
-// @Produce json
-// @Param seriesID path string true "Series ID"
-// @Param seriesBody body models.UpdateSeriesRequestBody true "Series Body"
-// @Success 200 {object} models.Series
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
-// @Router /events/{eventID}/series/{seriesID}/ [patch]
-func (e *EventController) UpdateSeriesByID(c *fiber.Ctx) error {
- var seriesBody models.UpdateSeriesRequestBody
- if err := c.BodyParser(&seriesBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
- }
-
- updatedSeries, err := e.eventService.UpdateSeries(c.Params("seriesID"), seriesBody)
- if err != nil {
- return err.FiberError(c)
- }
-
- return c.Status(fiber.StatusOK).JSON(updatedSeries)
-}
-
-// UpdateSeriesByEventID godoc
-//
-// @Summary Update a series by event ID
-// @Description Updates a series by event ID
-// @ID update-series-by-event-id
-// @Tags event
-// @Accept json
-// @Produce json
-// @Param eventID path string true "Event ID"
-// @Param seriesBody body models.UpdateSeriesRequestBody true "Series Body"
-// @Success 200 {object} models.Series
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
-// @Router /events/{eventID}/series/{seriesID}/ [patch]
-func (e *EventController) UpdateSeriesByEventID(c *fiber.Ctx) error {
- var seriesBody models.UpdateSeriesRequestBody
- if err := c.BodyParser(&seriesBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
- }
-
- updatedSeries, err := e.eventService.UpdateSeriesByEventID(c.Params("eventID"), seriesBody)
- if err != nil {
- return err.FiberError(c)
- }
-
- return c.Status(fiber.StatusOK).JSON(updatedSeries)
-}
-
-// DeleteSeriesByID godoc
-//
-// @Summary Delete a series by ID
-// @Description Deletes a series by ID
-// @ID delete-series-by-id
-// @Tags event
-// @Produce json
-// @Param eventID path string true "Event ID"
-// @Param seriesID path string true "Series ID"
-// @Success 204 {string} utilities.SuccessResponse
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
-// @Router /events/{eventID}/series/{seriesID}/ [delete]
-func (e *EventController) DeleteSeriesByID(c *fiber.Ctx) error {
- if err := e.eventService.DeleteSeriesByID(c.Params("seriesID")); err != nil {
- return err.FiberError(c)
- }
-
- return c.SendStatus(fiber.StatusNoContent)
-}
-
-// DeleteSeriesByEventID godoc
-//
-// @Summary Delete all series by event
-// @Description Deletes all series associated with an event
-// @ID delete-series-by-event
-// @Tags event
-// @Produce json
-// @Param eventID path string true "Event ID"
-// @Success 204 {string} utilities.SuccessResponse
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
-// @Router /events/{eventID}/series/ [delete]
-func (e *EventController) DeleteSeriesByEventID(c *fiber.Ctx) error {
- if err := e.eventService.DeleteSeriesByEventID(c.Params("eventID")); err != nil {
- return err.FiberError(c)
- }
-
- return c.SendStatus(fiber.StatusNoContent)
-}
-
-// DeleteEvent godoc
-//
-// @Summary Delete an event
-// @Description Deletes an event
-// @ID delete-event
-// @Tags event
-// @Produce json
-// @Param eventID path string true "Event ID"
-// @Success 204 {string} utilities.SuccessResponse
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
-// @Router /events/{eventID}/ [delete]
func (e *EventController) DeleteEvent(c *fiber.Ctx) error {
- if err := e.eventService.DeleteEvent(c.Params("eventID")); err != nil {
- return err.FiberError(c)
- }
-
- return c.SendStatus(fiber.StatusNoContent)
-}
-
-// GetHostsByEventID godoc
-//
-// @Summary Retrieve all hosts by event
-// @Description Retrieves all hosts associated with an event
-// @ID get-hosts-by-event
-// @Tags event
-// @Produce json
-// @Param eventID path string true "Event ID"
-// @Success 200 {object} []models.Club
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
-// @Router /events/{eventID}/hosts [get]
-func (e *EventController) GetHostsByEventID(c *fiber.Ctx) error {
- hosts, err := e.eventService.GetHostsByEventID(c.Params("eventID"))
- if err != nil {
- return err.FiberError(c)
- }
-
- return c.Status(fiber.StatusOK).JSON(hosts)
-}
-
-// GetTagsByEventID godoc
-//
-// @Summary Retrieve all tags by event
-// @Description Retrieves all tags associated with an event
-// @ID get-tags-by-event
-// @Tags event
-// @Produce json
-// @Param eventID path string true "Event ID"
-// @Success 200 {object} []models.Tag
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
-// @Router /events/{eventID}/tags [get]
-func (e *EventController) GetTagsByEventID(c *fiber.Ctx) error {
- tags, err := e.eventService.GetTagsByEventID(c.Params("eventID"))
+ err := e.eventService.DeleteEvent(c.Params("eventID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(tags)
+ return c.SendStatus(http.StatusNoContent)
}
diff --git a/backend/entities/events/base/routes.go b/backend/entities/events/base/routes.go
index a755ede52..c0be2cb84 100644
--- a/backend/entities/events/base/routes.go
+++ b/backend/entities/events/base/routes.go
@@ -1,38 +1,40 @@
package base
import (
+ "github.com/GenerateNU/sac/backend/entities/events/series"
+ "github.com/GenerateNU/sac/backend/entities/events/tags"
+ "github.com/gofiber/fiber/v2"
+
+ authMiddleware "github.com/GenerateNU/sac/backend/middleware/auth"
"github.com/GenerateNU/sac/backend/types"
)
-func Event(eventParams types.RouteParams) {
+func EventRoutes(eventParams types.RouteParams) {
+ eventParams.Router = EventRouter(eventParams)
+
+ series.EventSeries(eventParams)
+ tags.EventTags(eventParams)
+}
+
+func EventRouter(eventParams types.RouteParams) fiber.Router {
eventController := NewEventController(NewEventService(eventParams.ServiceParams))
// api/v1/events/*
events := eventParams.Router.Group("/events")
- events.Get("/", eventController.GetAllEvents)
- events.Post("/", eventParams.AuthMiddleware.ClubAuthorizeById, eventController.CreateEvent)
+ events.Get("/", eventParams.UtilityMiddleware.Paginator, eventController.GetAllEvents)
+ events.Post(
+ "/",
+ authMiddleware.AttachExtractor(eventParams.AuthMiddleware.ClubAuthorizeById, authMiddleware.ExtractFromParams("clubID")),
+ eventController.CreateEvent,
+ )
// api/v1/events/:eventID/*
eventID := events.Group("/:eventID")
eventID.Get("/", eventController.GetEvent)
- eventID.Get("/series", eventController.GetSeriesByEventID)
eventID.Patch("/", eventController.UpdateEvent)
- eventID.Patch("/series", eventController.UpdateSeriesByEventID)
eventID.Delete("/", eventController.DeleteEvent)
- eventID.Delete("/series", eventController.DeleteSeriesByEventID)
-
- eventID.Get("/hosts", eventController.GetHostsByEventID)
- eventID.Get("/tags", eventController.GetTagsByEventID)
-
- // api/v1/events/series/*
- series := events.Group("/series")
-
- // api/v1/events/series/:seriesID/*
- seriesID := series.Group("/:seriesID")
- seriesID.Get("/", eventController.GetSeriesByID)
- seriesID.Patch("/", eventParams.AuthMiddleware.ClubAuthorizeById, eventController.UpdateSeriesByID)
- seriesID.Delete("/", eventParams.AuthMiddleware.ClubAuthorizeById, eventController.DeleteSeriesByID)
+ return events
}
diff --git a/backend/entities/events/base/service.go b/backend/entities/events/base/service.go
index 5062454ab..0f7c9fa1e 100644
--- a/backend/entities/events/base/service.go
+++ b/backend/entities/events/base/service.go
@@ -1,26 +1,22 @@
package base
import (
+ "github.com/GenerateNU/sac/backend/entities/events"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+
"github.com/GenerateNU/sac/backend/types"
"github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
)
type EventServiceInterface interface {
- GetEvents(limit string, page string) ([]models.Event, *errors.Error)
- GetEvent(eventID string) ([]models.Event, *errors.Error)
- GetSeriesByEventID(eventID string) ([]models.Event, *errors.Error)
- GetSeriesByID(seriesID string) ([]models.Event, *errors.Error)
- CreateEvent(eventBodies models.CreateEventRequestBody) ([]models.Event, *errors.Error)
- UpdateEvent(eventID string, eventBody models.UpdateEventRequestBody) ([]models.Event, *errors.Error)
- UpdateSeries(seriesID string, seriesBody models.UpdateSeriesRequestBody) ([]models.Event, *errors.Error)
- UpdateSeriesByEventID(eventID string, seriesBody models.UpdateSeriesRequestBody) ([]models.Event, *errors.Error)
- DeleteEvent(eventID string) *errors.Error
- DeleteSeriesByEventID(seriesID string) *errors.Error
- DeleteSeriesByID(seriesID string) *errors.Error
- GetHostsByEventID(eventID string) ([]models.Club, *errors.Error)
- GetTagsByEventID(eventID string) ([]models.Tag, *errors.Error)
+ // getters
+ GetEvents(pageInfo fiberpaginate.PageInfo) ([]models.Event, error)
+ GetEvent(eventID string) (*models.Event, error)
+ // event cud
+ CreateEvent(body events.CreateEventRequestBody) (*models.Event, error)
+ UpdateEvent(eventID string, eventBody events.UpdateEventRequestBody) ([]models.Event, error)
+ DeleteEvent(eventID string) error
}
type EventService struct {
@@ -31,241 +27,50 @@ func NewEventService(serviceParams types.ServiceParams) EventServiceInterface {
return &EventService{serviceParams}
}
-func (e *EventService) GetEvents(limit string, page string) ([]models.Event, *errors.Error) {
- limitAsInt, err := utilities.ValidateNonNegative(limit)
- if err != nil {
- return nil, &errors.FailedToValidateLimit
- }
-
- pageAsInt, err := utilities.ValidateNonNegative(page)
- if err != nil {
- return nil, &errors.FailedToValidatePage
- }
-
- return GetEvents(e.DB, *limitAsInt, *pageAsInt)
-}
-
-// right now we are always returning a slice
-func (e *EventService) CreateEvent(eventBody models.CreateEventRequestBody) ([]models.Event, *errors.Error) {
- if err := e.Validate.Struct(eventBody); err != nil {
- return nil, &errors.FailedToValidateEvent
- }
-
- event := &models.Event{
- Name: eventBody.Name,
- Preview: eventBody.Preview,
- Content: eventBody.Content,
- StartTime: eventBody.StartTime,
- EndTime: eventBody.EndTime,
- Location: eventBody.Location,
- EventType: eventBody.EventType,
- IsRecurring: *eventBody.IsRecurring,
-
- Host: eventBody.Host,
- Clubs: eventBody.Clubs,
- Tag: eventBody.Tag,
- Notification: eventBody.Notification,
- }
-
- if !event.IsRecurring {
- event, err := CreateEvent(e.DB, *event)
- if err != nil {
- return nil, &errors.FailedToCreateEvent
- }
- return event, err
- }
-
- if err := e.Validate.Struct(eventBody.Series); err != nil {
- return nil, &errors.FailedToValidateEventSeries
- }
-
- series, err := utilities.MapRequestToModel(eventBody.Series, &models.Series{})
- if err != nil {
- return nil, &errors.FailedToMapRequestToModel
- }
-
- // Create other events in series and update field in series (for join table)
- events := createEventSlice(event, *series)
- series.Events = events
-
- return CreateEventSeries(e.DB, *series)
+func (e *EventService) GetEvents(pageInfo fiberpaginate.PageInfo) ([]models.Event, error) {
+ return GetEvents(e.DB, pageInfo)
}
-func (e *EventService) GetEvent(eventID string) ([]models.Event, *errors.Error) {
+func (e *EventService) GetEvent(eventID string) (*models.Event, error) {
idAsUUID, err := utilities.ValidateID(eventID)
if err != nil {
- return nil, &errors.FailedToValidateID
+ return nil, err
}
- return GetEvent(e.DB, *idAsUUID)
+ return events.GetEvent(e.DB, *idAsUUID)
}
-func (e *EventService) GetSeriesByEventID(eventID string) ([]models.Event, *errors.Error) {
- idAsUUID, err := utilities.ValidateID(eventID)
- if err != nil {
- return nil, &errors.FailedToValidateID
+func (e *EventService) CreateEvent(body events.CreateEventRequestBody) (*models.Event, error) {
+ if err := utilities.Validate(e.Validate, body); err != nil {
+ return nil, err
}
- return GetSeriesByEventID(e.DB, *idAsUUID)
+ return CreateEvent(e.DB, *body.Into())
}
-func (e *EventService) GetSeriesByID(seriesID string) ([]models.Event, *errors.Error) {
- idAsUUID, err := utilities.ValidateID(seriesID)
- if err != nil {
- return nil, &errors.FailedToValidateID
- }
-
- return GetSeriesByID(e.DB, *idAsUUID)
-}
-
-func (e *EventService) UpdateEvent(id string, eventBody models.UpdateEventRequestBody) ([]models.Event, *errors.Error) {
- idAsUUID, idErr := utilities.ValidateID(id)
- if idErr != nil {
- return nil, idErr
- }
-
- if utilities.AtLeastOne(eventBody, models.UpdateEventRequestBody{}) {
- return nil, &errors.FailedToValidateTag
- }
-
- if err := e.Validate.Struct(eventBody); err != nil {
- return nil, &errors.FailedToValidateEvent
- }
-
- updatedEvent := mapToEvent(eventBody)
-
- return UpdateEvent(e.DB, *idAsUUID, *updatedEvent)
-}
-
-func (e *EventService) UpdateSeries(seriesID string, seriesBody models.UpdateSeriesRequestBody) ([]models.Event, *errors.Error) {
- seriesIDAsUUID, idErr := utilities.ValidateID(seriesID)
- if idErr != nil {
- return nil, idErr
- }
-
- if err := e.Validate.Struct(seriesBody); err != nil {
- return nil, &errors.FailedToValidateEventSeries
- }
-
- series, err := utilities.MapRequestToModel(seriesBody, &models.Series{})
- if err != nil {
- return nil, &errors.FailedToMapRequestToModel
- }
-
- updatedEventBody := mapToEvent(seriesBody.EventDetails)
-
- newEvents := createEventSlice(updatedEventBody, *series)
- series.Events = newEvents
-
- return UpdateSeries(e.DB, *seriesIDAsUUID, *series)
-}
-
-func (e *EventService) UpdateSeriesByEventID(eventID string, seriesBody models.UpdateSeriesRequestBody) ([]models.Event, *errors.Error) {
- eventIDAsUUID, idErr := utilities.ValidateID(eventID)
- if idErr != nil {
- return nil, idErr
- }
-
- if err := e.Validate.Struct(seriesBody); err != nil {
- return nil, &errors.FailedToValidateEventSeries
- }
-
- series, err := utilities.MapRequestToModel(seriesBody, &models.Series{})
- if err != nil {
- return nil, &errors.FailedToMapRequestToModel
- }
-
- updatedEventBody := mapToEvent(seriesBody.EventDetails)
-
- newEvents := createEventSlice(updatedEventBody, *series)
- series.Events = newEvents
-
- return UpdateSeriesByEventID(e.DB, *eventIDAsUUID, *series)
-}
-
-func (e *EventService) DeleteEvent(eventID string) *errors.Error {
- idAsUUID, err := utilities.ValidateID(eventID)
- if err != nil {
- return &errors.FailedToValidateID
- }
-
- return DeleteEvent(e.DB, *idAsUUID)
-}
-
-func (e *EventService) DeleteSeriesByEventID(eventID string) *errors.Error {
+func (e *EventService) UpdateEvent(eventID string, eventBody events.UpdateEventRequestBody) ([]models.Event, error) {
idAsUUID, err := utilities.ValidateID(eventID)
if err != nil {
- return &errors.FailedToValidateID
+ return nil, err
}
- return DeleteSeriesByEventID(e.DB, *idAsUUID)
-}
-
-func (e *EventService) DeleteSeriesByID(seriesID string) *errors.Error {
- idAsUUID, err := utilities.ValidateID(seriesID)
- if err != nil {
- return &errors.FailedToValidateID
+ if err := utilities.Validate(e.Validate, eventBody); err != nil {
+ return nil, err
}
- return DeleteSeriesByID(e.DB, *idAsUUID)
-}
-
-func (e *EventService) GetHostsByEventID(eventID string) ([]models.Club, *errors.Error) {
- idAsUUID, err := utilities.ValidateID(eventID)
+ event, err := utilities.MapJsonTags(eventBody, &models.Event{})
if err != nil {
- return nil, &errors.FailedToValidateID
+ return nil, err
}
- return GetHostsByEventID(e.DB, *idAsUUID)
+ return UpdateEvent(e.DB, *idAsUUID, *event, *eventBody.UpdateAllInSeries)
}
-func (e *EventService) GetTagsByEventID(eventID string) ([]models.Tag, *errors.Error) {
+func (e *EventService) DeleteEvent(eventID string) error {
idAsUUID, err := utilities.ValidateID(eventID)
if err != nil {
- return nil, &errors.FailedToValidateID
+ return err
}
- return GetTagsByEventID(e.DB, *idAsUUID)
-}
-
-func createEventSlice(firstEvent *models.Event, series models.Series) []models.Event {
- eventBodies := []models.Event{*firstEvent}
- months, days := 0, 0
-
- switch series.RecurringType {
- case "daily":
- days = 1
- case "weekly":
- days = 7
- case "monthly":
- months = 1
- }
-
- for i := 1; i < series.MaxOccurrences; i++ {
- eventToAdd := *firstEvent
- eventToAdd.StartTime = eventToAdd.StartTime.AddDate(0, i*months, i*days)
- eventToAdd.EndTime = eventToAdd.EndTime.AddDate(0, i*months, i*days)
- eventBodies = append(eventBodies, eventToAdd)
- }
-
- return eventBodies
-}
-
-func mapToEvent(eventBody models.UpdateEventRequestBody) *models.Event {
- return &models.Event{
- Name: eventBody.Name,
- Preview: eventBody.Preview,
- Content: eventBody.Content,
- StartTime: eventBody.StartTime,
- EndTime: eventBody.EndTime,
- Location: eventBody.Location,
- EventType: eventBody.EventType,
-
- Host: eventBody.Host,
- RSVP: eventBody.RSVP,
- Waitlist: eventBody.Waitlist,
- Clubs: eventBody.Clubs,
- Tag: eventBody.Tag,
- Notification: eventBody.Notification,
- }
+ return DeleteEvent(e.DB, *idAsUUID)
}
diff --git a/backend/entities/events/base/transactions.go b/backend/entities/events/base/transactions.go
index f66f790a4..566d0c262 100644
--- a/backend/entities/events/base/transactions.go
+++ b/backend/entities/events/base/transactions.go
@@ -1,248 +1,86 @@
package base
import (
- stdliberrors "errors"
+ "errors"
+ "log/slog"
- "github.com/GenerateNU/sac/backend/entities/clubs"
+ "github.com/GenerateNU/sac/backend/entities/events"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
- "github.com/GenerateNU/sac/backend/transactions"
+ "github.com/garrettladley/fiberpaginate"
+
+ "github.com/GenerateNU/sac/backend/utilities"
"github.com/google/uuid"
"gorm.io/gorm"
+ "gorm.io/gorm/clause"
)
-func GetEvents(db *gorm.DB, limit int, page int) ([]models.Event, *errors.Error) {
+func GetEvents(db *gorm.DB, pageInfo fiberpaginate.PageInfo) ([]models.Event, error) {
var events []models.Event
-
- offset := (page - 1) * limit
-
- if db.Limit(limit).Offset(offset).Find(&events).Error != nil {
- return nil, &errors.FailedToGetEvents
+ if err := db.Scopes(utilities.IntoScope(pageInfo, db)).Find(&events).Error; err != nil {
+ return nil, err
}
return events, nil
}
-func GetEvent(db *gorm.DB, eventID uuid.UUID, preloads ...transactions.OptionalQuery) ([]models.Event, *errors.Error) {
- var event models.Event
-
- query := db
-
- for _, preload := range preloads {
- query = preload(query)
- }
-
- if err := query.First(&event, eventID).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.EventNotFound
- } else {
- return nil, &errors.FailedToGetEvent
- }
- }
-
- return []models.Event{event}, nil
-}
-
-func GetSeriesID(db *gorm.DB, eventID uuid.UUID) (*uuid.UUID, *errors.Error) {
- var event models.Event
-
- if err := db.First(&event, eventID).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.EventNotFound
- } else {
- return nil, &errors.FailedToGetEvent
- }
- }
-
- var seriesID string
-
- if err := db.Model(&models.EventSeries{}).Where("event_id = ?", event.ID).Select("series_id").Find(&seriesID).Error; err != nil {
- return nil, &errors.FailedToGetEventSeries
- }
-
- parsedSeriesID, err := uuid.Parse(seriesID)
- if err != nil {
- return nil, &errors.FailedToGetEventSeries
- }
-
- return &parsedSeriesID, nil
-}
-
-func GetSeriesByEventID(db *gorm.DB, id uuid.UUID) ([]models.Event, *errors.Error) {
- seriesID, err := GetSeriesID(db, id)
- if err != nil {
+func CreateEvent(db *gorm.DB, event models.Event) (*models.Event, error) {
+ if err := db.Create(&event).Error; err != nil {
return nil, err
}
- events, err := GetSeriesByID(db, *seriesID)
- if err != nil {
- return nil, &errors.FailedToGetEventSeries
- }
- return events, nil
-}
-
-func GetSeriesByID(db *gorm.DB, id uuid.UUID) ([]models.Event, *errors.Error) {
- var series models.Series
-
- if err := db.Preload("Events").Find(&series, id).Error; err != nil {
- return nil, &errors.FailedToGetEventSeries
- }
-
- return series.Events, nil
-}
-
-func CreateEvent(db *gorm.DB, event models.Event) ([]models.Event, *errors.Error) {
- tx := db.Begin()
-
- if err := tx.Create(&event).Error; err != nil {
- tx.Rollback()
- return nil, &errors.FailedToCreateEvent
- }
-
- if err := tx.Commit().Error; err != nil {
- tx.Rollback()
- return nil, &errors.FailedToCreateEvent
- }
- return []models.Event{event}, nil
+ return &event, nil
}
-func CreateEventSeries(db *gorm.DB, series models.Series) ([]models.Event, *errors.Error) {
- if err := db.Create(&series).Error; err != nil {
- return nil, &errors.FailedToCreateEventSeries
+func UpdateEvent(db *gorm.DB, id uuid.UUID, event models.Event, updateAllInSeries bool) ([]models.Event, error) {
+ if updateAllInSeries {
+ return updateEventSeries(db, id, event)
+ } else {
+ return updateEvent(db, id, event)
}
-
- return series.Events, nil
}
-func UpdateEvent(db *gorm.DB, id uuid.UUID, event models.Event) ([]models.Event, *errors.Error) {
- if err := db.Model(&models.Event{}).Where("id = ?", id).Updates(event).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.UserNotFound
- } else {
- return nil, &errors.FailedToUpdateEvent
- }
- }
-
- var existingEvent models.Event
-
- if err := db.First(&existingEvent, id).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.EventNotFound
- } else {
- return nil, &errors.FailedToCreateEvent
+func updateEvent(db *gorm.DB, id uuid.UUID, event models.Event) ([]models.Event, error) {
+ var resultingEvent models.Event
+ if result := db.Model(&resultingEvent).Clauses(clause.Returning{}).Where("id = ?", id).Updates(&event); result.RowsAffected == 0 {
+ if result.Error == nil {
+ return nil, utilities.ErrNotFound
}
+ return nil, result.Error
}
- if err := db.Model(&existingEvent).Updates(&event).Error; err != nil {
- return nil, &errors.FailedToUpdateUser
- }
-
- return []models.Event{existingEvent}, nil
+ return []models.Event{resultingEvent}, nil
}
-func UpdateSeries(db *gorm.DB, seriesID uuid.UUID, series models.Series) ([]models.Event, *errors.Error) {
- err := DeleteSeriesByID(db, seriesID)
- if err != nil {
- return nil, err
- }
-
- series.ID = seriesID
-
- events, err := CreateEventSeries(db, series)
+func updateEventSeries(db *gorm.DB, id uuid.UUID, event models.Event) ([]models.Event, error) {
+ targetEvent, err := events.GetEvent(db, id)
if err != nil {
return nil, err
}
- return events, nil
-}
-func UpdateSeriesByEventID(db *gorm.DB, eventID uuid.UUID, series models.Series) ([]models.Event, *errors.Error) {
- seriesID, err := GetSeriesID(db, eventID)
- if err != nil {
- return nil, err
+ if targetEvent.SeriesID == nil {
+ slog.Error("event is not part of a series", "eventID", id)
+ return nil, utilities.BadRequest(errors.New("event is not part of a series"))
}
- events, err := UpdateSeries(db, *seriesID, series)
- if err != nil {
- return nil, err
+ var resultingEvents []models.Event
+ if result := db.Model(&resultingEvents).Clauses(clause.Returning{}).Where("series_id = ?", targetEvent.SeriesID).Updates(&event); result.RowsAffected == 0 {
+ if result.Error == nil {
+ return nil, utilities.ErrNotFound
+ }
+ return nil, result.Error
}
- return events, nil
+ return resultingEvents, nil
}
-func DeleteEvent(db *gorm.DB, id uuid.UUID) *errors.Error {
+func DeleteEvent(db *gorm.DB, id uuid.UUID) error {
if result := db.Delete(&models.Event{}, id); result.RowsAffected == 0 {
if result.Error == nil {
- return &errors.EventNotFound
- } else {
- return &errors.FailedToDeleteEvent
+ return utilities.ErrNotFound
}
+ return result.Error
}
return nil
}
-
-func DeleteSeriesByEventID(db *gorm.DB, eventID uuid.UUID) *errors.Error {
- seriesID, err := GetSeriesID(db, eventID)
- if err != nil {
- return err
- }
-
- if err := DeleteSeriesByID(db, *seriesID); err != nil {
- return err
- }
-
- return nil
-}
-
-func DeleteSeriesByID(db *gorm.DB, seriesID uuid.UUID) *errors.Error {
- tx := db.Begin()
-
- var eventIDs uuid.UUIDs
-
- if err := tx.Model(&models.EventSeries{}).Select("event_id").Where("series_id = (?)", seriesID).Find(&eventIDs).Error; err != nil {
- tx.Rollback()
- return &errors.FailedToDeleteSeries
- } else if len(eventIDs) < 1 {
- tx.Rollback()
- return &errors.SeriesNotFound
- }
-
- if result := tx.Delete(&models.Event{}, eventIDs); result.RowsAffected == 0 {
- tx.Rollback()
- return &errors.FailedToDeleteSeries
- }
-
- if result := tx.Delete(&models.Series{}, seriesID); result.RowsAffected == 0 {
- tx.Rollback()
- return &errors.FailedToDeleteSeries
- }
-
- tx.Commit()
-
- return nil
-}
-
-func GetHostsByEventID(db *gorm.DB, eventID uuid.UUID) ([]models.Club, *errors.Error) {
- // Get the club that hosts the event
- event, err := GetEvent(db, eventID)
- if err != nil {
- return nil, err
- }
-
- clubs, err := clubs.GetClub(db, *event[0].Host, transactions.PreloadEvent())
- if err != nil {
- return nil, err
- }
-
- return []models.Club{*clubs}, nil
-}
-
-func GetTagsByEventID(db *gorm.DB, eventID uuid.UUID) ([]models.Tag, *errors.Error) {
- event, err := GetEvent(db, eventID, transactions.PreloadTag())
- if err != nil {
- return nil, err
- }
-
- return event[0].Tag, nil
-}
diff --git a/backend/entities/events/models.go b/backend/entities/events/models.go
new file mode 100644
index 000000000..f0f4c547e
--- /dev/null
+++ b/backend/entities/events/models.go
@@ -0,0 +1,71 @@
+package events
+
+import (
+ "time"
+
+ "github.com/GenerateNU/sac/backend/entities/models"
+ "github.com/google/uuid"
+)
+
+type CreateEventRequestBody struct {
+ // details
+ Name string `json:"name" validate:"required,max=255"`
+ Preview string `json:"preview" validate:"required,max=255"`
+ Description string `json:"description" validate:"required,max=255"`
+ HostID uuid.UUID `json:"host" validate:"uuid4"`
+
+ // geoshi
+ EventType models.EventType `json:"event_type" validate:"required,max=255,oneof=hybrid in_person virtual"`
+ Location string `json:"location" validate:"max=255,required_if=EventType in_person,required_if=EventType hybrid"`
+ Link string `json:"link" validate:"http_url,max=255,required_if=EventType virtual,required_if=EventType hybrid"`
+
+ // internal housekeeping states
+ IsPublic *bool `json:"is_public" validate:"required"`
+ IsDraft *bool `json:"is_draft" validate:"required"`
+ IsArchived *bool `json:"is_archived" validate:"required"`
+
+ // timing
+ StartTime time.Time `json:"start_time" validate:"required,ltefield=EndTime"`
+ EndTime time.Time `json:"end_time" validate:"required,gtefield=StartTime"`
+}
+
+func (c *CreateEventRequestBody) Into() *models.Event {
+ return &models.Event{
+ Name: c.Name,
+ Preview: c.Preview,
+ Description: c.Description,
+ Host: &c.HostID,
+ EventType: c.EventType,
+ Location: c.Location,
+ Link: c.Link,
+ IsPublic: *c.IsPublic,
+ IsDraft: *c.IsDraft,
+ IsArchived: *c.IsArchived,
+ StartTime: c.StartTime,
+ EndTime: c.EndTime,
+ }
+}
+
+type UpdateEventRequestBody struct {
+ // details
+ Name string `json:"name" validate:"omitempty,max=255"`
+ Preview string `json:"preview" validate:"omitempty,max=255"`
+ Description string `json:"description" validate:"omitempty,max=255"`
+ HostID *uuid.UUID `json:"host" validate:"omitempty,uuid4"`
+
+ // geoshi
+ EventType models.EventType `json:"event_type" validate:"omitempty,max=255,oneof=hybrid in_person virtual"`
+ Location string `json:"location" validate:"omitempty,max=255,required_if=EventType in_person,required_if=EventType hybrid"`
+ Link string `json:"link" validate:"omitempty,url,max=255,required_if=EventType virtual,required_if=EventType hybrid"`
+
+ // internal housekeeping states
+ IsPublic bool `json:"is_public" validate:"omitempty"`
+ IsDraft bool `json:"is_draft" validate:"omitempty"`
+ IsArchived bool `json:"is_archived" validate:"omitempty"`
+
+ // timing
+ StartTime time.Time `json:"start_time" validate:"omitempty,ltecsfield=EndTime"`
+ EndTime time.Time `json:"end_time" validate:"omitempty,gtecsfield=StartTime"`
+
+ UpdateAllInSeries *bool `json:"update_all_in_series" validate:"required"`
+}
diff --git a/backend/entities/events/series/controller.go b/backend/entities/events/series/controller.go
new file mode 100644
index 000000000..470a6b4c0
--- /dev/null
+++ b/backend/entities/events/series/controller.go
@@ -0,0 +1,47 @@
+package series
+
+import (
+ "net/http"
+
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/gofiber/fiber/v2"
+)
+
+type EventSeriesController struct {
+ eventSeriesService EventSeriesServiceInterface
+}
+
+func NewEventSeriesController(eventSeriesService EventSeriesServiceInterface) *EventSeriesController {
+ return &EventSeriesController{eventSeriesService: eventSeriesService}
+}
+
+func (e *EventSeriesController) CreateEventSeries(c *fiber.Ctx) error {
+ var body CreateEventSeriesRequestBody
+ if err := c.BodyParser(&body); err != nil {
+ return utilities.InvalidJSON()
+ }
+
+ events, err := e.eventSeriesService.CreateEventSeries(body)
+ if err != nil {
+ return err
+ }
+
+ return c.Status(http.StatusCreated).JSON(events)
+}
+
+func (e *EventSeriesController) GetEventSeries(c *fiber.Ctx) error {
+ events, err := e.eventSeriesService.GetEventSeries(c.Params("seriesID"))
+ if err != nil {
+ return err
+ }
+
+ return c.Status(http.StatusOK).JSON(events)
+}
+
+func (e *EventSeriesController) DeleteEventSeries(c *fiber.Ctx) error {
+ if err := e.eventSeriesService.DeleteEventSeries(c.Params("seriesID")); err != nil {
+ return err
+ }
+
+ return c.SendStatus(http.StatusNoContent)
+}
diff --git a/backend/entities/events/series/models.go b/backend/entities/events/series/models.go
new file mode 100644
index 000000000..6d98cb4c4
--- /dev/null
+++ b/backend/entities/events/series/models.go
@@ -0,0 +1,50 @@
+package series
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/GenerateNU/sac/backend/entities/events"
+ "github.com/GenerateNU/sac/backend/entities/models"
+ "github.com/GenerateNU/sac/backend/protos"
+ "github.com/GenerateNU/sac/backend/utilities"
+)
+
+type CreateEventSeriesRequestBody struct {
+ events.CreateEventRequestBody
+ Recurrence protos.StringRecurrence `json:"recurrence" validate:"required"`
+ Termination time.Time `json:"termination" validate:"required"`
+}
+
+func (c *CreateEventSeriesRequestBody) Validate() (*ValidatedCreateEventSeriesRequestBody, error) {
+ errors := make(map[string]string)
+ recurrence, err := protos.RecurrenceFrom(c.Recurrence)
+ if err != nil {
+ errors["Recurrence"] = fmt.Sprintf("%s failed %s", "Recurrence", "StringRecurrenceProto")
+ }
+
+ if len(errors) > 0 {
+ return nil, utilities.InvalidRequestData(errors)
+ }
+
+ return &ValidatedCreateEventSeriesRequestBody{
+ CreateEventRequestBody: c.CreateEventRequestBody,
+ Recurrence: *recurrence,
+ Termination: c.Termination,
+ }, nil
+}
+
+type ValidatedCreateEventSeriesRequestBody struct {
+ events.CreateEventRequestBody
+ Recurrence protos.Recurrence `json:"recurrence"`
+ Termination time.Time `json:"termination"`
+}
+
+func (v *ValidatedCreateEventSeriesRequestBody) Into() *models.Event {
+ return v.CreateEventRequestBody.Into()
+}
+
+type Series struct {
+ models.Model
+ Events []models.Event `gorm:"foreignKey:SeriesID" json:"events"`
+}
diff --git a/backend/entities/events/series/routes.go b/backend/entities/events/series/routes.go
new file mode 100644
index 000000000..b4310c2da
--- /dev/null
+++ b/backend/entities/events/series/routes.go
@@ -0,0 +1,32 @@
+package series
+
+import (
+ "github.com/GenerateNU/sac/backend/extractors"
+ authMiddleware "github.com/GenerateNU/sac/backend/middleware/auth"
+ "github.com/GenerateNU/sac/backend/types"
+)
+
+func EventSeries(eventParams types.RouteParams) {
+ eventSeriesController := NewEventSeriesController(NewEventSeriesService(eventParams.ServiceParams))
+
+ // api/v1/events/series/*
+ eventSeries := eventParams.Router.Group("/series")
+
+ eventSeries.Post(
+ "/",
+ authMiddleware.AttachExtractor(eventParams.AuthMiddleware.ClubAuthorizeById, authMiddleware.ExtractFromBody("host")),
+ eventSeriesController.CreateEventSeries,
+ )
+
+ eventSeriedID := eventSeries.Group("/:seriesID")
+
+ eventSeriedID.Get("/", eventSeriesController.GetEventSeries)
+ eventSeriedID.Delete(
+ "/",
+ authMiddleware.AttachExtractor(
+ eventParams.AuthMiddleware.ClubAuthorizeById,
+ authMiddleware.FromExtractFromParamIntoQuery("seriesID", eventParams.ServiceParams.DB, extractors.GetSeriesHost),
+ ),
+ eventSeriesController.DeleteEventSeries,
+ )
+}
diff --git a/backend/entities/events/series/service.go b/backend/entities/events/series/service.go
new file mode 100644
index 000000000..d8886a31d
--- /dev/null
+++ b/backend/entities/events/series/service.go
@@ -0,0 +1,78 @@
+package series
+
+import (
+ "fmt"
+
+ "github.com/GenerateNU/sac/backend/entities/models"
+ "github.com/GenerateNU/sac/backend/types"
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/google/uuid"
+)
+
+type EventSeriesServiceInterface interface {
+ CreateEventSeries(body CreateEventSeriesRequestBody) (*Series, error)
+ GetEventSeries(seriesID string) ([]models.Event, error)
+ DeleteEventSeries(seriesID string) error
+}
+
+type EventSeriesService struct {
+ types.ServiceParams
+}
+
+func NewEventSeriesService(serviceParams types.ServiceParams) EventSeriesServiceInterface {
+ return &EventSeriesService{serviceParams}
+}
+
+func (e *EventSeriesService) CreateEventSeries(body CreateEventSeriesRequestBody) (*Series, error) {
+ if err := utilities.Validate(e.Validate, body); err != nil {
+ return nil, err
+ }
+
+ validatedBody, err := body.Validate()
+ if err != nil {
+ return nil, err
+ }
+
+ if validatedBody.Termination.After(e.Calendar.MaxTerminationDate) {
+ return nil, utilities.BadRequest(fmt.Errorf("termination date is after max termination date. termination: %s, max termination: %s", validatedBody.Termination, e.Calendar.MaxTerminationDate))
+ }
+
+ rootEvent := validatedBody.Into()
+
+ occurrences, err := validatedBody.Recurrence.ReccurUntil(rootEvent.StartTime, rootEvent.EndTime, validatedBody.Termination)
+ if err != nil {
+ return nil, utilities.BadRequest(fmt.Errorf("error creating recurring event series: %w", err))
+ }
+
+ events := make([]models.Event, len(occurrences))
+ seriesID := uuid.New()
+
+ for index, occurrence := range occurrences {
+ eventOccurence := *rootEvent
+ eventOccurence.ID = uuid.New()
+ eventOccurence.SeriesID = &seriesID
+ eventOccurence.StartTime = occurrence.Start
+ eventOccurence.EndTime = occurrence.End
+ events[index] = eventOccurence
+ }
+
+ return CreateEventSeries(e.DB, seriesID, events)
+}
+
+func (e *EventSeriesService) GetEventSeries(seriesID string) ([]models.Event, error) {
+ idAsUUID, err := utilities.ValidateID(seriesID)
+ if err != nil {
+ return nil, err
+ }
+
+ return GetEventSeries(e.DB, *idAsUUID)
+}
+
+func (e *EventSeriesService) DeleteEventSeries(seriesID string) error {
+ idAsUUID, err := utilities.ValidateID(seriesID)
+ if err != nil {
+ return err
+ }
+
+ return DeleteEventSeries(e.DB, *idAsUUID)
+}
diff --git a/backend/entities/events/series/transactions.go b/backend/entities/events/series/transactions.go
new file mode 100644
index 000000000..2c4b3c598
--- /dev/null
+++ b/backend/entities/events/series/transactions.go
@@ -0,0 +1,77 @@
+package series
+
+import (
+ "errors"
+
+ "github.com/GenerateNU/sac/backend/entities/models"
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/google/uuid"
+ "gorm.io/gorm"
+)
+
+func createSeries(db *gorm.DB, seriesID uuid.UUID) (*Series, error) {
+ series := &Series{
+ Model: models.Model{
+ ID: seriesID,
+ },
+ }
+
+ if err := db.Create(series).Error; err != nil {
+ return nil, err
+ }
+
+ return series, nil
+}
+
+func CreateEventSeries(db *gorm.DB, seriesID uuid.UUID, events []models.Event) (*Series, error) {
+ tx := db.Begin()
+ defer func() {
+ if r := recover(); r != nil {
+ tx.Rollback()
+ }
+ }()
+
+ if err := tx.Error; err != nil {
+ return nil, err
+ }
+
+ series, err := createSeries(tx, seriesID)
+ if err != nil {
+ tx.Rollback()
+ return nil, err
+ }
+
+ if err := tx.Create(&events).Error; err != nil {
+ tx.Rollback()
+ return nil, err
+ }
+
+ series.Events = events
+
+ return series, tx.Commit().Error
+}
+
+func GetEventSeries(db *gorm.DB, seriesID uuid.UUID) ([]models.Event, error) {
+ var events []models.Event
+
+ if err := db.Where("series_id = ?", seriesID).Find(&events).Error; err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
+ }
+ return nil, err
+ }
+
+ return events, nil
+}
+
+func DeleteEventSeries(db *gorm.DB, seriesID uuid.UUID) error {
+ if err := db.Where("id = ?", seriesID).Delete(&Series{}).Error; err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return utilities.ErrNotFound
+ }
+
+ return err
+ }
+
+ return nil
+}
diff --git a/backend/entities/events/tags/controller.go b/backend/entities/events/tags/controller.go
new file mode 100644
index 000000000..347ab6241
--- /dev/null
+++ b/backend/entities/events/tags/controller.go
@@ -0,0 +1,48 @@
+package tags
+
+import (
+ "net/http"
+
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/gofiber/fiber/v2"
+)
+
+type EventTagController struct {
+ eventTagService EventTagServiceInterface
+}
+
+func NewEventTagController(eventTagService EventTagServiceInterface) *EventTagController {
+ return &EventTagController{eventTagService: eventTagService}
+}
+
+func (e *EventTagController) CreateEventTags(c *fiber.Ctx) error {
+ var eventTagsBody CreateEventTagsRequestBody
+ if err := c.BodyParser(&eventTagsBody); err != nil {
+ return utilities.InvalidJSON()
+ }
+
+ eventTags, err := e.eventTagService.CreateEventTags(c.Params("eventID"), eventTagsBody)
+ if err != nil {
+ return err
+ }
+
+ return c.Status(http.StatusCreated).JSON(eventTags)
+}
+
+func (e *EventTagController) GetEventTags(c *fiber.Ctx) error {
+ tags, err := e.eventTagService.GetEventTags(c.Params("eventID"))
+ if err != nil {
+ return err
+ }
+
+ return c.Status(http.StatusCreated).JSON(tags)
+}
+
+func (e *EventTagController) DeleteEventTag(c *fiber.Ctx) error {
+ err := e.eventTagService.DeleteEventTag(c.Params("eventID"), c.Params("tagID"))
+ if err != nil {
+ return err
+ }
+
+ return c.SendStatus(http.StatusNoContent)
+}
diff --git a/backend/entities/events/tags/models.go b/backend/entities/events/tags/models.go
new file mode 100644
index 000000000..6619f1fc2
--- /dev/null
+++ b/backend/entities/events/tags/models.go
@@ -0,0 +1,7 @@
+package tags
+
+import "github.com/google/uuid"
+
+type CreateEventTagsRequestBody struct {
+ Tags []uuid.UUID `json:"tags" validate:"required"`
+}
diff --git a/backend/entities/events/tags/routes.go b/backend/entities/events/tags/routes.go
new file mode 100644
index 000000000..7ba3bb9c4
--- /dev/null
+++ b/backend/entities/events/tags/routes.go
@@ -0,0 +1,24 @@
+package tags
+
+import (
+ authMiddleware "github.com/GenerateNU/sac/backend/middleware/auth"
+ "github.com/GenerateNU/sac/backend/types"
+)
+
+func EventTags(eventParams types.RouteParams) {
+ eventTagController := NewEventTagController(NewEventTagService(eventParams.ServiceParams))
+
+ eventTags := eventParams.Router.Group("/:eventID/tags")
+
+ eventTags.Get("/", eventTagController.GetEventTags)
+ eventTags.Post(
+ "/",
+ authMiddleware.AttachExtractor(eventParams.AuthMiddleware.EventAuthorizeById, authMiddleware.ExtractFromParams("eventID")),
+ eventTagController.CreateEventTags,
+ )
+ eventTags.Delete(
+ "/:tagID",
+ authMiddleware.AttachExtractor(eventParams.AuthMiddleware.EventAuthorizeById, authMiddleware.ExtractFromParams("eventID")),
+ eventTagController.DeleteEventTag,
+ )
+}
diff --git a/backend/entities/events/tags/service.go b/backend/entities/events/tags/service.go
new file mode 100644
index 000000000..b2287fb73
--- /dev/null
+++ b/backend/entities/events/tags/service.go
@@ -0,0 +1,63 @@
+package tags
+
+import (
+ "github.com/GenerateNU/sac/backend/entities/models"
+ "github.com/GenerateNU/sac/backend/entities/tags"
+ "github.com/GenerateNU/sac/backend/types"
+ "github.com/GenerateNU/sac/backend/utilities"
+)
+
+type EventTagServiceInterface interface {
+ CreateEventTags(id string, clubTagsBody CreateEventTagsRequestBody) ([]models.Tag, error)
+ GetEventTags(id string) ([]models.Tag, error)
+ DeleteEventTag(id string, tagId string) error
+}
+
+type EventTagService struct {
+ types.ServiceParams
+}
+
+func NewEventTagService(serviceParams types.ServiceParams) EventTagServiceInterface {
+ return &EventTagService{serviceParams}
+}
+
+func (e *EventTagService) CreateEventTags(id string, eventTagsBody CreateEventTagsRequestBody) ([]models.Tag, error) {
+ idAsUUID, err := utilities.ValidateID(id)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := utilities.Validate(e.Validate, eventTagsBody); err != nil {
+ return nil, err
+ }
+
+ tags, err := tags.GetTagsByIDs(e.DB, eventTagsBody.Tags)
+ if err != nil {
+ return nil, err
+ }
+
+ return CreateEventTags(e.DB, *idAsUUID, tags)
+}
+
+func (e *EventTagService) GetEventTags(id string) ([]models.Tag, error) {
+ idAsUUID, err := utilities.ValidateID(id)
+ if err != nil {
+ return nil, err
+ }
+
+ return GetEventTags(e.DB, *idAsUUID)
+}
+
+func (e *EventTagService) DeleteEventTag(id string, tagId string) error {
+ idAsUUID, err := utilities.ValidateID(id)
+ if err != nil {
+ return err
+ }
+
+ tagIdAsUUID, err := utilities.ValidateID(tagId)
+ if err != nil {
+ return err
+ }
+
+ return DeleteEventTag(e.DB, *idAsUUID, *tagIdAsUUID)
+}
diff --git a/backend/entities/events/tags/transactions.go b/backend/entities/events/tags/transactions.go
new file mode 100644
index 000000000..a7815b074
--- /dev/null
+++ b/backend/entities/events/tags/transactions.go
@@ -0,0 +1,56 @@
+package tags
+
+import (
+ "github.com/GenerateNU/sac/backend/entities/events"
+
+ "github.com/GenerateNU/sac/backend/entities/models"
+ "github.com/GenerateNU/sac/backend/entities/tags"
+ "github.com/GenerateNU/sac/backend/transactions"
+ "github.com/google/uuid"
+
+ "gorm.io/gorm"
+)
+
+func CreateEventTags(db *gorm.DB, id uuid.UUID, tags []models.Tag) ([]models.Tag, error) {
+ event, err := events.GetEvent(db, id, transactions.PreloadTag())
+ if err != nil {
+ return nil, err
+ }
+
+ if err := db.Model(&event).Association("Tag").Append(tags); err != nil {
+ return nil, err
+ }
+
+ return tags, nil
+}
+
+func GetEventTags(db *gorm.DB, id uuid.UUID) ([]models.Tag, error) {
+ var tags []models.Tag
+
+ event, err := events.GetEvent(db, id, transactions.PreloadTag())
+ if err != nil {
+ return nil, err
+ }
+
+ if err := db.Model(&event).Association("Tag").Find(&tags); err != nil {
+ return nil, err
+ }
+ return tags, nil
+}
+
+func DeleteEventTag(db *gorm.DB, id uuid.UUID, tagID uuid.UUID) error {
+ event, err := events.GetEvent(db, id, transactions.PreloadTag())
+ if err != nil {
+ return err
+ }
+
+ tag, err := tags.GetTag(db, tagID)
+ if err != nil {
+ return err
+ }
+
+ if err := db.Model(&event).Association("Tag").Delete(&tag); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/backend/entities/events/transactions.go b/backend/entities/events/transactions.go
new file mode 100644
index 000000000..1a4b3ca7a
--- /dev/null
+++ b/backend/entities/events/transactions.go
@@ -0,0 +1,51 @@
+package events
+
+import (
+ "errors"
+
+ "github.com/GenerateNU/sac/backend/entities/clubs"
+ "github.com/GenerateNU/sac/backend/entities/models"
+ "github.com/GenerateNU/sac/backend/transactions"
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/google/uuid"
+ "gorm.io/gorm"
+)
+
+func GetEvent(db *gorm.DB, eventID uuid.UUID, preloads ...transactions.OptionalQuery) (*models.Event, error) {
+ var event models.Event
+
+ query := db
+
+ for _, preload := range preloads {
+ query = preload(query)
+ }
+ if err := query.First(&event, eventID).Error; err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
+ }
+ return nil, err
+ }
+
+ return &event, nil
+}
+
+func GetEventHostAdminIDs(db *gorm.DB, eventID uuid.UUID) ([]uuid.UUID, error) {
+ event, err := GetEvent(db, eventID)
+ if err != nil {
+ return nil, err
+ }
+
+ return clubs.GetAdminIDs(db, *event.Host)
+}
+
+func GetFirstEventInSeries(db *gorm.DB, seriesID uuid.UUID) (*models.Event, error) {
+ var event models.Event
+ if err := db.Where("series_id = ?", seriesID).First(&event).Error; err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
+ }
+ return nil, err
+ }
+
+ return &event, nil
+}
diff --git a/backend/entities/files/base/controller.go b/backend/entities/files/base/controller.go
index 029803d53..de0efaed3 100644
--- a/backend/entities/files/base/controller.go
+++ b/backend/entities/files/base/controller.go
@@ -1,9 +1,10 @@
package base
import (
- "github.com/GenerateNU/sac/backend/constants"
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+ "net/http"
+
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
"github.com/gofiber/fiber/v2"
)
@@ -25,15 +26,20 @@ func NewFileController(fileService FileServiceInterface) *FileController {
// @Param limit query int false "Limit"
// @Param page query int false "Page"
// @Success 200 {object} []models.File
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /files/ [get]
func (f *FileController) GetFiles(c *fiber.Ctx) error {
- files, err := f.fileService.GetFiles(c.Query("limit", constants.DEFAULT_LIMIT_STRING), c.Query("page", constants.DEFAULT_PAGE_STRING))
+ pagination, ok := fiberpaginate.FromContext(c)
+ if !ok {
+ return utilities.ErrExpectedPagination
+ }
+
+ files, err := f.fileService.GetFiles(*pagination)
if err != nil {
- return err.FiberError(c)
+ return err
}
return c.JSON(files)
@@ -48,17 +54,17 @@ func (f *FileController) GetFiles(c *fiber.Ctx) error {
// @Produce json
// @Param fileID path string true "File ID"
// @Success 200 {object} models.File
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /files/:fileID [get]
func (f *FileController) GetFile(c *fiber.Ctx) error {
fileID := c.Params("fileID")
file, err := f.fileService.GetFile(fileID)
if err != nil {
- return err.FiberError(c)
+ return err
}
return c.JSON(file)
@@ -72,31 +78,31 @@ func (f *FileController) GetFile(c *fiber.Ctx) error {
// @Tags file
// @Accept multipart/form-data
// @Produce json
-// @Param file body models.CreateFileRequestBody true "File"
+// @Param file body CreateFileRequestBody true "File"
// @Success 201 {object} models.File
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /files/ [post]
func (f *FileController) CreateFile(c *fiber.Ctx) error {
- var fileBody models.CreateFileRequestBody
+ var fileBody CreateFileRequestBody
- if parseErr := c.BodyParser(&fileBody); parseErr != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ if err := c.BodyParser(&fileBody); err != nil {
+ return utilities.InvalidJSON()
}
- formFile, parseErr := c.FormFile("file")
- if parseErr != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ formFile, err := c.FormFile("file")
+ if err != nil {
+ return err
}
file, err := f.fileService.CreateFile(&fileBody, formFile)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusCreated).JSON(file)
+ return c.Status(http.StatusCreated).JSON(file)
}
// DeleteFile godoc
@@ -108,18 +114,18 @@ func (f *FileController) CreateFile(c *fiber.Ctx) error {
// @Produce json
// @Param fileID path string true "File ID"
// @Success 201 {object} models.File
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /files/:fileID [delete]
func (f *FileController) DeleteFile(c *fiber.Ctx) error {
fileID := c.Params("fileID")
err := f.fileService.DeleteFile(fileID)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.SendStatus(fiber.StatusNoContent)
+ return c.SendStatus(http.StatusNoContent)
}
diff --git a/backend/entities/files/base/models.go b/backend/entities/files/base/models.go
new file mode 100644
index 000000000..120959250
--- /dev/null
+++ b/backend/entities/files/base/models.go
@@ -0,0 +1,8 @@
+package base
+
+import "github.com/google/uuid"
+
+type CreateFileRequestBody struct {
+ OwnerID uuid.UUID `json:"owner_id" validate:"required,uuid4"`
+ OwnerType string `json:"owner_type" validate:"required,max=255"`
+}
diff --git a/backend/entities/files/base/routes.go b/backend/entities/files/base/routes.go
index 150382f65..c52205db5 100644
--- a/backend/entities/files/base/routes.go
+++ b/backend/entities/files/base/routes.go
@@ -8,7 +8,8 @@ func File(fileParams types.RouteParams) {
fileController := NewFileController(NewFileService(fileParams.ServiceParams))
file := fileParams.Router.Group("/files")
- file.Get("/", fileController.GetFiles)
+
+ file.Get("/", fileParams.UtilityMiddleware.Paginator, fileController.GetFiles)
file.Get("/:fileID", fileController.GetFile)
file.Post("/", fileController.CreateFile)
file.Delete("/:fileID", fileController.DeleteFile)
diff --git a/backend/entities/files/base/service.go b/backend/entities/files/base/service.go
index a92580d4a..b7969201d 100644
--- a/backend/entities/files/base/service.go
+++ b/backend/entities/files/base/service.go
@@ -4,17 +4,17 @@ import (
"mime/multipart"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/integrations/file"
"github.com/GenerateNU/sac/backend/types"
"github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
)
type FileServiceInterface interface {
- GetFiles(limit string, page string) ([]models.File, *errors.Error)
- GetFile(fileID string) (*models.File, *errors.Error)
- CreateFile(fileBody *models.CreateFileRequestBody, formFile *multipart.FileHeader) (*models.File, *errors.Error)
- DeleteFile(fileID string) *errors.Error
+ GetFiles(pageInfo fiberpaginate.PageInfo) ([]models.File, error)
+ GetFile(fileID string) (*models.File, error)
+ CreateFile(fileBody *CreateFileRequestBody, formFile *multipart.FileHeader) (*models.File, error)
+ DeleteFile(fileID string) error
}
type FileService struct {
@@ -25,51 +25,41 @@ func NewFileService(serviceParams types.ServiceParams) FileServiceInterface {
return &FileService{serviceParams}
}
-func (f *FileService) GetFiles(limit string, page string) ([]models.File, *errors.Error) {
- limitAsInt, err := utilities.ValidateNonNegative(limit)
- if err != nil {
- return nil, &errors.FailedToValidateLimit
- }
-
- pageAsInt, err := utilities.ValidateNonNegative(page)
- if err != nil {
- return nil, &errors.FailedToValidatePage
- }
-
- return GetFiles(f.DB, *limitAsInt, *pageAsInt)
+func (f *FileService) GetFiles(pageInfo fiberpaginate.PageInfo) ([]models.File, error) {
+ return GetFiles(f.DB, pageInfo)
}
-func (f *FileService) GetFile(fileID string) (*models.File, *errors.Error) {
+func (f *FileService) GetFile(fileID string) (*models.File, error) {
idAsUUID, err := utilities.ValidateID(fileID)
if err != nil {
- return nil, &errors.FailedToValidateID
+ return nil, err
}
return GetFile(f.DB, *idAsUUID)
}
-func (f *FileService) CreateFile(fileBody *models.CreateFileRequestBody, fileHeader *multipart.FileHeader) (*models.File, *errors.Error) {
- if err := f.Validate.Struct(fileBody); err != nil {
- return nil, &errors.FailedToValidateFile
+func (f *FileService) CreateFile(fileBody *CreateFileRequestBody, fileHeader *multipart.FileHeader) (*models.File, error) {
+ if err := utilities.Validate(f.Validate, fileBody); err != nil {
+ return nil, err
}
fileInfo, err := f.Integrations.File.UploadFile(fileBody.OwnerType, fileHeader, []file.FileType{file.ALL})
if err != nil {
- return nil, &errors.FailedToUploadFile
+ return nil, err
}
file, err := CreateFile(f.DB, fileBody.OwnerID, fileBody.OwnerType, *fileInfo)
if err != nil {
- return nil, &errors.FailedToCreateFile
+ return nil, err
}
return file, nil
}
-func (f *FileService) DeleteFile(fileID string) *errors.Error {
+func (f *FileService) DeleteFile(fileID string) error {
idAsUUID, err := utilities.ValidateID(fileID)
if err != nil {
- return &errors.FailedToValidateID
+ return err
}
return DeleteFile(f.DB, *idAsUUID)
diff --git a/backend/entities/files/base/transactions.go b/backend/entities/files/base/transactions.go
index 948a7d903..45310102c 100644
--- a/backend/entities/files/base/transactions.go
+++ b/backend/entities/files/base/transactions.go
@@ -1,15 +1,17 @@
package base
import (
- stdliberrors "errors"
+ "errors"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+ "github.com/garrettladley/fiberpaginate"
+
+ "github.com/GenerateNU/sac/backend/utilities"
"github.com/google/uuid"
"gorm.io/gorm"
)
-func CreateFile(db *gorm.DB, ownerID uuid.UUID, ownerType string, fileInfo models.FileInfo) (*models.File, *errors.Error) {
+func CreateFile(db *gorm.DB, ownerID uuid.UUID, ownerType string, fileInfo models.FileInfo) (*models.File, error) {
file := &models.File{
OwnerID: ownerID,
OwnerType: ownerType,
@@ -21,25 +23,24 @@ func CreateFile(db *gorm.DB, ownerID uuid.UUID, ownerType string, fileInfo model
}
if err := db.Create(file).Error; err != nil {
- return nil, &errors.FailedToCreateFileInDB
+ return nil, err
}
return file, nil
}
-func DeleteFile(db *gorm.DB, fileID uuid.UUID) *errors.Error {
+func DeleteFile(db *gorm.DB, fileID uuid.UUID) error {
if err := db.Delete(&models.File{}, fileID).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return &errors.FileNotFound
- } else {
- return &errors.FailedToDeleteFile
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return utilities.ErrNotFound
}
+ return err
}
return nil
}
-func UpdateFile(db *gorm.DB, fileID uuid.UUID, fileInfo models.FileInfo) (*models.File, *errors.Error) {
+func UpdateFile(db *gorm.DB, fileID uuid.UUID, fileInfo models.FileInfo) (*models.File, error) {
existingFile, err := GetFile(db, fileID)
if err != nil {
return nil, err
@@ -52,32 +53,28 @@ func UpdateFile(db *gorm.DB, fileID uuid.UUID, fileInfo models.FileInfo) (*model
FileURL: fileInfo.FileURL,
ObjectKey: fileInfo.ObjectKey,
}).Error; err != nil {
- return nil, &errors.FailedToUpdateFile
+ return nil, err
}
return existingFile, nil
}
-func GetFiles(db *gorm.DB, limit, page int) ([]models.File, *errors.Error) {
+func GetFiles(db *gorm.DB, pageInfo fiberpaginate.PageInfo) ([]models.File, error) {
var files []models.File
-
- offset := (page - 1) * limit
-
- if err := db.Limit(limit).Offset(offset).Find(&files).Error; err != nil {
- return nil, &errors.FailedToGetFiles
+ if err := db.Scopes(utilities.IntoScope(pageInfo, db)).Find(&files).Error; err != nil {
+ return nil, err
}
return files, nil
}
-func GetFile(db *gorm.DB, fileID uuid.UUID) (*models.File, *errors.Error) {
+func GetFile(db *gorm.DB, fileID uuid.UUID) (*models.File, error) {
var file models.File
if err := db.First(&file, fileID).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.FileNotFound
- } else {
- return nil, &errors.FailedToGetFile
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
}
+ return nil, err
}
return &file, nil
diff --git a/backend/entities/models/category.go b/backend/entities/models/category.go
index f4a15da46..f6aaf3df4 100644
--- a/backend/entities/models/category.go
+++ b/backend/entities/models/category.go
@@ -3,10 +3,6 @@ package models
type Category struct {
Model
- Name string `json:"name" validate:"required,max=255"`
- Tag []Tag `json:"-" validate:"-"`
-}
-
-type CategoryRequestBody struct {
- Name string `json:"name" validate:"required,max=255"`
+ Name string `json:"name"`
+ Tag []Tag `json:"-"`
}
diff --git a/backend/entities/models/club.go b/backend/entities/models/club.go
index ec71db8e7..217338f87 100644
--- a/backend/entities/models/club.go
+++ b/backend/entities/models/club.go
@@ -8,83 +8,36 @@ import (
"gorm.io/gorm"
)
-type RecruitmentCycle string
-
-const (
- Fall RecruitmentCycle = "fall"
- Spring RecruitmentCycle = "spring"
- FallSpring RecruitmentCycle = "fallSpring"
- Always RecruitmentCycle = "always"
-)
-
-type RecruitmentType string
-
-const (
- Unrestricted RecruitmentType = "unrestricted"
- Tryout RecruitmentType = "tryout"
- Application RecruitmentType = "application"
-)
-
type Club struct {
Model
- SoftDeletedAt gorm.DeletedAt `json:"-" validate:"-"`
-
- Name string `json:"name" validate:"required,max=255"`
- Preview string `json:"preview" validate:"required,max=255"`
- Description string `json:"description" validate:"required,http_url,s3_url,max=255"`
- NumMembers int `json:"num_members" validate:"required,min=1"`
- IsRecruiting bool `json:"is_recruiting" validate:"required"`
- RecruitmentCycle RecruitmentCycle `json:"recruitment_cycle" validate:"required,max=255,oneof=fall spring fallSpring always"`
- RecruitmentType RecruitmentType `json:"recruitment_type" validate:"required,max=255,oneof=unrestricted tryout application"`
- WeeklyTimeCommitment int `json:"weekly_time_commitment" validate:"omitempty,min=1"`
- OneWordToDescribeUs string `json:"one_word_to_describe_us" validate:"omitempty,max=255"`
- ApplicationLink string `json:"application_link" validate:"required,max=255,http_url"`
- Logo string `json:"logo" validate:"omitempty,http_url,s3_url,max=255"`
-
- Parent *uuid.UUID `gorm:"foreignKey:Parent;" json:"-" validate:"uuid4"`
- Tag []Tag `gorm:"many2many:club_tags;" json:"-" validate:"-"`
- Member []User `gorm:"many2many:user_club_members;" json:"-" validate:"required"`
- Follower []User `gorm:"many2many:user_club_followers;" json:"-" validate:"-"`
- IntendedApplicant []User `gorm:"many2many:user_club_intended_applicants;" json:"-" validate:"-"`
- Comment []Comment `json:"-" validate:"-"`
- PointOfContact []PointOfContact `json:"-" validate:"-"`
- Contact []Contact `json:"-" validate:"-"`
- // Event
- HostEvent []Event `gorm:"foreignKey:Host;" json:"-" validate:"-"`
- Event []Event `gorm:"many2many:club_events;" json:"-" validate:"-"`
- Notifcation []Notification `gorm:"polymorphic:Reference;" json:"-" validate:"-"`
-}
-
-type CreateClubRequestBody struct {
- UserID uuid.UUID `json:"user_id" validate:"required,uuid4"`
- Name string `json:"name" validate:"required,max=255"`
- Preview string `json:"preview" validate:"required,max=255"`
- Description string `json:"description" validate:"required,http_url,s3_url,max=255"`
- IsRecruiting bool `json:"is_recruiting" validate:"required"`
- RecruitmentCycle RecruitmentCycle `json:"recruitment_cycle" validate:"required,max=255,oneof=fall spring fallSpring always"`
- RecruitmentType RecruitmentType `json:"recruitment_type" validate:"required,max=255,oneof=unrestricted tryout application"`
- WeeklyTimeCommitment *int `json:"weekly_time_commitment" validate:"omitempty,min=1"`
- OneWordToDescribeUs string `json:"one_word_to_describe_us" validate:"omitempty,max=255"`
- ApplicationLink string `json:"application_link" validate:"required,max=255,http_url"`
- Logo string `json:"logo" validate:"omitempty,http_url,s3_url,max=255"`
-}
+ SoftDeletedAt gorm.DeletedAt `json:"-"`
+
+ Name string `json:"name"`
+ Preview string `json:"preview"`
+ Description string `json:"description"`
+ NumMembers int `json:"num_members"`
+ IsRecruiting bool `json:"is_recruiting"`
+ RecruitmentCycle RecruitmentCycle `json:"recruitment_cycle"`
+ RecruitmentType RecruitmentType `json:"recruitment_type"`
+ WeeklyTimeCommitment int `json:"weekly_time_commitment"`
+ OneWordToDescribeUs string `json:"one_word_to_describe_us"`
+ ApplicationLink string `json:"application_link"`
+ Logo string `json:"logo"`
+
+ Parent *uuid.UUID `gorm:"foreignKey:Parent;" json:"-"`
+ Tag []Tag `gorm:"many2many:club_tags;" json:"-"`
+ Member []User `gorm:"many2many:user_club_members;" json:"-"`
+ Follower []User `gorm:"many2many:user_club_followers;" json:"-"`
+ IntendedApplicant []User `gorm:"many2many:user_club_intended_applicants;" json:"-"`
+ Comment []Comment `json:"-"`
+ PointOfContact []PointOfContact `json:"-"`
+ Contact []Contact `json:"-"`
-type UpdateClubRequestBody struct {
- Name string `json:"name" validate:"omitempty,max=255"`
- Preview string `json:"preview" validate:"omitempty,max=255"`
- Description string `json:"description" validate:"omitempty,http_url,s3_url,max=255"`
- IsRecruiting bool `json:"is_recruiting" validate:"omitempty"`
- RecruitmentCycle RecruitmentCycle `json:"recruitment_cycle" validate:"required,max=255,oneof=fall spring fallSpring always"`
- RecruitmentType RecruitmentType `json:"recruitment_type" validate:"required,max=255,oneof=unrestricted tryout application"`
- WeeklyTimeCommitment *int `json:"weekly_time_commitment" validate:"omitempty,min=1"`
- OneWordToDescribeUs string `json:"one_word_to_describe_us" validate:"omitempty,max=255"`
- ApplicationLink string `json:"application_link" validate:"omitempty,required,max=255,http_url"`
- Logo string `json:"logo" validate:"omitempty,s3_url,max=255,http_url"`
-}
-
-type CreateClubTagsRequestBody struct {
- Tags []uuid.UUID `json:"tags" validate:"required"`
+ // Event
+ HostEvent []Event `gorm:"foreignKey:Host;" json:"-"`
+ Event []Event `gorm:"many2many:club_events;" json:"-"`
+ Notifcation []Notification `gorm:"polymorphic:Reference;" json:"-"`
}
type ClubQueryParams struct {
@@ -96,8 +49,6 @@ type ClubQueryParams struct {
MinWeeklyTimeCommitment int `query:"min_weekly_time_commitment"`
MaxWeeklyTimeCommitment int `query:"max_weekly_time_commitment"`
OneWordToDescribeUs string `query:"one_word_to_describe_us"`
- Limit int `query:"limit"`
- Page int `query:"page"`
Search string `query:"search"`
}
diff --git a/backend/entities/models/college.go b/backend/entities/models/college.go
new file mode 100644
index 000000000..2defefb71
--- /dev/null
+++ b/backend/entities/models/college.go
@@ -0,0 +1,15 @@
+package models
+
+type College string
+
+const (
+ CAMD College = "CAMD" // College of Arts, Media and Design
+ DMSB College = "DMSB" // D'Amore-McKim School of Business
+ KCCS College = "KCCS" // Khoury College of Computer Sciences
+ CE College = "CE" // College of Engineering
+ BCHS College = "BCHS" // Bouvé College of Health Sciences
+ SL College = "SL" // School of Law
+ CPS College = "CPS" // College of Professional Studies
+ CS College = "CS" // College of Science
+ CSSH College = "CSSH" // College of Social Sciences and Humanities
+)
diff --git a/backend/entities/models/comment.go b/backend/entities/models/comment.go
index 00f73e552..fde2fa825 100644
--- a/backend/entities/models/comment.go
+++ b/backend/entities/models/comment.go
@@ -5,16 +5,16 @@ import "github.com/google/uuid"
type Comment struct {
Model
- Question string `json:"question" validate:"required,max=255"`
- Answer string `json:"answer" validate:",max=255"`
- NumFoundHelpful uint `json:"num_found_helpful" validate:"min=0"`
+ Question string `json:"question"`
+ Answer string `json:"answer"`
+ NumFoundHelpful uint `json:"num_found_helpful"`
- AskedByID uuid.UUID `json:"-" validate:"uuid4"`
- AskedBy User `json:"-" validate:"-"`
+ AskedByID uuid.UUID `json:"-"`
+ AskedBy User `json:"-"`
- ClubID uuid.UUID `json:"-" validate:"uuid4"`
- Club Club `json:"-" validate:"-"`
+ ClubID uuid.UUID `json:"-"`
+ Club Club `json:"-"`
- AnsweredByID *uuid.UUID `json:"-" validate:"uuid4"`
- AnsweredBy *User `json:"-" validate:"-"`
+ AnsweredByID *uuid.UUID `json:"-"`
+ AnsweredBy *User `json:"-"`
}
diff --git a/backend/entities/models/contact.go b/backend/entities/models/contact.go
index cf17c5f6f..82b3de1d3 100644
--- a/backend/entities/models/contact.go
+++ b/backend/entities/models/contact.go
@@ -43,13 +43,8 @@ func GetContentPrefix(contactType ContactType) string {
type Contact struct {
Model
- Type ContactType `json:"type" validate:"required,max=255,oneof=facebook instagram x linkedin youtube github slack discord email customSite"`
- Content string `json:"content" validate:"required,max=255"`
+ Type ContactType `json:"type"`
+ Content string `json:"content"`
- ClubID uuid.UUID `json:"-" validate:"uuid4"`
-}
-
-type PutContactRequestBody struct {
- Type ContactType `json:"type" validate:"required,max=255,oneof=facebook instagram x linkedin youtube github slack discord email customSite,contact_pointer"`
- Content string `json:"content" validate:"required,contact_pointer,max=255"`
+ ClubID uuid.UUID `json:"-"`
}
diff --git a/backend/entities/models/event.go b/backend/entities/models/event.go
index 74b0185da..12eb1b0f6 100644
--- a/backend/entities/models/event.go
+++ b/backend/entities/models/event.go
@@ -9,111 +9,41 @@ import (
type EventType string
const (
- Open EventType = "open"
- MembersOnly EventType = "membersOnly"
-)
-
-type RecurringType string
-
-const (
- Daily RecurringType = "daily"
- Weekly RecurringType = "weekly"
- Monthly RecurringType = "monthly"
+ Hybrid EventType = "hybrid"
+ InPerson EventType = "in_person"
+ Virtual EventType = "virtual"
)
type Event struct {
Model
- Name string `json:"name" validate:"required,max=255"`
- Preview string `json:"preview" validate:"required,max=255"`
- Content string `json:"content" validate:"required,max=255"`
- StartTime time.Time `json:"start_time" validate:"required,ltecsfield=EndTime"`
- EndTime time.Time `json:"end_time" validate:"required,gtecsfield=StartTime"`
- Location string `json:"location" validate:"required,max=255"`
- EventType EventType `json:"event_type" validate:"required,max=255,oneof=open membersOnly"`
- IsRecurring bool `json:"is_recurring" validate:"-"`
- MeetingLink string `json:"meeting_link" validate:"url"`
- Host *uuid.UUID `json:"host" validate:"uuid4"`
-
- RSVP []User `gorm:"many2many:user_event_rsvps;" json:"-" validate:"-"`
- Waitlist []User `gorm:"many2many:user_event_waitlists;" json:"-" validate:"-"`
- Clubs []Club `gorm:"many2many:club_events;" json:"-" validate:"-"`
- Tag []Tag `gorm:"many2many:event_tags;" json:"-" validate:"-"`
- Notification []Notification `gorm:"polymorphic:Reference;" json:"-" validate:"-"`
-}
-
-type Series struct {
- Model
- RecurringType RecurringType `json:"recurring_type" validate:"max=255"`
- MaxOccurrences int `json:"max_occurrences" validate:"min=1"`
- Events []Event `gorm:"many2many:event_series;" json:"events" validate:"-"`
-}
-
-type EventSeries struct {
- EventID uuid.UUID `json:"event_id" validate:"uuid4"`
- Event Event `json:"-" validate:"-"`
- SeriesID uuid.UUID `json:"series_id" validate:"uuid4"`
- Series Series `json:"-" validate:"-"`
-}
-
-// Not needed for now, we will just update the events separately
-type EventInstanceException struct {
- Model
- EventID int `json:"event_id" validate:"required"`
- Event Event
- IsRescheduled bool `json:"is_rescheduled" validate:"required"`
- IsCancelled bool `json:"is_cancelled" validate:"required"`
- StartTime time.Time `json:"start_time" validate:"required,datetime,ltecsfield=EndTime"`
- EndTime time.Time `json:"end_time" validate:"required,datetime,gtecsfield=StartTime"`
-}
-
-// TODO We will likely need to update the create and update structs to account for recurring series
-type CreateEventRequestBody struct {
- Name string `json:"name" validate:"required,max=255"`
- Preview string `json:"preview" validate:"required,max=255"`
- Content string `json:"content" validate:"required,max=255"`
- StartTime time.Time `json:"start_time" validate:"required,ltecsfield=EndTime"`
- EndTime time.Time `json:"end_time" validate:"required,gtecsfield=StartTime"`
- Location string `json:"location" validate:"required,max=255"`
- EventType EventType `json:"event_type" validate:"required,max=255,oneof=open membersOnly"`
- IsRecurring *bool `json:"is_recurring" validate:"required"`
-
- // TODO club/tag/notification logic
- Host *uuid.UUID `json:"host" validate:"required,uuid4"`
- Clubs []Club `json:"-" validate:"omitempty"`
- Tag []Tag `json:"-" validate:"omitempty"`
- Notification []Notification `json:"-" validate:"omitempty"`
-
- // TODO validate if isRecurring, then series is required
- Series CreateSeriesRequestBody `json:"series" validate:"-"`
-}
-
-type CreateSeriesRequestBody struct {
- RecurringType RecurringType `json:"recurring_type" validate:"required,max=255,oneof=daily weekly monthly"`
- MaxOccurrences int `json:"max_occurrences" validate:"required,min=2"`
-}
-
-type UpdateEventRequestBody struct {
- Name string `json:"name" validate:"omitempty,max=255"`
- Preview string `json:"preview" validate:"omitempty,max=255"`
- Content string `json:"content" validate:"omitempty,max=255"`
- StartTime time.Time `json:"start_time" validate:"omitempty,ltecsfield=EndTime"`
- EndTime time.Time `json:"end_time" validate:"omitempty,gtecsfield=StartTime"`
- Location string `json:"location" validate:"omitempty,max=255"`
- EventType EventType `json:"event_type" validate:"omitempty,max=255,oneof=open membersOnly"`
-
- Host *uuid.UUID `json:"host" validate:"omitempty"`
- RSVP []User `json:"-" validate:"omitempty"`
- Waitlist []User `json:"-" validate:"omitempty"`
- Clubs []Club `json:"-" validate:"omitempty"`
- Tag []Tag `json:"-" validate:"omitempty"`
- Notification []Notification `json:"-" validate:"omitempty"`
-}
-
-// TODO: probably need to make changes to this to update the events as well
-type UpdateSeriesRequestBody struct {
- RecurringType RecurringType `json:"recurring_type" validate:"omitempty,max=255,oneof=daily weekly monthly"`
- MaxOccurrences int `json:"max_occurrences" validate:"omitempty,min=2"`
-
- EventDetails UpdateEventRequestBody `json:"event_details" validate:"omitempty"`
+ // details
+ Name string `json:"name"`
+ Preview string `json:"preview"`
+ Description string `json:"description"`
+ Host *uuid.UUID `json:"host"`
+
+ // geoshi
+ EventType EventType `json:"event_type"`
+ Location string `json:"location"`
+ Link string `json:"link"`
+
+ // internal housekeeping states
+ IsPublic bool `json:"is_public"`
+ IsDraft bool `json:"is_draft"`
+ IsArchived bool `json:"is_archived"`
+
+ // timing
+ StartTime time.Time `json:"start_time"`
+ EndTime time.Time `json:"end_time"`
+
+ // series
+ SeriesID *uuid.UUID `json:"-"`
+
+ // bridgerton
+ RSVP []User `gorm:"many2many:user_event_rsvps;" json:"-"`
+ Waitlist []User `gorm:"many2many:user_event_waitlists;" json:"-"`
+ Clubs []Club `gorm:"many2many:club_events;" json:"-"`
+ Tag []Tag `gorm:"many2many:event_tags;" json:"-"`
+ Notification []Notification `gorm:"polymorphic:Reference;" json:"-"`
}
diff --git a/backend/entities/models/file.go b/backend/entities/models/file.go
index a5ea52b43..215618a6a 100644
--- a/backend/entities/models/file.go
+++ b/backend/entities/models/file.go
@@ -15,17 +15,12 @@ type FileInfo struct {
type File struct {
Model
- OwnerID uuid.UUID `json:"-" validate:"required,uuid4"`
- OwnerType string `json:"-" validate:"required,max=255"`
+ OwnerID uuid.UUID `json:"-"`
+ OwnerType string `json:"-"`
- FileName string `json:"file_name" validate:"required,max=255"`
- FileType string `json:"file_type" validate:"required,max=255"`
- FileSize int `json:"file_size" validate:"required,min=1"`
- FileURL string `json:"file_url" validate:"required,max=255"`
- ObjectKey string `json:"object_key" validate:"required,max=255"`
-}
-
-type CreateFileRequestBody struct {
- OwnerID uuid.UUID `json:"owner_id" validate:"required,uuid4"`
- OwnerType string `json:"owner_type" validate:"required,max=255"`
+ FileName string `json:"file_name"`
+ FileType string `json:"file_type"`
+ FileSize int `json:"file_size"`
+ FileURL string `json:"file_url"`
+ ObjectKey string `json:"object_key"`
}
diff --git a/backend/entities/models/follower.go b/backend/entities/models/follower.go
index 9d9f015ca..de469eac1 100644
--- a/backend/entities/models/follower.go
+++ b/backend/entities/models/follower.go
@@ -9,9 +9,9 @@ func (Follower) TableName() string {
}
type Follower struct {
- UserID uuid.UUID `gorm:"primaryKey;" json:"user_id" validate:"required,uuid4"`
- ClubID uuid.UUID `gorm:"primaryKey" json:"club_id" validate:"required,uuid4"`
+ UserID uuid.UUID `gorm:"primaryKey;" json:"user_id"`
+ ClubID uuid.UUID `gorm:"primaryKey" json:"club_id"`
- Club *Club `json:"-" validate:"-"`
- User *User `json:"-" validate:"-"`
+ Club *Club `json:"-"`
+ User *User `json:"-"`
}
diff --git a/backend/entities/models/graduation_cycle.go b/backend/entities/models/graduation_cycle.go
new file mode 100644
index 000000000..9bd1f7102
--- /dev/null
+++ b/backend/entities/models/graduation_cycle.go
@@ -0,0 +1,8 @@
+package models
+
+type GraduationCycle string
+
+const (
+ December GraduationCycle = "december"
+ May GraduationCycle = "may"
+)
diff --git a/backend/entities/models/major.go b/backend/entities/models/major.go
new file mode 100644
index 000000000..29da28102
--- /dev/null
+++ b/backend/entities/models/major.go
@@ -0,0 +1,107 @@
+package models
+
+type Major string
+
+// see https://admissions.northeastern.edu/academics/areas-of-study/
+const (
+ AfricanaStudies Major = "africanaStudies"
+ AmericanSignLanguage Major = "americanSignLanguage"
+ AmericanSignLanguageEnglishInterpreting Major = "americanSignLanguage-EnglishInterpreting"
+ AppliedPhysics Major = "appliedPhysics"
+ ArchitecturalStudies Major = "architecturalStudies"
+ Architecture Major = "architecture"
+ ArtArtVisualStudies Major = "art:ArtVisualStudies"
+ BehavioralNeuroscience Major = "behavioralNeuroscience"
+ Biochemistry Major = "biochemistry"
+ Bioengineering Major = "bioengineering"
+ Biology Major = "biology"
+ BiomedicalPhysics Major = "biomedicalPhysics"
+ BusinessAdministration Major = "businessAdministration"
+ BusinessAdministrationAccounting Major = "businessAdministration:Accounting"
+ BusinessAdministrationAccountingAndAdvisoryServices Major = "businessAdministration:AccountingAndAdvisoryServices"
+ BusinessAdministrationBrandManagement Major = "businessAdministration:BrandManagement"
+ BusinessAdministrationBusinessAnalytics Major = "businessAdministration:BusinessAnalytics"
+ BusinessAdministrationCorporateInnovation Major = "businessAdministration:CorporateInnovation"
+ BusinessAdministrationEntrepreneurialStartups Major = "businessAdministration:EntrepreneurialStartups"
+ BusinessAdministrationFamilyBusiness Major = "businessAdministration:FamilyBusiness"
+ BusinessAdministrationFinance Major = "businessAdministration:Finance"
+ BusinessAdministrationFintech Major = "businessAdministration:Fintech"
+ BusinessAdministrationHealthcareManagementAndConsulting Major = "businessAdministration:HealthcareManagementAndConsulting"
+ BusinessAdministrationManagement Major = "businessAdministration:Management"
+ BusinessAdministrationManagementInformationSystems Major = "businessAdministration:ManagementInformationSystems"
+ BusinessAdministrationMarketing Major = "businessAdministration:Marketing"
+ BusinessAdministrationMarketingAnalytics Major = "businessAdministration:MarketingAnalytics"
+ BusinessAdministrationSocialInnovationAndEntrepreneurship Major = "businessAdministration:SocialInnovationAndEntrepreneurship"
+ BusinessAdministrationSupplyChainManagement Major = "businessAdministration:SupplyChainManagement"
+ CellAndMolecularBiology Major = "cellAndMolecularBiology"
+ ChemicalEngineering Major = "chemicalEngineering"
+ Chemistry Major = "chemistry"
+ CivilEngineering Major = "civilEngineering"
+ CommunicationStudies Major = "communicationStudies"
+ ComputerEngineering Major = "computerEngineering"
+ ComputerScience Major = "computerScience"
+ ComputingAndLaw Major = "computingAndLaw"
+ CriminologyAndCriminalJustice Major = "criminologyAndCriminalJustice"
+ CulturalAnthropology Major = "culturalAnthropology"
+ Cybersecurity Major = "cybersecurity"
+ DataScience Major = "dataScience"
+ Design Major = "design"
+ Economics Major = "economics"
+ ElectricalEngineering Major = "electricalEngineering"
+ English Major = "english"
+ EnvironmentalAndSustainabilityStudies Major = "environmentalAndSustainabilityStudies"
+ EnvironmentalEngineering Major = "environmentalEngineering"
+ EnvironmentalScience Major = "environmentalScience"
+ EnvironmentalStudies Major = "environmentalStudies"
+ GameArtAndAnimation Major = "gameArtAndAnimation"
+ GameDesign Major = "gameDesign"
+ GlobalAsianStudies Major = "globalAsianStudies"
+ HealthScience Major = "healthScience"
+ History Major = "history"
+ HistoryCultureAndLaw Major = "historyCultureAndLaw"
+ HumanServices Major = "humanServices"
+ IndustrialEngineering Major = "industrialEngineering"
+ InternationalAffairs Major = "internationalAffairs"
+ InternationalBusiness Major = "internationalBusiness"
+ InternationalBusinessAccounting Major = "internationalBusiness:Accounting"
+ InternationalBusinessAccountingAndAdvisoryServices Major = "internationalBusiness:AccountingAndAdvisoryServices"
+ InternationalBusinessBrandManagement Major = "internationalBusiness:BrandManagement"
+ InternationalBusinessBusinessAnalytics Major = "internationalBusiness:BusinessAnalytics"
+ InternationalBusinessCorporateInnovation Major = "internationalBusiness:CorporateInnovation"
+ InternationalBusinessEntrepreneurialStartups Major = "internationalBusiness:EntrepreneurialStartups"
+ InternationalBusinessFamilyBusiness Major = "internationalBusiness:FamilyBusiness"
+ InternationalBusinessFinance Major = "internationalBusiness:Finance"
+ InternationalBusinessFintech Major = "internationalBusiness:Fintech"
+ InternationalBusinessHealthcareManagementAndConsulting Major = "internationalBusiness:HealthcareManagementAndConsulting"
+ InternationalBusinessManagement Major = "internationalBusiness:Management"
+ InternationalBusinessManagementInformationSystems Major = "internationalBusiness:ManagementInformationSystems"
+ InternationalBusinessMarketing Major = "internationalBusiness:Marketing"
+ InternationalBusinessMarketingAnalytics Major = "internationalBusiness:MarketingAnalytics"
+ InternationalBusinessSocialInnovationAndEntrepreneurship Major = "internationalBusiness:SocialInnovationAndEntrepreneurship"
+ InternationalBusinessSupplyChainManagement Major = "internationalBusiness:SupplyChainManagement"
+ Journalism Major = "journalism"
+ LandscapeArchitecture Major = "landscapeArchitecture"
+ Linguistics Major = "linguistics"
+ MarineBiology Major = "marineBiology"
+ Mathematics Major = "mathematics"
+ MechanicalEngineering Major = "mechanicalEngineering"
+ MediaAndScreenStudies Major = "mediaAndScreenStudies"
+ MediaArts Major = "mediaArts"
+ Music Major = "music"
+ MusicTechnology Major = "musicTechnology"
+ Nursing Major = "nursing"
+ PharmaceuticalSciences Major = "pharmaceuticalSciences"
+ PharmacyPharmD Major = "pharmacy(PharmD)"
+ Philosophy Major = "philosophy"
+ Physics Major = "physics"
+ PoliticalScience Major = "politicalScience"
+ PoliticsPhilosophyEconomics Major = "politicsPhilosophyEconomics"
+ Psychology Major = "psychology"
+ PublicHealth Major = "publicHealth"
+ PublicRelations Major = "publicRelations"
+ ReligiousStudies Major = "religiousStudies"
+ Sociology Major = "sociology"
+ Spanish Major = "spanish"
+ SpeechLanguagePathologyAndAudiology Major = "speechLanguagePathologyAndAudiology"
+ Theatre Major = "theatre"
+)
diff --git a/backend/entities/models/membership.go b/backend/entities/models/membership.go
index a4a963911..48c6f79d1 100644
--- a/backend/entities/models/membership.go
+++ b/backend/entities/models/membership.go
@@ -16,11 +16,11 @@ func (Membership) TableName() string {
}
type Membership struct {
- UserID uuid.UUID `gorm:"primaryKey;" json:"user_id" validate:"required,uuid4"`
- ClubID uuid.UUID `gorm:"primaryKey;" json:"club_id" validate:"required,uuid4"`
+ UserID uuid.UUID `gorm:"primaryKey;" json:"user_id"`
+ ClubID uuid.UUID `gorm:"primaryKey;" json:"club_id"`
- Club *Club `json:"-" validate:"-"`
- User *User `json:"-" validate:"-"`
+ Club *Club `json:"-"`
+ User *User `json:"-"`
- MembershipType MembershipType `json:"membership_type" validate:"required,oneof=member admin"`
+ MembershipType MembershipType `json:"membership_type"`
}
diff --git a/backend/entities/models/notification.go b/backend/entities/models/notification.go
index 1e1dda738..2c6af0c25 100644
--- a/backend/entities/models/notification.go
+++ b/backend/entities/models/notification.go
@@ -16,12 +16,12 @@ const (
type Notification struct {
Model
- SendAt time.Time `json:"send_at" validate:"required"`
- Title string `json:"title" validate:"required,max=255"`
- Content string `json:"content" validate:"required,max=255"`
- DeepLink string `json:"deep_link" validate:"required,max=255"`
- Icon string `json:"icon" validate:"required,s3_url,http_url,max=255"`
+ SendAt time.Time `json:"send_at"`
+ Title string `json:"title"`
+ Content string `json:"content"`
+ DeepLink string `json:"deep_link"`
+ Icon string `json:"icon"`
- ReferenceID uuid.UUID `json:"-" validate:"uuid4"`
- ReferenceType NotificationType `json:"-" validate:"max=255"`
+ ReferenceID uuid.UUID `json:"-"`
+ ReferenceType NotificationType `json:"-"`
}
diff --git a/backend/entities/models/poc.go b/backend/entities/models/poc.go
index ee03c015b..9a94b45dd 100644
--- a/backend/entities/models/poc.go
+++ b/backend/entities/models/poc.go
@@ -7,23 +7,11 @@ import (
type PointOfContact struct {
Model
- Name string `json:"name" validate:"required,max=255"`
- Email string `json:"email" validate:"required,email,max=255"`
- Position string `json:"position" validate:"required,max=255"`
+ Name string `json:"name"`
+ Email string `json:"email"`
+ Position string `json:"position"`
- ClubID uuid.UUID `json:"-" validate:"required,uuid4"`
+ ClubID uuid.UUID `json:"-"`
PhotoFile File `gorm:"polymorphic:Owner;" json:"photo_file"`
}
-
-type CreatePointOfContactBody struct {
- Name string `json:"name" validate:"required,max=255"`
- Email string `json:"email" validate:"required,email,max=255"`
- Position string `json:"position" validate:"required,max=255"`
-}
-
-type UpdatePointOfContactBody struct {
- Name string `json:"name" validate:"omitempty,max=255"`
- Email string `json:"email" validate:"omitempty,email,max=255"`
- Position string `json:"position" validate:"omitempty,max=255"`
-}
diff --git a/backend/entities/models/recruitment_cycle.go b/backend/entities/models/recruitment_cycle.go
new file mode 100644
index 000000000..95a775f7e
--- /dev/null
+++ b/backend/entities/models/recruitment_cycle.go
@@ -0,0 +1,10 @@
+package models
+
+type RecruitmentCycle string
+
+const (
+ Fall RecruitmentCycle = "fall"
+ Spring RecruitmentCycle = "spring"
+ FallSpring RecruitmentCycle = "fallSpring"
+ Always RecruitmentCycle = "always"
+)
diff --git a/backend/entities/models/recruitment_type.go b/backend/entities/models/recruitment_type.go
new file mode 100644
index 000000000..6ebcc6542
--- /dev/null
+++ b/backend/entities/models/recruitment_type.go
@@ -0,0 +1,9 @@
+package models
+
+type RecruitmentType string
+
+const (
+ Unrestricted RecruitmentType = "unrestricted"
+ Tryout RecruitmentType = "tryout"
+ Application RecruitmentType = "application"
+)
diff --git a/backend/entities/models/role.go b/backend/entities/models/role.go
new file mode 100644
index 000000000..0675e6ae1
--- /dev/null
+++ b/backend/entities/models/role.go
@@ -0,0 +1,8 @@
+package models
+
+type UserRole string
+
+var (
+ Super UserRole = "super"
+ Student UserRole = "student"
+)
diff --git a/backend/entities/models/tag.go b/backend/entities/models/tag.go
index 705210aa8..ec3235e41 100644
--- a/backend/entities/models/tag.go
+++ b/backend/entities/models/tag.go
@@ -5,21 +5,11 @@ import "github.com/google/uuid"
type Tag struct {
Model
- Name string `json:"name" validate:"required,max=255"`
+ Name string `json:"name"`
- CategoryID uuid.UUID `json:"category_id" validate:"required,uuid4"`
+ CategoryID uuid.UUID `json:"category_id"`
- User []User `gorm:"many2many:user_tags;" json:"-" validate:"-"`
- Club []Club `gorm:"many2many:club_tags;" json:"-" validate:"-"`
- Event []Event `gorm:"many2many:event_tags;" json:"-" validate:"-"`
-}
-
-type CreateTagRequestBody struct {
- Name string `json:"name" validate:"required,max=255"`
- CategoryID uuid.UUID `json:"category_id" validate:"required,uuid4"`
-}
-
-type UpdateTagRequestBody struct {
- Name string `json:"name" validate:"omitempty,max=255"`
- CategoryID uuid.UUID `json:"category_id" validate:"omitempty,uuid4"`
+ User []User `gorm:"many2many:user_tags;" json:"-"`
+ Club []Club `gorm:"many2many:club_tags;" json:"-"`
+ Event []Event `gorm:"many2many:event_tags;" json:"-"`
}
diff --git a/backend/entities/models/tokens.go b/backend/entities/models/tokens.go
new file mode 100644
index 000000000..b1b527f76
--- /dev/null
+++ b/backend/entities/models/tokens.go
@@ -0,0 +1,6 @@
+package models
+
+type Tokens struct {
+ AccessToken string `json:"access_token"`
+ RefreshToken string `json:"refresh_token"`
+}
diff --git a/backend/entities/models/user.go b/backend/entities/models/user.go
index c814eb4a5..bf1bb3b1e 100644
--- a/backend/entities/models/user.go
+++ b/backend/entities/models/user.go
@@ -4,209 +4,31 @@ import (
"gorm.io/gorm"
)
-type UserRole string
-
-var (
- Super UserRole = "super"
- Student UserRole = "student"
-)
-
-type College string
-
-const (
- CAMD College = "CAMD" // College of Arts, Media and Design
- DMSB College = "DMSB" // D'Amore-McKim School of Business
- KCCS College = "KCCS" // Khoury College of Computer Sciences
- CE College = "CE" // College of Engineering
- BCHS College = "BCHS" // Bouvé College of Health Sciences
- SL College = "SL" // School of Law
- CPS College = "CPS" // College of Professional Studies
- CS College = "CS" // College of Science
- CSSH College = "CSSH" // College of Social Sciences and Humanities
-)
-
-type Major string
-
-// see https://admissions.northeastern.edu/academics/areas-of-study/
-const (
- AfricanaStudies Major = "africanaStudies"
- AmericanSignLanguage Major = "americanSignLanguage"
- AmericanSignLanguageEnglishInterpreting Major = "americanSignLanguage-EnglishInterpreting"
- AppliedPhysics Major = "appliedPhysics"
- ArchitecturalStudies Major = "architecturalStudies"
- Architecture Major = "architecture"
- ArtArtVisualStudies Major = "art:ArtVisualStudies"
- BehavioralNeuroscience Major = "behavioralNeuroscience"
- Biochemistry Major = "biochemistry"
- Bioengineering Major = "bioengineering"
- Biology Major = "biology"
- BiomedicalPhysics Major = "biomedicalPhysics"
- BusinessAdministration Major = "businessAdministration"
- BusinessAdministrationAccounting Major = "businessAdministration:Accounting"
- BusinessAdministrationAccountingAndAdvisoryServices Major = "businessAdministration:AccountingAndAdvisoryServices"
- BusinessAdministrationBrandManagement Major = "businessAdministration:BrandManagement"
- BusinessAdministrationBusinessAnalytics Major = "businessAdministration:BusinessAnalytics"
- BusinessAdministrationCorporateInnovation Major = "businessAdministration:CorporateInnovation"
- BusinessAdministrationEntrepreneurialStartups Major = "businessAdministration:EntrepreneurialStartups"
- BusinessAdministrationFamilyBusiness Major = "businessAdministration:FamilyBusiness"
- BusinessAdministrationFinance Major = "businessAdministration:Finance"
- BusinessAdministrationFintech Major = "businessAdministration:Fintech"
- BusinessAdministrationHealthcareManagementAndConsulting Major = "businessAdministration:HealthcareManagementAndConsulting"
- BusinessAdministrationManagement Major = "businessAdministration:Management"
- BusinessAdministrationManagementInformationSystems Major = "businessAdministration:ManagementInformationSystems"
- BusinessAdministrationMarketing Major = "businessAdministration:Marketing"
- BusinessAdministrationMarketingAnalytics Major = "businessAdministration:MarketingAnalytics"
- BusinessAdministrationSocialInnovationAndEntrepreneurship Major = "businessAdministration:SocialInnovationAndEntrepreneurship"
- BusinessAdministrationSupplyChainManagement Major = "businessAdministration:SupplyChainManagement"
- CellAndMolecularBiology Major = "cellAndMolecularBiology"
- ChemicalEngineering Major = "chemicalEngineering"
- Chemistry Major = "chemistry"
- CivilEngineering Major = "civilEngineering"
- CommunicationStudies Major = "communicationStudies"
- ComputerEngineering Major = "computerEngineering"
- ComputerScience Major = "computerScience"
- ComputingAndLaw Major = "computingAndLaw"
- CriminologyAndCriminalJustice Major = "criminologyAndCriminalJustice"
- CulturalAnthropology Major = "culturalAnthropology"
- Cybersecurity Major = "cybersecurity"
- DataScience Major = "dataScience"
- Design Major = "design"
- Economics Major = "economics"
- ElectricalEngineering Major = "electricalEngineering"
- English Major = "english"
- EnvironmentalAndSustainabilityStudies Major = "environmentalAndSustainabilityStudies"
- EnvironmentalEngineering Major = "environmentalEngineering"
- EnvironmentalScience Major = "environmentalScience"
- EnvironmentalStudies Major = "environmentalStudies"
- GameArtAndAnimation Major = "gameArtAndAnimation"
- GameDesign Major = "gameDesign"
- GlobalAsianStudies Major = "globalAsianStudies"
- HealthScience Major = "healthScience"
- History Major = "history"
- HistoryCultureAndLaw Major = "historyCultureAndLaw"
- HumanServices Major = "humanServices"
- IndustrialEngineering Major = "industrialEngineering"
- InternationalAffairs Major = "internationalAffairs"
- InternationalBusiness Major = "internationalBusiness"
- InternationalBusinessAccounting Major = "internationalBusiness:Accounting"
- InternationalBusinessAccountingAndAdvisoryServices Major = "internationalBusiness:AccountingAndAdvisoryServices"
- InternationalBusinessBrandManagement Major = "internationalBusiness:BrandManagement"
- InternationalBusinessBusinessAnalytics Major = "internationalBusiness:BusinessAnalytics"
- InternationalBusinessCorporateInnovation Major = "internationalBusiness:CorporateInnovation"
- InternationalBusinessEntrepreneurialStartups Major = "internationalBusiness:EntrepreneurialStartups"
- InternationalBusinessFamilyBusiness Major = "internationalBusiness:FamilyBusiness"
- InternationalBusinessFinance Major = "internationalBusiness:Finance"
- InternationalBusinessFintech Major = "internationalBusiness:Fintech"
- InternationalBusinessHealthcareManagementAndConsulting Major = "internationalBusiness:HealthcareManagementAndConsulting"
- InternationalBusinessManagement Major = "internationalBusiness:Management"
- InternationalBusinessManagementInformationSystems Major = "internationalBusiness:ManagementInformationSystems"
- InternationalBusinessMarketing Major = "internationalBusiness:Marketing"
- InternationalBusinessMarketingAnalytics Major = "internationalBusiness:MarketingAnalytics"
- InternationalBusinessSocialInnovationAndEntrepreneurship Major = "internationalBusiness:SocialInnovationAndEntrepreneurship"
- InternationalBusinessSupplyChainManagement Major = "internationalBusiness:SupplyChainManagement"
- Journalism Major = "journalism"
- LandscapeArchitecture Major = "landscapeArchitecture"
- Linguistics Major = "linguistics"
- MarineBiology Major = "marineBiology"
- Mathematics Major = "mathematics"
- MechanicalEngineering Major = "mechanicalEngineering"
- MediaAndScreenStudies Major = "mediaAndScreenStudies"
- MediaArts Major = "mediaArts"
- Music Major = "music"
- MusicTechnology Major = "musicTechnology"
- Nursing Major = "nursing"
- PharmaceuticalSciences Major = "pharmaceuticalSciences"
- PharmacyPharmD Major = "pharmacy(PharmD)"
- Philosophy Major = "philosophy"
- Physics Major = "physics"
- PoliticalScience Major = "politicalScience"
- PoliticsPhilosophyEconomics Major = "politicsPhilosophyEconomics"
- Psychology Major = "psychology"
- PublicHealth Major = "publicHealth"
- PublicRelations Major = "publicRelations"
- ReligiousStudies Major = "religiousStudies"
- Sociology Major = "sociology"
- Spanish Major = "spanish"
- SpeechLanguagePathologyAndAudiology Major = "speechLanguagePathologyAndAudiology"
- Theatre Major = "theatre"
-)
-
-type GraduationCycle string
-
-const (
- December GraduationCycle = "december"
- May GraduationCycle = "may"
-)
-
-type Tokens struct {
- AccessToken string `json:"access_token"`
- RefreshToken string `json:"refresh_token"`
-}
-
type User struct {
Model
- Role UserRole `json:"role" validate:"required,oneof=super student"`
- FirstName string `json:"first_name" validate:"required,max=255"`
- LastName string `json:"last_name" validate:"required,max=255"`
- Email string `json:"email" validate:"required,email,max=255"`
- PasswordHash string `json:"-" validate:"required,len=97"`
- Major0 Major `json:"major0" validate:"not_equal_if_not_empty=Major1,not_equal_if_not_empty=Major2,required,max=255,oneof=africanaStudies americanSignLanguage americanSignLanguage-EnglishInterpreting appliedPhysics architecturalStudies architecture art:ArtVisualStudies behavioralNeuroscience biochemistry bioengineering biology biomedicalPhysics businessAdministration businessAdministration:Accounting businessAdministration:AccountingAndAdvisoryServices businessAdministration:BrandManagement businessAdministration:BusinessAnalytics businessAdministration:CorporateInnovation businessAdministration:EntrepreneurialStartups businessAdministration:FamilyBusiness businessAdministration:Finance businessAdministration:Fintech businessAdministration:HealthcareManagementAndConsulting businessAdministration:Management businessAdministration:ManagementInformationSystems businessAdministration:Marketing businessAdministration:MarketingAnalytics businessAdministration:SocialInnovationAndEntrepreneurship businessAdministration:SupplyChainManagement cellAndMolecularBiology chemicalEngineering chemistry civilEngineering communicationStudies computerEngineering computerScience computingAndLaw criminologyAndCriminalJustice culturalAnthropology cybersecurity dataScience design economics electricalEngineering english environmentalAndSustainabilityStudies environmentalEngineering environmentalScience environmentalStudies gameArtAndAnimation gameDesign globalAsianStudies healthScience history historyCultureAndLaw humanServices industrialEngineering internationalAffairs internationalBusiness internationalBusiness:Accounting internationalBusiness:AccountingAndAdvisoryServices internationalBusiness:BrandManagement internationalBusiness:BusinessAnalytics internationalBusiness:CorporateInnovation internationalBusiness:EntrepreneurialStartups internationalBusiness:FamilyBusiness internationalBusiness:Finance internationalBusiness:Fintech internationalBusiness:HealthcareManagementAndConsulting internationalBusiness:Management internationalBusiness:ManagementInformationSystems internationalBusiness:Marketing internationalBusiness:MarketingAnalytics internationalBusiness:SocialInnovationAndEntrepreneurship internationalBusiness:SupplyChainManagement journalism landscapeArchitecture linguistics marineBiology mathematics mechanicalEngineering mediaAndScreenStudies mediaArts music musicTechnology nursing pharmaceuticalSciences pharmacy(PharmD) philosophy physics politicalScience politicsPhilosophyEconomics psychology publicHealth publicRelations religiousStudies sociology spanish speechLanguagePathologyAndAudiology theatre"`
- Major1 Major `json:"major1" validate:"not_equal_if_not_empty=Major0,not_equal_if_not_empty=Major2,omitempty,max=255,oneof=africanaStudies americanSignLanguage americanSignLanguage-EnglishInterpreting appliedPhysics architecturalStudies architecture art:ArtVisualStudies behavioralNeuroscience biochemistry bioengineering biology biomedicalPhysics businessAdministration businessAdministration:Accounting businessAdministration:AccountingAndAdvisoryServices businessAdministration:BrandManagement businessAdministration:BusinessAnalytics businessAdministration:CorporateInnovation businessAdministration:EntrepreneurialStartups businessAdministration:FamilyBusiness businessAdministration:Finance businessAdministration:Fintech businessAdministration:HealthcareManagementAndConsulting businessAdministration:Management businessAdministration:ManagementInformationSystems businessAdministration:Marketing businessAdministration:MarketingAnalytics businessAdministration:SocialInnovationAndEntrepreneurship businessAdministration:SupplyChainManagement cellAndMolecularBiology chemicalEngineering chemistry civilEngineering communicationStudies computerEngineering computerScience computingAndLaw criminologyAndCriminalJustice culturalAnthropology cybersecurity dataScience design economics electricalEngineering english environmentalAndSustainabilityStudies environmentalEngineering environmentalScience environmentalStudies gameArtAndAnimation gameDesign globalAsianStudies healthScience history historyCultureAndLaw humanServices industrialEngineering internationalAffairs internationalBusiness internationalBusiness:Accounting internationalBusiness:AccountingAndAdvisoryServices internationalBusiness:BrandManagement internationalBusiness:BusinessAnalytics internationalBusiness:CorporateInnovation internationalBusiness:EntrepreneurialStartups internationalBusiness:FamilyBusiness internationalBusiness:Finance internationalBusiness:Fintech internationalBusiness:HealthcareManagementAndConsulting internationalBusiness:Management internationalBusiness:ManagementInformationSystems internationalBusiness:Marketing internationalBusiness:MarketingAnalytics internationalBusiness:SocialInnovationAndEntrepreneurship internationalBusiness:SupplyChainManagement journalism landscapeArchitecture linguistics marineBiology mathematics mechanicalEngineering mediaAndScreenStudies mediaArts music musicTechnology nursing pharmaceuticalSciences pharmacy(PharmD) philosophy physics politicalScience politicsPhilosophyEconomics psychology publicHealth publicRelations religiousStudies sociology spanish speechLanguagePathologyAndAudiology theatre"`
- Major2 Major `json:"major2" validate:"not_equal_if_not_empty=Major0,not_equal_if_not_empty=Major1,omitempty,max=255,oneof=africanaStudies americanSignLanguage americanSignLanguage-EnglishInterpreting appliedPhysics architecturalStudies architecture art:ArtVisualStudies behavioralNeuroscience biochemistry bioengineering biology biomedicalPhysics businessAdministration businessAdministration:Accounting businessAdministration:AccountingAndAdvisoryServices businessAdministration:BrandManagement businessAdministration:BusinessAnalytics businessAdministration:CorporateInnovation businessAdministration:EntrepreneurialStartups businessAdministration:FamilyBusiness businessAdministration:Finance businessAdministration:Fintech businessAdministration:HealthcareManagementAndConsulting businessAdministration:Management businessAdministration:ManagementInformationSystems businessAdministration:Marketing businessAdministration:MarketingAnalytics businessAdministration:SocialInnovationAndEntrepreneurship businessAdministration:SupplyChainManagement cellAndMolecularBiology chemicalEngineering chemistry civilEngineering communicationStudies computerEngineering computerScience computingAndLaw criminologyAndCriminalJustice culturalAnthropology cybersecurity dataScience design economics electricalEngineering english environmentalAndSustainabilityStudies environmentalEngineering environmentalScience environmentalStudies gameArtAndAnimation gameDesign globalAsianStudies healthScience history historyCultureAndLaw humanServices industrialEngineering internationalAffairs internationalBusiness internationalBusiness:Accounting internationalBusiness:AccountingAndAdvisoryServices internationalBusiness:BrandManagement internationalBusiness:BusinessAnalytics internationalBusiness:CorporateInnovation internationalBusiness:EntrepreneurialStartups internationalBusiness:FamilyBusiness internationalBusiness:Finance internationalBusiness:Fintech internationalBusiness:HealthcareManagementAndConsulting internationalBusiness:Management internationalBusiness:ManagementInformationSystems internationalBusiness:Marketing internationalBusiness:MarketingAnalytics internationalBusiness:SocialInnovationAndEntrepreneurship internationalBusiness:SupplyChainManagement journalism landscapeArchitecture linguistics marineBiology mathematics mechanicalEngineering mediaAndScreenStudies mediaArts music musicTechnology nursing pharmaceuticalSciences pharmacy(PharmD) philosophy physics politicalScience politicsPhilosophyEconomics psychology publicHealth publicRelations religiousStudies sociology spanish speechLanguagePathologyAndAudiology theatre"`
- College College `json:"college" validate:"required,max=255"`
- GraduationCycle GraduationCycle `json:"graduation_cycle" validate:"required,max=255,oneof=december may"`
- GraduationYear int16 `json:"graduation_year" validate:"required"`
+ Role UserRole `json:"role"`
+ FirstName string `json:"first_name"`
+ LastName string `json:"last_name"`
+ Email string `json:"email"`
+ PasswordHash string `json:"-"`
+ Major0 Major `json:"major0"`
+ Major1 Major `json:"major1"`
+ Major2 Major `json:"major2"`
+ College College `json:"college"`
+ GraduationCycle GraduationCycle `json:"graduation_cycle"`
+ GraduationYear int16 `json:"graduation_year"`
IsVerified bool `json:"is_verified"`
- Tag []Tag `gorm:"many2many:user_tags;" json:"-" validate:"-"`
- Admin []Club `gorm:"many2many:user_club_admins;" json:"-" validate:"-"`
- Member []Club `gorm:"many2many:user_club_members;" json:"-" validate:"-"`
- Follower []Club `gorm:"many2many:user_club_followers;" json:"-" validate:"-"`
- IntendedApplicant []Club `gorm:"many2many:user_club_intended_applicants;" json:"-" validate:"-"`
- Asked []Comment `gorm:"foreignKey:AskedByID;" json:"-" validate:"-"`
- Answered []Comment `gorm:"foreignKey:AnsweredByID;" json:"-" validate:"-"`
- RSVP []Event `gorm:"many2many:user_event_rsvps;" json:"-" validate:"-"`
- Waitlist []Event `gorm:"many2many:user_event_waitlists;" json:"-" validate:"-"`
-}
-
-type CreateUserRequestBody struct {
- FirstName string `json:"first_name" validate:"required,max=255"`
- LastName string `json:"last_name" validate:"required,max=255"`
- Email string `json:"email" validate:"required,email,neu_email,max=255"`
- Password string `json:"password" validate:"required,max=255"` // MARK: must be validated manually
- // Optional fields
- Major0 Major `json:"major0" validate:"not_equal_if_not_empty=Major1,not_equal_if_not_empty=Major2,omitempty,max=255,oneof=africanaStudies americanSignLanguage americanSignLanguage-EnglishInterpreting appliedPhysics architecturalStudies architecture art:ArtVisualStudies behavioralNeuroscience biochemistry bioengineering biology biomedicalPhysics businessAdministration businessAdministration:Accounting businessAdministration:AccountingAndAdvisoryServices businessAdministration:BrandManagement businessAdministration:BusinessAnalytics businessAdministration:CorporateInnovation businessAdministration:EntrepreneurialStartups businessAdministration:FamilyBusiness businessAdministration:Finance businessAdministration:Fintech businessAdministration:HealthcareManagementAndConsulting businessAdministration:Management businessAdministration:ManagementInformationSystems businessAdministration:Marketing businessAdministration:MarketingAnalytics businessAdministration:SocialInnovationAndEntrepreneurship businessAdministration:SupplyChainManagement cellAndMolecularBiology chemicalEngineering chemistry civilEngineering communicationStudies computerEngineering computerScience computingAndLaw criminologyAndCriminalJustice culturalAnthropology cybersecurity dataScience design economics electricalEngineering english environmentalAndSustainabilityStudies environmentalEngineering environmentalScience environmentalStudies gameArtAndAnimation gameDesign globalAsianStudies healthScience history historyCultureAndLaw humanServices industrialEngineering internationalAffairs internationalBusiness internationalBusiness:Accounting internationalBusiness:AccountingAndAdvisoryServices internationalBusiness:BrandManagement internationalBusiness:BusinessAnalytics internationalBusiness:CorporateInnovation internationalBusiness:EntrepreneurialStartups internationalBusiness:FamilyBusiness internationalBusiness:Finance internationalBusiness:Fintech internationalBusiness:HealthcareManagementAndConsulting internationalBusiness:Management internationalBusiness:ManagementInformationSystems internationalBusiness:Marketing internationalBusiness:MarketingAnalytics internationalBusiness:SocialInnovationAndEntrepreneurship internationalBusiness:SupplyChainManagement journalism landscapeArchitecture linguistics marineBiology mathematics mechanicalEngineering mediaAndScreenStudies mediaArts music musicTechnology nursing pharmaceuticalSciences pharmacy(PharmD) philosophy physics politicalScience politicsPhilosophyEconomics psychology publicHealth publicRelations religiousStudies sociology spanish speechLanguagePathologyAndAudiology theatre"`
- Major1 Major `json:"major1" validate:"not_equal_if_not_empty=Major0,not_equal_if_not_empty=Major2,omitempty,max=255,oneof=africanaStudies americanSignLanguage americanSignLanguage-EnglishInterpreting appliedPhysics architecturalStudies architecture art:ArtVisualStudies behavioralNeuroscience biochemistry bioengineering biology biomedicalPhysics businessAdministration businessAdministration:Accounting businessAdministration:AccountingAndAdvisoryServices businessAdministration:BrandManagement businessAdministration:BusinessAnalytics businessAdministration:CorporateInnovation businessAdministration:EntrepreneurialStartups businessAdministration:FamilyBusiness businessAdministration:Finance businessAdministration:Fintech businessAdministration:HealthcareManagementAndConsulting businessAdministration:Management businessAdministration:ManagementInformationSystems businessAdministration:Marketing businessAdministration:MarketingAnalytics businessAdministration:SocialInnovationAndEntrepreneurship businessAdministration:SupplyChainManagement cellAndMolecularBiology chemicalEngineering chemistry civilEngineering communicationStudies computerEngineering computerScience computingAndLaw criminologyAndCriminalJustice culturalAnthropology cybersecurity dataScience design economics electricalEngineering english environmentalAndSustainabilityStudies environmentalEngineering environmentalScience environmentalStudies gameArtAndAnimation gameDesign globalAsianStudies healthScience history historyCultureAndLaw humanServices industrialEngineering internationalAffairs internationalBusiness internationalBusiness:Accounting internationalBusiness:AccountingAndAdvisoryServices internationalBusiness:BrandManagement internationalBusiness:BusinessAnalytics internationalBusiness:CorporateInnovation internationalBusiness:EntrepreneurialStartups internationalBusiness:FamilyBusiness internationalBusiness:Finance internationalBusiness:Fintech internationalBusiness:HealthcareManagementAndConsulting internationalBusiness:Management internationalBusiness:ManagementInformationSystems internationalBusiness:Marketing internationalBusiness:MarketingAnalytics internationalBusiness:SocialInnovationAndEntrepreneurship internationalBusiness:SupplyChainManagement journalism landscapeArchitecture linguistics marineBiology mathematics mechanicalEngineering mediaAndScreenStudies mediaArts music musicTechnology nursing pharmaceuticalSciences pharmacy(PharmD) philosophy physics politicalScience politicsPhilosophyEconomics psychology publicHealth publicRelations religiousStudies sociology spanish speechLanguagePathologyAndAudiology theatre"`
- Major2 Major `json:"major2" validate:"not_equal_if_not_empty=Major0,not_equal_if_not_empty=Major1,omitempty,max=255,oneof=africanaStudies americanSignLanguage americanSignLanguage-EnglishInterpreting appliedPhysics architecturalStudies architecture art:ArtVisualStudies behavioralNeuroscience biochemistry bioengineering biology biomedicalPhysics businessAdministration businessAdministration:Accounting businessAdministration:AccountingAndAdvisoryServices businessAdministration:BrandManagement businessAdministration:BusinessAnalytics businessAdministration:CorporateInnovation businessAdministration:EntrepreneurialStartups businessAdministration:FamilyBusiness businessAdministration:Finance businessAdministration:Fintech businessAdministration:HealthcareManagementAndConsulting businessAdministration:Management businessAdministration:ManagementInformationSystems businessAdministration:Marketing businessAdministration:MarketingAnalytics businessAdministration:SocialInnovationAndEntrepreneurship businessAdministration:SupplyChainManagement cellAndMolecularBiology chemicalEngineering chemistry civilEngineering communicationStudies computerEngineering computerScience computingAndLaw criminologyAndCriminalJustice culturalAnthropology cybersecurity dataScience design economics electricalEngineering english environmentalAndSustainabilityStudies environmentalEngineering environmentalScience environmentalStudies gameArtAndAnimation gameDesign globalAsianStudies healthScience history historyCultureAndLaw humanServices industrialEngineering internationalAffairs internationalBusiness internationalBusiness:Accounting internationalBusiness:AccountingAndAdvisoryServices internationalBusiness:BrandManagement internationalBusiness:BusinessAnalytics internationalBusiness:CorporateInnovation internationalBusiness:EntrepreneurialStartups internationalBusiness:FamilyBusiness internationalBusiness:Finance internationalBusiness:Fintech internationalBusiness:HealthcareManagementAndConsulting internationalBusiness:Management internationalBusiness:ManagementInformationSystems internationalBusiness:Marketing internationalBusiness:MarketingAnalytics internationalBusiness:SocialInnovationAndEntrepreneurship internationalBusiness:SupplyChainManagement journalism landscapeArchitecture linguistics marineBiology mathematics mechanicalEngineering mediaAndScreenStudies mediaArts music musicTechnology nursing pharmaceuticalSciences pharmacy(PharmD) philosophy physics politicalScience politicsPhilosophyEconomics psychology publicHealth publicRelations religiousStudies sociology spanish speechLanguagePathologyAndAudiology theatre"`
- College College `json:"college" validate:"omitempty,oneof=CAMD DMSB KCCS CE BCHS SL CPS CS CSSH"`
- GraduationCycle GraduationCycle `json:"graduation_cycle" validate:"omitempty,max=255,oneof=december may"`
- GraduationYear int16 `json:"graduation_year" validate:"omitempty"`
-}
-
-type UpdateUserRequestBody struct {
- FirstName string `json:"first_name" validate:"omitempty,max=255"`
- LastName string `json:"last_name" validate:"omitempty,max=255"`
- Major0 Major `json:"major0" validate:"not_equal_if_not_empty=Major1,not_equal_if_not_empty=Major2,omitempty,max=255,oneof=africanaStudies americanSignLanguage americanSignLanguage-EnglishInterpreting appliedPhysics architecturalStudies architecture art:ArtVisualStudies behavioralNeuroscience biochemistry bioengineering biology biomedicalPhysics businessAdministration businessAdministration:Accounting businessAdministration:AccountingAndAdvisoryServices businessAdministration:BrandManagement businessAdministration:BusinessAnalytics businessAdministration:CorporateInnovation businessAdministration:EntrepreneurialStartups businessAdministration:FamilyBusiness businessAdministration:Finance businessAdministration:Fintech businessAdministration:HealthcareManagementAndConsulting businessAdministration:Management businessAdministration:ManagementInformationSystems businessAdministration:Marketing businessAdministration:MarketingAnalytics businessAdministration:SocialInnovationAndEntrepreneurship businessAdministration:SupplyChainManagement cellAndMolecularBiology chemicalEngineering chemistry civilEngineering communicationStudies computerEngineering computerScience computingAndLaw criminologyAndCriminalJustice culturalAnthropology cybersecurity dataScience design economics electricalEngineering english environmentalAndSustainabilityStudies environmentalEngineering environmentalScience environmentalStudies gameArtAndAnimation gameDesign globalAsianStudies healthScience history historyCultureAndLaw humanServices industrialEngineering internationalAffairs internationalBusiness internationalBusiness:Accounting internationalBusiness:AccountingAndAdvisoryServices internationalBusiness:BrandManagement internationalBusiness:BusinessAnalytics internationalBusiness:CorporateInnovation internationalBusiness:EntrepreneurialStartups internationalBusiness:FamilyBusiness internationalBusiness:Finance internationalBusiness:Fintech internationalBusiness:HealthcareManagementAndConsulting internationalBusiness:Management internationalBusiness:ManagementInformationSystems internationalBusiness:Marketing internationalBusiness:MarketingAnalytics internationalBusiness:SocialInnovationAndEntrepreneurship internationalBusiness:SupplyChainManagement journalism landscapeArchitecture linguistics marineBiology mathematics mechanicalEngineering mediaAndScreenStudies mediaArts music musicTechnology nursing pharmaceuticalSciences pharmacy(PharmD) philosophy physics politicalScience politicsPhilosophyEconomics psychology publicHealth publicRelations religiousStudies sociology spanish speechLanguagePathologyAndAudiology theatre"`
- Major1 Major `json:"major1" validate:"not_equal_if_not_empty=Major0,not_equal_if_not_empty=Major2,omitempty,max=255,oneof=africanaStudies americanSignLanguage americanSignLanguage-EnglishInterpreting appliedPhysics architecturalStudies architecture art:ArtVisualStudies behavioralNeuroscience biochemistry bioengineering biology biomedicalPhysics businessAdministration businessAdministration:Accounting businessAdministration:AccountingAndAdvisoryServices businessAdministration:BrandManagement businessAdministration:BusinessAnalytics businessAdministration:CorporateInnovation businessAdministration:EntrepreneurialStartups businessAdministration:FamilyBusiness businessAdministration:Finance businessAdministration:Fintech businessAdministration:HealthcareManagementAndConsulting businessAdministration:Management businessAdministration:ManagementInformationSystems businessAdministration:Marketing businessAdministration:MarketingAnalytics businessAdministration:SocialInnovationAndEntrepreneurship businessAdministration:SupplyChainManagement cellAndMolecularBiology chemicalEngineering chemistry civilEngineering communicationStudies computerEngineering computerScience computingAndLaw criminologyAndCriminalJustice culturalAnthropology cybersecurity dataScience design economics electricalEngineering english environmentalAndSustainabilityStudies environmentalEngineering environmentalScience environmentalStudies gameArtAndAnimation gameDesign globalAsianStudies healthScience history historyCultureAndLaw humanServices industrialEngineering internationalAffairs internationalBusiness internationalBusiness:Accounting internationalBusiness:AccountingAndAdvisoryServices internationalBusiness:BrandManagement internationalBusiness:BusinessAnalytics internationalBusiness:CorporateInnovation internationalBusiness:EntrepreneurialStartups internationalBusiness:FamilyBusiness internationalBusiness:Finance internationalBusiness:Fintech internationalBusiness:HealthcareManagementAndConsulting internationalBusiness:Management internationalBusiness:ManagementInformationSystems internationalBusiness:Marketing internationalBusiness:MarketingAnalytics internationalBusiness:SocialInnovationAndEntrepreneurship internationalBusiness:SupplyChainManagement journalism landscapeArchitecture linguistics marineBiology mathematics mechanicalEngineering mediaAndScreenStudies mediaArts music musicTechnology nursing pharmaceuticalSciences pharmacy(PharmD) philosophy physics politicalScience politicsPhilosophyEconomics psychology publicHealth publicRelations religiousStudies sociology spanish speechLanguagePathologyAndAudiology theatre"`
- Major2 Major `json:"major2" validate:"not_equal_if_not_empty=Major0,not_equal_if_not_empty=Major1,omitempty,max=255,oneof=africanaStudies americanSignLanguage americanSignLanguage-EnglishInterpreting appliedPhysics architecturalStudies architecture art:ArtVisualStudies behavioralNeuroscience biochemistry bioengineering biology biomedicalPhysics businessAdministration businessAdministration:Accounting businessAdministration:AccountingAndAdvisoryServices businessAdministration:BrandManagement businessAdministration:BusinessAnalytics businessAdministration:CorporateInnovation businessAdministration:EntrepreneurialStartups businessAdministration:FamilyBusiness businessAdministration:Finance businessAdministration:Fintech businessAdministration:HealthcareManagementAndConsulting businessAdministration:Management businessAdministration:ManagementInformationSystems businessAdministration:Marketing businessAdministration:MarketingAnalytics businessAdministration:SocialInnovationAndEntrepreneurship businessAdministration:SupplyChainManagement cellAndMolecularBiology chemicalEngineering chemistry civilEngineering communicationStudies computerEngineering computerScience computingAndLaw criminologyAndCriminalJustice culturalAnthropology cybersecurity dataScience design economics electricalEngineering english environmentalAndSustainabilityStudies environmentalEngineering environmentalScience environmentalStudies gameArtAndAnimation gameDesign globalAsianStudies healthScience history historyCultureAndLaw humanServices industrialEngineering internationalAffairs internationalBusiness internationalBusiness:Accounting internationalBusiness:AccountingAndAdvisoryServices internationalBusiness:BrandManagement internationalBusiness:BusinessAnalytics internationalBusiness:CorporateInnovation internationalBusiness:EntrepreneurialStartups internationalBusiness:FamilyBusiness internationalBusiness:Finance internationalBusiness:Fintech internationalBusiness:HealthcareManagementAndConsulting internationalBusiness:Management internationalBusiness:ManagementInformationSystems internationalBusiness:Marketing internationalBusiness:MarketingAnalytics internationalBusiness:SocialInnovationAndEntrepreneurship internationalBusiness:SupplyChainManagement journalism landscapeArchitecture linguistics marineBiology mathematics mechanicalEngineering mediaAndScreenStudies mediaArts music musicTechnology nursing pharmaceuticalSciences pharmacy(PharmD) philosophy physics politicalScience politicsPhilosophyEconomics psychology publicHealth publicRelations religiousStudies sociology spanish speechLanguagePathologyAndAudiology theatre"`
- College College `json:"college" validate:"omitempty,oneof=CAMD DMSB KCCS CE BCHS SL CPS CS CSSH"`
- GraduationCycle GraduationCycle `json:"graduation_cycle" validate:"omitempty,max=255,oneof=december may"`
- GraduationYear int16 `json:"graduation_year" validate:"omitempty"`
-}
-
-type LoginUserResponseBody struct {
- Email string `json:"email" validate:"required,email"`
- Password string `json:"password" validate:"required,max=255"` // MARK: must be validated manually
-}
-
-type UpdatePasswordRequestBody struct {
- OldPassword string `json:"old_password" validate:"required,max=255"` // MARK: must be validated manually
- NewPassword string `json:"new_password" validate:"required,not_equal_if_not_empty=OldPassword,max=255"` // MARK: must be validated manually
-}
-
-type RefreshTokenRequestBody struct {
- RefreshToken string `json:"refresh_token" validate:"required"`
+ Tag []Tag `gorm:"many2many:user_tags;" json:"-"`
+ Admin []Club `gorm:"many2many:user_club_admins;" json:"-"`
+ Member []Club `gorm:"many2many:user_club_members;" json:"-"`
+ Follower []Club `gorm:"many2many:user_club_followers;" json:"-"`
+ IntendedApplicant []Club `gorm:"many2many:user_club_intended_applicants;" json:"-"`
+ Asked []Comment `gorm:"foreignKey:AskedByID;" json:"-"`
+ Answered []Comment `gorm:"foreignKey:AnsweredByID;" json:"-"`
+ RSVP []Event `gorm:"many2many:user_event_rsvps;" json:"-"`
+ Waitlist []Event `gorm:"many2many:user_event_waitlists;" json:"-"`
}
func (u *User) AfterCreate(tx *gorm.DB) (err error) {
diff --git a/backend/entities/models/verification.go b/backend/entities/models/verification.go
index 96ee2035a..77546ec05 100644
--- a/backend/entities/models/verification.go
+++ b/backend/entities/models/verification.go
@@ -14,23 +14,8 @@ const (
)
type Verification struct {
- UserID uuid.UUID `json:"user_id" validate:"required,uuid4"`
- Token string `json:"token" validate:"required,max=255"`
- ExpiresAt time.Time `json:"expires_at" validate:"required"`
- Type VerificationType `json:"type" validate:"required,oneof=email_verification password_reset"`
-}
-
-type VerifyEmailRequestBody struct {
- Email string `json:"email" validate:"required,email"`
- Token string `json:"token" validate:"required,len=6"`
-}
-
-type VerifyPasswordResetTokenRequestBody struct {
- Token string `json:"token" validate:"required"`
- NewPassword string `json:"new_password" validate:"required,min=8,password"`
- VerifyNewPassword string `json:"verify_new_password" validate:"required,min=8,password,eqfield=NewPassword"`
-}
-
-type EmailRequestBody struct {
- Email string `json:"email" validate:"required,email"`
+ UserID uuid.UUID `json:"user_id"`
+ Token string `json:"token"`
+ ExpiresAt time.Time `json:"expires_at"`
+ Type VerificationType `json:"type"`
}
diff --git a/backend/entities/pocs/base/controller.go b/backend/entities/pocs/base/controller.go
index d338e2307..e0d610a34 100644
--- a/backend/entities/pocs/base/controller.go
+++ b/backend/entities/pocs/base/controller.go
@@ -1,7 +1,10 @@
package base
import (
- "github.com/GenerateNU/sac/backend/constants"
+ "net/http"
+
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
"github.com/gofiber/fiber/v2"
)
@@ -23,17 +26,22 @@ func NewPointOfContactController(pointOfContactService PointOfContactServiceInte
// @Param limit query int false "Limit"
// @Param page query int false "Page"
// @Success 200 {object} []models.PointOfContact
-// @Failure 400 {string} errors.Error
-// @Failure 404 {string} errors.Error
-// @Failure 500 {string} errors.Error
+// @Failure 400 {string} error
+// @Failure 404 {string} error
+// @Failure 500 {string} error
// @Router /pocs/ [get]
func (poc *PointOfContactController) GetPointOfContacts(c *fiber.Ctx) error {
- pointOfContacts, err := poc.pointOfContactService.GetPointOfContacts(c.Query("limit", constants.DEFAULT_LIMIT_STRING), c.Query("page", constants.DEFAULT_PAGE_STRING))
+ pagination, ok := fiberpaginate.FromContext(c)
+ if !ok {
+ return utilities.ErrExpectedPagination
+ }
+
+ pointOfContacts, err := poc.pointOfContactService.GetPointOfContacts(*pagination)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(pointOfContacts)
+ return c.Status(http.StatusOK).JSON(pointOfContacts)
}
// GetPointOfContact godoc
@@ -45,15 +53,15 @@ func (poc *PointOfContactController) GetPointOfContacts(c *fiber.Ctx) error {
// @Produce json
// @Param pocID path string true "Point of Contact ID"
// @Success 200 {object} models.PointOfContact
-// @Failure 400 {string} errors.Error
-// @Failure 404 {string} errors.Error
-// @Failure 500 {string} errors.Error
+// @Failure 400 {string} error
+// @Failure 404 {string} error
+// @Failure 500 {string} error
// @Router /pocs/{pocID}/ [get]
func (poc *PointOfContactController) GetPointOfContact(c *fiber.Ctx) error {
pointOfContact, err := poc.pointOfContactService.GetPointOfContact(c.Params("pocID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(pointOfContact)
+ return c.Status(http.StatusOK).JSON(pointOfContact)
}
diff --git a/backend/entities/pocs/base/routes.go b/backend/entities/pocs/base/routes.go
index 67827a7b7..907459002 100644
--- a/backend/entities/pocs/base/routes.go
+++ b/backend/entities/pocs/base/routes.go
@@ -10,7 +10,7 @@ func PointOfContact(pointOfContactParams types.RouteParams) {
// api/v1/pocs/*
pointofContact := pointOfContactParams.Router.Group("/pocs")
- pointofContact.Get("/", pointOfContactController.GetPointOfContacts)
+ pointofContact.Get("/", pointOfContactParams.UtilityMiddleware.Paginator, pointOfContactController.GetPointOfContacts)
pointofContact.Get("/:pocID", pointOfContactController.GetPointOfContact)
- // pointOfContact.Get("/:pocID/file", pointOfContactController.GetPointOfContacFileInfo)
+ // pointOfContact.Get("/:pocID/file", pointOfContactController.GetPointOfContacFileInfo))
}
diff --git a/backend/entities/pocs/base/service.go b/backend/entities/pocs/base/service.go
index 6717c3c93..3c2b0efc9 100644
--- a/backend/entities/pocs/base/service.go
+++ b/backend/entities/pocs/base/service.go
@@ -2,14 +2,14 @@ package base
import (
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/types"
"github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
)
type PointOfContactServiceInterface interface {
- GetPointOfContacts(limit string, page string) ([]models.PointOfContact, *errors.Error)
- GetPointOfContact(pocID string) (*models.PointOfContact, *errors.Error)
+ GetPointOfContacts(pageInfo fiberpaginate.PageInfo) ([]models.PointOfContact, error)
+ GetPointOfContact(pocID string) (*models.PointOfContact, error)
}
type PointOfContactService struct {
@@ -20,24 +20,14 @@ func NewPointOfContactService(serviceParams types.ServiceParams) PointOfContactS
return &PointOfContactService{serviceParams}
}
-func (poc *PointOfContactService) GetPointOfContacts(limit string, page string) ([]models.PointOfContact, *errors.Error) {
- limitAsInt, err := utilities.ValidateNonNegative(limit)
- if err != nil {
- return nil, &errors.FailedToValidateLimit
- }
-
- pageAsInt, err := utilities.ValidateNonNegative(page)
- if err != nil {
- return nil, &errors.FailedToValidatePage
- }
-
- return GetPointOfContacts(poc.DB, *limitAsInt, *pageAsInt)
+func (poc *PointOfContactService) GetPointOfContacts(pageInfo fiberpaginate.PageInfo) ([]models.PointOfContact, error) {
+ return GetPointOfContacts(poc.DB, pageInfo)
}
-func (poc *PointOfContactService) GetPointOfContact(pocID string) (*models.PointOfContact, *errors.Error) {
+func (poc *PointOfContactService) GetPointOfContact(pocID string) (*models.PointOfContact, error) {
idAsUUID, err := utilities.ValidateID(pocID)
if err != nil {
- return nil, &errors.FailedToValidateID
+ return nil, err
}
return GetPointOfContact(poc.DB, *idAsUUID)
diff --git a/backend/entities/pocs/base/transactions.go b/backend/entities/pocs/base/transactions.go
index 910a49437..a31d5c0c9 100644
--- a/backend/entities/pocs/base/transactions.go
+++ b/backend/entities/pocs/base/transactions.go
@@ -1,40 +1,36 @@
package base
import (
- stdliberrors "errors"
+ "errors"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
"github.com/google/uuid"
"gorm.io/gorm"
)
-func GetPointOfContacts(db *gorm.DB, limit int, page int) ([]models.PointOfContact, *errors.Error) {
+func GetPointOfContacts(db *gorm.DB, pageInfo fiberpaginate.PageInfo) ([]models.PointOfContact, error) {
var pointOfContacts []models.PointOfContact
-
- offset := (page - 1) * limit
-
- result := db.Preload("PhotoFile").Limit(limit).Offset(offset).Find(&pointOfContacts)
+ result := db.Preload("PhotoFile").Scopes(utilities.IntoScope(pageInfo, db)).Find(&pointOfContacts)
if result.Error != nil {
- if stdliberrors.Is(result.Error, gorm.ErrRecordNotFound) {
- return nil, &errors.PointOfContactsNotFound
- } else {
- return nil, &errors.FailedToGetPointOfContacts
+ if errors.Is(result.Error, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
}
+ return nil, result.Error
}
return pointOfContacts, nil
}
-func GetPointOfContact(db *gorm.DB, id uuid.UUID) (*models.PointOfContact, *errors.Error) {
+func GetPointOfContact(db *gorm.DB, id uuid.UUID) (*models.PointOfContact, error) {
var pointOfContact models.PointOfContact
if err := db.Preload("PhotoFile").First(&pointOfContact, id).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.PointOfContactNotFound
- } else {
- return nil, &errors.FailedToGetPointOfContact
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
}
+ return nil, err
}
return &pointOfContact, nil
diff --git a/backend/entities/tags/base/controller.go b/backend/entities/tags/base/controller.go
index 405dbbf01..29d63572c 100644
--- a/backend/entities/tags/base/controller.go
+++ b/backend/entities/tags/base/controller.go
@@ -1,8 +1,9 @@
package base
import (
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+ "net/http"
+
+ "github.com/GenerateNU/sac/backend/utilities"
"github.com/gofiber/fiber/v2"
)
@@ -25,17 +26,17 @@ func NewTagController(tagService TagServiceInterface) *TagController {
// @Param limit query int false "Limit"
// @Param page query int false "Page"
// @Success 200 {object} []models.Tag
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /tags [get]
func (t *TagController) GetTags(c *fiber.Ctx) error {
tags, err := t.tagService.GetTags()
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(&tags)
+ return c.Status(http.StatusOK).JSON(&tags)
}
// CreateTag godoc
@@ -46,26 +47,26 @@ func (t *TagController) GetTags(c *fiber.Ctx) error {
// @Tags tag
// @Accept json
// @Produce json
-// @Param tagBody body models.CreateTagRequestBody true "Tag Body"
+// @Param tagBody body CreateTagRequestBody true "Tag Body"
// @Success 201 {object} models.Tag
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /tags/ [post]
func (t *TagController) CreateTag(c *fiber.Ctx) error {
- var tagBody models.CreateTagRequestBody
+ var tagBody CreateTagRequestBody
if err := c.BodyParser(&tagBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ return utilities.InvalidJSON()
}
dbTag, err := t.tagService.CreateTag(tagBody)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusCreated).JSON(&dbTag)
+ return c.Status(http.StatusCreated).JSON(&dbTag)
}
// GetTag godoc
@@ -77,17 +78,17 @@ func (t *TagController) CreateTag(c *fiber.Ctx) error {
// @Produce json
// @Param tagID path string true "Tag ID"
// @Success 200 {object} models.Tag
-// @Failure 400 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /tags/{tagID}/ [get]
func (t *TagController) GetTag(c *fiber.Ctx) error {
tag, err := t.tagService.GetTag(c.Params("tagID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(&tag)
+ return c.Status(http.StatusOK).JSON(&tag)
}
// UpdateTag godoc
@@ -99,26 +100,26 @@ func (t *TagController) GetTag(c *fiber.Ctx) error {
// @Accept json
// @Produce json
// @Param tagID path string true "Tag ID"
-// @Param tag body models.UpdateTagRequestBody true "Tag"
+// @Param tag body UpdateTagRequestBody true "Tag"
// @Success 200 {object} models.Tag
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /tags/{tagID}/ [patch]
func (t *TagController) UpdateTag(c *fiber.Ctx) error {
- var tagBody models.UpdateTagRequestBody
+ var tagBody UpdateTagRequestBody
if err := c.BodyParser(&tagBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ return utilities.InvalidJSON()
}
tag, err := t.tagService.UpdateTag(c.Params("tagID"), tagBody)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(&tag)
+ return c.Status(http.StatusOK).JSON(&tag)
}
// DeleteTag godoc
@@ -130,16 +131,16 @@ func (t *TagController) UpdateTag(c *fiber.Ctx) error {
// @Produce json
// @Param tagID path string true "Tag ID"
// @Success 204 {string} utilities.SuccessResponse
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /tags/{tagID}/ [delete]
func (t *TagController) DeleteTag(c *fiber.Ctx) error {
err := t.tagService.DeleteTag(c.Params("tagID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.SendStatus(fiber.StatusNoContent)
+ return c.SendStatus(http.StatusNoContent)
}
diff --git a/backend/entities/tags/base/models.go b/backend/entities/tags/base/models.go
new file mode 100644
index 000000000..ced3bd807
--- /dev/null
+++ b/backend/entities/tags/base/models.go
@@ -0,0 +1,13 @@
+package base
+
+import "github.com/google/uuid"
+
+type CreateTagRequestBody struct {
+ Name string `json:"name" validate:"required,max=255"`
+ CategoryID uuid.UUID `json:"category_id" validate:"required,uuid4"`
+}
+
+type UpdateTagRequestBody struct {
+ Name string `json:"name" validate:"omitempty,max=255"`
+ CategoryID uuid.UUID `json:"category_id" validate:"omitempty,uuid4"`
+}
diff --git a/backend/entities/tags/base/service.go b/backend/entities/tags/base/service.go
index 6a380c411..6c11a40d6 100644
--- a/backend/entities/tags/base/service.go
+++ b/backend/entities/tags/base/service.go
@@ -1,19 +1,21 @@
package base
import (
+ "errors"
+
"github.com/GenerateNU/sac/backend/entities/models"
"github.com/GenerateNU/sac/backend/entities/tags"
- "github.com/GenerateNU/sac/backend/errors"
+
"github.com/GenerateNU/sac/backend/types"
"github.com/GenerateNU/sac/backend/utilities"
)
type TagServiceInterface interface {
- GetTags() ([]models.Tag, *errors.Error)
- CreateTag(tagBody models.CreateTagRequestBody) (*models.Tag, *errors.Error)
- GetTag(id string) (*models.Tag, *errors.Error)
- UpdateTag(id string, tagBody models.UpdateTagRequestBody) (*models.Tag, *errors.Error)
- DeleteTag(id string) *errors.Error
+ GetTags() ([]models.Tag, error)
+ CreateTag(tagBody CreateTagRequestBody) (*models.Tag, error)
+ GetTag(id string) (*models.Tag, error)
+ UpdateTag(id string, tagBody UpdateTagRequestBody) (*models.Tag, error)
+ DeleteTag(id string) error
}
type TagService struct {
@@ -24,61 +26,58 @@ func NewTagService(serviceParams types.ServiceParams) TagServiceInterface {
return &TagService{serviceParams}
}
-func (t *TagService) CreateTag(tagBody models.CreateTagRequestBody) (*models.Tag, *errors.Error) {
- if err := t.Validate.Struct(tagBody); err != nil {
- return nil, &errors.FailedToValidateTag
+func (t *TagService) CreateTag(tagBody CreateTagRequestBody) (*models.Tag, error) {
+ if err := utilities.Validate(t.Validate, tagBody); err != nil {
+ return nil, err
}
- tag, err := utilities.MapRequestToModel(tagBody, &models.Tag{})
+ tag, err := utilities.MapJsonTags(tagBody, &models.Tag{})
if err != nil {
- return nil, &errors.FailedToMapRequestToModel
+ return nil, err
}
return CreateTag(t.DB, *tag)
}
-func (t *TagService) GetTags() ([]models.Tag, *errors.Error) {
+func (t *TagService) GetTags() ([]models.Tag, error) {
return GetTags(t.DB)
}
-func (t *TagService) GetTag(tagID string) (*models.Tag, *errors.Error) {
- tagIDAsUUID, idErr := utilities.ValidateID(tagID)
-
- if idErr != nil {
- return nil, idErr
+func (t *TagService) GetTag(tagID string) (*models.Tag, error) {
+ tagIDAsUUID, err := utilities.ValidateID(tagID)
+ if err != nil {
+ return nil, err
}
return tags.GetTag(t.DB, *tagIDAsUUID)
}
-func (t *TagService) UpdateTag(tagID string, tagBody models.UpdateTagRequestBody) (*models.Tag, *errors.Error) {
- tagIDAsUUID, idErr := utilities.ValidateID(tagID)
-
- if idErr != nil {
- return nil, idErr
+func (t *TagService) UpdateTag(tagID string, tagBody UpdateTagRequestBody) (*models.Tag, error) {
+ tagIDAsUUID, err := utilities.ValidateID(tagID)
+ if err != nil {
+ return nil, err
}
- if utilities.AtLeastOne(tagBody, models.UpdateTagRequestBody{}) {
- return nil, &errors.FailedToValidateTag
+ if utilities.AtLeastOne(tagBody, UpdateTagRequestBody{}) {
+ return nil, errors.New("at least one field must be present")
}
- if err := t.Validate.Struct(tagBody); err != nil {
- return nil, &errors.FailedToValidateTag
+ if err := utilities.Validate(t.Validate, tagBody); err != nil {
+ return nil, err
}
- tag, err := utilities.MapRequestToModel(tagBody, &models.Tag{})
+ tag, err := utilities.MapJsonTags(tagBody, &models.Tag{})
if err != nil {
- return nil, &errors.FailedToMapRequestToModel
+ return nil, err
}
return UpdateTag(t.DB, *tagIDAsUUID, *tag)
}
-func (t *TagService) DeleteTag(tagID string) *errors.Error {
- tagIDAsUUID, idErr := utilities.ValidateID(tagID)
-
- if idErr != nil {
- return idErr
+func (t *TagService) DeleteTag(tagID string) error {
+ tagIDAsUUID, err := utilities.ValidateID(tagID)
+ if err != nil {
+ return err
}
return DeleteTag(t.DB, *tagIDAsUUID)
diff --git a/backend/entities/tags/base/transactions.go b/backend/entities/tags/base/transactions.go
index bed204b71..b1aa2cd76 100644
--- a/backend/entities/tags/base/transactions.go
+++ b/backend/entities/tags/base/transactions.go
@@ -1,86 +1,89 @@
package base
import (
- stdliberrors "errors"
+ "errors"
- "github.com/GenerateNU/sac/backend/errors"
+ "github.com/GenerateNU/sac/backend/utilities"
"github.com/google/uuid"
"github.com/GenerateNU/sac/backend/entities/models"
"github.com/GenerateNU/sac/backend/entities/tags"
"gorm.io/gorm"
+ "gorm.io/gorm/clause"
)
-func CreateTag(db *gorm.DB, tag models.Tag) (*models.Tag, *errors.Error) {
+func CreateTag(db *gorm.DB, tag models.Tag) (*models.Tag, error) {
tx := db.Begin()
+ defer func() {
+ if r := recover(); r != nil {
+ tx.Rollback()
+ }
+ }()
var category models.Category
if err := tx.Where("id = ?", tag.CategoryID).First(&category).Error; err != nil {
- if err == gorm.ErrRecordNotFound {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
tx.Rollback()
- return nil, &errors.CategoryNotFound
+ return nil, utilities.ErrNotFound
} else {
tx.Rollback()
- return nil, &errors.InternalServerError
+ return nil, err
}
}
if err := tx.Create(&tag).Error; err != nil {
tx.Rollback()
- return nil, &errors.FailedToCreateTag
+ return nil, err
}
- tx.Commit()
-
- return &tag, nil
+ return &tag, tx.Commit().Error
}
-func GetTags(db *gorm.DB) ([]models.Tag, *errors.Error) {
+func GetTags(db *gorm.DB) ([]models.Tag, error) {
var tags []models.Tag
if err := db.Find(&tags).Error; err != nil {
- return nil, &errors.FailedToGetTags
+ return nil, err
}
return tags, nil
}
-func UpdateTag(db *gorm.DB, id uuid.UUID, tag models.Tag) (*models.Tag, *errors.Error) {
- if err := db.Model(&models.Tag{}).Where("id = ?", id).Updates(tag).First(&tag, id).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.TagNotFound
- } else {
- return nil, &errors.FailedToUpdateTag
+func UpdateTag(db *gorm.DB, id uuid.UUID, tag models.Tag) (*models.Tag, error) {
+ var resultingTag models.Tag
+ if err := db.Model(&resultingTag).Clauses(clause.Returning{}).Where("id = ?", id).Updates(tag).First(&tag, id).Error; err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
}
+ return nil, err
}
- return &tag, nil
+ return &resultingTag, nil
}
-func DeleteTag(db *gorm.DB, tagID uuid.UUID) *errors.Error {
+func DeleteTag(db *gorm.DB, tagID uuid.UUID) error {
if result := db.Where("id = ?", tagID).Delete(&models.Tag{}); result.RowsAffected == 0 {
if result.Error == nil {
- return &errors.TagNotFound
- } else {
- return &errors.FailedToDeleteTag
+ return utilities.ErrNotFound
}
+ return result.Error
}
return nil
}
-// Get clubs for a tag
-func GetTagClubs(db *gorm.DB, id uuid.UUID) ([]models.Club, *errors.Error) {
+func GetTagClubs(db *gorm.DB, id uuid.UUID) ([]models.Club, error) {
var clubs []models.Club
tag, err := tags.GetTag(db, id)
if err != nil {
- return nil, &errors.ClubNotFound
+ return nil, err
}
if err := db.Model(&tag).Association("Club").Find(&clubs); err != nil {
- return nil, &errors.FailedToGetTag
+ return nil, err
}
+
return clubs, nil
}
diff --git a/backend/entities/tags/transactions.go b/backend/entities/tags/transactions.go
index 447fe7d90..5b795ce47 100644
--- a/backend/entities/tags/transactions.go
+++ b/backend/entities/tags/transactions.go
@@ -1,32 +1,31 @@
package tags
import (
- stdliberrors "errors"
+ "errors"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+ "github.com/GenerateNU/sac/backend/utilities"
"github.com/google/uuid"
"gorm.io/gorm"
)
-func GetTag(db *gorm.DB, tagID uuid.UUID) (*models.Tag, *errors.Error) {
+func GetTag(db *gorm.DB, tagID uuid.UUID) (*models.Tag, error) {
var tag models.Tag
if err := db.Where("id = ?", tagID).First(&tag).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.TagNotFound
- } else {
- return nil, &errors.FailedToGetTag
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
}
+ return nil, err
}
return &tag, nil
}
-func GetTagsByIDs(db *gorm.DB, selectedTagIDs []uuid.UUID) ([]models.Tag, *errors.Error) {
+func GetTagsByIDs(db *gorm.DB, selectedTagIDs []uuid.UUID) ([]models.Tag, error) {
if len(selectedTagIDs) != 0 {
var tags []models.Tag
if err := db.Model(models.Tag{}).Where("id IN ?", selectedTagIDs).Find(&tags).Error; err != nil {
- return nil, &errors.FailedToGetTag
+ return nil, err
}
return tags, nil
diff --git a/backend/entities/users/base/controller.go b/backend/entities/users/base/controller.go
index e6f2373d4..2a158273c 100644
--- a/backend/entities/users/base/controller.go
+++ b/backend/entities/users/base/controller.go
@@ -1,11 +1,12 @@
package base
import (
+ "net/http"
+
"github.com/GenerateNU/sac/backend/auth"
- "github.com/GenerateNU/sac/backend/constants"
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+ authEntities "github.com/GenerateNU/sac/backend/entities/auth"
"github.com/GenerateNU/sac/backend/utilities"
+ "github.com/garrettladley/fiberpaginate"
"github.com/gofiber/fiber/v2"
)
@@ -18,42 +19,6 @@ func NewUserController(userService UserServiceInterface) *UserController {
return &UserController{userService: userService}
}
-// CreateUser godoc
-//
-// @Summary Create a user
-// @Description Creates a user
-// @ID create-user
-// @Tags user
-// @Accept json
-// @Produce json
-// @Param userBody body models.CreateUserRequestBody true "User Body"
-// @Success 201 {object} models.User
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 409 {object} errors.Error
-// @Failure 500 {object} errors.Error
-// @Router /users/ [post]
-func (u *UserController) CreateUser(c *fiber.Ctx) error {
- var userBody models.CreateUserRequestBody
-
- if err := c.BodyParser(&userBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
- }
-
- user, tokens, err := u.userService.CreateUser(userBody)
- if err != nil {
- return err.FiberError(c)
- }
-
- err = auth.SetResponseTokens(c, tokens)
- if err != nil {
- return err.FiberError(c)
- }
-
- return c.Status(fiber.StatusCreated).JSON(user)
-}
-
// GetUsers godoc
//
// @Summary Retrieve all users
@@ -64,17 +29,22 @@ func (u *UserController) CreateUser(c *fiber.Ctx) error {
// @Param limit query int false "Limit"
// @Param page query int false "Page"
// @Success 200 {object} []models.User
-// @Failure 401 {object} errors.Error
-// @Failure 400 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 401 {object} error
+// @Failure 400 {object} error
+// @Failure 500 {object} error
// @Router /users/ [get]
func (u *UserController) GetUsers(c *fiber.Ctx) error {
- users, err := u.userService.GetUsers(c.Query("limit", constants.DEFAULT_LIMIT_STRING), c.Query("page", constants.DEFAULT_PAGE_STRING))
+ pagination, ok := fiberpaginate.FromContext(c)
+ if !ok {
+ return utilities.ErrExpectedPagination
+ }
+
+ users, err := u.userService.GetUsers(*pagination)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(&users)
+ return c.Status(http.StatusOK).JSON(&users)
}
// Me godoc
@@ -87,23 +57,23 @@ func (u *UserController) GetUsers(c *fiber.Ctx) error {
// @Produce json
// @Security Bearer
// @Success 200 {object} models.User
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /auth/me [get]
func (u *UserController) GetMe(c *fiber.Ctx) error {
claims, err := auth.From(c)
if err != nil {
- return err.FiberError(c)
+ return err
}
user, err := u.userService.GetMe(claims.Issuer)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(user)
+ return c.Status(http.StatusOK).JSON(user)
}
// GetUser godoc
@@ -115,18 +85,18 @@ func (u *UserController) GetMe(c *fiber.Ctx) error {
// @Produce json
// @Param userID path string true "User ID"
// @Success 200 {object} models.User
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /users/{userID}/ [get]
func (u *UserController) GetUser(c *fiber.Ctx) error {
user, err := u.userService.GetUser(c.Params("userID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(user)
+ return c.Status(http.StatusOK).JSON(user)
}
// UpdateUser godoc
@@ -138,26 +108,26 @@ func (u *UserController) GetUser(c *fiber.Ctx) error {
// @Accept json
// @Produce json
// @Param userID path string true "User ID"
-// @Param userBody body models.UpdateUserRequestBody true "User Body"
+// @Param userBody body UpdateUserRequestBody true "User Body"
// @Success 200 {object} models.User
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /users/{userID}/ [patch]
func (u *UserController) UpdateUser(c *fiber.Ctx) error {
- var user models.UpdateUserRequestBody
+ var user UpdateUserRequestBody
if err := c.BodyParser(&user); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ return utilities.InvalidJSON()
}
updatedUser, err := u.userService.UpdateUser(c.Params("userID"), user)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(updatedUser)
+ return c.Status(http.StatusOK).JSON(updatedUser)
}
// UpdatePassword godoc
@@ -169,26 +139,26 @@ func (u *UserController) UpdateUser(c *fiber.Ctx) error {
// @Accept json
// @Produce json
// @Param userID path string true "User ID"
-// @Param passwordBody body models.UpdatePasswordRequestBody true "Password Body"
+// @Param passwordBody body authEntities.UpdatePasswordRequestBody true "Password Body"
// @Success 200 {string} utilities.SuccessResponse
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /users/{userID}/password [patch]
func (u *UserController) UpdatePassword(c *fiber.Ctx) error {
- var passwordBody models.UpdatePasswordRequestBody
+ var passwordBody authEntities.UpdatePasswordRequestBody
if err := c.BodyParser(&passwordBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ return utilities.InvalidJSON()
}
err := u.userService.UpdatePassword(c.Params("userID"), passwordBody)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return utilities.FiberMessage(c, fiber.StatusOK, "success")
+ return utilities.FiberMessage(c, http.StatusOK, "success")
}
// DeleteUser godoc
@@ -200,16 +170,16 @@ func (u *UserController) UpdatePassword(c *fiber.Ctx) error {
// @Produce json
// @Param userID path string true "User ID"
// @Success 204 {string} utilities.SuccessResponse
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /users/{userID}/ [delete]
func (u *UserController) DeleteUser(c *fiber.Ctx) error {
err := u.userService.DeleteUser(c.Params("userID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.SendStatus(fiber.StatusNoContent)
+ return c.SendStatus(http.StatusNoContent)
}
diff --git a/backend/entities/users/base/models.go b/backend/entities/users/base/models.go
new file mode 100644
index 000000000..d145e8993
--- /dev/null
+++ b/backend/entities/users/base/models.go
@@ -0,0 +1,28 @@
+package base
+
+import "github.com/GenerateNU/sac/backend/entities/models"
+
+type CreateUserRequestBody struct {
+ FirstName string `json:"first_name" validate:"required,max=255"`
+ LastName string `json:"last_name" validate:"required,max=255"`
+ Email string `json:"email" validate:"required,email,neu_email,max=255"`
+ Password string `json:"password" validate:"required,max=255"` // MARK: must be validated manually
+ // Optional fields
+ Major0 models.Major `json:"major0" validate:"not_equal_if_not_empty=Major1,not_equal_if_not_empty=Major2,omitempty,max=255,oneof=africanaStudies americanSignLanguage americanSignLanguage-EnglishInterpreting appliedPhysics architecturalStudies architecture art:ArtVisualStudies behavioralNeuroscience biochemistry bioengineering biology biomedicalPhysics businessAdministration businessAdministration:Accounting businessAdministration:AccountingAndAdvisoryServices businessAdministration:BrandManagement businessAdministration:BusinessAnalytics businessAdministration:CorporateInnovation businessAdministration:EntrepreneurialStartups businessAdministration:FamilyBusiness businessAdministration:Finance businessAdministration:Fintech businessAdministration:HealthcareManagementAndConsulting businessAdministration:Management businessAdministration:ManagementInformationSystems businessAdministration:Marketing businessAdministration:MarketingAnalytics businessAdministration:SocialInnovationAndEntrepreneurship businessAdministration:SupplyChainManagement cellAndMolecularBiology chemicalEngineering chemistry civilEngineering communicationStudies computerEngineering computerScience computingAndLaw criminologyAndCriminalJustice culturalAnthropology cybersecurity dataScience design economics electricalEngineering english environmentalAndSustainabilityStudies environmentalEngineering environmentalScience environmentalStudies gameArtAndAnimation gameDesign globalAsianStudies healthScience history historyCultureAndLaw humanServices industrialEngineering internationalAffairs internationalBusiness internationalBusiness:Accounting internationalBusiness:AccountingAndAdvisoryServices internationalBusiness:BrandManagement internationalBusiness:BusinessAnalytics internationalBusiness:CorporateInnovation internationalBusiness:EntrepreneurialStartups internationalBusiness:FamilyBusiness internationalBusiness:Finance internationalBusiness:Fintech internationalBusiness:HealthcareManagementAndConsulting internationalBusiness:Management internationalBusiness:ManagementInformationSystems internationalBusiness:Marketing internationalBusiness:MarketingAnalytics internationalBusiness:SocialInnovationAndEntrepreneurship internationalBusiness:SupplyChainManagement journalism landscapeArchitecture linguistics marineBiology mathematics mechanicalEngineering mediaAndScreenStudies mediaArts music musicTechnology nursing pharmaceuticalSciences pharmacy(PharmD) philosophy physics politicalScience politicsPhilosophyEconomics psychology publicHealth publicRelations religiousStudies sociology spanish speechLanguagePathologyAndAudiology theatre"`
+ Major1 models.Major `json:"major1" validate:"not_equal_if_not_empty=Major0,not_equal_if_not_empty=Major2,omitempty,max=255,oneof=africanaStudies americanSignLanguage americanSignLanguage-EnglishInterpreting appliedPhysics architecturalStudies architecture art:ArtVisualStudies behavioralNeuroscience biochemistry bioengineering biology biomedicalPhysics businessAdministration businessAdministration:Accounting businessAdministration:AccountingAndAdvisoryServices businessAdministration:BrandManagement businessAdministration:BusinessAnalytics businessAdministration:CorporateInnovation businessAdministration:EntrepreneurialStartups businessAdministration:FamilyBusiness businessAdministration:Finance businessAdministration:Fintech businessAdministration:HealthcareManagementAndConsulting businessAdministration:Management businessAdministration:ManagementInformationSystems businessAdministration:Marketing businessAdministration:MarketingAnalytics businessAdministration:SocialInnovationAndEntrepreneurship businessAdministration:SupplyChainManagement cellAndMolecularBiology chemicalEngineering chemistry civilEngineering communicationStudies computerEngineering computerScience computingAndLaw criminologyAndCriminalJustice culturalAnthropology cybersecurity dataScience design economics electricalEngineering english environmentalAndSustainabilityStudies environmentalEngineering environmentalScience environmentalStudies gameArtAndAnimation gameDesign globalAsianStudies healthScience history historyCultureAndLaw humanServices industrialEngineering internationalAffairs internationalBusiness internationalBusiness:Accounting internationalBusiness:AccountingAndAdvisoryServices internationalBusiness:BrandManagement internationalBusiness:BusinessAnalytics internationalBusiness:CorporateInnovation internationalBusiness:EntrepreneurialStartups internationalBusiness:FamilyBusiness internationalBusiness:Finance internationalBusiness:Fintech internationalBusiness:HealthcareManagementAndConsulting internationalBusiness:Management internationalBusiness:ManagementInformationSystems internationalBusiness:Marketing internationalBusiness:MarketingAnalytics internationalBusiness:SocialInnovationAndEntrepreneurship internationalBusiness:SupplyChainManagement journalism landscapeArchitecture linguistics marineBiology mathematics mechanicalEngineering mediaAndScreenStudies mediaArts music musicTechnology nursing pharmaceuticalSciences pharmacy(PharmD) philosophy physics politicalScience politicsPhilosophyEconomics psychology publicHealth publicRelations religiousStudies sociology spanish speechLanguagePathologyAndAudiology theatre"`
+ Major2 models.Major `json:"major2" validate:"not_equal_if_not_empty=Major0,not_equal_if_not_empty=Major1,omitempty,max=255,oneof=africanaStudies americanSignLanguage americanSignLanguage-EnglishInterpreting appliedPhysics architecturalStudies architecture art:ArtVisualStudies behavioralNeuroscience biochemistry bioengineering biology biomedicalPhysics businessAdministration businessAdministration:Accounting businessAdministration:AccountingAndAdvisoryServices businessAdministration:BrandManagement businessAdministration:BusinessAnalytics businessAdministration:CorporateInnovation businessAdministration:EntrepreneurialStartups businessAdministration:FamilyBusiness businessAdministration:Finance businessAdministration:Fintech businessAdministration:HealthcareManagementAndConsulting businessAdministration:Management businessAdministration:ManagementInformationSystems businessAdministration:Marketing businessAdministration:MarketingAnalytics businessAdministration:SocialInnovationAndEntrepreneurship businessAdministration:SupplyChainManagement cellAndMolecularBiology chemicalEngineering chemistry civilEngineering communicationStudies computerEngineering computerScience computingAndLaw criminologyAndCriminalJustice culturalAnthropology cybersecurity dataScience design economics electricalEngineering english environmentalAndSustainabilityStudies environmentalEngineering environmentalScience environmentalStudies gameArtAndAnimation gameDesign globalAsianStudies healthScience history historyCultureAndLaw humanServices industrialEngineering internationalAffairs internationalBusiness internationalBusiness:Accounting internationalBusiness:AccountingAndAdvisoryServices internationalBusiness:BrandManagement internationalBusiness:BusinessAnalytics internationalBusiness:CorporateInnovation internationalBusiness:EntrepreneurialStartups internationalBusiness:FamilyBusiness internationalBusiness:Finance internationalBusiness:Fintech internationalBusiness:HealthcareManagementAndConsulting internationalBusiness:Management internationalBusiness:ManagementInformationSystems internationalBusiness:Marketing internationalBusiness:MarketingAnalytics internationalBusiness:SocialInnovationAndEntrepreneurship internationalBusiness:SupplyChainManagement journalism landscapeArchitecture linguistics marineBiology mathematics mechanicalEngineering mediaAndScreenStudies mediaArts music musicTechnology nursing pharmaceuticalSciences pharmacy(PharmD) philosophy physics politicalScience politicsPhilosophyEconomics psychology publicHealth publicRelations religiousStudies sociology spanish speechLanguagePathologyAndAudiology theatre"`
+ College models.College `json:"college" validate:"omitempty,oneof=CAMD DMSB KCCS CE BCHS SL CPS CS CSSH"`
+ GraduationCycle models.GraduationCycle `json:"graduation_cycle" validate:"omitempty,max=255,oneof=december may"`
+ GraduationYear int16 `json:"graduation_year" validate:"omitempty"`
+}
+
+type UpdateUserRequestBody struct {
+ FirstName string `json:"first_name" validate:"omitempty,max=255"`
+ LastName string `json:"last_name" validate:"omitempty,max=255"`
+ Major0 models.Major `json:"major0" validate:"not_equal_if_not_empty=Major1,not_equal_if_not_empty=Major2,omitempty,max=255,oneof=africanaStudies americanSignLanguage americanSignLanguage-EnglishInterpreting appliedPhysics architecturalStudies architecture art:ArtVisualStudies behavioralNeuroscience biochemistry bioengineering biology biomedicalPhysics businessAdministration businessAdministration:Accounting businessAdministration:AccountingAndAdvisoryServices businessAdministration:BrandManagement businessAdministration:BusinessAnalytics businessAdministration:CorporateInnovation businessAdministration:EntrepreneurialStartups businessAdministration:FamilyBusiness businessAdministration:Finance businessAdministration:Fintech businessAdministration:HealthcareManagementAndConsulting businessAdministration:Management businessAdministration:ManagementInformationSystems businessAdministration:Marketing businessAdministration:MarketingAnalytics businessAdministration:SocialInnovationAndEntrepreneurship businessAdministration:SupplyChainManagement cellAndMolecularBiology chemicalEngineering chemistry civilEngineering communicationStudies computerEngineering computerScience computingAndLaw criminologyAndCriminalJustice culturalAnthropology cybersecurity dataScience design economics electricalEngineering english environmentalAndSustainabilityStudies environmentalEngineering environmentalScience environmentalStudies gameArtAndAnimation gameDesign globalAsianStudies healthScience history historyCultureAndLaw humanServices industrialEngineering internationalAffairs internationalBusiness internationalBusiness:Accounting internationalBusiness:AccountingAndAdvisoryServices internationalBusiness:BrandManagement internationalBusiness:BusinessAnalytics internationalBusiness:CorporateInnovation internationalBusiness:EntrepreneurialStartups internationalBusiness:FamilyBusiness internationalBusiness:Finance internationalBusiness:Fintech internationalBusiness:HealthcareManagementAndConsulting internationalBusiness:Management internationalBusiness:ManagementInformationSystems internationalBusiness:Marketing internationalBusiness:MarketingAnalytics internationalBusiness:SocialInnovationAndEntrepreneurship internationalBusiness:SupplyChainManagement journalism landscapeArchitecture linguistics marineBiology mathematics mechanicalEngineering mediaAndScreenStudies mediaArts music musicTechnology nursing pharmaceuticalSciences pharmacy(PharmD) philosophy physics politicalScience politicsPhilosophyEconomics psychology publicHealth publicRelations religiousStudies sociology spanish speechLanguagePathologyAndAudiology theatre"`
+ Major1 models.Major `json:"major1" validate:"not_equal_if_not_empty=Major0,not_equal_if_not_empty=Major2,omitempty,max=255,oneof=africanaStudies americanSignLanguage americanSignLanguage-EnglishInterpreting appliedPhysics architecturalStudies architecture art:ArtVisualStudies behavioralNeuroscience biochemistry bioengineering biology biomedicalPhysics businessAdministration businessAdministration:Accounting businessAdministration:AccountingAndAdvisoryServices businessAdministration:BrandManagement businessAdministration:BusinessAnalytics businessAdministration:CorporateInnovation businessAdministration:EntrepreneurialStartups businessAdministration:FamilyBusiness businessAdministration:Finance businessAdministration:Fintech businessAdministration:HealthcareManagementAndConsulting businessAdministration:Management businessAdministration:ManagementInformationSystems businessAdministration:Marketing businessAdministration:MarketingAnalytics businessAdministration:SocialInnovationAndEntrepreneurship businessAdministration:SupplyChainManagement cellAndMolecularBiology chemicalEngineering chemistry civilEngineering communicationStudies computerEngineering computerScience computingAndLaw criminologyAndCriminalJustice culturalAnthropology cybersecurity dataScience design economics electricalEngineering english environmentalAndSustainabilityStudies environmentalEngineering environmentalScience environmentalStudies gameArtAndAnimation gameDesign globalAsianStudies healthScience history historyCultureAndLaw humanServices industrialEngineering internationalAffairs internationalBusiness internationalBusiness:Accounting internationalBusiness:AccountingAndAdvisoryServices internationalBusiness:BrandManagement internationalBusiness:BusinessAnalytics internationalBusiness:CorporateInnovation internationalBusiness:EntrepreneurialStartups internationalBusiness:FamilyBusiness internationalBusiness:Finance internationalBusiness:Fintech internationalBusiness:HealthcareManagementAndConsulting internationalBusiness:Management internationalBusiness:ManagementInformationSystems internationalBusiness:Marketing internationalBusiness:MarketingAnalytics internationalBusiness:SocialInnovationAndEntrepreneurship internationalBusiness:SupplyChainManagement journalism landscapeArchitecture linguistics marineBiology mathematics mechanicalEngineering mediaAndScreenStudies mediaArts music musicTechnology nursing pharmaceuticalSciences pharmacy(PharmD) philosophy physics politicalScience politicsPhilosophyEconomics psychology publicHealth publicRelations religiousStudies sociology spanish speechLanguagePathologyAndAudiology theatre"`
+ Major2 models.Major `json:"major2" validate:"not_equal_if_not_empty=Major0,not_equal_if_not_empty=Major1,omitempty,max=255,oneof=africanaStudies americanSignLanguage americanSignLanguage-EnglishInterpreting appliedPhysics architecturalStudies architecture art:ArtVisualStudies behavioralNeuroscience biochemistry bioengineering biology biomedicalPhysics businessAdministration businessAdministration:Accounting businessAdministration:AccountingAndAdvisoryServices businessAdministration:BrandManagement businessAdministration:BusinessAnalytics businessAdministration:CorporateInnovation businessAdministration:EntrepreneurialStartups businessAdministration:FamilyBusiness businessAdministration:Finance businessAdministration:Fintech businessAdministration:HealthcareManagementAndConsulting businessAdministration:Management businessAdministration:ManagementInformationSystems businessAdministration:Marketing businessAdministration:MarketingAnalytics businessAdministration:SocialInnovationAndEntrepreneurship businessAdministration:SupplyChainManagement cellAndMolecularBiology chemicalEngineering chemistry civilEngineering communicationStudies computerEngineering computerScience computingAndLaw criminologyAndCriminalJustice culturalAnthropology cybersecurity dataScience design economics electricalEngineering english environmentalAndSustainabilityStudies environmentalEngineering environmentalScience environmentalStudies gameArtAndAnimation gameDesign globalAsianStudies healthScience history historyCultureAndLaw humanServices industrialEngineering internationalAffairs internationalBusiness internationalBusiness:Accounting internationalBusiness:AccountingAndAdvisoryServices internationalBusiness:BrandManagement internationalBusiness:BusinessAnalytics internationalBusiness:CorporateInnovation internationalBusiness:EntrepreneurialStartups internationalBusiness:FamilyBusiness internationalBusiness:Finance internationalBusiness:Fintech internationalBusiness:HealthcareManagementAndConsulting internationalBusiness:Management internationalBusiness:ManagementInformationSystems internationalBusiness:Marketing internationalBusiness:MarketingAnalytics internationalBusiness:SocialInnovationAndEntrepreneurship internationalBusiness:SupplyChainManagement journalism landscapeArchitecture linguistics marineBiology mathematics mechanicalEngineering mediaAndScreenStudies mediaArts music musicTechnology nursing pharmaceuticalSciences pharmacy(PharmD) philosophy physics politicalScience politicsPhilosophyEconomics psychology publicHealth publicRelations religiousStudies sociology spanish speechLanguagePathologyAndAudiology theatre"`
+ College models.College `json:"college" validate:"omitempty,oneof=CAMD DMSB KCCS CE BCHS SL CPS CS CSSH"`
+ GraduationCycle models.GraduationCycle `json:"graduation_cycle" validate:"omitempty,max=255,oneof=december may"`
+ GraduationYear int16 `json:"graduation_year" validate:"omitempty"`
+}
diff --git a/backend/entities/users/base/routes.go b/backend/entities/users/base/routes.go
index 2a0a9c67b..898a981ba 100644
--- a/backend/entities/users/base/routes.go
+++ b/backend/entities/users/base/routes.go
@@ -2,9 +2,9 @@ package base
import (
p "github.com/GenerateNU/sac/backend/auth"
- "github.com/GenerateNU/sac/backend/entities/users/follower"
- "github.com/GenerateNU/sac/backend/entities/users/member"
- "github.com/GenerateNU/sac/backend/entities/users/tag"
+ "github.com/GenerateNU/sac/backend/entities/users/followers"
+ "github.com/GenerateNU/sac/backend/entities/users/members"
+ "github.com/GenerateNU/sac/backend/entities/users/tags"
"github.com/GenerateNU/sac/backend/types"
"github.com/gofiber/fiber/v2"
@@ -15,9 +15,9 @@ func UserRoutes(userParams types.RouteParams) {
userParams.Router = usersRouter
- tag.UserTag(userParams)
- follower.UserFollower(userParams)
- member.UserMember(userParams)
+ tags.UserTag(userParams)
+ followers.UserFollower(userParams)
+ members.UserMember(userParams)
}
func UsersRouter(userParams types.RouteParams) fiber.Router {
@@ -26,8 +26,7 @@ func UsersRouter(userParams types.RouteParams) fiber.Router {
// api/v1/users/*
users := userParams.Router.Group("/users")
- users.Get("/", userParams.AuthMiddleware.Authorize(p.ReadAll), userController.GetUsers)
- users.Post("/", userController.CreateUser)
+ users.Get("/", userParams.AuthMiddleware.Authorize(p.ReadAll), userParams.UtilityMiddleware.Paginator, userController.GetUsers)
users.Get("/me", userParams.AuthMiddleware.Authorize(p.UserRead), userController.GetMe)
// api/v1/users/:userID/*
diff --git a/backend/entities/users/base/service.go b/backend/entities/users/base/service.go
index 29f16a3dc..92b03cfa2 100644
--- a/backend/entities/users/base/service.go
+++ b/backend/entities/users/base/service.go
@@ -1,27 +1,25 @@
package base
import (
- "fmt"
- "strings"
+ "errors"
"github.com/GenerateNU/sac/backend/auth"
- "github.com/GenerateNU/sac/backend/entities/auth/base"
+ authEntities "github.com/GenerateNU/sac/backend/entities/auth"
"github.com/GenerateNU/sac/backend/entities/models"
+ "github.com/garrettladley/fiberpaginate"
"github.com/GenerateNU/sac/backend/entities/users"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/types"
"github.com/GenerateNU/sac/backend/utilities"
)
type UserServiceInterface interface {
- GetUsers(limit string, page string) ([]models.User, *errors.Error)
- GetMe(id string) (*models.User, *errors.Error)
- GetUser(id string) (*models.User, *errors.Error)
- CreateUser(userBody models.CreateUserRequestBody) (*models.User, *auth.Token, *errors.Error)
- UpdateUser(id string, userBody models.UpdateUserRequestBody) (*models.User, *errors.Error)
- UpdatePassword(id string, passwordBody models.UpdatePasswordRequestBody) *errors.Error
- DeleteUser(id string) *errors.Error
+ GetUsers(pageInfo fiberpaginate.PageInfo) ([]models.User, error)
+ GetMe(id string) (*models.User, error)
+ GetUser(id string) (*models.User, error)
+ UpdateUser(id string, userBody UpdateUserRequestBody) (*models.User, error)
+ UpdatePassword(id string, passwordBody authEntities.UpdatePasswordRequestBody) error
+ DeleteUser(id string) error
}
type UserService struct {
@@ -32,70 +30,14 @@ func NewUserService(serviceParams types.ServiceParams) UserServiceInterface {
return &UserService{serviceParams}
}
-func (u *UserService) CreateUser(userBody models.CreateUserRequestBody) (*models.User, *auth.Token, *errors.Error) {
- if err := u.Validate.Struct(userBody); err != nil {
- return nil, nil, &errors.FailedToValidateUser
- }
-
- if pwordValErr := auth.ValidatePassword(userBody.Password); pwordValErr != nil {
- return nil, nil, pwordValErr
- }
-
- user, err := utilities.MapRequestToModel(userBody, &models.User{})
- if err != nil {
- return nil, nil, &errors.FailedToMapRequestToModel
- }
-
- passwordHash, err := auth.ComputeHash(userBody.Password)
- if err != nil {
- return nil, nil, &errors.FailedToComputePasswordHash
- }
-
- user.Email = strings.ToLower(userBody.Email)
- user.PasswordHash = *passwordHash
-
- emailErr := u.Integrations.Email.SendWelcomeEmail(fmt.Sprintf("%s %s", user.FirstName, user.LastName), user.Email)
- if emailErr != nil {
- return nil, nil, &errors.FailedToSendEmail
- }
-
- user, userErr := CreateUser(u.DB, user)
- if userErr != nil {
- return nil, nil, userErr
- }
-
- authService := base.NewAuthService(u.ServiceParams)
- authErr := authService.SendCode(user.Email)
- if authErr != nil {
- return nil, nil, authErr
- }
-
- _, tokens, authErr := authService.Login(models.LoginUserResponseBody{Email: user.Email, Password: userBody.Password})
- if authErr != nil {
- return nil, nil, authErr
- }
-
- return user, tokens, nil
+func (u *UserService) GetUsers(pageInfo fiberpaginate.PageInfo) ([]models.User, error) {
+ return GetUsers(u.DB, pageInfo)
}
-func (u *UserService) GetUsers(limit string, page string) ([]models.User, *errors.Error) {
- limitAsInt, err := utilities.ValidateNonNegative(limit)
- if err != nil {
- return nil, &errors.FailedToValidateLimit
- }
-
- pageAsInt, err := utilities.ValidateNonNegative(page)
+func (u *UserService) GetMe(id string) (*models.User, error) {
+ idAsUUID, err := utilities.ValidateID(id)
if err != nil {
- return nil, &errors.FailedToValidatePage
- }
-
- return GetUsers(u.DB, *limitAsInt, *pageAsInt)
-}
-
-func (u *UserService) GetMe(id string) (*models.User, *errors.Error) {
- idAsUUID, idErr := utilities.ValidateID(id)
- if idErr != nil {
- return nil, idErr
+ return nil, err
}
user, err := users.GetUser(u.DB, *idAsUUID)
@@ -106,53 +48,47 @@ func (u *UserService) GetMe(id string) (*models.User, *errors.Error) {
return user, nil
}
-func (u *UserService) GetUser(id string) (*models.User, *errors.Error) {
+func (u *UserService) GetUser(id string) (*models.User, error) {
idAsUUID, err := utilities.ValidateID(id)
if err != nil {
- return nil, &errors.FailedToValidateID
+ return nil, err
}
return users.GetUser(u.DB, *idAsUUID)
}
-func (u *UserService) UpdateUser(id string, userBody models.UpdateUserRequestBody) (*models.User, *errors.Error) {
+func (u *UserService) UpdateUser(id string, userBody UpdateUserRequestBody) (*models.User, error) {
idAsUUID, idErr := utilities.ValidateID(id)
if idErr != nil {
return nil, idErr
}
- if utilities.AtLeastOne(userBody, models.UpdateUserRequestBody{}) {
- return nil, &errors.FailedToValidateUser
+ if utilities.AtLeastOne(userBody, UpdateUserRequestBody{}) {
+ return nil, errors.New("no fields to update")
}
- if err := u.Validate.Struct(userBody); err != nil {
- return nil, &errors.FailedToValidateUser
+ if err := utilities.Validate(u.Validate, userBody); err != nil {
+ return nil, err
}
- user, err := utilities.MapRequestToModel(userBody, &models.User{})
+ user, err := utilities.MapJsonTags(userBody, &models.User{})
if err != nil {
- return nil, &errors.FailedToMapRequestToModel
+ return nil, err
}
return UpdateUser(u.DB, *idAsUUID, *user)
}
-func (u *UserService) UpdatePassword(id string, passwordBody models.UpdatePasswordRequestBody) *errors.Error {
- idAsUUID, idErr := utilities.ValidateID(id)
- if idErr != nil {
- return idErr
- }
-
- if err := u.Validate.Struct(passwordBody); err != nil {
- return &errors.FailedToValidateUpdatePasswordBody
- }
-
- if pwordValErr := auth.ValidatePassword(passwordBody.OldPassword); pwordValErr != nil {
- return pwordValErr
+func (u *UserService) UpdatePassword(id string, passwordBody authEntities.UpdatePasswordRequestBody) error {
+ idAsUUID, err := utilities.ValidateID(id)
+ if err != nil {
+ return err
}
- if pwordValErr := auth.ValidatePassword(passwordBody.NewPassword); pwordValErr != nil {
- return pwordValErr
+ if err := utilities.Validate(u.Validate, passwordBody,
+ *utilities.NewMaybeError("old_password", auth.ValidatePassword(passwordBody.OldPassword)),
+ *utilities.NewMaybeError("new_password", auth.ValidatePassword(passwordBody.NewPassword))); err != nil {
+ return err
}
passwordHash, err := GetUserPasswordHash(u.DB, *idAsUUID)
@@ -162,18 +98,18 @@ func (u *UserService) UpdatePassword(id string, passwordBody models.UpdatePasswo
correct, passwordErr := auth.CompareHash(passwordBody.OldPassword, *passwordHash)
if passwordErr != nil || !correct {
- return &errors.FailedToValidateUser
+ return err
}
hash, hashErr := auth.ComputeHash(passwordBody.NewPassword)
if hashErr != nil {
- return &errors.FailedToValidateUser
+ return err
}
return users.UpdatePassword(u.DB, *idAsUUID, *hash)
}
-func (u *UserService) DeleteUser(id string) *errors.Error {
+func (u *UserService) DeleteUser(id string) error {
idAsUUID, err := utilities.ValidateID(id)
if err != nil {
return err
diff --git a/backend/entities/users/base/transactions.go b/backend/entities/users/base/transactions.go
index 27451352e..e3acaf1bb 100644
--- a/backend/entities/users/base/transactions.go
+++ b/backend/entities/users/base/transactions.go
@@ -1,78 +1,63 @@
package base
import (
- stdliberrors "errors"
+ "errors"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+ "github.com/garrettladley/fiberpaginate"
+
+ "github.com/GenerateNU/sac/backend/utilities"
"github.com/google/uuid"
"gorm.io/gorm"
+ "gorm.io/gorm/clause"
)
-func CreateUser(db *gorm.DB, user *models.User) (*models.User, *errors.Error) {
- if err := db.Create(user).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrDuplicatedKey) {
- return nil, &errors.UserAlreadyExists
- } else {
- return nil, &errors.FailedToCreateUser
- }
- }
-
- return user, nil
-}
-
-func GetUsers(db *gorm.DB, limit int, page int) ([]models.User, *errors.Error) {
+func GetUsers(db *gorm.DB, pageInfo fiberpaginate.PageInfo) ([]models.User, error) {
var users []models.User
-
- offset := (page - 1) * limit
-
- if err := db.Omit("password_hash").Limit(limit).Offset(offset).Find(&users).Error; err != nil {
- return nil, &errors.FailedToGetUsers
+ if err := db.Omit("password_hash").Scopes(utilities.IntoScope(pageInfo, db)).Find(&users).Error; err != nil {
+ return nil, err
}
return users, nil
}
-func GetUserPasswordHash(db *gorm.DB, id uuid.UUID) (*string, *errors.Error) {
+func GetUserPasswordHash(db *gorm.DB, id uuid.UUID) (*string, error) {
var user models.User
if err := db.Select("password_hash").First(&user, id).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.UserNotFound
- } else {
- return nil, &errors.FailedToGetUser
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
}
+ return nil, err
}
return &user.PasswordHash, nil
}
-func UpdateUser(db *gorm.DB, id uuid.UUID, user models.User) (*models.User, *errors.Error) {
+func UpdateUser(db *gorm.DB, id uuid.UUID, user models.User) (*models.User, error) {
var existingUser models.User
err := db.First(&existingUser, id).Error
if err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.UserNotFound
- } else {
- return nil, &errors.FailedToUpdateUser
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
}
+ return nil, err
}
- if err := db.Model(&existingUser).Updates(&user).Error; err != nil {
- return nil, &errors.FailedToUpdateUser
+ if err := db.Model(&existingUser).Clauses(clause.Returning{}).Updates(&user).Error; err != nil {
+ return nil, err
}
return &existingUser, nil
}
-func DeleteUser(db *gorm.DB, id uuid.UUID) *errors.Error {
+func DeleteUser(db *gorm.DB, id uuid.UUID) error {
if result := db.Delete(&models.User{}, id); result.RowsAffected == 0 {
if result.Error == nil {
- return &errors.UserNotFound
- } else {
- return &errors.FailedToDeleteUser
+ return utilities.ErrNotFound
}
+ return result.Error
}
return nil
}
diff --git a/backend/entities/users/follower/controller.go b/backend/entities/users/followers/controller.go
similarity index 72%
rename from backend/entities/users/follower/controller.go
rename to backend/entities/users/followers/controller.go
index 4646b20ac..b41741937 100644
--- a/backend/entities/users/follower/controller.go
+++ b/backend/entities/users/followers/controller.go
@@ -1,6 +1,8 @@
-package follower
+package followers
import (
+ "net/http"
+
"github.com/GenerateNU/sac/backend/utilities"
"github.com/gofiber/fiber/v2"
)
@@ -24,16 +26,16 @@ func NewUserFollowerController(userFollowerService UserFollowerServiceInterface)
// @Param userID path string true "User ID"
// @Param clubID path string true "Club ID"
// @Success 201 {object} utilities.SuccessResponse
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /users/{userID}/follower/{clubID}/ [post]
func (uf *UserFollowerController) CreateFollowing(c *fiber.Ctx) error {
err := uf.userFollowerService.CreateFollowing(c.Params("userID"), c.Params("clubID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return utilities.FiberMessage(c, fiber.StatusCreated, "Successfully followed club")
+ return utilities.FiberMessage(c, http.StatusCreated, "Successfully followed club")
}
// DeleteFollowing godoc
@@ -47,16 +49,16 @@ func (uf *UserFollowerController) CreateFollowing(c *fiber.Ctx) error {
// @Param userID path string true "User ID"
// @Param clubID path string true "Club ID"
// @Success 204 {object} utilities.SuccessResponse
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /users/{userID}/follower/{clubID}/ [delete]
func (uf *UserFollowerController) DeleteFollowing(c *fiber.Ctx) error {
err := uf.userFollowerService.DeleteFollowing(c.Params("userID"), c.Params("clubID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.SendStatus(fiber.StatusNoContent)
+ return c.SendStatus(http.StatusNoContent)
}
// GetAllFollowing godoc
@@ -68,15 +70,15 @@ func (uf *UserFollowerController) DeleteFollowing(c *fiber.Ctx) error {
// @Produce json
// @Param userID path string true "User ID"
// @Success 200 {object} []models.Club
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /users/{userID}/follower/ [get]
func (uf *UserFollowerController) GetFollowing(c *fiber.Ctx) error {
clubs, err := uf.userFollowerService.GetFollowing(c.Params("userID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(clubs)
+ return c.Status(http.StatusOK).JSON(clubs)
}
diff --git a/backend/entities/users/follower/routes.go b/backend/entities/users/followers/routes.go
similarity index 97%
rename from backend/entities/users/follower/routes.go
rename to backend/entities/users/followers/routes.go
index c01fc1a80..9928f0932 100644
--- a/backend/entities/users/follower/routes.go
+++ b/backend/entities/users/followers/routes.go
@@ -1,4 +1,4 @@
-package follower
+package followers
import (
"github.com/GenerateNU/sac/backend/types"
diff --git a/backend/entities/users/follower/service.go b/backend/entities/users/followers/service.go
similarity index 78%
rename from backend/entities/users/follower/service.go
rename to backend/entities/users/followers/service.go
index ea32871c4..2d2af7519 100644
--- a/backend/entities/users/follower/service.go
+++ b/backend/entities/users/followers/service.go
@@ -1,16 +1,15 @@
-package follower
+package followers
import (
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/types"
"github.com/GenerateNU/sac/backend/utilities"
)
type UserFollowerServiceInterface interface {
- CreateFollowing(userId string, clubId string) *errors.Error
- DeleteFollowing(userId string, clubId string) *errors.Error
- GetFollowing(userId string) ([]models.Club, *errors.Error)
+ CreateFollowing(userId string, clubId string) error
+ DeleteFollowing(userId string, clubId string) error
+ GetFollowing(userId string) ([]models.Club, error)
}
type UserFollowerService struct {
@@ -21,7 +20,7 @@ func NewUserFollowerService(serviceParams types.ServiceParams) UserFollowerServi
return &UserFollowerService{serviceParams}
}
-func (u *UserFollowerService) CreateFollowing(userId string, clubId string) *errors.Error {
+func (u *UserFollowerService) CreateFollowing(userId string, clubId string) error {
userIdAsUUID, err := utilities.ValidateID(userId)
if err != nil {
return err
@@ -33,7 +32,7 @@ func (u *UserFollowerService) CreateFollowing(userId string, clubId string) *err
return CreateFollowing(u.DB, *userIdAsUUID, *clubIdAsUUID)
}
-func (u *UserFollowerService) DeleteFollowing(userId string, clubId string) *errors.Error {
+func (u *UserFollowerService) DeleteFollowing(userId string, clubId string) error {
userIdAsUUID, err := utilities.ValidateID(userId)
if err != nil {
return err
@@ -45,7 +44,7 @@ func (u *UserFollowerService) DeleteFollowing(userId string, clubId string) *err
return DeleteFollowing(u.DB, *userIdAsUUID, *clubIdAsUUID)
}
-func (u *UserFollowerService) GetFollowing(userId string) ([]models.Club, *errors.Error) {
+func (u *UserFollowerService) GetFollowing(userId string) ([]models.Club, error) {
userIdAsUUID, err := utilities.ValidateID(userId)
if err != nil {
return nil, err
diff --git a/backend/entities/users/follower/transactions.go b/backend/entities/users/followers/transactions.go
similarity index 81%
rename from backend/entities/users/follower/transactions.go
rename to backend/entities/users/followers/transactions.go
index d318657c8..169f2e9d7 100644
--- a/backend/entities/users/follower/transactions.go
+++ b/backend/entities/users/followers/transactions.go
@@ -1,16 +1,15 @@
-package follower
+package followers
import (
"github.com/GenerateNU/sac/backend/entities/clubs"
"github.com/GenerateNU/sac/backend/entities/models"
"github.com/GenerateNU/sac/backend/entities/users"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/google/uuid"
"gorm.io/gorm"
)
-func CreateFollowing(db *gorm.DB, userID uuid.UUID, clubID uuid.UUID) *errors.Error {
+func CreateFollowing(db *gorm.DB, userID uuid.UUID, clubID uuid.UUID) error {
user, err := users.GetUser(db, userID)
if err != nil {
return err
@@ -22,13 +21,13 @@ func CreateFollowing(db *gorm.DB, userID uuid.UUID, clubID uuid.UUID) *errors.Er
}
if err := db.Model(&user).Association("Follower").Append(club); err != nil {
- return &errors.FailedToFollowClub
+ return err
}
return nil
}
-func DeleteFollowing(db *gorm.DB, userID uuid.UUID, clubID uuid.UUID) *errors.Error {
+func DeleteFollowing(db *gorm.DB, userID uuid.UUID, clubID uuid.UUID) error {
user, err := users.GetUser(db, userID)
if err != nil {
return err
@@ -40,13 +39,13 @@ func DeleteFollowing(db *gorm.DB, userID uuid.UUID, clubID uuid.UUID) *errors.Er
}
if err := db.Model(&user).Association("Follower").Delete(club); err != nil {
- return &errors.UserNotFollowingClub
+ return err
}
return nil
}
-func GetClubFollowing(db *gorm.DB, userID uuid.UUID) ([]models.Club, *errors.Error) {
+func GetClubFollowing(db *gorm.DB, userID uuid.UUID) ([]models.Club, error) {
var clubs []models.Club
user, err := users.GetUser(db, userID)
@@ -55,7 +54,7 @@ func GetClubFollowing(db *gorm.DB, userID uuid.UUID) ([]models.Club, *errors.Err
}
if err := db.Model(&user).Association("Follower").Find(&clubs); err != nil {
- return nil, &errors.FailedToGetUserFollowing
+ return nil, err
}
return clubs, nil
diff --git a/backend/entities/users/member/controller.go b/backend/entities/users/member/controller.go
deleted file mode 100644
index 221fc76aa..000000000
--- a/backend/entities/users/member/controller.go
+++ /dev/null
@@ -1,85 +0,0 @@
-package member
-
-import (
- "github.com/GenerateNU/sac/backend/utilities"
- "github.com/gofiber/fiber/v2"
-)
-
-type UserMemberController struct {
- clubMemberService UserMemberServiceInterface
-}
-
-func NewUserMemberController(clubMemberService UserMemberServiceInterface) *UserMemberController {
- return &UserMemberController{clubMemberService: clubMemberService}
-}
-
-// CreateMembership godoc
-//
-// @Summary Join a club
-// @Description Join a club
-// @ID create-membership
-// @Tags user-member
-// @Accept json
-// @Produce json
-// @Param userID path string true "User ID"
-// @Param clubID path string true "Club ID"
-// @Success 201 {object} utilities.SuccessResponse
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
-// @Router /users/{userID}/member/{clubID}/ [post]
-func (um *UserMemberController) CreateMembership(c *fiber.Ctx) error {
- err := um.clubMemberService.CreateMembership(c.Params("userID"), c.Params("clubID"))
- if err != nil {
- return err.FiberError(c)
- }
-
- return utilities.FiberMessage(c, fiber.StatusCreated, "Successfully joined club")
-}
-
-// DeleteMembership godoc
-//
-// @Summary Leave a club
-// @Description Leave a club
-// @ID delete-membership
-// @Tags user-member
-// @Accept json
-// @Produce json
-// @Param userID path string true "User ID"
-// @Param clubID path string true "Club ID"
-// @Success 204 {object} utilities.SuccessResponse
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
-// @Router /users/{userID}/member/{clubID}/ [delete]
-func (um *UserMemberController) DeleteMembership(c *fiber.Ctx) error {
- err := um.clubMemberService.DeleteMembership(c.Params("userID"), c.Params("clubID"))
- if err != nil {
- return err.FiberError(c)
- }
-
- return c.SendStatus(fiber.StatusNoContent)
-}
-
-// GetMembership godoc
-//
-// @Summary Retrieve all clubs a user is a member of
-// @Description Retrieves all clubs a user is a member of
-// @ID get-membership
-// @Tags user-member
-// @Produce json
-// @Param userID path string true "User ID"
-// @Success 200 {object} []models.Club
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
-// @Router /users/{userID}/member/ [get]
-func (um *UserMemberController) GetMembership(c *fiber.Ctx) error {
- followers, err := um.clubMemberService.GetMembership(c.Params("userID"))
- if err != nil {
- return err.FiberError(c)
- }
-
- return c.Status(fiber.StatusOK).JSON(followers)
-}
diff --git a/backend/entities/users/member/service.go b/backend/entities/users/member/service.go
deleted file mode 100644
index 9e5c51b3a..000000000
--- a/backend/entities/users/member/service.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package member
-
-import (
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
- "github.com/GenerateNU/sac/backend/types"
- "github.com/GenerateNU/sac/backend/utilities"
-)
-
-type UserMemberServiceInterface interface {
- CreateMembership(userID string, clubID string) *errors.Error
- DeleteMembership(userID string, clubID string) *errors.Error
- GetMembership(userID string) ([]models.Club, *errors.Error)
-}
-
-type UserMemberService struct {
- types.ServiceParams
-}
-
-func NewUserMemberService(serviceParams types.ServiceParams) UserMemberServiceInterface {
- return &UserMemberService{serviceParams}
-}
-
-func (u *UserMemberService) CreateMembership(userID string, clubID string) *errors.Error {
- userIdAsUUID, err := utilities.ValidateID(userID)
- if err != nil {
- return err
- }
- clubIdAsUUID, err := utilities.ValidateID(clubID)
- if err != nil {
- return err
- }
-
- return CreateMember(u.DB, *userIdAsUUID, *clubIdAsUUID)
-}
-
-func (u *UserMemberService) DeleteMembership(userID string, clubID string) *errors.Error {
- userIdAsUUID, err := utilities.ValidateID(userID)
- if err != nil {
- return err
- }
-
- clubIdAsUUID, err := utilities.ValidateID(clubID)
- if err != nil {
- return err
- }
- return DeleteMember(u.DB, *userIdAsUUID, *clubIdAsUUID)
-}
-
-func (u *UserMemberService) GetMembership(userID string) ([]models.Club, *errors.Error) {
- userIdAsUUID, err := utilities.ValidateID(userID)
- if err != nil {
- return nil, err
- }
-
- return GetClubMembership(u.DB, *userIdAsUUID)
-}
diff --git a/backend/entities/users/members/controller.go b/backend/entities/users/members/controller.go
new file mode 100644
index 000000000..5fb0ae78c
--- /dev/null
+++ b/backend/entities/users/members/controller.go
@@ -0,0 +1,38 @@
+package members
+
+import (
+ "net/http"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+type UserMemberController struct {
+ clubMemberService UserMemberServiceInterface
+}
+
+func NewUserMemberController(clubMemberService UserMemberServiceInterface) *UserMemberController {
+ return &UserMemberController{clubMemberService: clubMemberService}
+}
+
+// GetMembership godoc
+//
+// @Summary Retrieve all clubs a user is a member of
+// @Description Retrieves all clubs a user is a member of
+// @ID get-membership
+// @Tags user-member
+// @Produce json
+// @Param userID path string true "User ID"
+// @Success 200 {object} []models.Club
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
+// @Router /users/{userID}/member/ [get]
+func (um *UserMemberController) GetMembership(c *fiber.Ctx) error {
+ followers, err := um.clubMemberService.GetMembership(c.Params("userID"))
+ if err != nil {
+ return err
+ }
+
+ return c.Status(http.StatusOK).JSON(followers)
+}
diff --git a/backend/entities/users/member/routes.go b/backend/entities/users/members/routes.go
similarity index 58%
rename from backend/entities/users/member/routes.go
rename to backend/entities/users/members/routes.go
index c1b5fb64b..d3f5bcab5 100644
--- a/backend/entities/users/member/routes.go
+++ b/backend/entities/users/members/routes.go
@@ -1,4 +1,4 @@
-package member
+package members
import (
"github.com/GenerateNU/sac/backend/types"
@@ -11,6 +11,4 @@ func UserMember(userParams types.RouteParams) {
userMember := userParams.Router.Group("/member")
userMember.Get("/", userMemberController.GetMembership)
- userMember.Post("/:clubID", userParams.AuthMiddleware.UserAuthorizeById, userMemberController.CreateMembership)
- userMember.Delete("/:clubID", userParams.AuthMiddleware.UserAuthorizeById, userMemberController.DeleteMembership)
}
diff --git a/backend/entities/users/members/service.go b/backend/entities/users/members/service.go
new file mode 100644
index 000000000..2fd30dbd4
--- /dev/null
+++ b/backend/entities/users/members/service.go
@@ -0,0 +1,28 @@
+package members
+
+import (
+ "github.com/GenerateNU/sac/backend/entities/models"
+ "github.com/GenerateNU/sac/backend/types"
+ "github.com/GenerateNU/sac/backend/utilities"
+)
+
+type UserMemberServiceInterface interface {
+ GetMembership(userID string) ([]models.Club, error)
+}
+
+type UserMemberService struct {
+ types.ServiceParams
+}
+
+func NewUserMemberService(serviceParams types.ServiceParams) UserMemberServiceInterface {
+ return &UserMemberService{serviceParams}
+}
+
+func (u *UserMemberService) GetMembership(userID string) ([]models.Club, error) {
+ userIdAsUUID, err := utilities.ValidateID(userID)
+ if err != nil {
+ return nil, err
+ }
+
+ return GetClubMembership(u.DB, *userIdAsUUID)
+}
diff --git a/backend/entities/users/members/transactions.go b/backend/entities/users/members/transactions.go
new file mode 100644
index 000000000..de0679011
--- /dev/null
+++ b/backend/entities/users/members/transactions.go
@@ -0,0 +1,24 @@
+package members
+
+import (
+ "github.com/GenerateNU/sac/backend/entities/models"
+ "github.com/GenerateNU/sac/backend/entities/users"
+
+ "github.com/google/uuid"
+ "gorm.io/gorm"
+)
+
+func GetClubMembership(db *gorm.DB, userID uuid.UUID) ([]models.Club, error) {
+ var clubs []models.Club
+
+ user, err := users.GetUser(db, userID)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := db.Model(&user).Association("Member").Find(&clubs); err != nil {
+ return nil, err
+ }
+
+ return clubs, nil
+}
diff --git a/backend/entities/users/tag/controller.go b/backend/entities/users/tags/controller.go
similarity index 67%
rename from backend/entities/users/tag/controller.go
rename to backend/entities/users/tags/controller.go
index 5b225220e..8d34a9fd2 100644
--- a/backend/entities/users/tag/controller.go
+++ b/backend/entities/users/tags/controller.go
@@ -1,8 +1,9 @@
-package tag
+package tags
import (
- "github.com/GenerateNU/sac/backend/errors"
+ "net/http"
+ "github.com/GenerateNU/sac/backend/utilities"
"github.com/gofiber/fiber/v2"
)
@@ -23,18 +24,18 @@ func NewUserTagController(userTagService UserTagServiceInterface) *UserTagContro
// @Produce json
// @Param userID path string true "User ID"
// @Success 200 {object} []models.Tag
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /users/{userID}/tags/ [get]
func (ut *UserTagController) GetUserTags(c *fiber.Ctx) error {
tags, err := ut.userTagService.GetUserTags(c.Params("userID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusOK).JSON(&tags)
+ return c.Status(http.StatusOK).JSON(&tags)
}
// CreateUserTags godoc
@@ -48,24 +49,24 @@ func (ut *UserTagController) GetUserTags(c *fiber.Ctx) error {
// @Param userID path string true "User ID"
// @Param userTagsBody body CreateUserTagsBody true "User Tags Body"
// @Success 201 {object} []models.Tag
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /users/{userID}/tags/ [post]
func (ut *UserTagController) CreateUserTags(c *fiber.Ctx) error {
var requestBody CreateUserTagsBody
if err := c.BodyParser(&requestBody); err != nil {
- return errors.FailedToParseRequestBody.FiberError(c)
+ return utilities.InvalidJSON()
}
tags, err := ut.userTagService.CreateUserTags(c.Params("userID"), requestBody)
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.Status(fiber.StatusCreated).JSON(&tags)
+ return c.Status(http.StatusCreated).JSON(&tags)
}
// DeleteUserTag godoc
@@ -78,16 +79,16 @@ func (ut *UserTagController) CreateUserTags(c *fiber.Ctx) error {
// @Produce json
// @Param userID path string true "User ID"
// @Success 201
-// @Failure 400 {object} errors.Error
-// @Failure 401 {object} errors.Error
-// @Failure 404 {object} errors.Error
-// @Failure 500 {object} errors.Error
+// @Failure 400 {object} error
+// @Failure 401 {object} error
+// @Failure 404 {object} error
+// @Failure 500 {object} error
// @Router /users/{userID}/tags/ [delete]
func (ut *UserTagController) DeleteUserTag(c *fiber.Ctx) error {
err := ut.userTagService.DeleteUserTag(c.Params("userID"), c.Params("tagID"))
if err != nil {
- return err.FiberError(c)
+ return err
}
- return c.SendStatus(fiber.StatusNoContent)
+ return c.SendStatus(http.StatusNoContent)
}
diff --git a/backend/entities/users/tag/model.go b/backend/entities/users/tags/model.go
similarity index 90%
rename from backend/entities/users/tag/model.go
rename to backend/entities/users/tags/model.go
index e70a8d879..155020975 100644
--- a/backend/entities/users/tag/model.go
+++ b/backend/entities/users/tags/model.go
@@ -1,4 +1,4 @@
-package tag
+package tags
import "github.com/google/uuid"
diff --git a/backend/entities/users/tag/routes.go b/backend/entities/users/tags/routes.go
similarity index 97%
rename from backend/entities/users/tag/routes.go
rename to backend/entities/users/tags/routes.go
index 620c58d11..26aaccc6c 100644
--- a/backend/entities/users/tag/routes.go
+++ b/backend/entities/users/tags/routes.go
@@ -1,4 +1,4 @@
-package tag
+package tags
import (
"github.com/GenerateNU/sac/backend/types"
diff --git a/backend/entities/users/tag/service.go b/backend/entities/users/tags/service.go
similarity index 75%
rename from backend/entities/users/tag/service.go
rename to backend/entities/users/tags/service.go
index f0f0134c4..fb5dfed8c 100644
--- a/backend/entities/users/tag/service.go
+++ b/backend/entities/users/tags/service.go
@@ -1,17 +1,16 @@
-package tag
+package tags
import (
"github.com/GenerateNU/sac/backend/entities/models"
"github.com/GenerateNU/sac/backend/entities/tags"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/types"
"github.com/GenerateNU/sac/backend/utilities"
)
type UserTagServiceInterface interface {
- GetUserTags(id string) ([]models.Tag, *errors.Error)
- CreateUserTags(id string, tagIDs CreateUserTagsBody) ([]models.Tag, *errors.Error)
- DeleteUserTag(id string, tagID string) *errors.Error
+ GetUserTags(id string) ([]models.Tag, error)
+ CreateUserTags(id string, tagIDs CreateUserTagsBody) ([]models.Tag, error)
+ DeleteUserTag(id string, tagID string) error
}
type UserTagService struct {
@@ -22,7 +21,7 @@ func NewUserTagService(serviceParams types.ServiceParams) UserTagServiceInterfac
return &UserTagService{serviceParams}
}
-func (u *UserTagService) GetUserTags(id string) ([]models.Tag, *errors.Error) {
+func (u *UserTagService) GetUserTags(id string) ([]models.Tag, error) {
idAsUUID, err := utilities.ValidateID(id)
if err != nil {
return nil, err
@@ -31,15 +30,15 @@ func (u *UserTagService) GetUserTags(id string) ([]models.Tag, *errors.Error) {
return GetUserTags(u.DB, *idAsUUID)
}
-func (u *UserTagService) CreateUserTags(id string, tagIDs CreateUserTagsBody) ([]models.Tag, *errors.Error) {
+func (u *UserTagService) CreateUserTags(id string, tagIDs CreateUserTagsBody) ([]models.Tag, error) {
// Validate the id:
idAsUUID, err := utilities.ValidateID(id)
if err != nil {
return nil, err
}
- if err := u.Validate.Struct(tagIDs); err != nil {
- return nil, &errors.FailedToValidateUserTags
+ if err := utilities.Validate(u.Validate, tagIDs); err != nil {
+ return nil, err
}
// Retrieve a list of valid tags from the ids:
@@ -52,7 +51,7 @@ func (u *UserTagService) CreateUserTags(id string, tagIDs CreateUserTagsBody) ([
return CreateUserTags(u.DB, *idAsUUID, tags)
}
-func (u *UserTagService) DeleteUserTag(id string, tagID string) *errors.Error {
+func (u *UserTagService) DeleteUserTag(id string, tagID string) error {
// Validate the userID:
userIDAsUUID, err := utilities.ValidateID(id)
if err != nil {
diff --git a/backend/entities/users/tag/transactions.go b/backend/entities/users/tags/transactions.go
similarity index 73%
rename from backend/entities/users/tag/transactions.go
rename to backend/entities/users/tags/transactions.go
index e36b9ac6c..5a1945ed4 100644
--- a/backend/entities/users/tag/transactions.go
+++ b/backend/entities/users/tags/transactions.go
@@ -1,17 +1,16 @@
-package tag
+package tags
import (
"github.com/GenerateNU/sac/backend/entities/models"
"github.com/GenerateNU/sac/backend/entities/tags"
"github.com/GenerateNU/sac/backend/entities/users"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/transactions"
"github.com/google/uuid"
"gorm.io/gorm"
)
-func GetUserTags(db *gorm.DB, id uuid.UUID) ([]models.Tag, *errors.Error) {
+func GetUserTags(db *gorm.DB, id uuid.UUID) ([]models.Tag, error) {
var tags []models.Tag
user, err := users.GetUser(db, id)
@@ -20,25 +19,25 @@ func GetUserTags(db *gorm.DB, id uuid.UUID) ([]models.Tag, *errors.Error) {
}
if err := db.Model(&user).Association("Tag").Find(&tags); err != nil {
- return nil, &errors.FailedToGetTag
+ return nil, err
}
return tags, nil
}
-func CreateUserTags(db *gorm.DB, id uuid.UUID, tags []models.Tag) ([]models.Tag, *errors.Error) {
+func CreateUserTags(db *gorm.DB, id uuid.UUID, tags []models.Tag) ([]models.Tag, error) {
user, err := users.GetUser(db, id, transactions.PreloadTag())
if err != nil {
return nil, err
}
if err := db.Model(&user).Association("Tag").Append(tags); err != nil {
- return nil, &errors.FailedToUpdateUser
+ return nil, err
}
return tags, nil
}
-func DeleteUserTag(db *gorm.DB, id uuid.UUID, tagID uuid.UUID) *errors.Error {
+func DeleteUserTag(db *gorm.DB, id uuid.UUID, tagID uuid.UUID) error {
user, err := users.GetUser(db, id, transactions.PreloadTag())
if err != nil {
return err
@@ -50,7 +49,7 @@ func DeleteUserTag(db *gorm.DB, id uuid.UUID, tagID uuid.UUID) *errors.Error {
}
if err := db.Model(&user).Association("Tag").Delete(&tag); err != nil {
- return &errors.FailedToUpdateUser
+ return err
}
return nil
diff --git a/backend/entities/users/transactions.go b/backend/entities/users/transactions.go
index fba6f7d09..38b093cc1 100644
--- a/backend/entities/users/transactions.go
+++ b/backend/entities/users/transactions.go
@@ -1,16 +1,16 @@
package users
import (
- stdliberrors "errors"
+ "errors"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/transactions"
+ "github.com/GenerateNU/sac/backend/utilities"
"github.com/google/uuid"
"gorm.io/gorm"
)
-func GetUser(db *gorm.DB, id uuid.UUID, preloads ...transactions.OptionalQuery) (*models.User, *errors.Error) {
+func GetUser(db *gorm.DB, id uuid.UUID, preloads ...transactions.OptionalQuery) (*models.User, error) {
var user models.User
query := db
@@ -20,46 +20,46 @@ func GetUser(db *gorm.DB, id uuid.UUID, preloads ...transactions.OptionalQuery)
}
if err := query.Omit("password_hash").First(&user, id).Error; err != nil {
- if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
- return nil, &errors.UserNotFound
- } else {
- return nil, &errors.FailedToGetUser
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
}
+ return nil, err
}
return &user, nil
}
-func GetUserByEmail(db *gorm.DB, email string) (*models.User, *errors.Error) {
+func GetUserByEmail(db *gorm.DB, email string) (*models.User, error) {
var user models.User
if err := db.Where("email = ?", email).First(&user).Error; err != nil {
- return nil, &errors.UserNotFound
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, utilities.ErrNotFound
+ }
+ return nil, err
}
return &user, nil
}
-func UpdateEmailVerification(db *gorm.DB, id uuid.UUID) *errors.Error {
+func UpdateEmailVerification(db *gorm.DB, id uuid.UUID) error {
result := db.Model(&models.User{}).Where("id = ?", id).Update("is_verified", true)
if result.RowsAffected == 0 {
if result.Error == nil {
- return &errors.UserNotFound
- } else {
- return &errors.FailedToUpdateEmailVerification
+ return utilities.ErrNotFound
}
+ return result.Error
}
return nil
}
-func UpdatePassword(db *gorm.DB, id uuid.UUID, passwordHash string) *errors.Error {
+func UpdatePassword(db *gorm.DB, id uuid.UUID, passwordHash string) error {
result := db.Model(&models.User{}).Where("id = ?", id).Update("password_hash", passwordHash)
if result.RowsAffected == 0 {
if result.Error == nil {
- return &errors.UserNotFound
- } else {
- return &errors.FailedToUpdateUser
+ return utilities.ErrNotFound
}
+ return result.Error
}
return nil
}
diff --git a/backend/errors/auth.go b/backend/errors/auth.go
deleted file mode 100644
index 83b3c46c4..000000000
--- a/backend/errors/auth.go
+++ /dev/null
@@ -1,114 +0,0 @@
-package errors
-
-import "github.com/gofiber/fiber/v2"
-
-var (
- FailedToExtractClaims = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to extract claims",
- }
- FailedToParseToken = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to parse token",
- }
- InvalidTokenType = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "invalid token type",
- }
- FailedToValidateUpdatePasswordBody = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate update password body",
- }
- FailedToCastToCustomClaims = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to cast to custom claims",
- }
- FailedToCreatePasswordReset = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to create password reset",
- }
- FailedToDeletePasswordReset = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to delete password reset",
- }
- TokenExpired = Error{
- StatusCode: fiber.StatusUnauthorized,
- Message: "token expired",
- }
- FailedToGetPasswordResetToken = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get password reset token",
- }
- FailedToGetToken = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get token",
- }
- FailedToDeleteToken = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to delete token",
- }
- FailedToSaveToken = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to save token",
- }
- PasswordResetTokenNotFound = Error{
- StatusCode: fiber.StatusNotFound,
- Message: "password reset token not found",
- }
- TokenNotFound = Error{
- StatusCode: fiber.StatusNotFound,
- Message: "token not found",
- }
- EmailAlreadyVerified = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "email already verified",
- }
- FailedToGenerateOTP = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to generate otp",
- }
- FailedToSaveOTP = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to save otp",
- }
- FailedToGetOTP = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get otp",
- }
- InvalidOTP = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "invalid otp",
- }
- OTPExpired = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "otp expired",
- }
- FailedToUpdateEmailVerification = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to update email verification",
- }
- FailedToDeleteOTP = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to delete otp",
- }
- FailedToSendCode = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to send code",
- }
- OTPNotFound = Error{
- StatusCode: fiber.StatusNotFound,
- Message: "otp not found",
- }
- InvalidPasswordNotLongEnough = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "password must be at least 8 characters long",
- }
- InvalidPasswordNoDigit = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "password must contain at least one digit",
- }
- InvalidPasswordNoSpecialCharacter = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "password must contain at least one special character",
- }
-)
diff --git a/backend/errors/category.go b/backend/errors/category.go
deleted file mode 100644
index cc3d4672c..000000000
--- a/backend/errors/category.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package errors
-
-import "github.com/gofiber/fiber/v2"
-
-var (
- FailedToValidateCategory = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate category",
- }
- FailedToCreateCategory = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to create category",
- }
- FailedToGetCategories = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get categories",
- }
- FailedToGetCategory = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get category",
- }
- FailedToUpdateCategory = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to update category",
- }
- FailedToDeleteCategory = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to delete category",
- }
- CategoryAlreadyExists = Error{
- StatusCode: fiber.StatusConflict,
- Message: "category already exists",
- }
- CategoryNotFound = Error{
- StatusCode: fiber.StatusNotFound,
- Message: "category not found",
- }
-)
diff --git a/backend/errors/club.go b/backend/errors/club.go
deleted file mode 100644
index 826c08e4a..000000000
--- a/backend/errors/club.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package errors
-
-import "github.com/gofiber/fiber/v2"
-
-var (
- FailedToValidateUserID = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate user id",
- }
- FailedToValidateClub = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate club",
- }
- FailedToCreateClub = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to create club",
- }
- FailedToGetClubs = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get clubs",
- }
- FailedToGetClub = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get club",
- }
- FailedToDeleteClub = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to delete club",
- }
- FailedToUpdateClub = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to update club",
- }
- ClubNotFound = Error{
- StatusCode: fiber.StatusNotFound,
- Message: "club not found",
- }
- FailedToValidateClubTags = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate club tags",
- }
- FailedToGetMembers = Error{
- StatusCode: fiber.StatusNotFound,
- Message: "failed to get members",
- }
- FailedtoGetAdminIDs = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get admin ids",
- }
- FailedToVectorizeClub = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to vectorize club",
- }
- FailedToGetClubFollowers = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get club followers",
- }
- FailedToGetClubMembers = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get club members",
- }
- FailedToGetClubEvents = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get club events",
- }
- FailedToJoinClub = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to join club",
- }
- AlreadyMemberOfClub = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "already member of club",
- }
-)
diff --git a/backend/errors/common.go b/backend/errors/common.go
deleted file mode 100644
index acf9e0906..000000000
--- a/backend/errors/common.go
+++ /dev/null
@@ -1,82 +0,0 @@
-package errors
-
-import "github.com/gofiber/fiber/v2"
-
-var (
- FailedToValidateAtLeastOneField = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate at least one field",
- }
- FailedToParseRequestBody = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "request body is not valid",
- }
- FailedtoParseQueryParams = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to parse query params",
- }
- FailedToValidateID = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate id",
- }
- FailedToValidateNonNegativeValue = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate non-negative value",
- }
- FailedToMapRequestToModel = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to map request to model",
- }
- InternalServerError = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "internal server error",
- }
- FailedToValidateLimit = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate limit",
- }
- FailedToValidatePage = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate page",
- }
- Unauthorized = Error{
- StatusCode: fiber.StatusUnauthorized,
- Message: "unauthorized",
- }
- Forbidden = Error{
- StatusCode: fiber.StatusForbidden,
- Message: "forbidden",
- }
- FailedToSignToken = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to sign token",
- }
- FailedToCreateAccessToken = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to create access token",
- }
- FailedToCreateRefreshToken = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to create refresh token",
- }
- FailedToParseRefreshToken = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to parse refresh token",
- }
- FailedToParseAccessToken = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to parse access token",
- }
- FailedToValidateRefreshToken = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate refresh token",
- }
- FailedToValidateAccessToken = Error{
- StatusCode: fiber.StatusUnauthorized,
- Message: "failed to validate access token",
- }
- FailedToGenerateToken = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to generate token",
- }
-)
diff --git a/backend/errors/contact.go b/backend/errors/contact.go
deleted file mode 100644
index d408a5a37..000000000
--- a/backend/errors/contact.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package errors
-
-import "github.com/gofiber/fiber/v2"
-
-var (
- FailedToGetContacts = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get contacts",
- }
- FailedToGetContact = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get contact",
- }
- ContactNotFound = Error{
- StatusCode: fiber.StatusNotFound,
- Message: "contact not found",
- }
- FailedToPutContact = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to put contact",
- }
- FailedToDeleteContact = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to delete contact",
- }
- FailedToValidateContact = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate contact",
- }
-)
diff --git a/backend/errors/error.go b/backend/errors/error.go
deleted file mode 100644
index ee5035f4e..000000000
--- a/backend/errors/error.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package errors
-
-import (
- "github.com/gofiber/fiber/v2"
-)
-
-type Error struct {
- StatusCode int
- Message string
-}
-
-func (e *Error) FiberError(c *fiber.Ctx) error {
- return c.Status(e.StatusCode).JSON(fiber.Map{"error": e.Message})
-}
-
-func (e *Error) Error() string {
- return e.Message
-}
diff --git a/backend/errors/event.go b/backend/errors/event.go
deleted file mode 100644
index e5b11b2a6..000000000
--- a/backend/errors/event.go
+++ /dev/null
@@ -1,66 +0,0 @@
-package errors
-
-import "github.com/gofiber/fiber/v2"
-
-var (
- FailedToValidateEvent = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate event",
- }
- FailedToValidateEventSeries = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate event series",
- }
- FailedToCreateEvent = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to create event",
- }
- FailedToCreateEventSeries = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to create event series",
- }
- FailedToGetEventSeries = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get event series",
- }
- FailedToGetEvents = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get events",
- }
- FailedToGetEvent = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get event",
- }
- FailedToDeleteEvent = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to delete event",
- }
- FailedToDeleteSeries = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to delete series",
- }
- FailedToUpdateEvent = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to update event",
- }
- FailedToUpdateSeries = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to update series",
- }
- EventNotFound = Error{
- StatusCode: fiber.StatusNotFound,
- Message: "event not found",
- }
- SeriesNotFound = Error{
- StatusCode: fiber.StatusNotFound,
- Message: "series not found",
- }
- FailedToUpdateEventSeries = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to update event series",
- }
- FailedToGetEventHosts = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get event hosts",
- }
-)
diff --git a/backend/errors/file.go b/backend/errors/file.go
deleted file mode 100644
index 00d57d266..000000000
--- a/backend/errors/file.go
+++ /dev/null
@@ -1,106 +0,0 @@
-package errors
-
-import "github.com/gofiber/fiber/v2"
-
-var (
- FailedToValidateFileId = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to validate file id",
- }
- InvalidFileSize = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "file size is greater than 5 MB",
- }
- InvalidFileType = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "invalid file type",
- }
- FileNotFound = Error{
- StatusCode: fiber.StatusNotFound,
- Message: "file not found",
- }
- FailedToCreateAWSSession = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to create AWS session",
- }
- FailedToUpdateFile = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to update file",
- }
- FailedToUploadFile = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to upload file",
- }
- FailedToCreateFileInDB = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to create file in database",
- }
- FailedToCreateFile = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to create file",
- }
- FailedToDeleteFile = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to delete file",
- }
- FailedToReadFile = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to read file",
- }
- FailedToValidateFile = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate file",
- }
- FailedToGetFiles = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get files",
- }
- FailedToGetFile = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to get file",
- }
- FailedToProcessRequest = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to process the request",
- }
- FailedToValidatedData = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate data",
- }
- FailedToOpenFile = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to open file",
- }
- InvalidImageFormat = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "invalid image format",
- }
- FailedToDownloadFile = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to download the file",
- }
- InvalidAssociationType = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "invalid association type",
- }
- FailedToFindAssociationID = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to find association ID",
- }
- FailedToParseDaysToInt = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to parse days to int",
- }
- FailedToGetSignedURL = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get signed URL",
- }
- InvalidFileID = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "invalid file id",
- }
- CannotFindFile = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "unable to find file",
- }
-)
diff --git a/backend/errors/point_of_contact.go b/backend/errors/point_of_contact.go
deleted file mode 100644
index 7ec6596b2..000000000
--- a/backend/errors/point_of_contact.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package errors
-
-import "github.com/gofiber/fiber/v2"
-
-var (
- FailedToUpsertPointOfContact = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to update or insert point of contact",
- }
- FailedToGetAllPointOfContact = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get all point of contact",
- }
- FailedToGetClubPointOfContacts = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get club point of contacts",
- }
- FailedToUpdateClubPointOfContact = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to update club point of contact",
- }
- FailedToGetClubPointOfContact = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get club point of contact",
- }
- FailedToDeleteClubPointOfContact = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to delete club point of contact",
- }
- PointOfContactNotFound = Error{
- StatusCode: fiber.StatusNotFound,
- Message: "point of contact not found",
- }
- PointOfContactsNotFound = Error{
- StatusCode: fiber.StatusNotFound,
- Message: "point of contact not found",
- }
- FailedToDeletePointOfContact = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to delete point of contact",
- }
- PointOfContactAlreadyExists = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "point of contact already exists",
- }
- FailedToValidatePointOfContact = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to validate point of contact",
- }
- FailedToCreatePointOfContact = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to create point of contact",
- }
- FailedToValidateEmail = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate email",
- }
- FailedToMapResponseToModel = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to map response to model",
- }
- FailedToGetAPointOfContact = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get a point of contact",
- }
- FailedToGetPointOfContacts = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get point of contacts",
- }
- FailedToValidatePointOfContactId = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate point of contact id",
- }
- FailedToGetPointOfContact = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get point of contact",
- }
-)
diff --git a/backend/errors/search.go b/backend/errors/search.go
deleted file mode 100644
index a9bb62328..000000000
--- a/backend/errors/search.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package errors
-
-import "github.com/gofiber/fiber/v2"
-
-var (
- ClubSeedingFailed = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to seed pinecone with clubs",
- }
- FailedToCreateEmbedding = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to create embedding from string",
- }
- FailedToCreateModeration = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to create moderation from string",
- }
- FailedToUpsertToPinecone = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to upsert to pinecone",
- }
- FailedToDeleteToPinecone = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to delete from pinecone",
- }
- ItemsMustHaveSameNamespace = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "items being deleted have differing namespaces",
- }
- FailedToSearchToPinecone = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to search on pinecone",
- }
- PotentiallyHarmfulSearch = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "detected potentially harmful content",
- }
-)
diff --git a/backend/errors/tag.go b/backend/errors/tag.go
deleted file mode 100644
index 9e67a0a7c..000000000
--- a/backend/errors/tag.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package errors
-
-import "github.com/gofiber/fiber/v2"
-
-var (
- FailedToValidateTag = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate tag",
- }
- FailedToCreateTag = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to create tag",
- }
- FailedToGetTags = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get tags",
- }
- FailedToGetTag = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get tag",
- }
- FailedToUpdateTag = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to update tag",
- }
- FailedToDeleteTag = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to delete tag",
- }
- TagNotFound = Error{
- StatusCode: fiber.StatusNotFound,
- Message: "tag not found",
- }
-)
diff --git a/backend/errors/user.go b/backend/errors/user.go
deleted file mode 100644
index bed706f4f..000000000
--- a/backend/errors/user.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package errors
-
-import "github.com/gofiber/fiber/v2"
-
-var (
- FailedToValidateUser = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate user",
- }
- FailedToValidateUserTags = Error{
- StatusCode: fiber.StatusBadRequest,
- Message: "failed to validate user tags",
- }
- FailedToCreateUser = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to create user",
- }
- FailedToUpdateUser = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to update user",
- }
- FailedToGetUsers = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get users",
- }
- FailedToGetUser = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get user",
- }
- FailedToDeleteUser = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to delete user",
- }
- UserAlreadyExists = Error{
- StatusCode: fiber.StatusConflict,
- Message: "user already exists",
- }
- UserNotFound = Error{
- StatusCode: fiber.StatusNotFound,
- Message: "user not found",
- }
- FailedToComputePasswordHash = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to compute password hash",
- }
- FailedToFindUsersByEmail = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get users by email",
- }
- FailedToGetUserMemberships = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get user memberships",
- }
- UserNotMemberOfClub = Error{
- StatusCode: fiber.StatusNotFound,
- Message: "user not member of club",
- }
- FailedToGetUserFollowing = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get user following",
- }
- UserNotFollowingClub = Error{
- StatusCode: fiber.StatusNotFound,
- Message: "user not following club",
- }
- FailedToUpdatePassword = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to update password",
- }
- FailedToFollowClub = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to follow club",
- }
-)
diff --git a/backend/errors/verification.go b/backend/errors/verification.go
deleted file mode 100644
index 1b4bfced3..000000000
--- a/backend/errors/verification.go
+++ /dev/null
@@ -1,14 +0,0 @@
-package errors
-
-import "github.com/gofiber/fiber/v2"
-
-var (
- FailedToGetTemplate = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to get template",
- }
- FailedToSendEmail = Error{
- StatusCode: fiber.StatusInternalServerError,
- Message: "failed to send email",
- }
-)
diff --git a/backend/extractors/series.go b/backend/extractors/series.go
new file mode 100644
index 000000000..3931149f7
--- /dev/null
+++ b/backend/extractors/series.go
@@ -0,0 +1,16 @@
+package extractors
+
+import (
+ "github.com/GenerateNU/sac/backend/entities/events"
+ "github.com/google/uuid"
+ "gorm.io/gorm"
+)
+
+func GetSeriesHost(db *gorm.DB, seriesID uuid.UUID) (*uuid.UUID, error) {
+ event, err := events.GetFirstEventInSeries(db, seriesID)
+ if err != nil {
+ return nil, err
+ }
+
+ return event.Host, nil
+}
diff --git a/backend/go.mod b/backend/go.mod
index 9213239be..f3312a02b 100644
--- a/backend/go.mod
+++ b/backend/go.mod
@@ -3,10 +3,12 @@ module github.com/GenerateNU/sac/backend
go 1.22.2
require (
+ github.com/a-h/templ v0.2.680
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5
- github.com/aws/aws-sdk-go v1.51.30
+ github.com/aws/aws-sdk-go v1.53.0
+ github.com/garrettladley/fiberpaginate v1.0.1
github.com/garrettladley/mattress v0.4.0
- github.com/go-playground/validator/v10 v10.19.0
+ github.com/go-playground/validator/v10 v10.20.0
github.com/goccy/go-json v0.10.2
github.com/gofiber/fiber/v2 v2.52.4
github.com/gofiber/swagger v1.0.0
@@ -16,14 +18,13 @@ require (
github.com/huandu/go-assert v1.1.6
github.com/joho/godotenv v1.5.1
github.com/mcnijman/go-emailaddress v1.1.1
- github.com/mitchellh/mapstructure v1.5.0
- github.com/redis/go-redis/v9 v9.5.1
github.com/resend/resend-go/v2 v2.6.0
github.com/sahilm/fuzzy v0.1.1
github.com/spf13/viper v1.18.2
github.com/swaggo/swag v1.16.3
- golang.org/x/crypto v0.22.0
- golang.org/x/text v0.14.0
+ go.opentelemetry.io/otel/sdk v1.26.0
+ golang.org/x/crypto v0.23.0
+ golang.org/x/text v0.15.0
gorm.io/driver/postgres v1.5.7
gorm.io/gorm v1.25.10
)
@@ -40,13 +41,17 @@ require (
)
require (
- github.com/cespare/xxhash/v2 v2.2.0 // indirect
- github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
+ github.com/go-logr/logr v1.4.1 // indirect
+ github.com/go-logr/stdr v1.2.2 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/lib/pq v1.10.9 // indirect
- go.uber.org/atomic v1.9.0 // indirect
+ github.com/mitchellh/mapstructure v1.5.0 // indirect
+ go.opentelemetry.io/contrib v1.17.0 // indirect
+ go.opentelemetry.io/otel/metric v1.26.0 // indirect
+ go.opentelemetry.io/otel/trace v1.26.0 // indirect
+ go.uber.org/atomic v1.11.0 // indirect
)
require (
@@ -61,6 +66,8 @@ require (
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
+ github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1
+ github.com/gofiber/contrib/otelfiber v1.0.10
github.com/golang-migrate/migrate/v4 v4.17.1
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
@@ -91,10 +98,12 @@ require (
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.52.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
+ go.opentelemetry.io/otel v1.26.0
+ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.26.0
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect
golang.org/x/net v0.24.0 // indirect
- golang.org/x/sys v0.19.0 // indirect
+ golang.org/x/sys v0.20.0 // indirect
golang.org/x/tools v0.20.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
diff --git a/backend/go.sum b/backend/go.sum
index 3e230ac48..66a022fc6 100644
--- a/backend/go.sum
+++ b/backend/go.sum
@@ -4,6 +4,8 @@ github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
+github.com/a-h/templ v0.2.680 h1:TflYFucxp5rmOxAXB9Xy3+QHTk8s8xG9+nCT/cLzjeE=
+github.com/a-h/templ v0.2.680/go.mod h1:NQGQOycaPKBxRB14DmAaeIpcGC1AOBPJEMO4ozS7m90=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 h1:rFw4nCn9iMW+Vajsk51NtYIcwSTkXr+JGrMd36kTDJw=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
@@ -12,14 +14,8 @@ github.com/awnumar/memcall v0.2.0 h1:sRaogqExTOOkkNwO9pzJsL8jrOV29UuUW7teRMfbqtI
github.com/awnumar/memcall v0.2.0/go.mod h1:S911igBPR9CThzd/hYQQmTc9SWNu3ZHIlCGaWsWsoJo=
github.com/awnumar/memguard v0.22.5 h1:PH7sbUVERS5DdXh3+mLo8FDcl1eIeVjJVYMnyuYpvuI=
github.com/awnumar/memguard v0.22.5/go.mod h1:+APmZGThMBWjnMlKiSM1X7MVpbIVewen2MTkqWkA/zE=
-github.com/aws/aws-sdk-go v1.51.30 h1:RVFkjn9P0JMwnuZCVH0TlV5k9zepHzlbc4943eZMhGw=
-github.com/aws/aws-sdk-go v1.51.30/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
-github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
-github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
-github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
-github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
-github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
-github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/aws/aws-sdk-go v1.53.0 h1:MMo1x1ggPPxDfHMXJnQudTbGXYlD4UigUAud1DJxPVo=
+github.com/aws/aws-sdk-go v1.53.0/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
@@ -42,8 +38,15 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
+github.com/garrettladley/fiberpaginate v1.0.1 h1:Ren6wx8L8KLcPvCKUkgRuaZaxX7CjCCoPhCUytnrGyk=
+github.com/garrettladley/fiberpaginate v1.0.1/go.mod h1:MHVWGQkhtnt2kE8F0wkTF5iUQOyqZlRktfcGgBLRBv0=
github.com/garrettladley/mattress v0.4.0 h1:ZB3iqyc5q6bqIryNfsh2FMcbMdnV1XEryvqivouceQE=
github.com/garrettladley/mattress v0.4.0/go.mod h1:OWKIRc9wC3gtD3Ng/nUuNEiR1TJvRYLmn/KZYw9nl5Q=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
+github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
@@ -58,10 +61,14 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4=
-github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
+github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
+github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
+github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 h1:TQcrn6Wq+sKGkpyPvppOz99zsMBaUOKXq6HSv655U1c=
+github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/gofiber/contrib/otelfiber v1.0.10 h1:Bu28Pi4pfYmGfIc/9+sNaBbFwTHGY/zpSIK5jBxuRtM=
+github.com/gofiber/contrib/otelfiber v1.0.10/go.mod h1:jN6AvS1HolDHTQHFURsV+7jSX96FpXYeKH6nmkq8AIw=
github.com/gofiber/fiber/v2 v2.52.4 h1:P+T+4iK7VaqUsq2PALYEfBBo6bJZ4q3FP8cZ84EggTM=
github.com/gofiber/fiber/v2 v2.52.4/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
github.com/gofiber/swagger v1.0.0 h1:BzUzDS9ZT6fDUa692kxmfOjc1DZiloLiPK/W5z1H1tc=
@@ -72,8 +79,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-migrate/migrate/v4 v4.17.1 h1:4zQ6iqL6t6AiItphxJctQb3cFqWiSpMnX7wLTPnnYO4=
github.com/golang-migrate/migrate/v4 v4.17.1/go.mod h1:m8hinFyWBn0SA4QKHuKh175Pm9wjmxj3S2Mia7dbXzM=
-github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
-github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
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/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
@@ -213,12 +220,30 @@ github.com/valyala/fasthttp v1.52.0 h1:wqBQpxH71XW0e2g+Og4dzQM8pk34aFYlA1Ga8db7g
github.com/valyala/fasthttp v1.52.0/go.mod h1:hf5C4QnVMkNXMspnsUlfM3WitlgYflyhHYoKol/szxQ=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
-go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
-go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.opentelemetry.io/contrib v1.17.0 h1:lJJdtuNsP++XHD7tXDYEFSpsqIc7DzShuXMR5PwkmzA=
+go.opentelemetry.io/contrib v1.17.0/go.mod h1:gIzjwWFoGazJmtCaDgViqOSJPde2mCWzv60o0bWPcZs=
+go.opentelemetry.io/contrib/propagators/b3 v1.17.0 h1:ImOVvHnku8jijXqkwCSyYKRDt2YrnGXD4BbhcpfbfJo=
+go.opentelemetry.io/contrib/propagators/b3 v1.17.0/go.mod h1:IkfUfMpKWmynvvE0264trz0sf32NRTZL4nuAN9AbWRc=
+go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs=
+go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.26.0 h1:0W5o9SzoR15ocYHEQfvfipzcNog1lBxOLfnex91Hk6s=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.26.0/go.mod h1:zVZ8nz+VSggWmnh6tTsJqXQ7rU4xLwRtna1M4x5jq58=
+go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30=
+go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4=
+go.opentelemetry.io/otel/oteltest v1.0.0-RC3 h1:MjaeegZTaX0Bv9uB9CrdVjOFM/8slRjReoWoV9xDCpY=
+go.opentelemetry.io/otel/oteltest v1.0.0-RC3/go.mod h1:xpzajI9JBRr7gX63nO6kAmImmYIAtuQblZ36Z+LfCjE=
+go.opentelemetry.io/otel/sdk v1.26.0 h1:Y7bumHf5tAiDlRYFmGqetNcLaVUZmh4iYfmGxtmz7F8=
+go.opentelemetry.io/otel/sdk v1.26.0/go.mod h1:0p8MXpqLeJ0pzcszQQN4F0S5FVjBLgypeGSngLsmirs=
+go.opentelemetry.io/otel/sdk/metric v0.39.0 h1:Kun8i1eYf48kHH83RucG93ffz0zGV1sh46FAScOTuDI=
+go.opentelemetry.io/otel/sdk/metric v0.39.0/go.mod h1:piDIRgjcK7u0HCL5pCA4e74qpK/jk3NiUoAHATVAmiI=
+go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA=
+go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0=
+go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
+go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
-golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
-golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
+golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8=
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
@@ -231,10 +256,10 @@ golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
-golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/backend/integrations/email/email.go b/backend/integrations/email/email.go
index 5ea9ea4b1..b4bcc8601 100644
--- a/backend/integrations/email/email.go
+++ b/backend/integrations/email/email.go
@@ -1,21 +1,25 @@
package email
import (
+ "bytes"
+ "context"
"fmt"
- "os"
"github.com/GenerateNU/sac/backend/config"
"github.com/GenerateNU/sac/backend/constants"
- "github.com/GenerateNU/sac/backend/errors"
+ "github.com/GenerateNU/sac/backend/templates/emails"
+
+ "github.com/a-h/templ"
+
"github.com/afex/hystrix-go/hystrix"
"github.com/resend/resend-go/v2"
)
type EmailClientInterface interface {
- SendPasswordResetEmail(name, email, token string) *errors.Error
- SendEmailVerification(email, code string) *errors.Error
- SendWelcomeEmail(name, email string) *errors.Error
- SendPasswordChangedEmail(name, email string) *errors.Error
+ SendPasswordResetEmail(name string, email string, token string) error
+ SendEmailVerification(email string, code string) error
+ SendWelcomeEmail(name string, email string) error
+ SendPasswordChangedEmail(name string, email string) error
}
type ResendClient struct {
@@ -36,90 +40,59 @@ func NewResendClient(settings config.ResendSettings, dev bool) EmailClientInterf
}
}
-func send(email, subject, html string, client *resend.Client) *errors.Error {
+func send(fromEmail string, toEmail string, subject string, template templ.Component, client *resend.Client) error {
+ buffer := new(bytes.Buffer)
+ err := template.Render(context.Background(), buffer)
+ if err != nil {
+ return fmt.Errorf("failed to render email template: %w", err)
+ }
+
params := &resend.SendEmailRequest{
- From: "onboarding" + constants.DOMAIN,
- To: []string{email},
+ From: fromEmail,
+ To: []string{toEmail},
Subject: subject,
- Html: html,
+ Html: buffer.String(),
}
- err := hystrix.Do("send-email", func() error {
+ err = hystrix.Do("send-email", func() error {
_, err := client.Emails.Send(params)
return err
}, nil)
if err != nil {
- return &errors.FailedToSendEmail
+ return fmt.Errorf("failed to send email: %w", err)
}
return nil
}
-func (r *ResendClient) SendPasswordResetEmail(name, email, token string) *errors.Error {
+func (r *ResendClient) SendPasswordResetEmail(name string, email string, token string) error {
if r.Dev {
return nil
}
- template, err := getTemplateString("password_reset")
- if err != nil {
- return &errors.FailedToGetTemplate
- }
-
- return send(email, "Password Reset", fmt.Sprintf(*template, name, token), r.Client)
+ return send(constants.DEFAULT_FROM_EMAIL, email, "Password Reset", emails.PasswordReset(name, fmt.Sprintf("https://hipponeu.com/reset/%s", token)), r.Client)
}
-func (r *ResendClient) SendEmailVerification(email, code string) *errors.Error {
+func (r *ResendClient) SendEmailVerification(email string, code string) error {
if r.Dev {
return nil
}
- template, err := getTemplateString("email_verification")
- if err != nil {
- return &errors.FailedToGetTemplate
- }
-
- return send(email, "Email Verification", fmt.Sprintf(*template, code), r.Client)
+ return send(constants.DEFAULT_FROM_EMAIL, email, "Email Verification", emails.Verification(code), r.Client)
}
-func (r *ResendClient) SendWelcomeEmail(name, email string) *errors.Error {
+func (r *ResendClient) SendWelcomeEmail(name string, email string) error {
if r.Dev {
return nil
}
- template, err := getTemplateString("welcome")
- if err != nil {
- return &errors.FailedToGetTemplate
- }
-
- return send(email, "Welcome to Resend", fmt.Sprintf(*template, name), r.Client)
+ return send(constants.ONBOARDING_EMAIL, email, "Welcome to Hippo", emails.Welcome(name), r.Client)
}
-func (r *ResendClient) SendPasswordChangedEmail(name, email string) *errors.Error {
+func (r *ResendClient) SendPasswordChangedEmail(name string, email string) error {
if r.Dev {
return nil
}
- template, err := getTemplateString("password_change_complete")
- if err != nil {
- return &errors.FailedToGetTemplate
- }
-
- return send(email, "Password Changed", fmt.Sprintf(*template, name), r.Client)
-}
-
-func getTemplateString(name string) (*string, error) {
- // TODO: use default file location
- cwd, err := os.Getwd()
- if err != nil {
- return nil, err
- }
-
- htmlBytes, err := os.ReadFile(fmt.Sprintf("%v/templates/emails/%s.html", cwd, name))
- if err != nil {
- return nil, err
- }
-
- htmlString := string(htmlBytes)
-
- return &htmlString, nil
+ return send(constants.DEFAULT_FROM_EMAIL, email, "Password Changed", emails.PasswordChangeComplete(name), r.Client)
}
diff --git a/backend/integrations/file/file.go b/backend/integrations/file/file.go
index c9c485289..f47e13f4e 100644
--- a/backend/integrations/file/file.go
+++ b/backend/integrations/file/file.go
@@ -2,6 +2,7 @@ package file
import (
"bytes"
+ "errors"
"fmt"
"io"
"mime/multipart"
@@ -10,7 +11,7 @@ import (
"github.com/GenerateNU/sac/backend/config"
"github.com/GenerateNU/sac/backend/constants"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
@@ -32,8 +33,8 @@ const (
type FileClientInterface interface {
GetFileURL(fileURL string) *string
- UploadFile(folder string, fileHeader *multipart.FileHeader, allowedTypes []FileType) (*models.FileInfo, *errors.Error)
- DeleteFile(fileURL string) *errors.Error
+ UploadFile(folder string, fileHeader *multipart.FileHeader, allowedTypes []FileType) (*models.FileInfo, error)
+ DeleteFile(fileURL string) error
}
type AWSClient struct {
@@ -58,23 +59,22 @@ func (aw *AWSClient) GetFileURL(fileURL string) *string {
return &fileURL
}
-func preProcessFile(fileHeader *multipart.FileHeader) (*string, []byte, *errors.Error) {
+func preProcessFile(fileHeader *multipart.FileHeader) (*string, []byte, error) {
if fileHeader.Size > constants.MAX_FILE_SIZE {
- return nil, nil, &errors.InvalidFileSize
+ return nil, nil, errors.New("file size is too large")
}
file, err := fileHeader.Open()
if err != nil {
- return nil, nil, &errors.FailedToOpenFile
+ return nil, nil, errors.New("failed to open file")
}
+ defer file.Close()
fileBytes, err := io.ReadAll(file)
if err != nil {
- return nil, nil, &errors.FailedToReadFile
+ return nil, nil, errors.New("failed to read file")
}
- defer file.Close()
-
fileName := generateUniqueFileName(fileHeader.Filename)
return &fileName, fileBytes, nil
@@ -106,10 +106,10 @@ func isFileTypeAllowed(fileType string, allowedTypes []FileType) bool {
return false
}
-func (aw *AWSClient) UploadFile(folder string, fileHeader *multipart.FileHeader, allowedTypes []FileType) (*models.FileInfo, *errors.Error) {
+func (aw *AWSClient) UploadFile(folder string, fileHeader *multipart.FileHeader, allowedTypes []FileType) (*models.FileInfo, error) {
fileType := fileHeader.Header.Get("Content-Type")
if !isFileTypeAllowed(fileType, allowedTypes) {
- return nil, &errors.InvalidFileType
+ return nil, errors.New("file type is not allowed")
}
fileName, file, err := preProcessFile(fileHeader)
@@ -122,26 +122,25 @@ func (aw *AWSClient) UploadFile(folder string, fileHeader *multipart.FileHeader,
bucket := aw.Settings.BUCKET_NAME.Expose()
key := fmt.Sprintf("%s/%s", folder, *fileName)
- _, s3Err := svc.PutObject(&s3.PutObjectInput{
+ _, err = svc.PutObject(&s3.PutObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
Body: bytes.NewReader(file),
})
- if s3Err != nil {
- return nil, &errors.FailedToUploadFile
+ if err != nil {
+ return nil, fmt.Errorf("failed to upload file: %s", err)
}
- fileURL := fmt.Sprintf("https://s3.amazonaws.com/%s/%s", bucket, key)
return &models.FileInfo{
FileName: *fileName,
FileType: fileHeader.Header.Get("Content-Type"),
FileSize: int(fileHeader.Size),
- FileURL: fileURL,
+ FileURL: fmt.Sprintf("https://s3.amazonaws.com/%s/%s", bucket, key),
ObjectKey: key,
}, nil
}
-func (aw *AWSClient) DeleteFile(fileURL string) *errors.Error {
+func (aw *AWSClient) DeleteFile(fileURL string) error {
svc := s3.New(aw.session)
bucket := aw.Settings.BUCKET_NAME.Expose()
@@ -152,7 +151,7 @@ func (aw *AWSClient) DeleteFile(fileURL string) *errors.Error {
Key: aws.String(key),
})
if err != nil {
- return &errors.FailedToDeleteFile
+ return fmt.Errorf("failed to delete file: %s", err)
}
return nil
diff --git a/backend/integrations/search/README.md b/backend/integrations/search/README.md
index 0e7fe43b5..f6e293b6d 100644
--- a/backend/integrations/search/README.md
+++ b/backend/integrations/search/README.md
@@ -54,9 +54,9 @@ type Searchable interface {
// in backend/src/search/pinecone.go
type PineconeClientInterface interface {
- Upsert(item Searchable) *errors.Error
- Delete(item Searchable) *errors.Error
- Search(item Searchable, topK int) ([]string, *errors.Error)
+ Upsert(item Searchable) error
+ Delete(item Searchable) error
+ Search(item Searchable, topK int) ([]string, error)
}
```
diff --git a/backend/integrations/search/ai.go b/backend/integrations/search/ai.go
index 10d802efe..cc84d26ff 100644
--- a/backend/integrations/search/ai.go
+++ b/backend/integrations/search/ai.go
@@ -2,19 +2,21 @@ package search
import (
"bytes"
+ "errors"
+ "fmt"
"net/http"
"github.com/goccy/go-json"
"github.com/GenerateNU/sac/backend/config"
- "github.com/GenerateNU/sac/backend/errors"
+
"github.com/GenerateNU/sac/backend/utilities"
"github.com/gofiber/fiber/v2"
)
type AIClientInterface interface {
- CreateEmbedding(items []Searchable) ([]Embedding, *errors.Error)
- CreateModeration(items []Searchable) ([]ModerationResult, *errors.Error)
+ CreateEmbedding(items []Searchable) ([]Embedding, error)
+ CreateModeration(items []Searchable) ([]ModerationResult, error)
}
type OpenAIClient struct {
@@ -38,7 +40,7 @@ type CreateEmbeddingResponseBody struct {
Data []Embedding `json:"data"`
}
-func (c *OpenAIClient) CreateEmbedding(items []Searchable) ([]Embedding, *errors.Error) {
+func (c *OpenAIClient) CreateEmbedding(items []Searchable) ([]Embedding, error) {
embeddingStrings := make([]string, len(items))
for i, item := range items {
embeddingStrings[i] = item.EmbeddingString()
@@ -50,14 +52,14 @@ func (c *OpenAIClient) CreateEmbedding(items []Searchable) ([]Embedding, *errors
Model: "text-embedding-ada-002",
})
if err != nil {
- return nil, &errors.FailedToCreateEmbedding
+ return nil, fmt.Errorf("failed to create embedding request body: %w", err)
}
req, err := http.NewRequest(fiber.MethodPost,
"https://api.openai.com/v1/embeddings",
bytes.NewBuffer(embeddingBody))
if err != nil {
- return nil, &errors.FailedToCreateEmbedding
+ return nil, fmt.Errorf("failed to create embedding: %w", err)
}
req = utilities.ApplyModifiers(req,
@@ -67,20 +69,19 @@ func (c *OpenAIClient) CreateEmbedding(items []Searchable) ([]Embedding, *errors
resp, err := http.DefaultClient.Do(req)
if err != nil {
- return nil, &errors.FailedToCreateEmbedding
+ return nil, fmt.Errorf("failed to create embedding: %w", err)
}
-
defer resp.Body.Close()
var embeddingResultBody CreateEmbeddingResponseBody
err = json.NewDecoder(resp.Body).Decode(&embeddingResultBody)
if err != nil {
- return nil, &errors.FailedToCreateEmbedding
+ return nil, fmt.Errorf("failed to create embedding: %w", err)
}
if len(embeddingResultBody.Data) < 1 {
- return nil, &errors.FailedToCreateEmbedding
+ return nil, fmt.Errorf("failed to create embedding: %w", err)
}
return embeddingResultBody.Data, nil
@@ -99,7 +100,7 @@ type ModerationResult struct {
Flagged bool `json:"flagged"`
}
-func (c *OpenAIClient) CreateModeration(items []Searchable) ([]ModerationResult, *errors.Error) {
+func (c *OpenAIClient) CreateModeration(items []Searchable) ([]ModerationResult, error) {
searchStrings := make([]string, len(items))
for i, item := range items {
searchStrings[i] = item.EmbeddingString()
@@ -111,14 +112,14 @@ func (c *OpenAIClient) CreateModeration(items []Searchable) ([]ModerationResult,
Model: "text-moderation-stable",
})
if err != nil {
- return nil, &errors.FailedToCreateModeration
+ return nil, fmt.Errorf("failed to create moderation request body: %w", err)
}
req, err := http.NewRequest(fiber.MethodPost,
"https://api.openai.com/v1/moderations",
bytes.NewBuffer(moderationBody))
if err != nil {
- return nil, &errors.FailedToCreateModeration
+ return nil, fmt.Errorf("failed to create moderation: %w", err)
}
req = utilities.ApplyModifiers(req,
@@ -128,20 +129,19 @@ func (c *OpenAIClient) CreateModeration(items []Searchable) ([]ModerationResult,
resp, err := http.DefaultClient.Do(req)
if err != nil {
- return nil, &errors.FailedToCreateModeration
+ return nil, fmt.Errorf("failed to create moderation: %w", err)
}
-
defer resp.Body.Close()
var moderationResultBody CreateModerationResponseBody
err = json.NewDecoder(resp.Body).Decode(&moderationResultBody)
if err != nil {
- return nil, &errors.FailedToCreateModeration
+ return nil, fmt.Errorf("failed to create moderation: %w", err)
}
if len(moderationResultBody.Results) < 1 {
- return nil, &errors.FailedToCreateModeration
+ return nil, errors.New("failed to create moderation")
}
return moderationResultBody.Results, nil
diff --git a/backend/integrations/search/search.go b/backend/integrations/search/search.go
index 07def1017..52ad00f79 100644
--- a/backend/integrations/search/search.go
+++ b/backend/integrations/search/search.go
@@ -15,15 +15,15 @@ import (
"github.com/GenerateNU/sac/backend/config"
"github.com/GenerateNU/sac/backend/constants"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
+
"github.com/GenerateNU/sac/backend/utilities"
)
type SearchClientInterface interface {
- Seed(db *gorm.DB) *errors.Error
- Upsert(items []Searchable) *errors.Error
- Delete(items []Searchable) *errors.Error
- Search(item Searchable) ([]string, *errors.Error)
+ Seed(db *gorm.DB) error
+ Upsert(items []Searchable) error
+ Delete(items []Searchable) error
+ Search(item Searchable) ([]string, error)
}
type PineconeClient struct {
@@ -41,11 +41,11 @@ func NewPineconeClient(aiClient AIClientInterface, pineconeSettings config.Pinec
}
// Seeds the pinecone index with the clubs currently in the database.
-func (c *PineconeClient) Seed(db *gorm.DB) *errors.Error {
+func (c *PineconeClient) Seed(db *gorm.DB) error {
var clubs []models.Club
if err := db.Find(&clubs).Error; err != nil {
- return &errors.ClubSeedingFailed
+ return fmt.Errorf("failed to get clubs from database: %w", err)
}
searchables := make([]Searchable, len(clubs))
@@ -70,7 +70,7 @@ func (c *PineconeClient) Seed(db *gorm.DB) *errors.Error {
log.Info("Uploading chunk #%d (of %d) to pinecone...\n", index+1, len(chunks))
err := c.Upsert(chunk)
if err != nil {
- return &errors.ClubSeedingFailed
+ return fmt.Errorf("failed to seed pinecone index: %w", err)
}
}
@@ -96,14 +96,14 @@ type PineconeUpsertRequestBody struct {
}
// Inserts the given list of searchables to the Pinecone index.
-func (c *PineconeClient) Upsert(items []Searchable) *errors.Error {
+func (c *PineconeClient) Upsert(items []Searchable) error {
if len(items) == 0 {
return nil
}
embeddings, embeddingErr := c.aiClient.CreateEmbedding(items)
if embeddingErr != nil {
- return &errors.FailedToUpsertToPinecone
+ return fmt.Errorf("failed to create embeddings: %w", embeddingErr)
}
vectors := []Vector{}
@@ -120,26 +120,26 @@ func (c *PineconeClient) Upsert(items []Searchable) *errors.Error {
Namespace: items[0].Namespace(),
})
if err != nil {
- return &errors.FailedToUpsertToPinecone
+ return fmt.Errorf("failed to marshal upsert body: %w", err)
}
req, err := http.NewRequest(fiber.MethodPost,
fmt.Sprintf("%s/vectors/upsert", c.PineconeSettings.IndexHost.Expose()),
bytes.NewBuffer(upsertBody))
if err != nil {
- return &errors.FailedToUpsertToPinecone
+ return fmt.Errorf("failed to create upsert request: %w", err)
}
req = pineconeRequest(c.PineconeSettings, req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
- return &errors.FailedToUpsertToPinecone
+ return fmt.Errorf("failed to upsert to pinecone: %w", err)
}
defer resp.Body.Close()
- if resp.StatusCode != fiber.StatusOK {
- return &errors.FailedToUpsertToPinecone
+ if resp.StatusCode != http.StatusOK {
+ return fmt.Errorf("failed to upsert to pinecone: %s", resp.Status)
}
return nil
@@ -152,7 +152,7 @@ type PineconeDeleteRequestBody struct {
}
// Deletes the given list of searchables from the Pinecone index.
-func (c *PineconeClient) Delete(items []Searchable) *errors.Error {
+func (c *PineconeClient) Delete(items []Searchable) error {
if len(items) == 0 {
return nil
}
@@ -161,7 +161,7 @@ func (c *PineconeClient) Delete(items []Searchable) *errors.Error {
namespace := items[0].Namespace()
for _, item := range items {
if item.Namespace() != namespace {
- return &errors.ItemsMustHaveSameNamespace
+ return fmt.Errorf("all items must be in the same namespace. item %s is in namespace %s, but expected %s", item.SearchId(), item.Namespace(), namespace)
}
}
@@ -177,25 +177,26 @@ func (c *PineconeClient) Delete(items []Searchable) *errors.Error {
DeleteAll: false,
})
if err != nil {
- return &errors.FailedToDeleteToPinecone
+ return fmt.Errorf("failed to marshal delete body: %w", err)
}
req, err := http.NewRequest(fiber.MethodPost,
fmt.Sprintf("%s/vectors/delete", c.PineconeSettings.IndexHost.Expose()),
bytes.NewBuffer(deleteBody))
if err != nil {
- return &errors.FailedToDeleteToPinecone
+ return fmt.Errorf("failed to create delete request: %w", err)
}
req = pineconeRequest(c.PineconeSettings, req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
- return &errors.FailedToDeleteToPinecone
+ return fmt.Errorf("failed to delete from pinecone: %w", err)
}
+ defer resp.Body.Close()
- if resp.StatusCode != fiber.StatusOK {
- return &errors.FailedToDeleteToPinecone
+ if resp.StatusCode != http.StatusOK {
+ return fmt.Errorf("failed to delete from pinecone: %s", resp.Status)
}
return nil
@@ -222,19 +223,19 @@ type PineconeSearchResponseBody struct {
// Runs a search on the Pinecone index given a searchable item, and returns the topK most similar
// elements' ids.
-func (c *PineconeClient) Search(item Searchable) ([]string, *errors.Error) {
- moderation, _err := c.aiClient.CreateModeration([]Searchable{item})
- if _err != nil {
- return []string{}, _err
+func (c *PineconeClient) Search(item Searchable) ([]string, error) {
+ moderation, err := c.aiClient.CreateModeration([]Searchable{item})
+ if err != nil {
+ return []string{}, err
}
if moderation[0].Flagged {
- return []string{}, &errors.PotentiallyHarmfulSearch
+ return []string{}, utilities.BadRequest(fmt.Errorf("potentially harmful content detected in item %s", item))
}
- values, embeddingErr := c.aiClient.CreateEmbedding([]Searchable{item})
- if embeddingErr != nil {
- return []string{}, embeddingErr
+ values, err := c.aiClient.CreateEmbedding([]Searchable{item})
+ if err != nil {
+ return []string{}, err
}
searchBody, err := json.Marshal(
@@ -247,33 +248,32 @@ func (c *PineconeClient) Search(item Searchable) ([]string, *errors.Error) {
Namespace: item.Namespace(),
})
if err != nil {
- return []string{}, &errors.FailedToSearchToPinecone
+ return []string{}, fmt.Errorf("failed to marshal search body: %w", err)
}
req, err := http.NewRequest(fiber.MethodPost,
fmt.Sprintf("%s/query", c.PineconeSettings.IndexHost.Expose()),
bytes.NewBuffer(searchBody))
if err != nil {
- return []string{}, &errors.FailedToSearchToPinecone
+ return []string{}, fmt.Errorf("failed to create search request: %w", err)
}
req = pineconeRequest(c.PineconeSettings, req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
- return []string{}, &errors.FailedToSearchToPinecone
+ return []string{}, fmt.Errorf("failed to search to pinecone: %w", err)
}
-
defer resp.Body.Close()
- if resp.StatusCode != fiber.StatusOK {
- return []string{}, &errors.FailedToSearchToPinecone
+ if resp.StatusCode != http.StatusOK {
+ return []string{}, fmt.Errorf("failed to search to pinecone: %w", err)
}
var results PineconeSearchResponseBody
err = json.NewDecoder(resp.Body).Decode(&results)
if err != nil {
- return []string{}, &errors.FailedToSearchToPinecone
+ return []string{}, fmt.Errorf("failed to decode search response: %w", err)
}
resultsToReturn := []string{}
diff --git a/backend/main.go b/backend/main.go
index 576ab6feb..87113b713 100644
--- a/backend/main.go
+++ b/backend/main.go
@@ -1,8 +1,10 @@
package main
import (
+ "context"
"flag"
"fmt"
+ "log/slog"
"net"
"os"
"path/filepath"
@@ -15,42 +17,12 @@ import (
"github.com/GenerateNU/sac/backend/integrations/file"
"github.com/GenerateNU/sac/backend/integrations/search"
"github.com/GenerateNU/sac/backend/server"
+ "github.com/GenerateNU/sac/backend/telemetry"
"github.com/GenerateNU/sac/backend/tests/api/mocks"
+ "go.opentelemetry.io/otel"
)
-func CheckServerRunning(host string, port uint16) error {
- address := fmt.Sprintf("%s:%d", host, port)
- conn, err := net.Dial("tcp", address)
- if err != nil {
- return err
- }
- defer conn.Close()
- return nil
-}
-
-func Exit(format string, a ...interface{}) {
- fmt.Fprintf(os.Stderr, format, a...)
- os.Exit(0)
-}
-
-func configureIntegrations(config *config.Settings, connectToPinecone bool) integrations.Integrations {
- openAi := search.NewOpenAIClient(config.OpenAISettings)
- var pinecone search.SearchClientInterface
-
- if connectToPinecone {
- pinecone = search.NewPineconeClient(openAi, config.PineconeSettings)
- } else {
- pinecone = mocks.NewPineconeMockClient()
- }
-
- integrations := integrations.Integrations{
- File: file.NewAWSProvider(config.AWS),
- AI: openAi,
- Email: email.NewResendClient(config.ResendSettings, true),
- Search: pinecone,
- }
- return integrations
-}
+var tracer = otel.Tracer("sac")
func main() {
onlyMigrate := flag.Bool("only-migrate", false, "Specify if you want to only perform the database migration")
@@ -63,17 +35,17 @@ func main() {
config, err := config.GetConfiguration(*configPath, *useDevDotEnv)
if err != nil {
- Exit("Error getting configuration: %s", err.Error())
+ exit("Error getting configuration: %s", err.Error())
}
- err = CheckServerRunning(config.Application.Host, config.Application.Port)
+ err = checkServerRunning(config.Application.Host, config.Application.Port)
if err == nil {
- Exit("A server is already running on %s:%d.\n", config.Application.Host, config.Application.Port)
+ exit("A server is already running on %s:%d.\n", config.Application.Host, config.Application.Port)
}
db, err := database.ConfigureDB(*config)
if err != nil {
- Exit("Error migrating database: %s", err.Error())
+ exit("Error migrating database: %s", err.Error())
}
if *onlyMigrate {
@@ -81,27 +53,71 @@ func main() {
}
if *onlySeedPinecone {
- openAi := search.NewOpenAIClient(config.OpenAISettings)
- pinecone := search.NewPineconeClient(openAi, config.PineconeSettings)
+ openAi := search.NewOpenAIClient(config.OpenAI)
+ pinecone := search.NewPineconeClient(openAi, config.Pinecone)
err := pinecone.Seed(db)
if err != nil {
- Exit("Error seeding PineconeDB: %s\n", err.Error())
+ exit("Error seeding PineconeDB: %s\n", err.Error())
}
return
}
err = database.ConnPooling(db)
if err != nil {
- Exit("Error with connection pooling: %s", err.Error())
+ exit("Error with connection pooling: %s", err.Error())
}
integrations := configureIntegrations(config, *connectToPinecone)
+ tp := telemetry.InitTracer()
+
+ slog.Info("appease linter since we aren't tracing anything yet", "tracer", tracer)
+
+ defer func() {
+ if err := tp.Shutdown(context.Background()); err != nil {
+ slog.Error("error shutting down tracer", "error", err)
+ }
+ }()
+
app := server.Init(db, integrations, *config)
err = app.Listen(fmt.Sprintf("%s:%d", config.Application.Host, config.Application.Port))
if err != nil {
- Exit("Error starting server: %s", err.Error())
+ exit("Error starting server: %s", err.Error())
+ }
+}
+
+func checkServerRunning(host string, port uint16) error {
+ address := fmt.Sprintf("%s:%d", host, port)
+ conn, err := net.Dial("tcp", address)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+ return nil
+}
+
+func exit(format string, a ...interface{}) {
+ fmt.Fprintf(os.Stderr, format, a...)
+ os.Exit(0)
+}
+
+func configureIntegrations(config *config.Settings, connectToPinecone bool) integrations.Integrations {
+ openAi := search.NewOpenAIClient(config.OpenAI)
+ var pinecone search.SearchClientInterface
+
+ if connectToPinecone {
+ pinecone = search.NewPineconeClient(openAi, config.Pinecone)
+ } else {
+ pinecone = mocks.NewPineconeMockClient()
}
+
+ integrations := integrations.Integrations{
+ File: file.NewAWSProvider(config.AWS),
+ AI: openAi,
+ Email: email.NewResendClient(config.Resend, true),
+ Search: pinecone,
+ }
+ return integrations
}
diff --git a/backend/middleware/auth.go b/backend/middleware/auth.go
deleted file mode 100644
index cf0ab8150..000000000
--- a/backend/middleware/auth.go
+++ /dev/null
@@ -1,117 +0,0 @@
-package middleware
-
-import (
- "fmt"
- "slices"
- "strings"
- "time"
-
- "github.com/GenerateNU/sac/backend/auth"
-
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
-
- "github.com/golang-jwt/jwt"
-
- "github.com/gofiber/fiber/v2"
- "github.com/gofiber/fiber/v2/middleware/limiter"
-)
-
-func (m *AuthMiddlewareService) IsSuper(c *fiber.Ctx) bool {
- claims, err := auth.From(c)
- if err != nil {
- _ = err.FiberError(c)
- return false
- }
- if claims == nil {
- return false
- }
- return claims.Role == string(models.Super)
-}
-
-func GetAuthroizationToken(c *fiber.Ctx) *string {
- accessToken := c.Get("Authorization")
- if accessToken == "" {
- return nil
- }
-
- token := strings.Split(accessToken, "Bearer ")
- if len(token) != 2 {
- return nil
- }
-
- return &token[1]
-}
-
-func (m *AuthMiddlewareService) Authenticate(c *fiber.Ctx) error {
- accessToken := GetAuthroizationToken(c)
- if accessToken == nil {
- return errors.Unauthorized.FiberError(c)
- }
-
- token, err := func() (*jwt.Token, error) {
- return jwt.ParseWithClaims(*accessToken, &auth.CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
- return []byte(m.AuthSettings.AccessKey.Expose()), nil
- })
- }()
- if err != nil {
- return errors.Unauthorized.FiberError(c)
- }
-
- claims, ok := token.Claims.(*auth.CustomClaims)
- if !ok || !token.Valid {
- return errors.Unauthorized.FiberError(c)
- }
-
- // if auth.IsBlacklisted(*accessToken) {
- // return errors.Unauthorized.FiberError(c)
- // }
-
- c.Locals("claims", claims)
-
- return nil
-}
-
-func (m *AuthMiddlewareService) Authorize(requiredPermissions ...auth.Permission) func(c *fiber.Ctx) error {
- return func(c *fiber.Ctx) error {
- authErr := m.Authenticate(c)
- if authErr != nil {
- return errors.Unauthorized.FiberError(c)
- }
-
- claims, fromErr := auth.From(c)
- if fromErr != nil {
- return fromErr.FiberError(c)
- }
-
- if claims != nil && claims.Role == string(models.Super) {
- return c.Next()
- }
-
- userPermissions := auth.GetPermissions(models.UserRole(claims.Role))
-
- for _, requiredPermission := range requiredPermissions {
- if !slices.Contains(userPermissions, requiredPermission) {
- return errors.Forbidden.FiberError(c)
- }
- }
-
- return c.Next()
- }
-}
-
-// TODO: implement rate limiting with redis
-func (m *AuthMiddlewareService) Limiter(rate int, expiration time.Duration) func(c *fiber.Ctx) error {
- return limiter.New(limiter.Config{
- Max: rate,
- Expiration: expiration,
- KeyGenerator: func(c *fiber.Ctx) string {
- return fmt.Sprintf("%s-%s", c.IP(), c.Path())
- },
- LimitReached: func(c *fiber.Ctx) error {
- return c.Status(fiber.StatusTooManyRequests).JSON(fiber.Map{
- "error": "Too many requests",
- })
- },
- })
-}
diff --git a/backend/middleware/auth/auth.go b/backend/middleware/auth/auth.go
new file mode 100644
index 000000000..1a0962766
--- /dev/null
+++ b/backend/middleware/auth/auth.go
@@ -0,0 +1,100 @@
+package auth
+
+import (
+ "slices"
+ "strings"
+
+ "github.com/GenerateNU/sac/backend/auth"
+ "github.com/GenerateNU/sac/backend/utilities"
+
+ "github.com/GenerateNU/sac/backend/entities/models"
+
+ "github.com/golang-jwt/jwt"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+func (m *AuthMiddlewareService) IsSuper(c *fiber.Ctx) bool {
+ claims, err := auth.From(c)
+ if err != nil {
+ _ = err
+ return false
+ }
+ if claims == nil {
+ return false
+ }
+ return claims.Role == string(models.Super)
+}
+
+func GetAuthroizationToken(c *fiber.Ctx) *string {
+ accessToken := c.Get("Authorization")
+ if accessToken == "" {
+ return nil
+ }
+
+ token := strings.Split(accessToken, "Bearer ")
+ if len(token) != 2 {
+ return nil
+ }
+
+ return &token[1]
+}
+
+func (m *AuthMiddlewareService) Authenticate(c *fiber.Ctx) error {
+ return func(c *fiber.Ctx) error {
+ accessToken := GetAuthroizationToken(c)
+ if accessToken == nil {
+ return utilities.Unauthorized()
+ }
+
+ token, err := func() (*jwt.Token, error) {
+ return jwt.ParseWithClaims(*accessToken, &auth.CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
+ return []byte(m.Auth.AccessKey.Expose()), nil
+ })
+ }()
+ if err != nil {
+ return utilities.Unauthorized()
+ }
+
+ claims, ok := token.Claims.(*auth.CustomClaims)
+ if !ok || !token.Valid {
+ return utilities.Unauthorized()
+ }
+
+ // if auth.IsBlacklisted(*accessToken) {
+ // return errors.Unauthorized.FiberError(c)
+ // }
+
+ c.Locals("claims", claims)
+
+ return nil
+ }(c)
+}
+
+func (m *AuthMiddlewareService) Authorize(requiredPermissions ...auth.Permission) func(c *fiber.Ctx) error {
+ return func(c *fiber.Ctx) error {
+ authErr := m.Authenticate(c)
+ if authErr != nil {
+ return utilities.Unauthorized()
+ }
+
+ claims, err := auth.From(c)
+ if err != nil {
+ return err
+ }
+
+ if claims != nil && claims.Role == string(models.Super) {
+ return c.Next()
+ }
+
+ userPermissions := auth.GetPermissions(models.UserRole(claims.Role))
+
+ for _, requiredPermission := range requiredPermissions {
+ if !slices.Contains(userPermissions, requiredPermission) {
+ return utilities.Forbidden()
+ }
+ }
+
+ return c.Next()
+ }
+}
diff --git a/backend/middleware/auth/club.go b/backend/middleware/auth/club.go
new file mode 100644
index 000000000..5a084fd7b
--- /dev/null
+++ b/backend/middleware/auth/club.go
@@ -0,0 +1,49 @@
+package auth
+
+import (
+ "slices"
+
+ "github.com/GenerateNU/sac/backend/auth"
+ "github.com/GenerateNU/sac/backend/entities/clubs"
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/gofiber/fiber/v2"
+)
+
+// Authorizes admins of the specific club to make this request, skips check if super user
+func (m *AuthMiddlewareService) ClubAuthorizeById(c *fiber.Ctx, extractor ExtractID) error {
+ return func(c *fiber.Ctx) error {
+ if err := m.Authenticate(c); err != nil {
+ return utilities.Unauthorized()
+ }
+
+ if m.IsSuper(c) {
+ return c.Next()
+ }
+
+ clubUUID, err := extractor(c)
+ if err != nil {
+ return err
+ }
+
+ claims, err := auth.From(c)
+ if err != nil {
+ return err
+ }
+
+ issuerUUID, err := utilities.ValidateID(claims.Issuer)
+ if err != nil {
+ return err
+ }
+
+ clubAdmin, err := clubs.GetAdminIDs(m.DB, *clubUUID)
+ if err != nil {
+ return err
+ }
+
+ if slices.Contains(clubAdmin, *issuerUUID) {
+ return c.Next()
+ }
+
+ return utilities.Forbidden()
+ }(c)
+}
diff --git a/backend/middleware/auth/event.go b/backend/middleware/auth/event.go
new file mode 100644
index 000000000..542f6e7c2
--- /dev/null
+++ b/backend/middleware/auth/event.go
@@ -0,0 +1,49 @@
+package auth
+
+import (
+ "slices"
+
+ "github.com/GenerateNU/sac/backend/auth"
+ "github.com/GenerateNU/sac/backend/entities/events"
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/gofiber/fiber/v2"
+)
+
+// Authorizes admins of the host club of this event to make this request, skips check if super user
+func (m *AuthMiddlewareService) EventAuthorizeById(c *fiber.Ctx, extractor ExtractID) error {
+ return func(c *fiber.Ctx) error {
+ if err := m.Authenticate(c); err != nil {
+ return utilities.Unauthorized()
+ }
+
+ if m.IsSuper(c) {
+ return c.Next()
+ }
+
+ eventUUID, err := extractor(c)
+ if err != nil {
+ return err
+ }
+
+ claims, err := auth.From(c)
+ if err != nil {
+ return err
+ }
+
+ issuerUUID, err := utilities.ValidateID(claims.Issuer)
+ if err != nil {
+ return err
+ }
+
+ eventHostAdmin, err := events.GetEventHostAdminIDs(m.DB, *eventUUID)
+ if err != nil {
+ return err
+ }
+
+ if slices.Contains(eventHostAdmin, *issuerUUID) {
+ return c.Next()
+ }
+
+ return utilities.Forbidden()
+ }(c)
+}
diff --git a/backend/middleware/auth/extractor.go b/backend/middleware/auth/extractor.go
new file mode 100644
index 000000000..8b10c29f5
--- /dev/null
+++ b/backend/middleware/auth/extractor.go
@@ -0,0 +1,81 @@
+package auth
+
+import (
+ "errors"
+ "fmt"
+
+ go_json "github.com/goccy/go-json"
+ "gorm.io/gorm"
+
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/gofiber/fiber/v2"
+ "github.com/google/uuid"
+)
+
+type ExtractID func(*fiber.Ctx) (*uuid.UUID, error)
+
+func AttachExtractor(middleware func(c *fiber.Ctx, extractor ExtractID) error, extractor ExtractID) fiber.Handler {
+ return func(c *fiber.Ctx) error {
+ return middleware(c, extractor)
+ }
+}
+
+func ExtractFromParams(param string) ExtractID {
+ return func(c *fiber.Ctx) (*uuid.UUID, error) {
+ return utilities.ValidateID(c.Params(param))
+ }
+}
+
+func ExtractFromBody(key string) ExtractID {
+ return func(c *fiber.Ctx) (*uuid.UUID, error) {
+ var bodyMap map[string]string
+
+ bodyBytes := c.BodyRaw()
+
+ if len(bodyBytes) == 0 {
+ return nil, errors.New("empty request body")
+ }
+
+ err := go_json.Unmarshal(bodyBytes, &bodyMap)
+ if err != nil {
+ return nil, err
+ }
+
+ id, ok := bodyMap[key]
+ if !ok {
+ return nil, fmt.Errorf("missing key %s in request body", key)
+ }
+
+ return utilities.ValidateID(id)
+ }
+}
+
+type QueryFn func(*gorm.DB, uuid.UUID) (*uuid.UUID, error)
+
+func ExtractFromQuery(db *gorm.DB, id uuid.UUID, query QueryFn) ExtractID {
+ return func(c *fiber.Ctx) (*uuid.UUID, error) {
+ id, err := query(db, id)
+ if err != nil {
+ return nil, err
+ }
+
+ return id, nil
+ }
+}
+
+func ExtractFromParamIntoQuery(param string, db *gorm.DB, query QueryFn) ExtractID {
+ return func(c *fiber.Ctx) (*uuid.UUID, error) {
+ id, err := ExtractFromParams(param)(c)
+ if err != nil {
+ return nil, err
+ }
+
+ return ExtractFromQuery(db, *id, query)(c)
+ }
+}
+
+func FromExtractFromParamIntoQuery(param string, db *gorm.DB, query QueryFn) ExtractID {
+ return func(c *fiber.Ctx) (*uuid.UUID, error) {
+ return ExtractFromParamIntoQuery(param, db, query)(c)
+ }
+}
diff --git a/backend/middleware/auth/middleware.go b/backend/middleware/auth/middleware.go
new file mode 100644
index 000000000..97b3cafa5
--- /dev/null
+++ b/backend/middleware/auth/middleware.go
@@ -0,0 +1,31 @@
+package auth
+
+import (
+ "github.com/GenerateNU/sac/backend/auth"
+ "github.com/GenerateNU/sac/backend/config"
+ "github.com/go-playground/validator/v10"
+ "github.com/gofiber/fiber/v2"
+ "gorm.io/gorm"
+)
+
+type AuthMiddlewareInterface interface {
+ ClubAuthorizeById(c *fiber.Ctx) error
+ UserAuthorizeById(c *fiber.Ctx) error
+ Authenticate(c *fiber.Ctx) error
+ Authorize(requiredPermissions ...auth.Permission) fiber.Handler
+ IsSuper(c *fiber.Ctx) bool
+}
+
+type AuthMiddlewareService struct {
+ DB *gorm.DB
+ Validate *validator.Validate
+ Auth config.AuthSettings
+}
+
+func New(db *gorm.DB, validate *validator.Validate, authSettings config.AuthSettings) *AuthMiddlewareService {
+ return &AuthMiddlewareService{
+ DB: db,
+ Validate: validate,
+ Auth: authSettings,
+ }
+}
diff --git a/backend/middleware/auth/user.go b/backend/middleware/auth/user.go
new file mode 100644
index 000000000..bf489faa2
--- /dev/null
+++ b/backend/middleware/auth/user.go
@@ -0,0 +1,40 @@
+package auth
+
+import (
+ "github.com/GenerateNU/sac/backend/auth"
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/gofiber/fiber/v2"
+)
+
+func (m *AuthMiddlewareService) UserAuthorizeById(c *fiber.Ctx) error {
+ return func(c *fiber.Ctx) error {
+ if err := m.Authenticate(c); err != nil {
+ return utilities.Unauthorized()
+ }
+
+ if m.IsSuper(c) {
+ return c.Next()
+ }
+
+ idAsUUID, err := utilities.ValidateID(c.Params("userID"))
+ if err != nil {
+ return err
+ }
+
+ claims, err := auth.From(c)
+ if err != nil {
+ return err
+ }
+
+ issuerIDAsUUID, err := utilities.ValidateID(claims.Issuer)
+ if err != nil {
+ return err
+ }
+
+ if issuerIDAsUUID.String() == idAsUUID.String() {
+ return c.Next()
+ }
+
+ return utilities.Forbidden()
+ }(c)
+}
diff --git a/backend/middleware/club.go b/backend/middleware/club.go
deleted file mode 100644
index d90d041b8..000000000
--- a/backend/middleware/club.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package middleware
-
-import (
- "slices"
-
- "github.com/GenerateNU/sac/backend/auth"
- "github.com/GenerateNU/sac/backend/entities/clubs"
- "github.com/GenerateNU/sac/backend/errors"
- "github.com/GenerateNU/sac/backend/utilities"
- "github.com/gofiber/fiber/v2"
-)
-
-// Authorizes admins of the specific club to make this request, skips check if super user
-func (m *AuthMiddlewareService) ClubAuthorizeById(c *fiber.Ctx) error {
- authErr := m.Authenticate(c)
- if authErr != nil {
- return errors.Unauthorized.FiberError(c)
- }
-
- if m.IsSuper(c) {
- return c.Next()
- }
-
- clubUUID, err := utilities.ValidateID(c.Params("clubID"))
- if err != nil {
- return errors.FailedToValidateID.FiberError(c)
- }
-
- claims, err := auth.From(c)
- if err != nil {
- return err.FiberError(c)
- }
-
- issuerUUID, issueErr := utilities.ValidateID(claims.Issuer)
- if issueErr != nil {
- return errors.FailedToParseAccessToken.FiberError(c)
- }
-
- clubAdmin, clubErr := clubs.GetAdminIDs(m.DB, *clubUUID)
- if clubErr != nil {
- return err
- }
-
- if slices.Contains(clubAdmin, *issuerUUID) {
- return c.Next()
- }
-
- return errors.Forbidden.FiberError(c)
-}
diff --git a/backend/middleware/middleware.go b/backend/middleware/middleware.go
deleted file mode 100644
index 2f9689e1d..000000000
--- a/backend/middleware/middleware.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package middleware
-
-import (
- "time"
-
- "github.com/GenerateNU/sac/backend/auth"
- "github.com/GenerateNU/sac/backend/config"
- "github.com/go-playground/validator/v10"
- "github.com/gofiber/fiber/v2"
- "gorm.io/gorm"
-)
-
-type AuthMiddlewareInterface interface {
- ClubAuthorizeById(c *fiber.Ctx) error
- UserAuthorizeById(c *fiber.Ctx) error
- Authenticate(c *fiber.Ctx) error
- Authorize(requiredPermissions ...auth.Permission) func(c *fiber.Ctx) error
- Skip(h fiber.Handler) fiber.Handler
- IsSuper(c *fiber.Ctx) bool
- Limiter(rate int, duration time.Duration) func(c *fiber.Ctx) error
-}
-
-type AuthMiddlewareService struct {
- DB *gorm.DB
- Validate *validator.Validate
- AuthSettings config.AuthSettings
-}
-
-func NewAuthAuthMiddlewareService(db *gorm.DB, validate *validator.Validate, authSettings config.AuthSettings) *AuthMiddlewareService {
- return &AuthMiddlewareService{
- DB: db,
- Validate: validate,
- AuthSettings: authSettings,
- }
-}
diff --git a/backend/middleware/user.go b/backend/middleware/user.go
deleted file mode 100644
index 3ffe4ce4e..000000000
--- a/backend/middleware/user.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package middleware
-
-import (
- "github.com/GenerateNU/sac/backend/auth"
- "github.com/GenerateNU/sac/backend/errors"
- "github.com/GenerateNU/sac/backend/utilities"
- "github.com/gofiber/fiber/v2"
-)
-
-func (m *AuthMiddlewareService) UserAuthorizeById(c *fiber.Ctx) error {
- authErr := m.Authenticate(c)
- if authErr != nil {
- return errors.Unauthorized.FiberError(c)
- }
-
- if m.IsSuper(c) {
- return c.Next()
- }
-
- idAsUUID, err := utilities.ValidateID(c.Params("userID"))
- if err != nil {
- return errors.FailedToValidateID.FiberError(c)
- }
-
- claims, err := auth.From(c)
- if err != nil {
- return err.FiberError(c)
- }
-
- issuerIDAsUUID, err := utilities.ValidateID(claims.Issuer)
- if err != nil {
- return errors.FailedToValidateID.FiberError(c)
- }
-
- if issuerIDAsUUID.String() == idAsUUID.String() {
- return c.Next()
- }
-
- return errors.Forbidden.FiberError(c)
-}
diff --git a/backend/middleware/utility/limiter.go b/backend/middleware/utility/limiter.go
new file mode 100644
index 000000000..dc6ed2887
--- /dev/null
+++ b/backend/middleware/utility/limiter.go
@@ -0,0 +1,24 @@
+package utility
+
+import (
+ "errors"
+ "fmt"
+ "time"
+
+ "github.com/GenerateNU/sac/backend/utilities"
+ "github.com/gofiber/fiber/v2"
+ "github.com/gofiber/fiber/v2/middleware/limiter"
+)
+
+func (u *UtilityMiddlewareService) Limiter(rate int, expiration time.Duration) func(c *fiber.Ctx) error {
+ return limiter.New(limiter.Config{
+ Max: rate,
+ Expiration: expiration,
+ KeyGenerator: func(c *fiber.Ctx) string {
+ return fmt.Sprintf("%s-%s", c.IP(), c.Path())
+ },
+ LimitReached: func(c *fiber.Ctx) error {
+ return utilities.NewAPIError(fiber.StatusTooManyRequests, errors.New("too many requests"))
+ },
+ })
+}
diff --git a/backend/middleware/utility/middleware.go b/backend/middleware/utility/middleware.go
new file mode 100644
index 000000000..cd940ea93
--- /dev/null
+++ b/backend/middleware/utility/middleware.go
@@ -0,0 +1,22 @@
+package utility
+
+import (
+ "time"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+type UtilityMiddlewareInterface interface {
+ Paginator(c *fiber.Ctx) error
+ Limiter(rate int, duration time.Duration) fiber.Handler
+}
+
+type UtilityMiddlewareService struct {
+ paginator fiber.Handler
+}
+
+func New(paginator fiber.Handler) *UtilityMiddlewareService {
+ return &UtilityMiddlewareService{
+ paginator: paginator,
+ }
+}
diff --git a/backend/middleware/utility/paginator.go b/backend/middleware/utility/paginator.go
new file mode 100644
index 000000000..0e2827fda
--- /dev/null
+++ b/backend/middleware/utility/paginator.go
@@ -0,0 +1,9 @@
+package utility
+
+import (
+ "github.com/gofiber/fiber/v2"
+)
+
+func (u *UtilityMiddlewareService) Paginator(c *fiber.Ctx) error {
+ return u.paginator(c)
+}
diff --git a/backend/migrations/000001_init.down.sql b/backend/migrations/000001_init.down.sql
index 71f9ab58b..53a2ab3b3 100644
--- a/backend/migrations/000001_init.down.sql
+++ b/backend/migrations/000001_init.down.sql
@@ -18,8 +18,6 @@ DROP TABLE IF EXISTS contacts CASCADE;
DROP TABLE IF EXISTS series CASCADE;
-DROP TABLE IF EXISTS event_series CASCADE;
-
DROP TABLE IF EXISTS event_tags CASCADE;
DROP TABLE IF EXISTS files CASCADE;
@@ -42,4 +40,6 @@ DROP TABLE IF EXISTS user_tags CASCADE;
DROP TABLE IF EXISTS verifications CASCADE;
-COMMIT;
\ No newline at end of file
+DROP EXTENSION IF EXISTS "uuid-ossp";
+
+COMMIT;
diff --git a/backend/migrations/000001_init.up.sql b/backend/migrations/000001_init.up.sql
index d85dd8355..a397a8cba 100644
--- a/backend/migrations/000001_init.up.sql
+++ b/backend/migrations/000001_init.up.sql
@@ -4,8 +4,8 @@ CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE IF NOT EXISTS users(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
- created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ created_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
role varchar(255) NOT NULL DEFAULT 'student'::character varying,
first_name varchar(255) NOT NULL,
last_name varchar(255) NOT NULL,
@@ -21,10 +21,12 @@ CREATE TABLE IF NOT EXISTS users(
PRIMARY KEY(id)
);
+CREATE UNIQUE INDEX IF NOT EXISTS uni_users_email ON users USING btree ("email");
+
CREATE TABLE IF NOT EXISTS clubs(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
- created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ created_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
soft_deleted_at timestamp with time zone,
name varchar(255) NOT NULL,
preview varchar(255) NOT NULL,
@@ -41,28 +43,45 @@ CREATE TABLE IF NOT EXISTS clubs(
PRIMARY KEY(id)
);
+CREATE UNIQUE INDEX IF NOT EXISTS uni_clubs_name ON clubs USING btree ("name");
+CREATE INDEX IF NOT EXISTS idx_clubs_num_members ON clubs USING btree ("num_members");
+CREATE INDEX IF NOT EXISTS idx_clubs_one_word_to_describe_us ON clubs USING btree ("one_word_to_describe_us");
+
+CREATE TABLE IF NOT EXISTS series(
+ id uuid NOT NULL DEFAULT uuid_generate_v4(),
+ created_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY(id)
+);
+
CREATE TABLE IF NOT EXISTS events(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
- created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ created_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
name varchar(255) NOT NULL,
preview varchar(255) NOT NULL,
- content text NOT NULL,
+ description varchar(255) NOT NULL,
+ event_type varchar(255) NOT NULL,
+ location varchar(255),
+ link varchar(255),
+ is_public boolean NOT NULL,
+ is_draft boolean NOT NULL,
+ is_archived boolean NOT NULL,
start_time timestamp with time zone NOT NULL,
end_time timestamp with time zone NOT NULL,
- location varchar(255) NOT NULL,
- event_type varchar(255) NOT NULL DEFAULT 'open'::character varying,
- is_recurring boolean NOT NULL DEFAULT false,
- meeting_link varchar(255),
host uuid NOT NULL,
+ series_id uuid,
PRIMARY KEY(id),
- CONSTRAINT fk_clubs_host_event FOREIGN key(host) REFERENCES clubs(id) ON UPDATE CASCADE ON DELETE CASCADE
+ CONSTRAINT fk_clubs_host_event FOREIGN key(host) REFERENCES clubs(id) ON UPDATE CASCADE ON DELETE CASCADE,
+ CONSTRAINT fk_series_event FOREIGN key(series_id) REFERENCES series(id) ON UPDATE CASCADE ON DELETE CASCADE
);
+CREATE INDEX IF NOT EXISTS idx_events_series_id ON events USING btree ("series_id");
+
CREATE TABLE IF NOT EXISTS categories(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
- created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ created_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
name varchar(255) NOT NULL,
PRIMARY KEY(id)
);
@@ -72,14 +91,16 @@ CREATE UNIQUE INDEX IF NOT EXISTS uni_categories_name ON categories USING btree
CREATE TABLE IF NOT EXISTS tags(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
- created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ created_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
name varchar(255) NOT NULL,
category_id uuid NOT NULL,
PRIMARY KEY(id),
CONSTRAINT fk_categories_tag FOREIGN key(category_id) REFERENCES categories(id) ON UPDATE CASCADE ON DELETE CASCADE
);
+CREATE INDEX IF NOT EXISTS idx_tags_category_id ON tags USING btree ("category_id");
+
CREATE TABLE IF NOT EXISTS club_events(
club_id uuid NOT NULL DEFAULT uuid_generate_v4(),
event_id uuid NOT NULL DEFAULT uuid_generate_v4(),
@@ -98,8 +119,8 @@ CREATE TABLE IF NOT EXISTS club_tags(
CREATE TABLE IF NOT EXISTS contacts(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
- created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ created_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
"type" varchar(255) NOT NULL,
content varchar(255) NOT NULL,
club_id uuid NOT NULL,
@@ -109,22 +130,6 @@ CREATE TABLE IF NOT EXISTS contacts(
CREATE UNIQUE INDEX IF NOT EXISTS idx_contact_type ON contacts USING btree ("type","club_id");
-CREATE TABLE IF NOT EXISTS series(
- id uuid NOT NULL DEFAULT uuid_generate_v4(),
- created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
- recurring_type varchar(255) NOT NULL DEFAULT 'open'::character varying,
- max_occurrences bigint NOT NULL,
- PRIMARY KEY(id)
-);
-
-CREATE TABLE IF NOT EXISTS event_series(
- event_id uuid NOT NULL,
- series_id uuid NOT NULL,
- CONSTRAINT fk_event_series_event FOREIGN key(event_id) REFERENCES events(id) ON UPDATE CASCADE ON DELETE CASCADE,
- CONSTRAINT fk_event_series_series FOREIGN key(series_id) REFERENCES series(id) ON UPDATE CASCADE ON DELETE CASCADE
-);
-
CREATE TABLE IF NOT EXISTS event_tags(
tag_id uuid NOT NULL DEFAULT uuid_generate_v4(),
event_id uuid NOT NULL DEFAULT uuid_generate_v4(),
@@ -135,8 +140,8 @@ CREATE TABLE IF NOT EXISTS event_tags(
CREATE TABLE IF NOT EXISTS files(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
- created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ created_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
owner_id uuid NOT NULL,
owner_type varchar(255) NOT NULL,
file_name varchar(255) NOT NULL,
@@ -151,8 +156,8 @@ CREATE INDEX IF NOT EXISTS idx_files_owner_id ON files USING btree ("owner_id");
-- CREATE TABLE IF NOT EXISTS notifications(
-- id uuid NOT NULL DEFAULT uuid_generate_v4(),
--- created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
--- updated_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+-- created_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+-- updated_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
-- send_at timestamp with time zone NOT NULL,
-- title varchar(255) NOT NULL,
-- content varchar(255) NOT NULL,
@@ -165,8 +170,8 @@ CREATE INDEX IF NOT EXISTS idx_files_owner_id ON files USING btree ("owner_id");
CREATE TABLE IF NOT EXISTS point_of_contacts(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
- created_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ created_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
name varchar(255) NOT NULL,
email varchar(255) NOT NULL,
position varchar(255) NOT NULL,
@@ -174,6 +179,7 @@ CREATE TABLE IF NOT EXISTS point_of_contacts(
PRIMARY KEY(id),
CONSTRAINT fk_clubs_point_of_contact FOREIGN key(club_id) REFERENCES clubs(id) ON UPDATE CASCADE ON DELETE CASCADE
);
+
CREATE UNIQUE INDEX IF NOT EXISTS compositeindex ON point_of_contacts USING btree ("email","club_id");
CREATE INDEX IF NOT EXISTS idx_point_of_contacts_club_id ON point_of_contacts USING btree ("club_id");
CREATE INDEX IF NOT EXISTS idx_point_of_contacts_email ON point_of_contacts USING btree ("email");
@@ -233,10 +239,11 @@ CREATE UNIQUE INDEX IF NOT EXISTS uni_users_email ON users USING btree ("email")
CREATE TABLE IF NOT EXISTS verifications(
user_id uuid NOT NULL,
token varchar(255),
- expires_at timestamp without time zone NOT NULL,
+ expires_at timestamp with time zone NOT NULL,
"type" varchar(255) NOT NULL,
PRIMARY KEY(user_id,expires_at)
);
+
CREATE UNIQUE INDEX IF NOT EXISTS uni_verifications_token ON verifications USING btree ("token");
-COMMIT;
\ No newline at end of file
+COMMIT;
diff --git a/backend/protos/recurrence.go b/backend/protos/recurrence.go
new file mode 100644
index 000000000..4543eb156
--- /dev/null
+++ b/backend/protos/recurrence.go
@@ -0,0 +1,271 @@
+package protos
+
+import (
+ "errors"
+ "slices"
+ "time"
+)
+
+type Cadence int
+
+const (
+ Weekly Cadence = iota
+ Biweekly
+ Monthly
+)
+
+type Recurrence struct {
+ Cadence Cadence
+ HappensOnMonday bool
+ HappensOnTuesday bool
+ HappensOnWednesday bool
+ HappensOnThursday bool
+ HappensOnFriday bool
+ HappensOnSaturday bool
+ HappensOnSunday bool
+}
+
+func NewRecurrence(cadence Cadence, happensOn ...HappensOn) (*Recurrence, error) {
+ if len(happensOn) == 0 {
+ return nil, errors.New("at least one happensOn function must be provided")
+ }
+
+ var r Recurrence
+ r.Cadence = cadence
+ for _, happens := range happensOn {
+ r = happens(r)
+ }
+
+ return &r, nil
+}
+
+func (r *Recurrence) HappensOn() []time.Weekday {
+ var result []time.Weekday
+ if r.HappensOnMonday {
+ result = append(result, time.Monday)
+ }
+ if r.HappensOnTuesday {
+ result = append(result, time.Tuesday)
+ }
+ if r.HappensOnWednesday {
+ result = append(result, time.Wednesday)
+ }
+ if r.HappensOnThursday {
+ result = append(result, time.Thursday)
+ }
+ if r.HappensOnFriday {
+ result = append(result, time.Friday)
+ }
+ if r.HappensOnSaturday {
+ result = append(result, time.Saturday)
+ }
+ if r.HappensOnSunday {
+ result = append(result, time.Sunday)
+ }
+
+ return result
+}
+
+type HappensOn func(Recurrence) Recurrence
+
+func Monday(r Recurrence) Recurrence {
+ r.HappensOnMonday = true
+ return r
+}
+
+func Tuesday(r Recurrence) Recurrence {
+ r.HappensOnTuesday = true
+ return r
+}
+
+func Wednesday(r Recurrence) Recurrence {
+ r.HappensOnWednesday = true
+ return r
+}
+
+func Thursday(r Recurrence) Recurrence {
+ r.HappensOnThursday = true
+ return r
+}
+
+func Friday(r Recurrence) Recurrence {
+ r.HappensOnFriday = true
+ return r
+}
+
+func Saturday(r Recurrence) Recurrence {
+ r.HappensOnSaturday = true
+ return r
+}
+
+func Sunday(r Recurrence) Recurrence {
+ r.HappensOnSunday = true
+ return r
+}
+
+type Occurrence struct {
+ Start time.Time
+ End time.Time
+}
+
+func (r *Recurrence) ReccurUntil(start time.Time, end time.Time, termination time.Time) (result []Occurrence, err error) {
+ if start.After(end) {
+ return nil, errors.New("start date is after end date")
+ }
+
+ if start.After(termination) {
+ return nil, errors.New("start date is after termination date")
+ }
+
+ if end.After(termination) {
+ return nil, errors.New("end date is after termination date")
+ }
+
+ if !slices.Contains(r.HappensOn(), start.Weekday()) {
+ return nil, errors.New("start date is on a day that the recurrence does not happen on")
+ }
+
+ var monthIncrement int
+ switch r.Cadence {
+ case Weekly:
+ monthIncrement = 0
+ case Biweekly:
+ monthIncrement = 0
+ case Monthly:
+ monthIncrement = 1
+ }
+
+ var dayIncrement int
+ switch r.Cadence {
+ case Weekly:
+ dayIncrement = 7
+ case Biweekly:
+ dayIncrement = 14
+ case Monthly:
+ dayIncrement = 0
+ }
+
+ current := start
+ currentEnd := end
+ for current.Before(termination) {
+ if current.After(termination) && currentEnd.After(termination) {
+ break
+ }
+
+ result = append(result, Occurrence{current, currentEnd})
+
+ current = current.AddDate(0, monthIncrement, dayIncrement)
+ currentEnd = currentEnd.AddDate(0, monthIncrement, dayIncrement)
+ }
+
+ return result, nil
+}
+
+const (
+ // housekeeping
+ PROTO_VERSION rune = '1'
+ PROTO_SIZE int = 9
+
+ // indices
+ VERSION_INDEX int = 0
+ CADENCE_INDEX int = 1
+ START_DAYS_OF_WEEK_INDEX int = 2
+ END_DAYS_OF_WEEK_INDEX int = 9
+)
+
+// PROTO v1
+// 0: [proto version]
+// 1: [cadence]
+// 2: [does this occur on Monday?]
+// 3: [does this occur on Tuesday?]
+// 4: [does this occur on Wednesday?]
+// 5: [does this occur on Thursday?]
+// 6: [does this occur on Friday?]
+// 7: [does this occur on Saturday?]
+// 8: [does this occur on Sunday?]
+type StringRecurrence string
+
+func (r *Recurrence) Into() string {
+ data := make([]rune, PROTO_SIZE)
+
+ data[VERSION_INDEX] = PROTO_VERSION
+
+ switch r.Cadence {
+ case Weekly:
+ data[CADENCE_INDEX] = '0'
+ case Biweekly:
+ data[CADENCE_INDEX] = '1'
+ case Monthly:
+ data[CADENCE_INDEX] = '2'
+ }
+
+ if r.HappensOnMonday {
+ data[START_DAYS_OF_WEEK_INDEX] = '1'
+ }
+ if r.HappensOnTuesday {
+ data[START_DAYS_OF_WEEK_INDEX+1] = '1'
+ }
+ if r.HappensOnWednesday {
+ data[START_DAYS_OF_WEEK_INDEX+2] = '1'
+ }
+ if r.HappensOnThursday {
+ data[START_DAYS_OF_WEEK_INDEX+3] = '1'
+ }
+ if r.HappensOnFriday {
+ data[START_DAYS_OF_WEEK_INDEX+4] = '1'
+ }
+ if r.HappensOnSaturday {
+ data[START_DAYS_OF_WEEK_INDEX+5] = '1'
+ }
+ if r.HappensOnSunday {
+ data[START_DAYS_OF_WEEK_INDEX+6] = '1'
+ }
+
+ return string(data)
+}
+
+func RecurrenceFrom(raw StringRecurrence) (recurrence *Recurrence, err error) {
+ runes := []rune(raw)
+
+ if runes[VERSION_INDEX] != PROTO_VERSION {
+ return nil, errors.New("invalid version")
+ }
+
+ if len(runes) != PROTO_SIZE {
+ return nil, errors.New("invalid data length")
+ }
+
+ if runes[CADENCE_INDEX] != '0' && runes[CADENCE_INDEX] != '1' && runes[CADENCE_INDEX] != '2' {
+ return nil, errors.New("invalid cadence")
+ }
+
+ cadence := int(runes[CADENCE_INDEX] - '0')
+
+ var happensOn []HappensOn
+ if runes[START_DAYS_OF_WEEK_INDEX] == '1' {
+ happensOn = append(happensOn, Monday)
+ }
+ if runes[START_DAYS_OF_WEEK_INDEX+1] == '1' {
+ happensOn = append(happensOn, Tuesday)
+ }
+ if runes[START_DAYS_OF_WEEK_INDEX+2] == '1' {
+ happensOn = append(happensOn, Wednesday)
+ }
+ if runes[START_DAYS_OF_WEEK_INDEX+3] == '1' {
+ happensOn = append(happensOn, Thursday)
+ }
+ if runes[START_DAYS_OF_WEEK_INDEX+4] == '1' {
+ happensOn = append(happensOn, Friday)
+ }
+ if runes[START_DAYS_OF_WEEK_INDEX+5] == '1' {
+ happensOn = append(happensOn, Saturday)
+ }
+ if runes[START_DAYS_OF_WEEK_INDEX+6] == '1' {
+ happensOn = append(happensOn, Sunday)
+ }
+
+ return NewRecurrence(
+ Cadence(cadence),
+ happensOn...,
+ )
+}
diff --git a/backend/server/server.go b/backend/server/server.go
index c0bf0727c..ebb1e8ac7 100644
--- a/backend/server/server.go
+++ b/backend/server/server.go
@@ -1,12 +1,14 @@
package server
import (
- "encoding/json"
"fmt"
- "github.com/GenerateNU/sac/backend/auth"
+ "github.com/garrettladley/fiberpaginate"
+ go_json "github.com/goccy/go-json"
+
+ authenticator "github.com/GenerateNU/sac/backend/auth"
"github.com/GenerateNU/sac/backend/config"
- authBase "github.com/GenerateNU/sac/backend/entities/auth/base"
+ auth "github.com/GenerateNU/sac/backend/entities/auth/base"
categories "github.com/GenerateNU/sac/backend/entities/categories/base"
clubs "github.com/GenerateNU/sac/backend/entities/clubs/base"
contacts "github.com/GenerateNU/sac/backend/entities/contacts/base"
@@ -16,11 +18,14 @@ import (
tags "github.com/GenerateNU/sac/backend/entities/tags/base"
users "github.com/GenerateNU/sac/backend/entities/users/base"
"github.com/GenerateNU/sac/backend/integrations"
- "github.com/GenerateNU/sac/backend/middleware"
+ authMiddleware "github.com/GenerateNU/sac/backend/middleware/auth"
+ utilityMiddleware "github.com/GenerateNU/sac/backend/middleware/utility"
"github.com/GenerateNU/sac/backend/types"
"github.com/GenerateNU/sac/backend/utilities"
+ "github.com/gofiber/contrib/otelfiber"
"github.com/gofiber/fiber/v2"
+ "github.com/gofiber/fiber/v2/middleware/compress"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/fiber/v2/middleware/requestid"
@@ -46,22 +51,25 @@ func Init(db *gorm.DB, integrations integrations.Integrations, settings config.S
panic(fmt.Sprintf("Error registering custom validators: %s", err))
}
- jwt := auth.NewJWTClient(settings.Auth, jwt.SigningMethodHS256)
- authMiddleware := middleware.NewAuthAuthMiddlewareService(db, validate, settings.Auth)
+ jwt := authenticator.NewJWTClient(settings.Auth, jwt.SigningMethodHS256)
+ authMiddleware := authMiddleware.New(db, validate, settings.Auth)
+ utilityMiddleware := utilityMiddleware.New(fiberpaginate.New())
apiv1 := app.Group("/api/v1")
- routeParams := types.RouteParams{
- Router: apiv1,
- AuthMiddleware: authMiddleware,
- ServiceParams: types.ServiceParams{
- DB: db,
- Validate: validate,
- AuthSettings: &settings.Auth,
- JWT: jwt,
- Integrations: integrations,
- },
- }
+ routeParams := types.NewRouteParams(
+ apiv1,
+ authMiddleware,
+ utilityMiddleware,
+ types.NewServiceParams(
+ db,
+ validate,
+ &settings.Auth,
+ jwt,
+ &settings.Calendar,
+ integrations,
+ ),
+ )
allRoutes(app, routeParams)
@@ -70,31 +78,43 @@ func Init(db *gorm.DB, integrations integrations.Integrations, settings config.S
func allRoutes(app *fiber.App, routeParams types.RouteParams) {
Utility(app)
- authBase.Auth(routeParams)
+ auth.Auth(routeParams)
users.UserRoutes(routeParams)
clubs.ClubRoutes(routeParams)
contacts.Contact(routeParams)
pocs.PointOfContact(routeParams)
tags.Tag(routeParams)
categories.CategoryRoutes(routeParams)
- events.Event(routeParams)
+ events.EventRoutes(routeParams)
files.File(routeParams)
}
func newFiberApp(appSettings config.ApplicationSettings) *fiber.App {
app := fiber.New(fiber.Config{
- JSONEncoder: json.Marshal,
- JSONDecoder: json.Unmarshal,
+ JSONEncoder: go_json.Marshal,
+ JSONDecoder: go_json.Unmarshal,
+ ErrorHandler: utilities.ErrorHandler,
})
app.Use(cors.New(cors.Config{
AllowOrigins: fmt.Sprintf("http://%s:%d", appSettings.Host, appSettings.Port),
AllowCredentials: true,
+ AllowHeaders: "Origin, Content-Type, Accept, Authorization",
+ AllowMethods: "GET, POST, PUT, DELETE, OPTIONS",
+ ExposeHeaders: "Authorization, Content-Length, Content-Type",
}))
+
app.Use(requestid.New())
+
app.Use(logger.New(logger.Config{
Format: "[${time}] ${ip}:${port} ${pid} ${locals:requestid} ${status} - ${latency} ${method} ${path}\n",
}))
+ app.Use(compress.New(compress.Config{
+ Level: compress.LevelBestSpeed,
+ }))
+
+ app.Use(otelfiber.Middleware())
+
return app
}
diff --git a/backend/telemetry/README.md b/backend/telemetry/README.md
new file mode 100644
index 000000000..db0a2ff9a
--- /dev/null
+++ b/backend/telemetry/README.md
@@ -0,0 +1,3 @@
+# tracing
+
+See this [example](https://github.com/gofiber/contrib/blob/main/otelfiber/README.md) for how to instrument an endpoint.
diff --git a/backend/telemetry/telemetry.go b/backend/telemetry/telemetry.go
new file mode 100644
index 000000000..842bd0376
--- /dev/null
+++ b/backend/telemetry/telemetry.go
@@ -0,0 +1,48 @@
+package telemetry
+
+import (
+ "fmt"
+ "log"
+
+ "github.com/gofiber/fiber/v2"
+ "go.opentelemetry.io/otel/sdk/resource"
+
+ "go.opentelemetry.io/otel"
+ stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
+
+ // uncomment the following line to use Jaeger
+ // "go.opentelemetry.io/otel/exporters/jaeger"
+ "github.com/gofiber/contrib/otelfiber"
+ "go.opentelemetry.io/otel/propagation"
+ sdktrace "go.opentelemetry.io/otel/sdk/trace"
+ semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
+)
+
+func InitTracer() *sdktrace.TracerProvider {
+ exporter, err := stdout.New(stdout.WithPrettyPrint())
+ // uncomment the following line to use Jaeger
+ // exporter, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint("http://localhost:14268/api/traces")))
+ if err != nil {
+ log.Fatal(err)
+ }
+ tp := sdktrace.NewTracerProvider(
+ sdktrace.WithSampler(sdktrace.AlwaysSample()),
+ sdktrace.WithBatcher(exporter),
+ sdktrace.WithResource(
+ resource.NewWithAttributes(
+ semconv.SchemaURL,
+ semconv.ServiceNameKey.String("sac-service"),
+ )),
+ )
+ otel.SetTracerProvider(tp)
+ otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
+ return tp
+}
+
+func Use(app *fiber.App) *fiber.App {
+ app.Use(otelfiber.Middleware(otelfiber.WithSpanNameFormatter(func(c *fiber.Ctx) string {
+ return fmt.Sprintf("%s - %s", c.Method(), c.Route().Path)
+ })))
+
+ return app
+}
diff --git a/backend/templates/README.md b/backend/templates/README.md
new file mode 100644
index 000000000..a6cb56cfe
--- /dev/null
+++ b/backend/templates/README.md
@@ -0,0 +1,8 @@
+# Templates Using templ
+
+templ is a HTML templating language for Go that has great developer tooling.
+
+[See](https://github.com/a-h/templ) for more.
+
+> [!NOTE]
+> When editing the templates, you need to run `templ generate` to see your changes. To download the CLI, run `go install github.com/a-h/templ/cmd/templ@latest`.
\ No newline at end of file
diff --git a/backend/templates/emails/layouts/base.templ b/backend/templates/emails/layouts/base.templ
new file mode 100644
index 000000000..04a097104
--- /dev/null
+++ b/backend/templates/emails/layouts/base.templ
@@ -0,0 +1,16 @@
+package layouts
+
+templ Base(title string, styles templ.Component) {
+
+
+
+ { title }
+
+
+ @styles
+
+
+ { children... }
+
+
+}
diff --git a/backend/templates/emails/layouts/base_templ.go b/backend/templates/emails/layouts/base_templ.go
new file mode 100644
index 000000000..3689f140b
--- /dev/null
+++ b/backend/templates/emails/layouts/base_templ.go
@@ -0,0 +1,64 @@
+// Code generated by templ - DO NOT EDIT.
+
+// templ: version: v0.2.639
+package layouts
+
+//lint:file-ignore SA4006 This context is only used if a nested component is present.
+
+import "github.com/a-h/templ"
+import "context"
+import "io"
+import "bytes"
+
+func Base(title string, styles templ.Component) templ.Component {
+ return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var1 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var1 == nil {
+ templ_7745c5c3_Var1 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var2 string
+ templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(title)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/emails/layouts/base.templ`, Line: 7, Col: 17}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = styles.Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
+ }
+ return templ_7745c5c3_Err
+ })
+}
diff --git a/backend/templates/emails/password_change_complete.html b/backend/templates/emails/password_change_complete.templ
similarity index 58%
rename from backend/templates/emails/password_change_complete.html
rename to backend/templates/emails/password_change_complete.templ
index dc6173767..5e21dadde 100644
--- a/backend/templates/emails/password_change_complete.html
+++ b/backend/templates/emails/password_change_complete.templ
@@ -1,9 +1,30 @@
-
+package emails
-
-
- Your Hippo Password Has Been Reset
-
-
-
-
-
-
Your Password Has Been Reset
-
Hi %s,
-
- This email confirms that your password for your Hippo account has been
- successfully reset.
-
-
You can now sign in using your new password:
-
Sign in to Hippo
-
- If you did not request this password reset, please contact our support
- team immediately.
-
-
Sincerely,
-
The Hippo Team
-
-
-
-
\ No newline at end of file
+}
diff --git a/backend/templates/emails/password_change_complete_templ.go b/backend/templates/emails/password_change_complete_templ.go
new file mode 100644
index 000000000..9dc55bc51
--- /dev/null
+++ b/backend/templates/emails/password_change_complete_templ.go
@@ -0,0 +1,89 @@
+// Code generated by templ - DO NOT EDIT.
+
+// templ: version: v0.2.639
+package emails
+
+//lint:file-ignore SA4006 This context is only used if a nested component is present.
+
+import "github.com/a-h/templ"
+import "context"
+import "io"
+import "bytes"
+
+import "github.com/GenerateNU/sac/backend/templates/emails/layouts"
+
+func PasswordChangeComplete(name string) templ.Component {
+ return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var1 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var1 == nil {
+ templ_7745c5c3_Var1 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("Your Password Has Been Reset Hi ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var3 string
+ templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(name)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/emails/password_change_complete.templ`, Line: 9, Col: 15}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(",
This email confirms that your password for your Hippo account has been successfully reset.
You can now sign in using your new password:
Sign in to Hippo If you did not request this password reset, please contact our support team immediately.
Sincerely,
The Hippo Team
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
+ }
+ return templ_7745c5c3_Err
+ })
+ templ_7745c5c3_Err = layouts.Base("Your Hippo Password Has Been Reset", passwordChangeCompleteStyles()).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
+ }
+ return templ_7745c5c3_Err
+ })
+}
+
+func passwordChangeCompleteStyles() templ.Component {
+ return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var4 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var4 == nil {
+ templ_7745c5c3_Var4 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
+ }
+ return templ_7745c5c3_Err
+ })
+}
diff --git a/backend/templates/emails/password_reset.html b/backend/templates/emails/password_reset.templ
similarity index 54%
rename from backend/templates/emails/password_reset.html
rename to backend/templates/emails/password_reset.templ
index f25d9f159..a6e0ed454 100644
--- a/backend/templates/emails/password_reset.html
+++ b/backend/templates/emails/password_reset.templ
@@ -1,9 +1,32 @@
-
-
-
-
- Password Reset Email
-
-
-
-
-
-
Your Hippo Account Needs a New Key!
-
Hi %s,
-
- Looks like you've misplaced the key to your Hippo account! Don't worry,
- we can help you unlock it in no time. Just click the button below to
- choose a new password:
-
-
Reset Your Password
-
- Remember, if you didn't request this change, simply disregard this
- message and your account remains secure.
-
-
See you soon,
-
The Hippo Team
-
-
-
+}
diff --git a/backend/templates/emails/password_reset_templ.go b/backend/templates/emails/password_reset_templ.go
new file mode 100644
index 000000000..bc9ca12dd
--- /dev/null
+++ b/backend/templates/emails/password_reset_templ.go
@@ -0,0 +1,100 @@
+// Code generated by templ - DO NOT EDIT.
+
+// templ: version: v0.2.639
+package emails
+
+//lint:file-ignore SA4006 This context is only used if a nested component is present.
+
+import "github.com/a-h/templ"
+import "context"
+import "io"
+import "bytes"
+
+import (
+ "github.com/GenerateNU/sac/backend/templates/emails/layouts"
+)
+
+func PasswordReset(name string, resetUrl string) templ.Component {
+ return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var1 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var1 == nil {
+ templ_7745c5c3_Var1 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("Your Hippo Account Needs a New Key! Hi ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var3 string
+ templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(name)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/emails/password_reset.templ`, Line: 11, Col: 15}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(",
Looks like you've misplaced the key to your Hippo account! Don't worry, we can help you unlock it in no time. Just click the button below to choose a new password:
Reset Your Password Remember, if you didn't request this change, simply disregard this message and your account remains secure.
See you soon,
The Hippo Team
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
+ }
+ return templ_7745c5c3_Err
+ })
+ templ_7745c5c3_Err = layouts.Base("Password Reset Email", passwordResetStyles()).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
+ }
+ return templ_7745c5c3_Err
+ })
+}
+
+func passwordResetStyles() templ.Component {
+ return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var5 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var5 == nil {
+ templ_7745c5c3_Var5 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
+ }
+ return templ_7745c5c3_Err
+ })
+}
diff --git a/backend/templates/emails/email_verification.html b/backend/templates/emails/verification.templ
similarity index 54%
rename from backend/templates/emails/email_verification.html
rename to backend/templates/emails/verification.templ
index 101d9f67b..fad4cff02 100644
--- a/backend/templates/emails/email_verification.html
+++ b/backend/templates/emails/verification.templ
@@ -1,8 +1,31 @@
-
-
-
- Welcome to Hippo! Verify your Email
-
-
-
-
-
-
Welcome to Hippo
-
- Thank you for signing up! To unlock the full potential of your account
- and start enjoying our services, please verify your email address by
- typing the following code in the verification page:
-
-
-
%s
-
-
- If you didn't create an account with Hippo, please disregard this email.
-
-
We look forward to having you on board!
-
Sincerely,
-
The Hippo Team
-
-
-
+}
diff --git a/backend/templates/emails/verification_templ.go b/backend/templates/emails/verification_templ.go
new file mode 100644
index 000000000..25b8af044
--- /dev/null
+++ b/backend/templates/emails/verification_templ.go
@@ -0,0 +1,91 @@
+// Code generated by templ - DO NOT EDIT.
+
+// templ: version: v0.2.639
+package emails
+
+//lint:file-ignore SA4006 This context is only used if a nested component is present.
+
+import "github.com/a-h/templ"
+import "context"
+import "io"
+import "bytes"
+
+import (
+ "github.com/GenerateNU/sac/backend/templates/emails/layouts"
+)
+
+func Verification(otp string) templ.Component {
+ return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var1 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var1 == nil {
+ templ_7745c5c3_Var1 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("Welcome to Hippo Thank you for signing up! To unlock the full potential of your account and start enjoying our services, please verify your email address by typing the following code in the verification page:
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var3 string
+ templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(otp)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/emails/verification.templ`, Line: 16, Col: 19}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
If you didn't create an account with Hippo, please disregard this email.
We look forward to having you on board!
Sincerely,
The Hippo Team
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
+ }
+ return templ_7745c5c3_Err
+ })
+ templ_7745c5c3_Err = layouts.Base("Welcome to Hippo! Verify your Email", verificationStyles()).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
+ }
+ return templ_7745c5c3_Err
+ })
+}
+
+func verificationStyles() templ.Component {
+ return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var4 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var4 == nil {
+ templ_7745c5c3_Var4 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
+ }
+ return templ_7745c5c3_Err
+ })
+}
diff --git a/backend/templates/emails/welcome.html b/backend/templates/emails/welcome.templ
similarity index 50%
rename from backend/templates/emails/welcome.html
rename to backend/templates/emails/welcome.templ
index 52673f0a6..85d1356f6 100644
--- a/backend/templates/emails/welcome.html
+++ b/backend/templates/emails/welcome.templ
@@ -1,9 +1,40 @@
-
+package emails
-
-
- Welcome to Hippo!
-
-
-
-
-
-
Welcome to Hippo %s!
-
- Thank you for creating an account with us. We're excited to have you on
- board!
-
-
- Your account is now active, and you can log in using your email address
- and password.
-
-
- If you haven't already, we recommend that you complete your profile to
- get the most out of your Hippo experience.
-
-
- To get started, you can visit our website at
- hipponeu.com .
-
-
- If you have any questions or need assistance, please don't hesitate to
- contact us at generatesac@gmail.com.
-
-
We look forward to seeing you around!
-
Sincerely,
-
The Hippo Team
-
-
-
-
\ No newline at end of file
+
+}
diff --git a/backend/templates/emails/welcome_templ.go b/backend/templates/emails/welcome_templ.go
new file mode 100644
index 000000000..2f3325b90
--- /dev/null
+++ b/backend/templates/emails/welcome_templ.go
@@ -0,0 +1,89 @@
+// Code generated by templ - DO NOT EDIT.
+
+// templ: version: v0.2.639
+package emails
+
+//lint:file-ignore SA4006 This context is only used if a nested component is present.
+
+import "github.com/a-h/templ"
+import "context"
+import "io"
+import "bytes"
+
+import "github.com/GenerateNU/sac/backend/templates/emails/layouts"
+
+func Welcome(name string) templ.Component {
+ return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var1 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var1 == nil {
+ templ_7745c5c3_Var1 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("Welcome to Hippo ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var3 string
+ templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(name)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/emails/welcome.templ`, Line: 8, Col: 30}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("! Thank you for creating an account with us. We're excited to have you on board!
Your account is now active, and you can log in using your email address and password.
If you haven't already, we recommend that you complete your profile to get the most out of your Hippo experience.
To get started, you can visit our website at hipponeu.com .
If you have any questions or need assistance, please don't hesitate to contact us at generatesac@gmail.com.
We look forward to seeing you around!
Sincerely,
The Hippo Team
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
+ }
+ return templ_7745c5c3_Err
+ })
+ templ_7745c5c3_Err = layouts.Base("Welcome to Hippo!", welcomeStyles()).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
+ }
+ return templ_7745c5c3_Err
+ })
+}
+
+func welcomeStyles() templ.Component {
+ return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
+ if !templ_7745c5c3_IsBuffer {
+ templ_7745c5c3_Buffer = templ.GetBuffer()
+ defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var4 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var4 == nil {
+ templ_7745c5c3_Var4 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
+ }
+ return templ_7745c5c3_Err
+ })
+}
diff --git a/backend/tests/README.md b/backend/tests/README.md
index 46e0813a2..25c391caa 100644
--- a/backend/tests/README.md
+++ b/backend/tests/README.md
@@ -54,7 +54,7 @@ appAssert.TestOnStatus(
Role: &models.Super,
TestUserIDReplaces: h.StringToPointer(":userID"),
},
- fiber.StatusCreated,
+ http.StatusCreated,
).TestOnStatusAndTester(
h.TestRequest{
Method: fiber.MethodDelete,
@@ -63,7 +63,7 @@ appAssert.TestOnStatus(
TestUserIDReplaces: h.StringToPointer(":userID"),
},
h.TesterWithStatus{
- Status: fiber.StatusNoContent,
+ Status: http.StatusNoContent,
Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
var user models.User
@@ -134,7 +134,7 @@ Say you want to test hitting the `[APP_ADDRESS]/health` endpoint with a GET requ
Method: fiber.MethodGet,
Path: "/health",
},
- fiber.StatusOK,
+ http.StatusOK,
).Close()
```
@@ -151,7 +151,7 @@ existingAppAssert.TestOnStatusAndTester(
Role: &models.Super,
},
h.TesterWithStatus{
- Status: fiber.StatusCreated,
+ Status: http.StatusCreated,
Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
sampleCategoryUUID = AssertSampleCategoryBodyRespDB(eaa, resp)
},
@@ -164,7 +164,7 @@ existingAppAssert.TestOnStatusAndTester(
Say you want to test a bad request to POST `[APP_ADDRESS]/api/v1/categories/` endpoint returns a `400` status code, the message is `failed to process the request`, and that a category was not created. We can leverage our errors defined in the error package to do this!
```go
- h.InitTest(t).TestOnErrorAndTester(
+ h.InitTest(t).TestOnStatusAndTester(
h.TestRequest{
Method: fiber.MethodPost,
Path: "/api/v1/categories/",
diff --git a/backend/tests/api/category_tag_test.go b/backend/tests/api/category_tag_test.go
deleted file mode 100644
index ab40acd23..000000000
--- a/backend/tests/api/category_tag_test.go
+++ /dev/null
@@ -1,203 +0,0 @@
-package tests
-
-import (
- "fmt"
- "net/http"
- "testing"
-
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
- h "github.com/GenerateNU/sac/backend/tests/api/helpers"
-
- "github.com/goccy/go-json"
- "github.com/gofiber/fiber/v2"
- "github.com/google/uuid"
-)
-
-func AssertTagsWithBodyRespDB(eaa h.ExistingAppAssert, resp *http.Response, body *[]map[string]interface{}) []uuid.UUID {
- var respTags []models.Tag
-
- err := json.NewDecoder(resp.Body).Decode(&respTags)
-
- eaa.Assert.NilError(err)
-
- var dbTags []models.Tag
-
- err = eaa.App.Conn.Find(&dbTags).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(len(dbTags), len(respTags))
-
- for i, dbTag := range dbTags {
- eaa.Assert.Equal(dbTag.ID, respTags[i].ID)
- eaa.Assert.Equal(dbTag.Name, respTags[i].Name)
- eaa.Assert.Equal(dbTag.CategoryID, respTags[i].CategoryID)
- }
-
- tagIDs := make([]uuid.UUID, len(dbTags))
- for i, dbTag := range dbTags {
- tagIDs[i] = dbTag.ID
- }
-
- return tagIDs
-}
-
-func TestGetCategoryTagsWorks(t *testing.T) {
- appAssert, categoryUUID, tagID := CreateSampleTag(h.InitTest(t))
-
- body := SampleTagFactory(categoryUUID)
- (*body)["id"] = tagID
-
- appAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/categories/%s/tags", categoryUUID),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertTagsWithBodyRespDB(eaa, resp, &[]map[string]interface{}{*body})
- },
- },
- ).Close()
-}
-
-func TestGetCategoryTagsFailsCategoryBadRequest(t *testing.T) {
- appAssert, _ := CreateSampleCategory(h.InitTest(t))
-
- badRequests := []string{
- "0",
- "-1",
- "1.1",
- "foo",
- "null",
- }
-
- for _, badRequest := range badRequests {
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/categories/%s/tags", badRequest),
- Role: &models.Super,
- },
- errors.FailedToValidateID,
- )
- }
-
- appAssert.Close()
-}
-
-func TestGetCategoryTagsFailsCategoryNotFound(t *testing.T) {
- appAssert, _ := CreateSampleCategory(h.InitTest(t))
-
- uuid := uuid.New()
-
- appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/categories/%s/tags", uuid),
- Role: &models.Super,
- }, h.ErrorWithTester{
- Error: errors.CategoryNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var category models.Category
- err := eaa.App.Conn.Where("id = ?", uuid).First(&category).Error
- eaa.Assert.Assert(err != nil)
- },
- },
- ).Close()
-}
-
-func TestGetCategoryTagWorks(t *testing.T) {
- existingAppAssert, categoryUUID, tagUUID := CreateSampleTag(h.InitTest(t))
-
- existingAppAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/categories/%s/tags/%s", categoryUUID, tagUUID),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertTagWithBodyRespDB(eaa, resp, SampleTagFactory(categoryUUID))
- },
- },
- ).Close()
-}
-
-func TestGetCategoryTagFailsCategoryBadRequest(t *testing.T) {
- appAssert, _, tagUUID := CreateSampleTag(h.InitTest(t))
-
- badRequests := []string{
- "0",
- "-1",
- "1.1",
- "foo",
- "null",
- }
-
- for _, badRequest := range badRequests {
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/categories/%s/tags/%s", badRequest, tagUUID),
- Role: &models.Super,
- }, errors.FailedToValidateID,
- )
- }
-
- appAssert.Close()
-}
-
-func TestGetCategoryTagFailsTagBadRequest(t *testing.T) {
- appAssert, categoryUUID := CreateSampleCategory(h.InitTest(t))
-
- badRequests := []string{
- "0",
- "-1",
- "1.1",
- "foo",
- "null",
- }
-
- for _, badRequest := range badRequests {
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/categories/%s/tags/%s", categoryUUID, badRequest),
- Role: &models.Super,
- },
- errors.FailedToValidateID)
- }
-
- appAssert.Close()
-}
-
-func TestGetCategoryTagFailsCategoryNotFound(t *testing.T) {
- appAssert, _, tagUUID := CreateSampleTag(h.InitTest(t))
-
- appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/categories/%s/tags/%s", uuid.New(), tagUUID),
- Role: &models.Super,
- },
- errors.TagNotFound,
- ).Close()
-}
-
-func TestGetCategoryTagFailsTagNotFound(t *testing.T) {
- appAssert, categoryUUID := CreateSampleCategory(h.InitTest(t))
-
- appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/categories/%s/tags/%s", categoryUUID, uuid.New()),
- Role: &models.Super,
- },
- errors.TagNotFound,
- ).Close()
-}
diff --git a/backend/tests/api/category_test.go b/backend/tests/api/category_test.go
deleted file mode 100644
index 6b2276bee..000000000
--- a/backend/tests/api/category_test.go
+++ /dev/null
@@ -1,445 +0,0 @@
-package tests
-
-import (
- "fmt"
- "net/http"
- "testing"
-
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
- h "github.com/GenerateNU/sac/backend/tests/api/helpers"
- "github.com/gofiber/fiber/v2"
- "github.com/google/uuid"
-
- "github.com/goccy/go-json"
-)
-
-func SampleCategoryFactory() *map[string]interface{} {
- return &map[string]interface{}{
- "name": "Foo",
- }
-}
-
-func AssertCategoryBodyRespDB(eaa h.ExistingAppAssert, resp *http.Response, body *map[string]interface{}) uuid.UUID {
- var respCategory models.Category
-
- err := json.NewDecoder(resp.Body).Decode(&respCategory)
-
- eaa.Assert.NilError(err)
-
- var dbCategories []models.Category
-
- err = eaa.App.Conn.Find(&dbCategories).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(1, len(dbCategories))
-
- dbCategory := dbCategories[0]
-
- eaa.Assert.Equal(dbCategory.ID, respCategory.ID)
- eaa.Assert.Equal(dbCategory.Name, respCategory.Name)
-
- eaa.Assert.Equal((*body)["name"].(string), dbCategory.Name)
-
- return dbCategory.ID
-}
-
-func AssertCategoryWithBodyRespDBMostRecent(eaa h.ExistingAppAssert, resp *http.Response, body *map[string]interface{}) uuid.UUID {
- var respCategory models.Category
-
- err := json.NewDecoder(resp.Body).Decode(&respCategory)
-
- eaa.Assert.NilError(err)
-
- var dbCategory models.Category
-
- err = eaa.App.Conn.Order("created_at desc").First(&dbCategory).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(dbCategory.ID, respCategory.ID)
- eaa.Assert.Equal(dbCategory.Name, respCategory.Name)
-
- eaa.Assert.Equal((*body)["name"].(string), dbCategory.Name)
-
- return dbCategory.ID
-}
-
-func AssertSampleCategoryBodyRespDB(eaa h.ExistingAppAssert, resp *http.Response) uuid.UUID {
- return AssertCategoryBodyRespDB(eaa, resp, SampleCategoryFactory())
-}
-
-func CreateSampleCategory(existingAppAssert h.ExistingAppAssert) (h.ExistingAppAssert, uuid.UUID) {
- var sampleCategoryUUID uuid.UUID
-
- existingAppAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/categories/",
- Body: SampleCategoryFactory(),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusCreated,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- sampleCategoryUUID = AssertSampleCategoryBodyRespDB(eaa, resp)
- },
- },
- )
-
- return existingAppAssert, sampleCategoryUUID
-}
-
-func TestCreateCategoryWorks(t *testing.T) {
- existingAppAssert, _ := CreateSampleCategory(h.InitTest(t))
- existingAppAssert.Close()
-}
-
-func TestCreateCategoryIgnoresid(t *testing.T) {
- h.InitTest(t).TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/categories/",
- Body: &map[string]interface{}{
- "id": 12,
- "name": "Foo",
- },
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusCreated,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertSampleCategoryBodyRespDB(eaa, resp)
- },
- },
- ).Close()
-}
-
-func Assert1Category(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertNumCategoriesRemainsAtN(eaa, resp, 1)
-}
-
-func AssertNoCategories(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertNumCategoriesRemainsAtN(eaa, resp, 0)
-}
-
-func AssertNumCategoriesRemainsAtN(eaa h.ExistingAppAssert, resp *http.Response, n int) {
- var categories []models.Category
-
- err := eaa.App.Conn.Find(&categories).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(n, len(categories))
-}
-
-func TestCreateCategoryFailsIfNameIsNotString(t *testing.T) {
- h.InitTest(t).TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/categories/",
- Body: &map[string]interface{}{
- "name": 1231,
- },
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.FailedToParseRequestBody,
- Tester: AssertNoCategories,
- },
- ).Close()
-}
-
-func TestCreateCategoryFailsIfNameIsMissing(t *testing.T) {
- h.InitTest(t).TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/categories/",
- Body: &map[string]interface{}{},
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.FailedToValidateCategory,
- Tester: AssertNoCategories,
- },
- ).Close()
-}
-
-func TestCreateCategoryFailsIfCategoryWithThatNameAlreadyExists(t *testing.T) {
- existingAppAssert, _ := CreateSampleCategory(h.InitTest(t))
-
- TestNumCategoriesRemainsAt1 := func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertNumCategoriesRemainsAtN(eaa, resp, 1)
- }
-
- for _, permutation := range h.AllCasingPermutations((*SampleCategoryFactory())["name"].(string)) {
- modifiedSampleCategoryBody := *SampleCategoryFactory()
- modifiedSampleCategoryBody["name"] = permutation
-
- existingAppAssert = existingAppAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/categories/",
- Body: &modifiedSampleCategoryBody,
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.CategoryAlreadyExists,
- Tester: TestNumCategoriesRemainsAt1,
- },
- )
- }
-
- existingAppAssert.Close()
-}
-
-func TestGetCategoryWorks(t *testing.T) {
- existingAppAssert, uuid := CreateSampleCategory(h.InitTest(t))
-
- existingAppAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/categories/%s", uuid),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertSampleCategoryBodyRespDB(eaa, resp)
- },
- },
- ).Close()
-}
-
-func TestGetCategoryFailsBadRequest(t *testing.T) {
- appAssert := h.InitTest(t)
-
- badRequests := []string{
- "0",
- "-1",
- "1.1",
- "foo",
- "null",
- }
-
- for _, badRequest := range badRequests {
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/categories/%s", badRequest),
- Role: &models.Super,
- },
- errors.FailedToValidateID,
- )
- }
-
- appAssert.Close()
-}
-
-func TestGetCategoryFailsNotFound(t *testing.T) {
- h.InitTest(t).TestOnError(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/categories/%s", uuid.New()),
- Role: &models.Super,
- }, errors.CategoryNotFound,
- ).Close()
-}
-
-func TestGetCategoriesWorks(t *testing.T) {
- existingAppAssert, _ := CreateSampleCategory(h.InitTest(t))
-
- existingAppAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: "/api/v1/categories/",
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var categories []models.Category
-
- err := eaa.App.Conn.Find(&categories).Error
-
- eaa.Assert.NilError(err)
-
- var respCategories []models.Category
-
- err = json.NewDecoder(resp.Body).Decode(&respCategories)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(1, len(respCategories))
- eaa.Assert.Equal(1, len(categories))
-
- eaa.Assert.Equal(categories[0].ID, respCategories[0].ID)
-
- eaa.Assert.Equal(categories[0].Name, respCategories[0].Name)
-
- eaa.Assert.Equal((*SampleCategoryFactory())["name"].(string), categories[0].Name)
- },
- },
- ).Close()
-}
-
-func AssertUpdatedCategoryBodyRespDB(eaa h.ExistingAppAssert, resp *http.Response, body *map[string]interface{}) {
- var respCategory models.Category
-
- err := json.NewDecoder(resp.Body).Decode(&respCategory)
-
- eaa.Assert.NilError(err)
-
- var dbCategories []models.Category
-
- err = eaa.App.Conn.Find(&dbCategories).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(1, len(dbCategories))
-
- dbCategory := dbCategories[0]
-
- eaa.Assert.Equal(dbCategory.ID, respCategory.ID)
- eaa.Assert.Equal(dbCategory.Name, respCategory.Name)
-
- eaa.Assert.Equal((*body)["id"].(uuid.UUID), dbCategory.ID)
- eaa.Assert.Equal((*body)["name"].(string), dbCategory.Name)
-}
-
-func TestUpdateCategoryWorks(t *testing.T) {
- existingAppAssert, uuid := CreateSampleCategory(h.InitTest(t))
-
- category := map[string]interface{}{
- "id": uuid,
- "name": "Arts & Crafts",
- }
-
- AssertUpdatedCategoryBodyRespDB := func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertUpdatedCategoryBodyRespDB(eaa, resp, &category)
- }
-
- existingAppAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPatch,
- Path: fmt.Sprintf("/api/v1/categories/%s", uuid),
- Body: &category,
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: AssertUpdatedCategoryBodyRespDB,
- },
- ).Close()
-}
-
-func TestUpdateCategoryWorksWithSameDetails(t *testing.T) {
- existingAppAssert, uuid := CreateSampleCategory(h.InitTest(t))
-
- category := *SampleCategoryFactory()
- category["id"] = uuid
-
- AssertSampleCategoryBodyRespDB := func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertUpdatedCategoryBodyRespDB(eaa, resp, &category)
- }
-
- existingAppAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPatch,
- Path: fmt.Sprintf("/api/v1/categories/%s", uuid),
- Body: &category,
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: AssertSampleCategoryBodyRespDB,
- },
- ).Close()
-}
-
-func TestUpdateCategoryFailsBadRequest(t *testing.T) {
- appAssert := h.InitTest(t)
-
- badRequests := []string{
- "0",
- "-1",
- "1.1",
- "foo",
- "null",
- }
-
- for _, badRequest := range badRequests {
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodPatch,
- Path: fmt.Sprintf("/api/v1/categories/%s", badRequest),
- Body: SampleCategoryFactory(),
- Role: &models.Super,
- },
- errors.FailedToValidateID,
- )
- }
-
- appAssert.Close()
-}
-
-func TestDeleteCategoryWorks(t *testing.T) {
- existingAppAssert, uuid := CreateSampleCategory(h.InitTest(t))
-
- existingAppAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/categories/%s", uuid),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusNoContent,
- Tester: AssertNoCategories,
- },
- ).Close()
-}
-
-func TestDeleteCategoryFailsBadRequest(t *testing.T) {
- existingAppAssert, _ := CreateSampleCategory(h.InitTest(t))
-
- badRequests := []string{
- "0",
- "-1",
- "1.1",
- "foo",
- "null",
- }
-
- for _, badRequest := range badRequests {
- existingAppAssert = existingAppAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/categories/%s", badRequest),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.FailedToValidateID,
- Tester: Assert1Category,
- },
- )
- }
-
- existingAppAssert.Close()
-}
-
-func TestDeleteCategoryFailsNotFound(t *testing.T) {
- existingAppAssert, _ := CreateSampleCategory(h.InitTest(t))
-
- existingAppAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/categories/%s", uuid.New()),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.CategoryNotFound,
- Tester: Assert1Category,
- },
- ).Close()
-}
diff --git a/backend/tests/api/club_contact_test.go b/backend/tests/api/club_contact_test.go
deleted file mode 100644
index 5cce4c522..000000000
--- a/backend/tests/api/club_contact_test.go
+++ /dev/null
@@ -1,138 +0,0 @@
-package tests
-
-import (
- stdliberrors "errors"
- "fmt"
- "net/http"
- "testing"
-
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
- h "github.com/GenerateNU/sac/backend/tests/api/helpers"
- "github.com/goccy/go-json"
- "github.com/gofiber/fiber/v2"
- "github.com/google/uuid"
- "gorm.io/gorm"
-)
-
-func AssertCreateBadContactDataFails(t *testing.T, jsonKey string, badValues []interface{}) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
- for _, badValue := range badValues {
- sampleContactPermutation := *SampleContactFactory()
- sampleContactPermutation[jsonKey] = badValue
-
- appAssert = appAssert.TestOnErrorAndTester(h.TestRequest{
- Method: fiber.MethodPut,
- Path: fmt.Sprintf("/api/v1/clubs/%s/contacts", clubUUID),
- Body: &sampleContactPermutation,
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.FailedToValidateContact,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertNumContactsRemainsAtN(eaa, resp, 0)
- },
- },
- )
- }
- appAssert.Close()
-}
-
-func TestCreateContactFailsOnInvalidType(t *testing.T) {
- AssertCreateBadContactDataFails(t,
- "type",
- []interface{}{
- "Not a valid type",
- "@#139081#$Ad_Axf",
- },
- )
-}
-
-func TestCreateContactFailsOnInvalidContent(t *testing.T) {
- AssertCreateBadContactDataFails(t,
- "content",
- []interface{}{
- "Not a valid url",
- "@#139081#$Ad_Axf",
- },
- )
-}
-
-func TestPutContactFailsOnClubIdNotExist(t *testing.T) {
- appAssert, _, _ := CreateSampleClub(h.InitTest(t))
-
- uuid := uuid.New()
-
- appAssert.TestOnErrorAndTester(h.TestRequest{
- Method: fiber.MethodPut,
- Path: fmt.Sprintf("/api/v1/clubs/%s/contacts", uuid),
- Body: SampleContactFactory(),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.ClubNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var club models.Club
-
- err := eaa.App.Conn.Where("id = ?", uuid).First(&club).Error
-
- eaa.Assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound))
- },
- },
- ).Close()
-}
-
-func TestPutContactUpdatesExistingContact(t *testing.T) {
- appAssert, clubUUID, contactUUID := CreateSampleContact(h.InitTest(t))
-
- updatedContact := SampleContactFactory()
- (*updatedContact)["content"] = "nedFlanders@gmail.com"
-
- appAssert.TestOnStatusAndTester(h.TestRequest{
- Method: fiber.MethodPut,
- Path: fmt.Sprintf("/api/v1/clubs/%s/contacts", clubUUID),
- Body: updatedContact,
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var dbContact models.Contact
-
- err := eaa.App.Conn.Where("id = ?", contactUUID).First(&dbContact).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(dbContact.Content, (*updatedContact)["content"])
- },
- },
- ).Close()
-}
-
-func TestGetClubContacts(t *testing.T) {
- appAssert, clubUUID, _ := CreateManyContacts(h.InitTest(t))
-
- appAssert.TestOnStatusAndTester(h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/clubs/%s/contacts", clubUUID),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var respContacts []models.Contact
- var dbContacts []models.Contact
- err := json.NewDecoder(resp.Body).Decode(&respContacts)
- eaa.Assert.NilError(err)
-
- err = eaa.App.Conn.Where("club_id = ?", clubUUID).Find(&dbContacts).Error
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(len(respContacts), len(dbContacts))
- },
- },
- )
-
- appAssert.Close()
-}
diff --git a/backend/tests/api/club_follower_test.go b/backend/tests/api/club_follower_test.go
deleted file mode 100644
index 278dc637b..000000000
--- a/backend/tests/api/club_follower_test.go
+++ /dev/null
@@ -1,58 +0,0 @@
-package tests
-
-import (
- "fmt"
- "net/http"
- "testing"
-
- "github.com/GenerateNU/sac/backend/entities/models"
- h "github.com/GenerateNU/sac/backend/tests/api/helpers"
- "github.com/goccy/go-json"
- "github.com/gofiber/fiber/v2"
-)
-
-func TestClubFollowerWorks(t *testing.T) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
- appAssert.TestOnStatus(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/users/:userID/follower/%s", clubUUID),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- fiber.StatusCreated,
- ).TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/clubs/%s/followers", clubUUID),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var followers []models.User
-
- err := json.NewDecoder(resp.Body).Decode(&followers)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(1, len(followers))
-
- var club models.Club
-
- err = eaa.App.Conn.Where("id = ?", clubUUID).First(&club).Error
-
- eaa.Assert.NilError(err)
-
- var dbFollowers []models.User
-
- err = eaa.App.Conn.Model(&club).Association("Follower").Find(&dbFollowers)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(len(dbFollowers), len(followers))
- },
- },
- ).Close()
-}
diff --git a/backend/tests/api/club_member_test.go b/backend/tests/api/club_member_test.go
deleted file mode 100644
index aab11d469..000000000
--- a/backend/tests/api/club_member_test.go
+++ /dev/null
@@ -1,58 +0,0 @@
-package tests
-
-import (
- "fmt"
- "net/http"
- "testing"
-
- "github.com/GenerateNU/sac/backend/entities/models"
- h "github.com/GenerateNU/sac/backend/tests/api/helpers"
- "github.com/goccy/go-json"
- "github.com/gofiber/fiber/v2"
-)
-
-func TestClubMemberWorks(t *testing.T) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
- appAssert.TestOnStatus(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/users/:userID/member/%s", clubUUID),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- fiber.StatusCreated,
- ).TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/clubs/%s/members", clubUUID),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var members []models.User
-
- err := json.NewDecoder(resp.Body).Decode(&members)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(1, len(members))
-
- var club models.Club
-
- err = eaa.App.Conn.Where("id = ?", clubUUID).First(&club).Error
-
- eaa.Assert.NilError(err)
-
- var dbMembers []models.User
-
- err = eaa.App.Conn.Model(&club).Association("Member").Find(&dbMembers)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(len(dbMembers), len(members))
- },
- },
- ).Close()
-}
diff --git a/backend/tests/api/club_tag_test.go b/backend/tests/api/club_tag_test.go
deleted file mode 100644
index c7dc6bbc3..000000000
--- a/backend/tests/api/club_tag_test.go
+++ /dev/null
@@ -1,269 +0,0 @@
-package tests
-
-import (
- "fmt"
- "net/http"
- "testing"
-
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
- h "github.com/GenerateNU/sac/backend/tests/api/helpers"
- "github.com/goccy/go-json"
- "github.com/gofiber/fiber/v2"
- "github.com/google/uuid"
-)
-
-func AssertClubTagsRespDB(eaa h.ExistingAppAssert, resp *http.Response, id uuid.UUID) {
- var respTags []models.Tag
-
- err := json.NewDecoder(resp.Body).Decode(&respTags)
-
- eaa.Assert.NilError(err)
-
- var dbClub models.Club
-
- err = eaa.App.Conn.First(&dbClub, id).Error
-
- eaa.Assert.NilError(err)
-
- var dbTags []models.Tag
-
- err = eaa.App.Conn.Model(&dbClub).Association("Tag").Find(&dbTags)
-
- eaa.Assert.NilError(err)
-
- for i, respTag := range respTags {
- eaa.Assert.Equal(respTag.ID, dbTags[i].ID)
- eaa.Assert.Equal(respTag.Name, dbTags[i].Name)
- eaa.Assert.Equal(respTag.CategoryID, dbTags[i].CategoryID)
- }
-}
-
-func AssertSampleClubTagsRespDB(eaa h.ExistingAppAssert, resp *http.Response, uuid uuid.UUID) {
- AssertClubTagsRespDB(eaa, resp, uuid)
-}
-
-func TestCreateClubTagsFailsOnInvalidDataType(t *testing.T) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
- invalidTags := []interface{}{
- []string{"1", "2", "34"},
- []models.Tag{{Name: "Test", CategoryID: uuid.UUID{}}, {Name: "Test2", CategoryID: uuid.UUID{}}},
- []float32{1.32, 23.5, 35.1},
- }
-
- for _, tag := range invalidTags {
- malformedTag := *SampleTagIDsFactory(nil)
- malformedTag["tags"] = tag
-
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/clubs/%s/tags/", clubUUID),
- Body: &malformedTag,
- Role: &models.Super,
- },
- errors.FailedToParseRequestBody,
- )
- }
-
- appAssert.Close()
-}
-
-func TestCreateClubTagsFailsOnInvalidUserID(t *testing.T) {
- appAssert := h.InitTest(t)
-
- badRequests := []string{
- "0",
- "-1",
- "1.1",
- "foo",
- "null",
- }
-
- for _, badRequest := range badRequests {
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/clubs/%s/tags", badRequest),
- Body: SampleTagIDsFactory(nil),
- Role: &models.Student,
- },
- errors.FailedToValidateID,
- )
- }
-
- appAssert.Close()
-}
-
-func TestCreateClubTagsFailsOnInvalidKey(t *testing.T) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
- invalidBody := []map[string]interface{}{
- {
- "tag": UUIDSlice{uuid.New(), uuid.New()},
- },
- {
- "tagIDs": []uint{1, 2, 3},
- },
- }
-
- for _, body := range invalidBody {
- body := body
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/clubs/%s/tags/", clubUUID),
- Body: &body,
- Role: &models.Student,
- },
- errors.FailedToValidateClubTags,
- )
- }
-
- appAssert.Close()
-}
-
-func TestCreateClubTagsFailsOnNonExistentClub(t *testing.T) {
- uuid := uuid.New()
-
- h.InitTest(t).TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/clubs/%s/tags/", uuid),
- Body: SampleTagIDsFactory(nil),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.ClubNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var dbClub models.Club
-
- err := eaa.App.Conn.First(&dbClub, uuid).Error
-
- eaa.Assert.Assert(err != nil)
- },
- },
- ).Close()
-}
-
-func TestCreateClubTagsWorks(t *testing.T) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
- tagUUIDs, appAssert := CreateSetOfTags(appAssert)
-
- appAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/clubs/%s/tags/", clubUUID),
- Body: SampleTagIDsFactory(&tagUUIDs),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusCreated,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertSampleClubTagsRespDB(eaa, resp, clubUUID)
- },
- },
- )
-
- appAssert.Close()
-}
-
-func TestCreateClubTagsNoneAddedIfInvalid(t *testing.T) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
- appAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/clubs/%s/tags/", clubUUID),
- Body: SampleTagIDsFactory(nil),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusCreated,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var respTags []models.Tag
-
- err := json.NewDecoder(resp.Body).Decode(&respTags)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(len(respTags), 0)
- },
- },
- ).Close()
-}
-
-func TestGetClubTagsFailsOnNonExistentClub(t *testing.T) {
- uuid := uuid.New()
-
- h.InitTest(t).TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/clubs/%s/tags/", uuid),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.ClubNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var dbClub models.Club
-
- err := eaa.App.Conn.First(&dbClub, uuid).Error
-
- eaa.Assert.Assert(err != nil)
- },
- },
- ).Close()
-}
-
-func TestGetClubTagsReturnsEmptyListWhenNoneAdded(t *testing.T) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
- appAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/clubs/%s/tags/", clubUUID),
- Role: &models.Student,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var respTags []models.Tag
-
- err := json.NewDecoder(resp.Body).Decode(&respTags)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(len(respTags), 0)
- },
- },
- ).Close()
-}
-
-func TestGetClubTagsReturnsCorrectList(t *testing.T) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
- tagUUIDs, appAssert := CreateSetOfTags(appAssert)
-
- appAssert.TestOnStatus(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/clubs/%s/tags/", clubUUID),
- Body: SampleTagIDsFactory(&tagUUIDs),
- Role: &models.Student,
- },
- fiber.StatusCreated,
- ).TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/clubs/%s/tags/", clubUUID),
- Role: &models.Student,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertSampleClubTagsRespDB(eaa, resp, clubUUID)
- },
- },
- ).Close()
-}
diff --git a/backend/tests/api/club_test.go b/backend/tests/api/club_test.go
deleted file mode 100644
index c97f47ed0..000000000
--- a/backend/tests/api/club_test.go
+++ /dev/null
@@ -1,513 +0,0 @@
-package tests
-
-import (
- stdliberrors "errors"
- "fmt"
- "net/http"
- "testing"
-
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
- h "github.com/GenerateNU/sac/backend/tests/api/helpers"
- "github.com/goccy/go-json"
- "github.com/gofiber/fiber/v2"
- "github.com/google/uuid"
- "gorm.io/gorm"
-)
-
-func SampleClubFactory(userID *uuid.UUID) *map[string]interface{} {
- return &map[string]interface{}{
- "user_id": userID,
- "name": "Generate",
- "preview": "Generate is Northeastern's premier student-led product development studio.",
- "description": "https://s3.amazonaws.com//",
- "is_recruiting": true,
- "recruitment_cycle": "always",
- "recruitment_type": "application",
- "weekly_time_commitment": 10,
- "one_word_to_describe_us": "muneer",
- "application_link": "https://generatenu.com/apply",
- "logo": "https://s3.amazonaws.com//",
- }
-}
-
-func AssertClubBodyRespDB(eaa h.ExistingAppAssert, resp *http.Response, body *map[string]interface{}) uuid.UUID {
- var respClub models.Club
-
- err := json.NewDecoder(resp.Body).Decode(&respClub)
-
- eaa.Assert.NilError(err)
-
- var dbClubs []models.Club
-
- err = eaa.App.Conn.Order("created_at desc").Find(&dbClubs).Error
-
- eaa.Assert.NilError(err)
-
- dbClub := dbClubs[0]
-
- eaa.Assert.Equal(dbClub.ID, respClub.ID)
- eaa.Assert.Equal(dbClub.Name, respClub.Name)
- eaa.Assert.Equal(dbClub.Preview, respClub.Preview)
- eaa.Assert.Equal(dbClub.Description, respClub.Description)
- eaa.Assert.Equal(dbClub.NumMembers, respClub.NumMembers)
- eaa.Assert.Equal(dbClub.IsRecruiting, respClub.IsRecruiting)
- eaa.Assert.Equal(dbClub.RecruitmentCycle, respClub.RecruitmentCycle)
- eaa.Assert.Equal(dbClub.RecruitmentType, respClub.RecruitmentType)
- eaa.Assert.Equal(dbClub.WeeklyTimeCommitment, respClub.WeeklyTimeCommitment)
- eaa.Assert.Equal(dbClub.OneWordToDescribeUs, respClub.OneWordToDescribeUs)
- eaa.Assert.Equal(dbClub.ApplicationLink, respClub.ApplicationLink)
- eaa.Assert.Equal(dbClub.Logo, respClub.Logo)
-
- var dbAdmins []models.Membership
-
- err = eaa.App.Conn.Where("club_id = ? AND membership_type = ?", dbClub.ID, models.MembershipTypeAdmin).Find(&dbAdmins).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(1, len(dbAdmins))
-
- eaa.Assert.Equal(*(*body)["user_id"].(*uuid.UUID), dbAdmins[0].UserID)
- eaa.Assert.Equal((*body)["name"].(string), dbClub.Name)
- eaa.Assert.Equal((*body)["preview"].(string), dbClub.Preview)
- eaa.Assert.Equal((*body)["description"].(string), dbClub.Description)
- eaa.Assert.Equal((*body)["is_recruiting"].(bool), dbClub.IsRecruiting)
- eaa.Assert.Equal(models.RecruitmentCycle((*body)["recruitment_cycle"].(string)), dbClub.RecruitmentCycle)
- eaa.Assert.Equal(models.RecruitmentType((*body)["recruitment_type"].(string)), dbClub.RecruitmentType)
- eaa.Assert.Equal((*body)["weekly_time_commitment"].(int), dbClub.WeeklyTimeCommitment)
- eaa.Assert.Equal((*body)["one_word_to_describe_us"].(string), dbClub.OneWordToDescribeUs)
- eaa.Assert.Equal((*body)["application_link"].(string), dbClub.ApplicationLink)
- eaa.Assert.Equal((*body)["logo"].(string), dbClub.Logo)
-
- return dbClub.ID
-}
-
-func AssertClubWithBodyRespDBMostRecent(eaa h.ExistingAppAssert, resp *http.Response, body *map[string]interface{}) uuid.UUID {
- var respClub models.Club
-
- err := json.NewDecoder(resp.Body).Decode(&respClub)
-
- eaa.Assert.NilError(err)
-
- var dbClub models.Club
-
- err = eaa.App.Conn.Order("created_at desc").First(&dbClub).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(dbClub.ID, respClub.ID)
- eaa.Assert.Equal(dbClub.Name, respClub.Name)
- eaa.Assert.Equal(dbClub.Preview, respClub.Preview)
- eaa.Assert.Equal(dbClub.Description, respClub.Description)
- eaa.Assert.Equal(dbClub.NumMembers, respClub.NumMembers)
- eaa.Assert.Equal(dbClub.IsRecruiting, respClub.IsRecruiting)
- eaa.Assert.Equal(dbClub.RecruitmentCycle, respClub.RecruitmentCycle)
- eaa.Assert.Equal(dbClub.RecruitmentType, respClub.RecruitmentType)
- eaa.Assert.Equal(dbClub.WeeklyTimeCommitment, respClub.WeeklyTimeCommitment)
- eaa.Assert.Equal(dbClub.OneWordToDescribeUs, respClub.OneWordToDescribeUs)
- eaa.Assert.Equal(dbClub.ApplicationLink, respClub.ApplicationLink)
- eaa.Assert.Equal(dbClub.Logo, respClub.Logo)
-
- var dbAdmins []models.User
-
- err = eaa.App.Conn.Model(&dbClub).Association("Admins").Find(&dbAdmins)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(1, len(dbAdmins))
-
- dbAdmin := dbAdmins[0]
-
- eaa.Assert.Equal((*body)["user_id"].(uuid.UUID), dbAdmin.ID)
- eaa.Assert.Equal((*body)["name"].(string), dbClub.Name)
- eaa.Assert.Equal((*body)["preview"].(string), dbClub.Preview)
- eaa.Assert.Equal((*body)["description"].(string), dbClub.Description)
- eaa.Assert.Equal((*body)["num_members"].(int), dbClub.NumMembers)
- eaa.Assert.Equal((*body)["is_recruiting"].(bool), dbClub.IsRecruiting)
- eaa.Assert.Equal((*body)["recruitment_cycle"].(string), dbClub.RecruitmentCycle)
- eaa.Assert.Equal((*body)["recruitment_type"].(string), dbClub.RecruitmentType)
- eaa.Assert.Equal((*body)["weekly_time_commitment"].(int), dbClub.WeeklyTimeCommitment)
- eaa.Assert.Equal((*body)["one_word_to_describe_us"].(string), dbClub.OneWordToDescribeUs)
- eaa.Assert.Equal((*body)["application_link"].(string), dbClub.ApplicationLink)
- eaa.Assert.Equal((*body)["logo"].(string), dbClub.Logo)
-
- return dbClub.ID
-}
-
-func AssertSampleClubBodyRespDB(eaa h.ExistingAppAssert, resp *http.Response, userID uuid.UUID) uuid.UUID {
- sampleClub := SampleClubFactory(&userID)
- return AssertClubBodyRespDB(eaa, resp, sampleClub)
-}
-
-func CreateSampleClub(existingAppAssert h.ExistingAppAssert) (eaa h.ExistingAppAssert, studentUUID uuid.UUID, clubUUID uuid.UUID) {
- var sampleClubUUID uuid.UUID
-
- newAppAssert := existingAppAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/clubs/",
- Body: SampleClubFactory(nil),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer("user_id"),
- },
- h.TesterWithStatus{
- Status: fiber.StatusCreated,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- sampleClubUUID = AssertSampleClubBodyRespDB(eaa, resp, eaa.App.TestUser.UUID)
- },
- },
- )
-
- return newAppAssert, newAppAssert.App.TestUser.UUID, sampleClubUUID
-}
-
-func TestCreateClubWorks(t *testing.T) {
- existingAppAssert, _, _ := CreateSampleClub(h.InitTest(t))
- existingAppAssert.Close()
-}
-
-func TestGetClubsWorks(t *testing.T) {
- existingAppAssert, _, _ := CreateSampleClub(h.InitTest(t))
-
- existingAppAssert.TestOnStatusAndTester(h.TestRequest{
- Method: fiber.MethodGet,
- Path: "/api/v1/clubs/",
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var respClubs []models.Club
-
- err := json.NewDecoder(resp.Body).Decode(&respClubs)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(1, len(respClubs))
-
- respClub := respClubs[0]
-
- var dbClubs []models.Club
-
- err = eaa.App.Conn.Order("created_at desc").Find(&dbClubs).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(2, len(dbClubs)) // SAC super club AND the club we just created
-
- dbClub := dbClubs[0]
-
- eaa.Assert.Equal(dbClub.ID, respClub.ID)
- eaa.Assert.Equal(dbClub.Name, respClub.Name)
- eaa.Assert.Equal(dbClub.Preview, respClub.Preview)
- eaa.Assert.Equal(dbClub.Description, respClub.Description)
- eaa.Assert.Equal(dbClub.NumMembers, respClub.NumMembers)
- eaa.Assert.Equal(dbClub.IsRecruiting, respClub.IsRecruiting)
- eaa.Assert.Equal(dbClub.RecruitmentCycle, respClub.RecruitmentCycle)
- eaa.Assert.Equal(dbClub.RecruitmentType, respClub.RecruitmentType)
- eaa.Assert.Equal(dbClub.WeeklyTimeCommitment, respClub.WeeklyTimeCommitment)
- eaa.Assert.Equal(dbClub.OneWordToDescribeUs, respClub.OneWordToDescribeUs)
- eaa.Assert.Equal(dbClub.ApplicationLink, respClub.ApplicationLink)
- eaa.Assert.Equal(dbClub.Logo, respClub.Logo)
- },
- },
- ).Close()
-}
-
-func AssertNumClubsRemainsAtN(eaa h.ExistingAppAssert, resp *http.Response, n int) {
- var dbClubs []models.Club
-
- err := eaa.App.Conn.Order("created_at desc").Find(&dbClubs).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(n, len(dbClubs))
-}
-
-var TestNumClubsRemainsAt1 = func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertNumClubsRemainsAtN(eaa, resp, 1)
-}
-
-func AssertCreateBadClubDataFails(t *testing.T, jsonKey string, badValues []interface{}) {
- appAssert, uuid, _ := CreateSampleStudent(t, nil)
-
- for _, badValue := range badValues {
- sampleClubPermutation := *SampleClubFactory(&uuid)
- sampleClubPermutation[jsonKey] = badValue
-
- appAssert = appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/clubs/",
- Body: &sampleClubPermutation,
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.FailedToValidateClub,
- Tester: TestNumClubsRemainsAt1,
- },
- )
- }
- appAssert.Close()
-}
-
-func TestCreateClubFailsOnInvalidDescription(t *testing.T) {
- AssertCreateBadClubDataFails(t,
- "description",
- []interface{}{
- "Not an URL",
- "@#139081#$Ad_Axf",
- "https://google.com",
- },
- )
-}
-
-func TestCreateClubFailsOnInvalidRecruitmentCycle(t *testing.T) {
- AssertCreateBadClubDataFails(t,
- "recruitment_cycle",
- []interface{}{
- "1234",
- "garbanzo",
- "@#139081#$Ad_Axf",
- "https://google.com",
- },
- )
-}
-
-func TestCreateClubFailsOnInvalidRecruitmentType(t *testing.T) {
- AssertCreateBadClubDataFails(t,
- "recruitment_type",
- []interface{}{
- "1234",
- "garbanzo",
- "@#139081#$Ad_Axf",
- "https://google.com",
- },
- )
-}
-
-func TestCreateClubFailsOnInvalidWeeklyTimeCommitment(t *testing.T) {
- AssertCreateBadClubDataFails(t,
- "weekly_time_commitment",
- []interface{}{
- 0,
- -1,
- },
- )
-}
-
-func TestCreateClubFailsOnInvalidApplicationLink(t *testing.T) {
- AssertCreateBadClubDataFails(t,
- "application_link",
- []interface{}{
- "Not an URL",
- "@#139081#$Ad_Axf",
- },
- )
-}
-
-func TestCreateClubFailsOnInvalidLogo(t *testing.T) {
- AssertCreateBadClubDataFails(t,
- "logo",
- []interface{}{
- "Not an URL",
- "@#139081#$Ad_Axf",
- "https://google.com",
- },
- )
-}
-
-func TestUpdateClubWorks(t *testing.T) {
- appAssert, studentUUID, clubUUID := CreateSampleClub(h.InitTest(t))
-
- updatedClub := SampleClubFactory(&studentUUID)
- (*updatedClub)["name"] = "Updated Name"
- (*updatedClub)["preview"] = "Updated Preview"
-
- appAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPatch,
- Path: fmt.Sprintf("/api/v1/clubs/%s", clubUUID),
- Body: updatedClub,
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertClubBodyRespDB(eaa, resp, updatedClub)
- },
- },
- ).Close()
-}
-
-func TestUpdateClubFailsOnInvalidBody(t *testing.T) {
- appAssert, studentUUID, clubUUID := CreateSampleClub(h.InitTest(t))
-
- body := SampleClubFactory(&studentUUID)
-
- for _, invalidData := range []map[string]interface{}{
- {"description": "Not a URL"},
- {"recruitment_cycle": "1234"},
- {"recruitment_type": "ALLLLWAYSSSS"},
- {"application_link": "Not an URL"},
- {"logo": "@12394X_2"},
- } {
- invalidData := invalidData
- appAssert = appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPatch,
- Path: fmt.Sprintf("/api/v1/clubs/%s", clubUUID),
- Body: &invalidData,
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.FailedToValidateClub,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var dbClubs []models.Club
-
- err := eaa.App.Conn.Order("created_at desc").Find(&dbClubs).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(2, len(dbClubs))
-
- dbClub := dbClubs[0]
-
- var dbAdmins []models.Membership
-
- err = eaa.App.Conn.Where("club_id = ? AND membership_type = ?", dbClub.ID, models.MembershipTypeAdmin).Find(&dbAdmins).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(1, len(dbAdmins))
-
- eaa.Assert.Equal(*(*body)["user_id"].(*uuid.UUID), dbAdmins[0].UserID)
- eaa.Assert.Equal((*body)["name"].(string), dbClub.Name)
- eaa.Assert.Equal((*body)["preview"].(string), dbClub.Preview)
- eaa.Assert.Equal((*body)["description"].(string), dbClub.Description)
- eaa.Assert.Equal((*body)["is_recruiting"].(bool), dbClub.IsRecruiting)
- eaa.Assert.Equal(models.RecruitmentCycle((*body)["recruitment_cycle"].(string)), dbClub.RecruitmentCycle)
- eaa.Assert.Equal(models.RecruitmentType((*body)["recruitment_type"].(string)), dbClub.RecruitmentType)
- eaa.Assert.Equal((*body)["application_link"].(string), dbClub.ApplicationLink)
- eaa.Assert.Equal((*body)["logo"].(string), dbClub.Logo)
- },
- },
- )
- }
- appAssert.Close()
-}
-
-func TestUpdateClubFailsBadRequest(t *testing.T) {
- appAssert := h.InitTest(t)
-
- badRequests := []string{
- "0",
- "-1",
- "1.1",
- "foo",
- "null",
- }
-
- sampleStudent, rawPassword := h.SampleStudentFactory()
-
- for _, badRequest := range badRequests {
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodPatch,
- Path: fmt.Sprintf("/api/v1/clubs/%s", badRequest),
- Body: h.SampleStudentJSONFactory(sampleStudent, rawPassword),
- Role: &models.Super,
- },
- errors.FailedToValidateID,
- )
- }
-
- appAssert.Close()
-}
-
-func TestUpdateClubFailsOnClubIdNotExist(t *testing.T) {
- uuid := uuid.New()
-
- h.InitTest(t).TestOnErrorAndTester(h.TestRequest{
- Method: fiber.MethodPatch,
- Path: fmt.Sprintf("/api/v1/clubs/%s", uuid),
- Body: SampleClubFactory(nil),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer("user_id"),
- },
- h.ErrorWithTester{
- Error: errors.ClubNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var club models.Club
-
- err := eaa.App.Conn.Where("id = ?", uuid).First(&club).Error
-
- eaa.Assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound))
- },
- },
- ).Close()
-}
-
-func TestDeleteClubWorks(t *testing.T) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
- appAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/clubs/%s", clubUUID),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusNoContent,
- Tester: TestNumClubsRemainsAt1,
- },
- ).Close()
-}
-
-func TestDeleteClubNotExist(t *testing.T) {
- uuid := uuid.New()
- h.InitTest(t).TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/clubs/%s", uuid),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.ClubNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var club models.Club
-
- err := eaa.App.Conn.Where("id = ?", uuid).First(&club).Error
-
- eaa.Assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound))
-
- AssertNumClubsRemainsAtN(eaa, resp, 1)
- },
- },
- ).Close()
-}
-
-func TestDeleteClubBadRequest(t *testing.T) {
- appAssert := h.InitTest(t)
-
- badRequests := []string{
- "0",
- "-1",
- "1.1",
- "hello",
- "null",
- }
-
- for _, badRequest := range badRequests {
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/clubs/%s", badRequest),
- Role: &models.Super,
- },
- errors.FailedToValidateID,
- )
- }
-
- appAssert.Close()
-}
diff --git a/backend/tests/api/contact_test.go b/backend/tests/api/contact_test.go
deleted file mode 100644
index 6bc3f70ee..000000000
--- a/backend/tests/api/contact_test.go
+++ /dev/null
@@ -1,279 +0,0 @@
-package tests
-
-import (
- stdliberrors "errors"
- "fmt"
- "net/http"
- "testing"
-
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
- h "github.com/GenerateNU/sac/backend/tests/api/helpers"
- "github.com/goccy/go-json"
- "github.com/gofiber/fiber/v2"
- "github.com/google/uuid"
- "gorm.io/gorm"
-)
-
-func SampleContactFactory() *map[string]interface{} {
- return &map[string]interface{}{
- "type": "email",
- "content": "jermaine@gmail.com",
- }
-}
-
-func ManyContactsFactory() map[string](*map[string]interface{}) {
- arr := make(map[string]*map[string]interface{})
-
- arr["facebook"] = &map[string]interface{}{
- "type": "facebook",
- "content": "https://facebook.com/cheeseClub",
- }
-
- arr["instagram"] = &map[string]interface{}{
- "type": "instagram",
- "content": "https://instagram.com/cheeseClub",
- }
-
- arr["x"] = &map[string]interface{}{
- "type": "x",
- "content": "https://x.com/cheeseClub",
- }
-
- arr["linkedin"] = &map[string]interface{}{
- "type": "linkedin",
- "content": "https://linkedin.com/cheeseClub",
- }
-
- arr["youtube"] = &map[string]interface{}{
- "type": "youtube",
- "content": "https://youtube.com/cheeseClub",
- }
-
- arr["github"] = &map[string]interface{}{
- "type": "github",
- "content": "https://github.com/GeneratNU/sac",
- }
-
- arr["slack"] = &map[string]interface{}{
- "type": "slack",
- "content": "https://join.slack.com/cheeseClub",
- }
-
- arr["discord"] = &map[string]interface{}{
- "type": "discord",
- "content": "https://discord.gg/cheeseClub",
- }
-
- arr["email"] = &map[string]interface{}{
- "type": "email",
- "content": "cheeseClub@gmail.com",
- }
-
- arr["customSite"] = &map[string]interface{}{
- "type": "customSite",
- "content": "https://cheeseClub.com",
- }
-
- return arr
-}
-
-func AssertContactBodyRespDB(eaa h.ExistingAppAssert, resp *http.Response, body *map[string]interface{}) uuid.UUID {
- var respContact models.Contact
-
- err := json.NewDecoder(resp.Body).Decode(&respContact)
-
- eaa.Assert.NilError(err)
-
- var dbContacts []models.Contact
-
- err = eaa.App.Conn.Order("created_at desc").Find(&dbContacts).Error
-
- eaa.Assert.NilError(err)
-
- dbContact := dbContacts[0]
-
- eaa.Assert.Equal(dbContact.ID, respContact.ID)
- eaa.Assert.Equal(dbContact.Type, respContact.Type)
- eaa.Assert.Equal(dbContact.Content, respContact.Content)
-
- return dbContact.ID
-}
-
-func CreateSampleContact(existingAppAssert h.ExistingAppAssert) (eaa h.ExistingAppAssert, clubUUID uuid.UUID, contactUUID uuid.UUID) {
- appAssert, _, clubUUID := CreateSampleClub(existingAppAssert)
-
- var sampleContactUUID uuid.UUID
-
- return appAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPut,
- Path: fmt.Sprintf("/api/v1/clubs/%s/contacts", clubUUID),
- Body: SampleContactFactory(),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- sampleContactUUID = AssertContactBodyRespDB(eaa, resp, SampleContactFactory())
- AssertNumContactsRemainsAtN(eaa, resp, 1)
- },
- },
- ), clubUUID, sampleContactUUID
-}
-
-func CreateManyContacts(existingAppAssert h.ExistingAppAssert) (eaa h.ExistingAppAssert, clubUUID uuid.UUID, contactUUIDs map[string]uuid.UUID) {
- existingAppAssert, _, clubUUID = CreateSampleClub(existingAppAssert)
-
- contactUUIDs = make(map[string]uuid.UUID)
-
- currentLength := 0
- for key, contact := range ManyContactsFactory() {
- existingAppAssert = existingAppAssert.TestOnStatusAndTester(h.TestRequest{
- Method: fiber.MethodPut,
- Path: fmt.Sprintf("/api/v1/clubs/%s/contacts", clubUUID),
- Body: contact,
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- contactUUIDs[key] = AssertContactBodyRespDB(eaa, resp, contact)
- currentLength++
- AssertNumContactsRemainsAtN(eaa, resp, currentLength)
- },
- },
- )
- }
-
- return existingAppAssert, clubUUID, contactUUIDs
-}
-
-func TestCreateManyContactsWorks(t *testing.T) {
- existingAppAssert, _, _ := CreateManyContacts(h.InitTest(t))
- existingAppAssert.Close()
-}
-
-func TestCreateContactWorks(t *testing.T) {
- existingAppAssert, _, _ := CreateSampleContact(h.InitTest(t))
- existingAppAssert.Close()
-}
-
-func AssertNumContactsRemainsAtN(eaa h.ExistingAppAssert, resp *http.Response, n int) {
- var dbContacts []models.Contact
-
- err := eaa.App.Conn.Order("created_at desc").Find(&dbContacts).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(n, len(dbContacts))
-}
-
-func TestGetContactByIdWorks(t *testing.T) {
- appAssert, _, contactUUID := CreateSampleContact(h.InitTest(t))
-
- appAssert.TestOnStatusAndTester(h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/contacts/%s", contactUUID),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var respContact models.Contact
-
- err := json.NewDecoder(resp.Body).Decode(&respContact)
-
- eaa.Assert.NilError(err)
-
- var dbContacts []models.Contact
-
- err = eaa.App.Conn.Order("created_at desc").Find(&dbContacts).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(dbContacts[0].ID, respContact.ID)
- eaa.Assert.Equal(dbContacts[0].Type, respContact.Type)
- eaa.Assert.Equal(dbContacts[0].Content, respContact.Content)
- },
- },
- ).Close()
-}
-
-func TestGetContactFailsOnContactIdNotExist(t *testing.T) {
- appAssert, _, _ := CreateSampleContact(h.InitTest(t))
-
- uuid := uuid.New()
-
- appAssert.TestOnErrorAndTester(h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/contacts/%s", uuid),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.ContactNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var contact models.Contact
-
- err := eaa.App.Conn.Where("id = ?", uuid).First(&contact).Error
-
- eaa.Assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound))
- },
- },
- ).Close()
-}
-
-func TestDeleteContactWorks(t *testing.T) {
- appAssert, _, contactUUID := CreateSampleContact(h.InitTest(t))
-
- appAssert.TestOnStatusAndTester(h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/contacts/%s", contactUUID),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusNoContent,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var contact models.Contact
-
- err := eaa.App.Conn.Where("id = ?", contactUUID).First(&contact).Error
-
- eaa.Assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound))
- },
- },
- ).Close()
-}
-
-func TestDeleteContactFailsOnContactIdNotExist(t *testing.T) {
- appAssert, _, _ := CreateSampleContact(h.InitTest(t))
- uuid := uuid.New()
-
- appAssert.TestOnErrorAndTester(h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/contacts/%s", uuid),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.ContactNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var contact models.Contact
- err := eaa.App.Conn.Where("id = ?", uuid).First(&contact).Error
- eaa.Assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound))
-
- AssertNumContactsRemainsAtN(eaa, resp, 1)
- },
- },
- ).Close()
-}
-
-// test that the request returns paginated contacts
-func TestGetContactsWorks(t *testing.T) {
- appAssert, _, _ := CreateManyContacts(h.InitTest(t))
-
- appAssert.TestOnStatus(h.TestRequest{
- Method: fiber.MethodGet,
- Path: "/api/v1/contacts",
- Role: &models.Super,
- }, fiber.StatusOK,
- ).Close()
-}
diff --git a/backend/tests/api/event_test.go b/backend/tests/api/event_test.go
deleted file mode 100644
index 3e397317e..000000000
--- a/backend/tests/api/event_test.go
+++ /dev/null
@@ -1,660 +0,0 @@
-package tests
-
-import (
- stdliberrors "errors"
- "fmt"
- "net/http"
- "testing"
- "time"
-
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
- h "github.com/GenerateNU/sac/backend/tests/api/helpers"
- "github.com/goccy/go-json"
- "github.com/gofiber/fiber/v2"
- "github.com/google/uuid"
- "gorm.io/gorm"
-)
-
-type EventFactory func(hostID uuid.UUID) *map[string]interface{}
-
-func SampleEventFactory(hostID uuid.UUID) *map[string]interface{} {
- return &map[string]interface{}{
- "name": "Generate",
- "preview": "Generate is Northeastern's premier student-led product development studio.",
- "content": "Come join us for Generate's end-of-semester showcase",
- "start_time": "2023-12-20T18:00:00Z",
- "end_time": "2023-12-20T21:00:00Z",
- "location": "Carter Fields",
- "event_type": "open",
- "is_recurring": false,
- "host": hostID,
- }
-}
-
-func SampleSeriesFactory(hostID uuid.UUID) *map[string]interface{} {
- return CustomSampleSeriesFactory(
- hostID,
- models.CreateSeriesRequestBody{
- RecurringType: "daily",
- MaxOccurrences: 10,
- },
- )
-}
-
-func CustomSampleSeriesFactory(hostID uuid.UUID, series models.CreateSeriesRequestBody) *map[string]interface{} {
- return &map[string]interface{}{
- "name": "Software Development",
- "preview": "CS4500 at northeastern",
- "content": "Software development with ben lerner",
- "start_time": "2024-03-20T18:00:00Z",
- "end_time": "2024-03-20T21:00:00Z",
- "location": "ISEC",
- "event_type": "membersOnly",
- "is_recurring": true,
- "host": hostID,
- "series": series,
- }
-}
-
-func CompareEventSlices(eaa h.ExistingAppAssert, dbEvents, respEvents []models.Event) {
- for i, respEvent := range respEvents {
- dbEvent := dbEvents[i]
- CompareEvents(eaa, dbEvent, respEvent)
- }
-}
-
-func CompareEvents(eaa h.ExistingAppAssert, dbEvent, respEvent models.Event) {
- eaa.Assert.Equal(dbEvent.ID, respEvent.ID)
- eaa.Assert.Equal(dbEvent.Name, respEvent.Name)
- eaa.Assert.Equal(dbEvent.Preview, respEvent.Preview)
- eaa.Assert.Equal(dbEvent.Content, respEvent.Content)
- eaa.Assert.Equal(dbEvent.StartTime.Compare(respEvent.StartTime), 0)
- eaa.Assert.Equal(dbEvent.EndTime.Compare(respEvent.EndTime), 0)
- eaa.Assert.Equal(dbEvent.Location, respEvent.Location)
- eaa.Assert.Equal(dbEvent.IsRecurring, respEvent.IsRecurring)
-}
-
-func GetRespAndDBEvents(eaa h.ExistingAppAssert, resp *http.Response) ([]models.Event, []models.Event) {
- var respEventList []models.Event
-
- err := json.NewDecoder(resp.Body).Decode(&respEventList)
- eaa.Assert.NilError(err)
-
- var dbEvents []models.Event
-
- err = eaa.App.Conn.Order("created_at desc").Find(&dbEvents).Error
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(len(respEventList), len(dbEvents))
-
- return respEventList, dbEvents
-}
-
-func AssertEventListBodyRespDB(eaa h.ExistingAppAssert, resp *http.Response, body *map[string]interface{}) []uuid.UUID {
- respEvents, dbEvents := GetRespAndDBEvents(eaa, resp)
-
- uuidList := []uuid.UUID{}
-
- for i, respEvent := range respEvents {
- dbEvent := dbEvents[i]
-
- CompareEvents(eaa, dbEvent, respEvent)
-
- uuidList = append(uuidList, dbEvent.ID)
- }
-
- return uuidList
-}
-
-func AssertEventBodyRespDB(eaa h.ExistingAppAssert, resp *http.Response, body *map[string]interface{}) uuid.UUID {
- var respEvent models.Event
-
- err := json.NewDecoder(resp.Body).Decode(&respEvent)
-
- eaa.Assert.NilError(err)
-
- var dbEvents []models.Event
-
- err = eaa.App.Conn.Order("created_at desc").Find(&dbEvents).Error
-
- eaa.Assert.NilError(err)
-
- dbEvent := dbEvents[0]
-
- CompareEvents(eaa, dbEvent, respEvent)
-
- bodyStartTime, err := time.Parse(time.RFC3339, (*body)["start_time"].(string))
- eaa.Assert.NilError(err)
- bodyEndTime, err := time.Parse(time.RFC3339, (*body)["end_time"].(string))
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal((*body)["name"].(string), dbEvent.Name)
- eaa.Assert.Equal((*body)["preview"].(string), dbEvent.Preview)
- eaa.Assert.Equal((*body)["content"].(string), dbEvent.Content)
- eaa.Assert.Equal(bodyStartTime.Compare(dbEvent.StartTime), 0)
- eaa.Assert.Equal(bodyEndTime.Compare(dbEvent.EndTime), 0)
- eaa.Assert.Equal((*body)["location"].(string), dbEvent.Location)
- eaa.Assert.Equal(models.EventType((*body)["event_type"].(string)), dbEvent.EventType)
- eaa.Assert.Equal((*body)["is_recurring"].(bool), dbEvent.IsRecurring)
-
- return dbEvent.ID
-}
-
-func AssertSampleEventBodyRespDB(eaa h.ExistingAppAssert, hostID uuid.UUID, resp *http.Response) []uuid.UUID {
- sampleEvent := SampleEventFactory(hostID)
- return AssertEventListBodyRespDB(eaa, resp, sampleEvent)
-}
-
-func CreateSampleEvent(existingAppAssert h.ExistingAppAssert, hostID uuid.UUID, factoryFunction EventFactory) (h.ExistingAppAssert, []uuid.UUID) {
- var sampleEventUUIDs []uuid.UUID
-
- newAppAssert := existingAppAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/events/",
- Body: factoryFunction(hostID),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusCreated,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- sampleEventUUIDs = AssertSampleEventBodyRespDB(eaa, hostID, resp)
- },
- },
- )
-
- return newAppAssert, sampleEventUUIDs
-}
-
-func AssertNumEventsRemainsAtN(eaa h.ExistingAppAssert, resp *http.Response, n int) {
- var dbEvents []models.Event
-
- err := eaa.App.Conn.Order("created_at desc").Find(&dbEvents).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(n, len(dbEvents))
-}
-
-func AssertNumSeriesRemainsAtN(eaa h.ExistingAppAssert, resp *http.Response, n int) {
- var dbSeries []models.Series
-
- err := eaa.App.Conn.Order("created_at desc").Find(&dbSeries).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(n, len(dbSeries))
-}
-
-func TestCreateEventWorks(t *testing.T) {
- eaa, _, clubID := CreateSampleClub(h.InitTest(t))
- eaa, _ = CreateSampleEvent(eaa, clubID, SampleEventFactory)
- eaa.Close()
-}
-
-func TestCreateEventSeriesWorks(t *testing.T) {
- eaa, _, clubID := CreateSampleClub(h.InitTest(t))
- eaa, _ = CreateSampleEvent(eaa, clubID, SampleSeriesFactory)
- eaa.Close()
-}
-
-func TestGetEventWorks(t *testing.T) {
- existingAppAssert, _, clubID := CreateSampleClub(h.InitTest(t))
- existingAppAssert, eventUUID := CreateSampleEvent(existingAppAssert, clubID, SampleEventFactory)
- existingAppAssert.TestOnStatusAndTester(h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/events/%s", eventUUID[0]),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertEventListBodyRespDB(eaa, resp, SampleEventFactory(clubID))
- },
- },
- ).Close()
-}
-
-func TestGetEventsWorks(t *testing.T) {
- existingAppAssert, _, clubID := CreateSampleClub(h.InitTest(t))
- existingAppAssert, _ = CreateSampleEvent(existingAppAssert, clubID, SampleEventFactory)
-
- existingAppAssert.TestOnStatusAndTester(h.TestRequest{
- Method: fiber.MethodGet,
- Path: "/api/v1/events/",
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- respEvents, dbEvents := GetRespAndDBEvents(eaa, resp)
-
- respEvent := respEvents[0]
-
- dbEvent := dbEvents[0]
-
- CompareEvents(eaa, dbEvent, respEvent)
- },
- },
- ).Close()
-}
-
-func TestGetSeriesByEventIDWorks(t *testing.T) {
- existingAppAssert, _, clubID := CreateSampleClub(h.InitTest(t))
- existingAppAssert, eventUUIDs := CreateSampleEvent(existingAppAssert, clubID, SampleSeriesFactory)
-
- existingAppAssert.TestOnStatusAndTester(h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/events/%s/series", eventUUIDs[2]),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- respEvents, dbEvents := GetRespAndDBEvents(eaa, resp)
- CompareEventSlices(eaa, dbEvents, respEvents)
- },
- },
- ).Close()
-}
-
-func AssertCreateBadEventDataFails(t *testing.T, jsonKey string, badValues []interface{}, expectedErr errors.Error) {
- appAssert, _, _ := CreateSampleStudent(t, nil)
- appAssert, _, clubID := CreateSampleClub(appAssert)
-
- for _, badValue := range badValues {
- sampleEventPermutation := *SampleEventFactory(clubID)
- sampleEventPermutation[jsonKey] = badValue
-
- appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/events/",
- Body: &sampleEventPermutation,
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: expectedErr,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertNumEventsRemainsAtN(eaa, resp, 0)
- },
- },
- )
- }
- appAssert.Close()
-}
-
-func TestCreateEventFailsOnInvalidStartTime(t *testing.T) {
- AssertCreateBadEventDataFails(t,
- "start_time",
- []interface{}{
- "2023-12-20, 18:00",
- },
- errors.FailedToParseRequestBody,
- )
-}
-
-func TestCreateEventFailsOnInvalidEndTime(t *testing.T) {
- AssertCreateBadEventDataFails(t,
- "end_time",
- []interface{}{
- "2023-12-20, 22:00",
- },
- errors.FailedToParseRequestBody,
- )
-}
-
-func TestCreateEventFailsOnEndTimeBeforeStartTime(t *testing.T) {
- AssertCreateBadEventDataFails(t,
- "end_time",
- []interface{}{
- "2023-12-20T17:00:00Z",
- },
- errors.FailedToValidateEvent,
- )
-}
-
-func TestCreateEventFailsOnInvalidEventType(t *testing.T) {
- AssertCreateBadEventDataFails(t,
- "event_type",
- []interface{}{
- "everyone",
- "open membersOnly",
- },
- errors.FailedToValidateEvent,
- )
-}
-
-func AssertCreateBadEventSeriesDataFails(t *testing.T, badSeries models.CreateSeriesRequestBody, expectedErr errors.Error) {
- appAssert, _, _ := CreateSampleStudent(t, nil)
- appAssert, _, clubID := CreateSampleClub(appAssert)
-
- sampleSeriesPermutation := CustomSampleSeriesFactory(clubID, badSeries)
-
- appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/events/",
- Body: sampleSeriesPermutation,
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: expectedErr,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertNumEventsRemainsAtN(eaa, resp, 0)
- },
- },
- )
- appAssert.Close()
-}
-
-func TestCreateSeriesFailsOnInvalidRecurringType(t *testing.T) {
- AssertCreateBadEventSeriesDataFails(t,
- models.CreateSeriesRequestBody{
- RecurringType: "annually",
- MaxOccurrences: 10,
- },
- errors.FailedToValidateEventSeries,
- )
-}
-
-func TestCreateSeriesFailsOnInvalidMaxOccurrences(t *testing.T) {
- AssertCreateBadEventSeriesDataFails(t,
- models.CreateSeriesRequestBody{
- RecurringType: "weekly",
- MaxOccurrences: -1,
- },
- errors.FailedToValidateEventSeries,
- )
-}
-
-func TestUpdateEventWorks(t *testing.T) {
- appAssert, _, clubID := CreateSampleClub(h.InitTest(t))
- appAssert, eventUUID := CreateSampleEvent(appAssert, clubID, SampleEventFactory)
-
- updatedEvent := SampleEventFactory(clubID)
- (*updatedEvent)["name"] = "Updated Name"
- (*updatedEvent)["preview"] = "Updated Preview"
-
- appAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPatch,
- Path: fmt.Sprintf("/api/v1/events/%s", eventUUID),
- Body: updatedEvent,
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertEventListBodyRespDB(eaa, resp, updatedEvent)
- },
- },
- ).Close()
-}
-
-func TestUpdateEventSeriesWorks(t *testing.T) {
- appAssert, _, clubID := CreateSampleClub(h.InitTest(t))
- appAssert, eventUUIDs := CreateSampleEvent(appAssert, clubID, SampleSeriesFactory)
-
- updatedSeries := &map[string]interface{}{
- "recurring_type": "daily",
- "max_occurrences": 5,
- "event_details": &map[string]interface{}{
- "name": "eece test",
- "preview": "the best class ever",
- "content": "EECE2322",
- "start_time": "2023-09-20T16:34:50Z",
- "end_time": "2023-09-20T18:34:50Z",
- "location": "Richards 224",
- "event_type": "open",
- "is_recurring": true,
- "host": clubID,
- },
- }
-
- appAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPatch,
- Path: fmt.Sprintf("/api/v1/events/%s/series", eventUUIDs[0]),
- Body: updatedSeries,
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertEventListBodyRespDB(eaa, resp, updatedSeries)
- },
- },
- ).Close()
-}
-
-func TestUpdateEventFailsOnInvalidBody(t *testing.T) {
- appAssert, _, clubID := CreateSampleClub(h.InitTest(t))
- appAssert, eventUUID := CreateSampleEvent(appAssert, clubID, SampleEventFactory)
-
- body := SampleEventFactory(clubID)
-
- for _, invalidData := range []map[string]interface{}{
- {"start_time": "Not a datetime"},
- {"end_time": "another non-datetime"},
- } {
- invalidData := invalidData
- appAssert = appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPatch,
- Path: fmt.Sprintf("/api/v1/events/%s", eventUUID),
- Body: &invalidData,
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.FailedToParseRequestBody,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var dbEvents []models.Event
-
- err := eaa.App.Conn.Order("created_at desc").Find(&dbEvents).Error
-
- eaa.Assert.NilError(err)
-
- dbEvent := dbEvents[0]
-
- bodyStartTime, err := time.Parse(time.RFC3339, (*body)["start_time"].(string))
- eaa.Assert.NilError(err)
- bodyEndTime, err := time.Parse(time.RFC3339, (*body)["end_time"].(string))
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal((*body)["name"].(string), dbEvent.Name)
- eaa.Assert.Equal((*body)["preview"].(string), dbEvent.Preview)
- eaa.Assert.Equal((*body)["content"].(string), dbEvent.Content)
- eaa.Assert.Equal(bodyStartTime.Compare(dbEvent.StartTime), 0)
- eaa.Assert.Equal(bodyEndTime.Compare(dbEvent.EndTime), 0)
- eaa.Assert.Equal((*body)["location"].(string), dbEvent.Location)
- eaa.Assert.Equal(models.EventType((*body)["event_type"].(string)), dbEvent.EventType)
- eaa.Assert.Equal((*body)["is_recurring"].(bool), dbEvent.IsRecurring)
- },
- },
- )
- }
- appAssert.Close()
-}
-
-func TestUpdateEventFailsBadRequest(t *testing.T) {
- appAssert, _, clubID := CreateSampleClub(h.InitTest(t))
-
- badRequests := []string{
- "0",
- "-1",
- "1.1",
- "foo",
- "null",
- }
-
- for _, badRequest := range badRequests {
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodPatch,
- Path: fmt.Sprintf("/api/v1/events/%s", badRequest),
- Body: SampleEventFactory(clubID),
- Role: &models.Super,
- },
- errors.FailedToValidateID,
- )
- }
-
- appAssert.Close()
-}
-
-func TestUpdateEventFailsOnEventIdNotExist(t *testing.T) {
- eaa, _, clubID := CreateSampleClub(h.InitTest(t))
-
- uuid := uuid.New()
-
- eaa.TestOnErrorAndTester(h.TestRequest{
- Method: fiber.MethodPatch,
- Path: fmt.Sprintf("/api/v1/events/%s", uuid),
- Body: SampleEventFactory(clubID),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer("user_id"),
- },
- h.ErrorWithTester{
- Error: errors.EventNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var event models.Event
-
- err := eaa.App.Conn.Where("id = ?", uuid).First(&event).Error
-
- eaa.Assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound))
- },
- },
- ).Close()
-}
-
-func TestUpdateSeriesFailsBadRequest(t *testing.T) {
- appAssert, _, clubID := CreateSampleClub(h.InitTest(t))
-
- badRequests := []string{
- "0",
- "-1",
- "1.1",
- "foo",
- "null",
- }
-
- for _, badRequest := range badRequests {
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodPatch,
- Path: fmt.Sprintf("/api/v1/events/%s/series", badRequest),
- Body: SampleEventFactory(clubID),
- Role: &models.Super,
- },
- errors.FailedToValidateID,
- )
- }
-
- appAssert.Close()
-}
-
-func AssertDeleteWorks(t *testing.T, factoryFunction EventFactory, requestPath string, tester h.Tester) {
- appAssert, _, clubID := CreateSampleClub(h.InitTest(t))
- appAssert, eventUUIDs := CreateSampleEvent(appAssert, clubID, factoryFunction)
-
- appAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf(requestPath, eventUUIDs[0]),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusNoContent,
- Tester: tester,
- },
- ).Close()
-}
-
-func TestDeleteEventWorks(t *testing.T) {
- AssertDeleteWorks(t, SampleEventFactory, "/api/v1/events/%s", func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertNumEventsRemainsAtN(eaa, resp, 0)
- })
-}
-
-func TestDeleteSeriesByEventIDWorks(t *testing.T) {
- AssertDeleteWorks(t, SampleEventFactory, "/api/v1/events/%s", func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertNumEventsRemainsAtN(eaa, resp, 0)
- AssertNumSeriesRemainsAtN(eaa, resp, 0)
- })
-}
-
-func AssertDeleteNotExistFails(t *testing.T, factoryFunction EventFactory, requestPath string, tester h.Tester, badUUID uuid.UUID) {
- appAssert, _, clubID := CreateSampleClub(h.InitTest(t))
- appAssert, _ = CreateSampleEvent(appAssert, clubID, factoryFunction)
-
- appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/events/%s", badUUID),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.EventNotFound,
- Tester: tester,
- },
- ).Close()
-}
-
-func TestDeleteEventNotExist(t *testing.T) {
- uuid := uuid.New()
-
- AssertDeleteNotExistFails(t, SampleEventFactory, "/api/v1/events/%s", func(eaa h.ExistingAppAssert, resp *http.Response) {
- var event []models.Event
- err := eaa.App.Conn.Where("id = ?", uuid).First(&event).Error
- eaa.Assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound))
-
- AssertNumEventsRemainsAtN(eaa, resp, 1)
- }, uuid)
-}
-
-func TestDeleteSeriesNotExist(t *testing.T) {
- uuid := uuid.New()
-
- AssertDeleteNotExistFails(t, SampleSeriesFactory, "/api/v1/events/%s/series", func(eaa h.ExistingAppAssert, resp *http.Response) {
- var events []models.Event
- err := eaa.App.Conn.Where("id = ?", uuid).First(&events).Error
- eaa.Assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound))
-
- AssertNumSeriesRemainsAtN(eaa, resp, 1)
- }, uuid)
-}
-
-func AssertDeleteBadRequestFails(t *testing.T, requestPath string) {
- appAssert := h.InitTest(t)
-
- badRequests := []string{
- "0",
- "-1",
- "1.1",
- "hello",
- "null",
- }
-
- for _, badRequest := range badRequests {
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf(requestPath, badRequest),
- Role: &models.Super,
- },
- errors.FailedToValidateID,
- )
- }
-
- appAssert.Close()
-}
-
-func TestDeleteEventBadRequest(t *testing.T) {
- AssertDeleteBadRequestFails(t, "/api/v1/events/%s")
-}
-
-func TestDeleteSeriesBadRequest(t *testing.T) {
- AssertDeleteBadRequestFails(t, "/api/v1/events/%s/series")
-}
diff --git a/backend/tests/api/health_test.go b/backend/tests/api/health_test.go
deleted file mode 100644
index 52e51fe9d..000000000
--- a/backend/tests/api/health_test.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package tests
-
-import (
- "testing"
-
- h "github.com/GenerateNU/sac/backend/tests/api/helpers"
- "github.com/gofiber/fiber/v2"
-)
-
-func TestHealthWorks(t *testing.T) {
- h.InitTest(t).TestOnStatus(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: "/health",
- },
- fiber.StatusOK,
- ).Close()
-}
diff --git a/backend/tests/api/helpers/requests.go b/backend/tests/api/helpers/requests.go
index a7bccc525..fca088662 100644
--- a/backend/tests/api/helpers/requests.go
+++ b/backend/tests/api/helpers/requests.go
@@ -8,8 +8,6 @@ import (
"strings"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
- "github.com/gofiber/fiber/v2"
"github.com/goccy/go-json"
)
@@ -104,7 +102,7 @@ func (existingAppAssert ExistingAppAssert) TestOnStatus(request TestRequest, sta
func (request *TestRequest) testOn(existingAppAssert ExistingAppAssert, status int, key string, value string) (ExistingAppAssert, *http.Response) {
appAssert, resp := request.test(existingAppAssert)
- if resp.StatusCode == fiber.StatusNoContent {
+ if resp.StatusCode == http.StatusNoContent {
return appAssert, resp
}
@@ -121,22 +119,11 @@ func (request *TestRequest) testOn(existingAppAssert ExistingAppAssert, status i
return appAssert, resp
}
-func (existingAppAssert ExistingAppAssert) TestOnError(request TestRequest, expectedError errors.Error) ExistingAppAssert {
- appAssert, _ := request.testOn(existingAppAssert, expectedError.StatusCode, "error", expectedError.Message)
- return appAssert
-}
-
type ErrorWithTester struct {
- Error errors.Error
+ Error error
Tester Tester
}
-func (existingAppAssert ExistingAppAssert) TestOnErrorAndTester(request TestRequest, errorWithTester ErrorWithTester) ExistingAppAssert {
- appAssert, resp := request.testOn(existingAppAssert, errorWithTester.Error.StatusCode, "error", errorWithTester.Error.Message)
- errorWithTester.Tester(appAssert, resp)
- return appAssert
-}
-
func (existingAppAssert ExistingAppAssert) TestOnMessage(request TestRequest, status int, message string) ExistingAppAssert {
request.testOn(existingAppAssert, status, "message", message)
return existingAppAssert
diff --git a/backend/tests/api/mocks/aws_mock.go b/backend/tests/api/mocks/aws_mock.go
index 070d16fc9..28d72e690 100644
--- a/backend/tests/api/mocks/aws_mock.go
+++ b/backend/tests/api/mocks/aws_mock.go
@@ -4,7 +4,6 @@ import (
"mime/multipart"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/integrations/file"
)
@@ -14,11 +13,11 @@ func NewAWSMockClient() file.FileClientInterface {
return &AWSMockClient{}
}
-func (c *AWSMockClient) UploadFile(folder string, fileHeader *multipart.FileHeader, allowedTypes []file.FileType) (*models.FileInfo, *errors.Error) {
+func (c *AWSMockClient) UploadFile(folder string, fileHeader *multipart.FileHeader, allowedTypes []file.FileType) (*models.FileInfo, error) {
return nil, nil
}
-func (c *AWSMockClient) DeleteFile(fileURL string) *errors.Error {
+func (c *AWSMockClient) DeleteFile(fileURL string) error {
return nil
}
diff --git a/backend/tests/api/mocks/jwt_mock.go b/backend/tests/api/mocks/jwt_mock.go
index 860da3134..221d3737b 100644
--- a/backend/tests/api/mocks/jwt_mock.go
+++ b/backend/tests/api/mocks/jwt_mock.go
@@ -2,7 +2,6 @@ package mocks
import (
"github.com/GenerateNU/sac/backend/auth"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/golang-jwt/jwt"
)
@@ -12,26 +11,26 @@ func NewJWTMockClient() auth.JWTClientInterface {
return &JWTMockClient{}
}
-func (c *JWTMockClient) GenerateTokenPair(accessClaims, refreshClaims auth.Claims) (*auth.Token, *errors.Error) {
+func (c *JWTMockClient) GenerateTokenPair(accessClaims, refreshClaims auth.Claims) (*auth.Token, error) {
return &auth.Token{}, nil
}
-func (c *JWTMockClient) GenerateToken(claims auth.Claims, tokenType auth.JWTType) ([]byte, *errors.Error) {
+func (c *JWTMockClient) GenerateToken(claims auth.Claims, tokenType auth.JWTType) ([]byte, error) {
return []byte{}, nil
}
-func (c *JWTMockClient) RefreshToken(token, refreshToken string, tokenType auth.JWTType, newClaims jwt.MapClaims) ([]byte, *errors.Error) {
+func (c *JWTMockClient) RefreshToken(token, refreshToken string, tokenType auth.JWTType, newClaims jwt.MapClaims) ([]byte, error) {
return []byte{}, nil
}
-func (c *JWTMockClient) ExtractClaims(tokenString string, tokenType auth.JWTType) (jwt.MapClaims, *errors.Error) {
+func (c *JWTMockClient) ExtractClaims(tokenString string, tokenType auth.JWTType) (jwt.MapClaims, error) {
return jwt.MapClaims{}, nil
}
-func (c *JWTMockClient) ParseToken(tokenString string, tokenType auth.JWTType) (*jwt.Token, *errors.Error) {
+func (c *JWTMockClient) ParseToken(tokenString string, tokenType auth.JWTType) (*jwt.Token, error) {
return &jwt.Token{}, nil
}
-func (c *JWTMockClient) IsTokenValid(tokenString string, tokenType auth.JWTType) (bool, *errors.Error) {
+func (c *JWTMockClient) IsTokenValid(tokenString string, tokenType auth.JWTType) (bool, error) {
return true, nil
}
diff --git a/backend/tests/api/mocks/openai_mock.go b/backend/tests/api/mocks/openai_mock.go
index 74919925e..cef61a620 100644
--- a/backend/tests/api/mocks/openai_mock.go
+++ b/backend/tests/api/mocks/openai_mock.go
@@ -1,7 +1,6 @@
package mocks
import (
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/integrations/search"
)
@@ -11,10 +10,10 @@ func NewOpenAIMockClient() search.AIClientInterface {
return &OpenAIMockClient{}
}
-func (c *OpenAIMockClient) CreateEmbedding(items []search.Searchable) ([]search.Embedding, *errors.Error) {
+func (c *OpenAIMockClient) CreateEmbedding(items []search.Searchable) ([]search.Embedding, error) {
return []search.Embedding{}, nil
}
-func (c *OpenAIMockClient) CreateModeration(items []search.Searchable) ([]search.ModerationResult, *errors.Error) {
+func (c *OpenAIMockClient) CreateModeration(items []search.Searchable) ([]search.ModerationResult, error) {
return []search.ModerationResult{}, nil
}
diff --git a/backend/tests/api/mocks/pinecone_mock.go b/backend/tests/api/mocks/pinecone_mock.go
index ab6dfa661..36e3dddf1 100644
--- a/backend/tests/api/mocks/pinecone_mock.go
+++ b/backend/tests/api/mocks/pinecone_mock.go
@@ -1,7 +1,6 @@
package mocks
import (
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/integrations/search"
"gorm.io/gorm"
)
@@ -13,18 +12,18 @@ func NewPineconeMockClient() search.SearchClientInterface {
return &PineconeMockClient{}
}
-func (c *PineconeMockClient) Upsert(items []search.Searchable) *errors.Error {
+func (c *PineconeMockClient) Upsert(items []search.Searchable) error {
return nil
}
-func (c *PineconeMockClient) Delete(items []search.Searchable) *errors.Error {
+func (c *PineconeMockClient) Delete(items []search.Searchable) error {
return nil
}
-func (c *PineconeMockClient) Search(item search.Searchable) ([]string, *errors.Error) {
+func (c *PineconeMockClient) Search(item search.Searchable) ([]string, error) {
return []string{}, nil
}
-func (c *PineconeMockClient) Seed(db *gorm.DB) *errors.Error {
+func (c *PineconeMockClient) Seed(db *gorm.DB) error {
return nil
}
diff --git a/backend/tests/api/mocks/resend_mock.go b/backend/tests/api/mocks/resend_mock.go
index ce165e4dc..3482cb382 100644
--- a/backend/tests/api/mocks/resend_mock.go
+++ b/backend/tests/api/mocks/resend_mock.go
@@ -1,7 +1,6 @@
package mocks
import (
- "github.com/GenerateNU/sac/backend/errors"
"github.com/GenerateNU/sac/backend/integrations/email"
)
@@ -11,18 +10,18 @@ func NewResendMockClient() email.EmailClientInterface {
return &ResendMockClient{}
}
-func (c *ResendMockClient) SendPasswordResetEmail(name, email, token string) *errors.Error {
+func (c *ResendMockClient) SendPasswordResetEmail(name, email, token string) error {
return nil
}
-func (c *ResendMockClient) SendEmailVerification(email, code string) *errors.Error {
+func (c *ResendMockClient) SendEmailVerification(email, code string) error {
return nil
}
-func (c *ResendMockClient) SendWelcomeEmail(name, email string) *errors.Error {
+func (c *ResendMockClient) SendWelcomeEmail(name, email string) error {
return nil
}
-func (c *ResendMockClient) SendPasswordChangedEmail(name, email string) *errors.Error {
+func (c *ResendMockClient) SendPasswordChangedEmail(name, email string) error {
return nil
}
diff --git a/backend/tests/api/tag_test.go b/backend/tests/api/tag_test.go
deleted file mode 100644
index f2c29fd35..000000000
--- a/backend/tests/api/tag_test.go
+++ /dev/null
@@ -1,389 +0,0 @@
-package tests
-
-import (
- "fmt"
- "net/http"
- "testing"
-
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
- h "github.com/GenerateNU/sac/backend/tests/api/helpers"
- "github.com/gofiber/fiber/v2"
- "github.com/google/uuid"
-
- "github.com/goccy/go-json"
-)
-
-func SampleTagFactory(categoryID uuid.UUID) *map[string]interface{} {
- return &map[string]interface{}{
- "name": "Generate",
- "category_id": categoryID,
- }
-}
-
-func AssertTagWithBodyRespDB(eaa h.ExistingAppAssert, resp *http.Response, body *map[string]interface{}) uuid.UUID {
- var respTag models.Tag
-
- err := json.NewDecoder(resp.Body).Decode(&respTag)
-
- eaa.Assert.NilError(err)
-
- var dbTag models.Tag
-
- err = eaa.App.Conn.First(&dbTag).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(dbTag.ID, respTag.ID)
- eaa.Assert.Equal(dbTag.Name, respTag.Name)
- eaa.Assert.Equal(dbTag.CategoryID, respTag.CategoryID)
-
- eaa.Assert.Equal((*body)["name"].(string), dbTag.Name)
- eaa.Assert.Equal((*body)["category_id"].(uuid.UUID), dbTag.CategoryID)
-
- return dbTag.ID
-}
-
-func AssertSampleTagBodyRespDB(t *testing.T, eaa h.ExistingAppAssert, resp *http.Response) uuid.UUID {
- appAssert, uuid := CreateSampleCategory(eaa)
- return AssertTagWithBodyRespDB(appAssert, resp, SampleTagFactory(uuid))
-}
-
-func CreateSampleTag(appAssert h.ExistingAppAssert) (existingAppAssert h.ExistingAppAssert, categoryUUID uuid.UUID, tagUUID uuid.UUID) {
- appAssert, categoryUUID = CreateSampleCategory(appAssert)
-
- AssertSampleTagBodyRespDB := func(eaa h.ExistingAppAssert, resp *http.Response) {
- tagUUID = AssertTagWithBodyRespDB(appAssert, resp, SampleTagFactory(categoryUUID))
- }
-
- appAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/tags/",
- Body: SampleTagFactory(categoryUUID),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusCreated,
- Tester: AssertSampleTagBodyRespDB,
- },
- )
-
- return appAssert, categoryUUID, tagUUID
-}
-
-func TestCreateTagWorks(t *testing.T) {
- appAssert, _, _ := CreateSampleTag(h.InitTest(t))
- appAssert.Close()
-}
-
-func AssertNumTagsRemainsAtN(eaa h.ExistingAppAssert, resp *http.Response, n int) {
- var tags []models.Tag
-
- err := eaa.App.Conn.Find(&tags).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(n, len(tags))
-}
-
-func AssertNoTags(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertNumTagsRemainsAtN(eaa, resp, 0)
-}
-
-func Assert1Tag(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertNumTagsRemainsAtN(eaa, resp, 1)
-}
-
-func TestCreateTagFailsBadRequest(t *testing.T) {
- appAssert := h.InitTest(t)
-
- badBodys := []map[string]interface{}{
- {
- "name": "Generate",
- "category_id": "1",
- },
- {
- "name": 1,
- "category_id": 1,
- },
- }
-
- for _, badBody := range badBodys {
- badBody := badBody
- appAssert = appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/tags/",
- Body: &badBody,
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.FailedToParseRequestBody,
- Tester: AssertNoTags,
- },
- )
- }
-
- appAssert.Close()
-}
-
-func TestCreateTagFailsValidation(t *testing.T) {
- appAssert := h.InitTest(t)
-
- badBodys := []map[string]interface{}{
- {
- "name": "Generate",
- },
- {
- "category_id": uuid.New(),
- },
- {},
- }
-
- for _, badBody := range badBodys {
- badBody := badBody
- appAssert = appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/tags/",
- Body: &badBody,
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.FailedToValidateTag,
- Tester: AssertNoTags,
- },
- )
- }
-
- appAssert.Close()
-}
-
-func TestGetTagWorks(t *testing.T) {
- existingAppAssert, categoryUUID, tagUUID := CreateSampleTag(h.InitTest(t))
-
- existingAppAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/tags/%s", tagUUID),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertTagWithBodyRespDB(eaa, resp, SampleTagFactory(categoryUUID))
- },
- },
- ).Close()
-}
-
-func TestGetTagFailsBadRequest(t *testing.T) {
- appAssert := h.InitTest(t)
-
- badRequests := []string{
- "0",
- "-1",
- "1.1",
- "foo",
- "null",
- }
-
- for _, badRequest := range badRequests {
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/tags/%s", badRequest),
- Role: &models.Super,
- },
- errors.FailedToValidateID,
- )
- }
-
- appAssert.Close()
-}
-
-func TestGetTagFailsNotFound(t *testing.T) {
- h.InitTest(t).TestOnError(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/tags/%s", uuid.New()),
- Role: &models.Super,
- },
- errors.TagNotFound,
- ).Close()
-}
-
-func TestUpdateTagWorksUpdateName(t *testing.T) {
- existingAppAssert, categoryUUID, tagUUID := CreateSampleTag(h.InitTest(t))
-
- generateNUTag := *SampleTagFactory(categoryUUID)
- generateNUTag["name"] = "GenerateNU"
-
- AssertUpdatedTagBodyRespDB := func(eaa h.ExistingAppAssert, resp *http.Response) {
- tagUUID = AssertTagWithBodyRespDB(eaa, resp, &generateNUTag)
- }
-
- existingAppAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPatch,
- Path: fmt.Sprintf("/api/v1/tags/%s", tagUUID),
- Body: &generateNUTag,
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: AssertUpdatedTagBodyRespDB,
- },
- ).Close()
-}
-
-func TestUpdateTagWorksUpdateCategory(t *testing.T) {
- existingAppAssert, _, tagUUID := CreateSampleTag(h.InitTest(t))
-
- technologyCategory := *SampleCategoryFactory()
- technologyCategory["name"] = "Technology"
-
- var technologyCategoryUUID uuid.UUID
-
- AssertNewCategoryBodyRespDB := func(eaa h.ExistingAppAssert, resp *http.Response) {
- technologyCategoryUUID = AssertCategoryWithBodyRespDBMostRecent(eaa, resp, &technologyCategory)
- }
-
- existingAppAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/categories/",
- Body: &technologyCategory,
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusCreated,
- Tester: AssertNewCategoryBodyRespDB,
- },
- )
-
- technologyTag := *SampleTagFactory(technologyCategoryUUID)
-
- AssertUpdatedTagBodyRespDB := func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertTagWithBodyRespDB(eaa, resp, &technologyTag)
- }
-
- existingAppAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPatch,
- Path: fmt.Sprintf("/api/v1/tags/%s", tagUUID),
- Body: &technologyTag,
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: AssertUpdatedTagBodyRespDB,
- },
- ).Close()
-}
-
-func TestUpdateTagWorksWithSameDetails(t *testing.T) {
- existingAppAssert, categoryUUID, tagUUID := CreateSampleTag(h.InitTest(t))
-
- existingAppAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPatch,
- Path: fmt.Sprintf("/api/v1/tags/%s", tagUUID),
- Body: SampleTagFactory(categoryUUID),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertTagWithBodyRespDB(eaa, resp, SampleTagFactory(categoryUUID))
- },
- },
- ).Close()
-}
-
-func TestUpdateTagFailsBadRequest(t *testing.T) {
- appAssert, uuid := CreateSampleCategory(h.InitTest(t))
-
- badRequests := []string{
- "0",
- "-1",
- "1.1",
- "foo",
- "null",
- }
-
- for _, badRequest := range badRequests {
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodPatch,
- Path: fmt.Sprintf("/api/v1/tags/%s", badRequest),
- Body: SampleTagFactory(uuid),
- Role: &models.Super,
- },
- errors.FailedToValidateID,
- )
- }
-
- appAssert.Close()
-}
-
-func TestDeleteTagWorks(t *testing.T) {
- existingAppAssert, _, tagUUID := CreateSampleTag(h.InitTest(t))
-
- existingAppAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/tags/%s", tagUUID),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusNoContent,
- Tester: AssertNoTags,
- },
- ).Close()
-}
-
-func TestDeleteTagFailsBadRequest(t *testing.T) {
- appAssert, _, _ := CreateSampleTag(h.InitTest(t))
-
- badRequests := []string{
- "0",
- "-1",
- "1.1",
- "foo",
- "null",
- }
-
- for _, badRequest := range badRequests {
- appAssert = appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/tags/%s", badRequest),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.FailedToValidateID,
- Tester: Assert1Tag,
- },
- )
- }
-
- appAssert.Close()
-}
-
-func TestDeleteTagFailsNotFound(t *testing.T) {
- appAssert, _, _ := CreateSampleTag(h.InitTest(t))
-
- appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/tags/%s", uuid.New()),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.TagNotFound,
- Tester: Assert1Tag,
- },
- ).Close()
-}
diff --git a/backend/tests/api/user_follower_test.go b/backend/tests/api/user_follower_test.go
deleted file mode 100644
index e860f2ed4..000000000
--- a/backend/tests/api/user_follower_test.go
+++ /dev/null
@@ -1,298 +0,0 @@
-package tests
-
-import (
- "fmt"
- "net/http"
- "testing"
-
- "github.com/goccy/go-json"
-
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
- h "github.com/GenerateNU/sac/backend/tests/api/helpers"
- "github.com/gofiber/fiber/v2"
- "github.com/google/uuid"
-)
-
-func TestCreateFollowingWorks(t *testing.T) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
- appAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/users/:userID/follower/%s", clubUUID),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.TesterWithStatus{
- Status: fiber.StatusCreated,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var user models.User
-
- err := eaa.App.Conn.Where("id = ?", eaa.App.TestUser.UUID).Preload("Follower").First(&user)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(2, len(user.Follower))
-
- eaa.Assert.Equal(clubUUID, user.Follower[1].ID)
-
- var club models.Club
-
- err = eaa.App.Conn.Where("id = ?", clubUUID).Preload("Follower").First(&club)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(1, len(club.Follower))
-
- eaa.Assert.Equal(eaa.App.TestUser.UUID, club.Follower[0].ID)
- },
- },
- ).Close()
-}
-
-func TestCreateFollowingFailsClubIdNotExists(t *testing.T) {
- appAssert, _, _ := CreateSampleClub(h.InitTest(t))
-
- uuid := uuid.New()
-
- appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/users/:userID/follower/%s", uuid),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.ErrorWithTester{
- Error: errors.ClubNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var club models.Club
-
- err := eaa.App.Conn.Where("id = ?", uuid).First(&club).Error
-
- eaa.Assert.Assert(err != nil)
- },
- },
- ).Close()
-}
-
-func TestCreateFollowingFailsUserIdNotExists(t *testing.T) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
- uuid := uuid.New()
-
- appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/users/%s/follower/%s", uuid, clubUUID),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.UserNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var user models.User
-
- err := eaa.App.Conn.Where("id = ?", uuid).First(&user).Error
-
- eaa.Assert.Assert(err != nil)
- },
- },
- ).Close()
-}
-
-func TestDeleteFollowingWorks(t *testing.T) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
- appAssert.TestOnStatus(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/users/:userID/follower/%s", clubUUID),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- fiber.StatusCreated,
- ).TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/users/:userID/follower/%s", clubUUID),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.TesterWithStatus{
- Status: fiber.StatusNoContent,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var user models.User
-
- err := eaa.App.Conn.Where("id = ?", eaa.App.TestUser.UUID).Preload("Follower").First(&user)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(1, len(user.Follower))
-
- var club models.Club
-
- err = eaa.App.Conn.Where("id = ?", clubUUID).Preload("Follower").First(&club)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(0, len(club.Follower))
- },
- },
- ).Close()
-}
-
-// TODO: test can't work because you become a follower when you create a club
-// func TestDeleteFollwerNotFollower(t *testing.T) {
-// appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
-// userClubsFollowerBefore, err := transactions.GetClubFollowing(appAssert.App.Conn, appAssert.App.TestUser.UUID)
-
-// appAssert.Assert.Assert(err == nil)
-
-// clubUsersFollowerBefore, err := transactions.GetClubFollowers(appAssert.App.Conn, clubUUID, 10, 0)
-
-// appAssert.Assert.Assert(err == nil)
-
-// appAssert.TestOnErrorAndTester(
-// h.TestRequest{
-// Method: fiber.MethodDelete,
-// Path: fmt.Sprintf("/api/v1/users/:userID/follower/%s", clubUUID),
-// Role: &models.Super,
-// TestUserIDReplaces: h.StringToPointer(":userID"),
-// },
-// h.ErrorWithTester{
-// Error: errors.UserNotFollowingClub,
-// Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
-// var user models.User
-
-// err := eaa.App.Conn.Where("id = ?", eaa.App.TestUser.UUID).Preload("Follower").First(&user)
-
-// eaa.Assert.NilError(err)
-
-// eaa.Assert.Equal(userClubsFollowerBefore, user.Follower)
-
-// var club models.Club
-
-// err = eaa.App.Conn.Where("id = ?", clubUUID).Preload("Follower").First(&club)
-
-// eaa.Assert.NilError(err)
-
-// eaa.Assert.Equal(clubUsersFollowerBefore, club.Follower)
-// },
-// },
-// ).Close()
-// }
-
-func TestDeleteFollowingFailsClubIdNotExists(t *testing.T) {
- appAssert, _, _ := CreateSampleClub(h.InitTest(t))
-
- uuid := uuid.New()
-
- appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/users/:userID/follower/%s", uuid),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.ErrorWithTester{
- Error: errors.ClubNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var club models.Club
-
- err := eaa.App.Conn.Where("id = ?", uuid).First(&club).Error
-
- eaa.Assert.Assert(err != nil)
- },
- },
- ).Close()
-}
-
-func TestDeleteFollowingFailsUserIdNotExists(t *testing.T) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
- uuid := uuid.New()
-
- appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/users/%s/follower/%s", uuid, clubUUID),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.UserNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var user models.User
-
- err := eaa.App.Conn.Where("id = ?", uuid).First(&user).Error
-
- eaa.Assert.Assert(err != nil)
- },
- },
- ).Close()
-}
-
-func TestGetFollowingWorks(t *testing.T) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
- appAssert.TestOnStatus(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/users/:userID/follower/%s", clubUUID),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- fiber.StatusCreated,
- ).TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: "/api/v1/users/:userID/follower",
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var clubs []models.Club
-
- err := json.NewDecoder(resp.Body).Decode(&clubs)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(2, len(clubs))
-
- var dbClubs []models.Club
-
- err = eaa.App.Conn.Where("id = ?", clubUUID).Preload("Follower").First(&dbClubs).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(2, len(clubs))
- },
- },
- ).Close()
-}
-
-func TestGetFollowingFailsUserIdNotExists(t *testing.T) {
- appAssert, _, _ := CreateSampleClub(h.InitTest(t))
-
- uuid := uuid.New()
-
- appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/users/%s/follower", uuid),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.UserNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var user models.User
-
- err := eaa.App.Conn.Where("id = ?", uuid).First(&user).Error
-
- eaa.Assert.Assert(err != nil)
- },
- },
- ).Close()
-}
diff --git a/backend/tests/api/user_member_test.go b/backend/tests/api/user_member_test.go
deleted file mode 100644
index 14a1d2180..000000000
--- a/backend/tests/api/user_member_test.go
+++ /dev/null
@@ -1,298 +0,0 @@
-package tests
-
-import (
- "fmt"
- "net/http"
- "testing"
-
- "github.com/goccy/go-json"
-
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
- h "github.com/GenerateNU/sac/backend/tests/api/helpers"
- "github.com/gofiber/fiber/v2"
- "github.com/google/uuid"
-)
-
-func TestCreateMembershipWorks(t *testing.T) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
- appAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/users/:userID/member/%s", clubUUID),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.TesterWithStatus{
- Status: fiber.StatusCreated,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var user models.User
-
- err := eaa.App.Conn.Where("id = ?", eaa.App.TestUser.UUID).Preload("Member").First(&user)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(2, len(user.Member)) // SAC Super Club and the one just added
-
- eaa.Assert.Equal(clubUUID, user.Member[1].ID) // second club AKA the one just added
-
- var club models.Club
-
- err = eaa.App.Conn.Where("id = ?", clubUUID).Preload("Member").First(&club)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(1, len(club.Member))
-
- eaa.Assert.Equal(eaa.App.TestUser.UUID, club.Member[0].ID)
- },
- },
- ).Close()
-}
-
-func TestCreateMembershipFailsClubIdNotExists(t *testing.T) {
- appAssert, _, _ := CreateSampleClub(h.InitTest(t))
-
- uuid := uuid.New()
-
- appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/users/:userID/member/%s", uuid),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.ErrorWithTester{
- Error: errors.ClubNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var club models.Club
-
- err := eaa.App.Conn.Where("id = ?", uuid).First(&club).Error
-
- eaa.Assert.Assert(err != nil)
- },
- },
- ).Close()
-}
-
-func TestCreateMembershipFailsUserIdNotExists(t *testing.T) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
- uuid := uuid.New()
-
- appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/users/%s/member/%s", uuid, clubUUID),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.UserNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var user models.User
-
- err := eaa.App.Conn.Where("id = ?", uuid).First(&user).Error
-
- eaa.Assert.Assert(err != nil)
- },
- },
- ).Close()
-}
-
-func TestDeleteMembershipWorks(t *testing.T) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
- appAssert.TestOnStatus(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/users/:userID/member/%s", clubUUID),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- fiber.StatusCreated,
- ).TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/users/:userID/member/%s", clubUUID),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.TesterWithStatus{
- Status: fiber.StatusNoContent,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var user models.User
-
- err := eaa.App.Conn.Where("id = ?", eaa.App.TestUser.UUID).Preload("Member").First(&user)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(1, len(user.Member)) // SAC Super Club
-
- var club models.Club
-
- err = eaa.App.Conn.Where("id = ?", clubUUID).Preload("Member").First(&club)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(0, len(club.Member))
- },
- },
- ).Close()
-}
-
-// TODO: test can't work because you become a member when you create a club
-// func TestDeleteMembershipNotMembership(t *testing.T) {
-// appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
-// userClubsMemberBefore, err := transactions.GetClubMembership(appAssert.App.Conn, appAssert.App.TestUser.UUID)
-
-// appAssert.Assert.Assert(err == nil)
-
-// clubUsersMemberBefore, err := transactions.GetClubMembers(appAssert.App.Conn, clubUUID, 10, 0)
-
-// appAssert.Assert.Assert(err == nil)
-
-// appAssert.TestOnErrorAndTester(
-// h.TestRequest{
-// Method: fiber.MethodDelete,
-// Path: fmt.Sprintf("/api/v1/users/:userID/member/%s", clubUUID),
-// Role: &models.Super,
-// TestUserIDReplaces: h.StringToPointer(":userID"),
-// },
-// h.ErrorWithTester{
-// Error: errors.UserNotMemberOfClub,
-// Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
-// var user models.User
-
-// err := eaa.App.Conn.Where("id = ?", eaa.App.TestUser.UUID).Preload("Member").First(&user)
-
-// eaa.Assert.NilError(err)
-
-// eaa.Assert.Equal(userClubsMemberBefore, user.Member)
-
-// var club models.Club
-
-// err = eaa.App.Conn.Where("id = ?", clubUUID).Preload("Member").First(&club)
-
-// eaa.Assert.NilError(err)
-
-// eaa.Assert.Equal(clubUsersMemberBefore, club.Member)
-// },
-// },
-// ).Close()
-// }
-
-func TestDeleteMembershipFailsClubIdNotExists(t *testing.T) {
- appAssert, _, _ := CreateSampleClub(h.InitTest(t))
-
- uuid := uuid.New()
-
- appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/users/:userID/member/%s", uuid),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.ErrorWithTester{
- Error: errors.ClubNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var club models.Club
-
- err := eaa.App.Conn.Where("id = ?", uuid).First(&club).Error
-
- eaa.Assert.Assert(err != nil)
- },
- },
- ).Close()
-}
-
-func TestDeleteMembershipFailsUserIdNotExists(t *testing.T) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
- uuid := uuid.New()
-
- appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/users/%s/member/%s", uuid, clubUUID),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.UserNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var user models.User
-
- err := eaa.App.Conn.Where("id = ?", uuid).First(&user).Error
-
- eaa.Assert.Assert(err != nil)
- },
- },
- ).Close()
-}
-
-func TestGetMembershipWorks(t *testing.T) {
- appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t))
-
- appAssert.TestOnStatus(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/users/:userID/member/%s", clubUUID),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- fiber.StatusCreated,
- ).TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: "/api/v1/users/:userID/member",
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var clubs []models.Club
-
- err := json.NewDecoder(resp.Body).Decode(&clubs)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(2, len(clubs)) // SAC Super Club and the one just added
-
- var dbClubs []models.Club
-
- err = eaa.App.Conn.Where("id = ?", clubUUID).Preload("Member").First(&dbClubs).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(2, len(clubs)) // SAC Super Club and the one just added
- },
- },
- ).Close()
-}
-
-func TestGetMembershipFailsUserIdNotExists(t *testing.T) {
- appAssert, _, _ := CreateSampleClub(h.InitTest(t))
-
- uuid := uuid.New()
-
- appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/users/%s/member", uuid),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.UserNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var user models.User
-
- err := eaa.App.Conn.Where("id = ?", uuid).First(&user).Error
-
- eaa.Assert.Assert(err != nil)
- },
- },
- ).Close()
-}
diff --git a/backend/tests/api/user_tag_test.go b/backend/tests/api/user_tag_test.go
deleted file mode 100644
index 923659cd4..000000000
--- a/backend/tests/api/user_tag_test.go
+++ /dev/null
@@ -1,572 +0,0 @@
-package tests
-
-import (
- "fmt"
- "net/http"
- "testing"
-
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/entities/users/tag"
- "github.com/GenerateNU/sac/backend/errors"
- h "github.com/GenerateNU/sac/backend/tests/api/helpers"
- "github.com/goccy/go-json"
- "github.com/gofiber/fiber/v2"
- "github.com/google/uuid"
-)
-
-func SampleCategoriesFactory() *[]map[string]interface{} {
- return &[]map[string]interface{}{
- {
- "name": "Business",
- },
- {
- "name": "STEM",
- },
- }
-}
-
-func SampleTagsFactory(categoryIDs []uuid.UUID) *[]map[string]interface{} {
- lenOfIDs := len(categoryIDs)
-
- return &[]map[string]interface{}{
- {
- "name": "Computer Science",
- "category_id": categoryIDs[1%lenOfIDs],
- },
- {
- "name": "Mechanical Engineering",
- "category_id": categoryIDs[1%lenOfIDs],
- },
- {
- "name": "Finance",
- "category_id": categoryIDs[0%lenOfIDs],
- },
- }
-}
-
-func SampleTagIDsFactory(tagIDs *[]uuid.UUID) *map[string]interface{} {
- tags := tagIDs
-
- if tags == nil {
- tags = &[]uuid.UUID{uuid.New()}
- }
-
- return &map[string]interface{}{
- "tags": tags,
- }
-}
-
-func CreateSetOfTags(appAssert h.ExistingAppAssert) ([]uuid.UUID, h.ExistingAppAssert) {
- categories := SampleCategoriesFactory()
-
- categoryIDs := []uuid.UUID{}
- for _, category := range *categories {
- category := category
- appAssert = appAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/categories/",
- Body: &category,
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusCreated,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var respCategory models.Category
-
- err := json.NewDecoder(resp.Body).Decode(&respCategory)
-
- eaa.Assert.NilError(err)
-
- categoryIDs = append(categoryIDs, respCategory.ID)
- },
- },
- )
- }
-
- tags := SampleTagsFactory(categoryIDs)
-
- tagIDs := []uuid.UUID{}
- for _, tag := range *tags {
- tag := tag
- appAssert = appAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/tags/",
- Body: &tag,
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusCreated,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var respTag models.Tag
-
- err := json.NewDecoder(resp.Body).Decode(&respTag)
-
- eaa.Assert.NilError(err)
-
- tagIDs = append(tagIDs, respTag.ID)
- },
- },
- )
- }
-
- return tagIDs, appAssert
-}
-
-func AssertUserTagsRespDB(eaa h.ExistingAppAssert, resp *http.Response, id uuid.UUID) {
- var respTags []models.Tag
-
- err := json.NewDecoder(resp.Body).Decode(&respTags)
-
- eaa.Assert.NilError(err)
-
- var dbUser models.User
-
- err = eaa.App.Conn.First(&dbUser, id).Error
-
- eaa.Assert.NilError(err)
-
- var dbTags []models.Tag
- err = eaa.App.Conn.Model(&dbUser).Association("Tag").Find(&dbTags)
-
- eaa.Assert.NilError(err)
-
- for i, respTag := range respTags {
- eaa.Assert.Equal(respTag.ID, dbTags[i].ID)
- eaa.Assert.Equal(respTag.Name, dbTags[i].Name)
- eaa.Assert.Equal(respTag.CategoryID, dbTags[i].CategoryID)
- }
-}
-
-func AssertSampleUserTagsRespDB(eaa h.ExistingAppAssert, resp *http.Response, uuid uuid.UUID) {
- AssertUserTagsRespDB(eaa, resp, uuid)
-}
-
-func TestCreateUserTagsFailsOnInvalidDataType(t *testing.T) {
- appAssert := h.InitTest(t)
-
- invalidTags := []interface{}{
- []string{"1", "2", "34"},
- []models.Tag{{Name: "Test", CategoryID: uuid.UUID{}}, {Name: "Test2", CategoryID: uuid.UUID{}}},
- []float32{1.32, 23.5, 35.1},
- }
-
- for _, tag := range invalidTags {
- malformedTag := *SampleTagIDsFactory(nil)
- malformedTag["tags"] = tag
-
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/users/:userID/tags/",
- Body: &malformedTag,
- Role: &models.Student,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- errors.FailedToParseRequestBody,
- )
- }
-
- appAssert.Close()
-}
-
-func TestCreateUserTagsFailsOnInvalidUserID(t *testing.T) {
- appAssert := h.InitTest(t)
-
- badRequests := []string{
- "0",
- "-1",
- "1.1",
- "foo",
- "null",
- }
-
- for _, badRequest := range badRequests {
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/users/%s/tags", badRequest),
- Body: SampleTagIDsFactory(nil),
- Role: &models.Student,
- },
- errors.FailedToValidateID,
- )
- }
-
- appAssert.Close()
-}
-
-type UUIDSlice []uuid.UUID
-
-func TestCreateUserTagsFailsOnInvalidKey(t *testing.T) {
- appAssert := h.InitTest(t)
-
- invalidBody := []map[string]interface{}{
- {
- "tag": UUIDSlice{uuid.New(), uuid.New()},
- },
- {
- "tagIDs": []uint{1, 2, 3},
- },
- }
-
- for _, body := range invalidBody {
- body := body
-
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/users/:userID/tags/",
- Body: &body,
- Role: &models.Student,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- errors.FailedToValidateUserTags,
- )
- }
-
- appAssert.Close()
-}
-
-func TestCreateUserTagsFailsOnNonExistentUser(t *testing.T) {
- uuid := uuid.New()
-
- h.InitTest(t).TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: fmt.Sprintf("/api/v1/users/%s/tags/", uuid),
- Body: SampleTagIDsFactory(nil),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.UserNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var dbUser models.User
- err := eaa.App.Conn.First(&dbUser, uuid).Error
-
- eaa.Assert.Assert(err != nil)
- },
- },
- ).Close()
-}
-
-func TestCreateUserTagsWorks(t *testing.T) {
- tagUUIDs, appAssert := CreateSetOfTags(h.InitTest(t))
-
- appAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/users/:userID/tags/",
- Body: SampleTagIDsFactory(&tagUUIDs),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.TesterWithStatus{
- Status: fiber.StatusCreated,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertSampleUserTagsRespDB(eaa, resp, eaa.App.TestUser.UUID)
- },
- },
- )
-
- appAssert.Close()
-}
-
-func TestCreateUserTagsNoneAddedIfInvalid(t *testing.T) {
- h.InitTest(t).TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/users/:userID/tags/",
- Body: SampleTagIDsFactory(nil),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.TesterWithStatus{
- Status: fiber.StatusCreated,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var respTags []models.Tag
-
- err := json.NewDecoder(resp.Body).Decode(&respTags)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(len(respTags), 0)
- },
- },
- ).Close()
-}
-
-func TestGetUserTagsFailsOnNonExistentUser(t *testing.T) {
- uuid := uuid.New()
-
- h.InitTest(t).TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/users/%s/tags/", uuid),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.UserNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var dbUser models.User
-
- err := eaa.App.Conn.First(&dbUser, uuid).Error
-
- eaa.Assert.Assert(err != nil)
- },
- },
- ).Close()
-}
-
-func TestGetUserTagsReturnsEmptyListWhenNoneAdded(t *testing.T) {
- h.InitTest(t).TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: "/api/v1/users/:userID/tags/",
- Role: &models.Student,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var respTags []models.Tag
-
- err := json.NewDecoder(resp.Body).Decode(&respTags)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(len(respTags), 0)
- },
- },
- ).Close()
-}
-
-func TestGetUserTagsReturnsCorrectList(t *testing.T) {
- tagUUIDs, appAssert := CreateSetOfTags(h.InitTest(t))
-
- appAssert.TestOnStatus(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/users/:userID/tags/",
- Body: SampleTagIDsFactory(&tagUUIDs),
- Role: &models.Student,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- fiber.StatusCreated,
- ).TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: "/api/v1/users/:userID/tags/",
- Role: &models.Student,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertSampleUserTagsRespDB(eaa, resp, eaa.App.TestUser.UUID)
- },
- },
- ).Close()
-}
-
-func TestDeleteUserTagFailsOnNonExistentUser(t *testing.T) {
- userID := uuid.New()
- tagID := uuid.New()
-
- h.InitTest(t).TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/users/%s/tags/%s/", userID, tagID),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.UserNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var dbUser models.User
-
- err := eaa.App.Conn.First(&dbUser, userID).Error
-
- eaa.Assert.Assert(err != nil)
- },
- },
- ).Close()
-}
-
-func TestDeleteUserTagFailsOnNonExistentTag(t *testing.T) {
- tagID := uuid.New()
-
- h.InitTest(t).TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/users/:userID/tags/%s/", tagID),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.ErrorWithTester{
- Error: errors.TagNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var dbTag models.Tag
-
- err := eaa.App.Conn.First(&dbTag, tagID).Error
- eaa.Assert.Assert(err != nil)
- },
- },
- ).Close()
-}
-
-func TestDeleteUserTagFailsOnInvalidUserUUID(t *testing.T) {
- appAssert := h.InitTest(t)
-
- badUserUUIDs := []string{
- "0",
- "-1",
- "1.1",
- "foo",
- "null",
- }
-
- for _, badUserUUID := range badUserUUIDs {
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/users/%s/tags/%s/", badUserUUID, uuid.New()),
- Role: &models.Super,
- },
- errors.FailedToValidateID,
- )
- }
-
- appAssert.Close()
-}
-
-func TestDeleteUserTagFailsOnInvalidTagUUID(t *testing.T) {
- appAssert := h.InitTest(t)
-
- badTagUUIDs := []string{
- "0",
- "-1",
- "1.1",
- "foo",
- "null",
- }
-
- for _, badTagUUID := range badTagUUIDs {
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/users/:userID/tags/%s/", badTagUUID),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- errors.FailedToValidateID,
- )
- }
-
- appAssert.Close()
-}
-
-func TestDeleteUserTagDoesNotAlterTagListOnNonAssociation(t *testing.T) {
- tagUUIDs, appAssert := CreateSetOfTags(h.InitTest(t))
- appAssert.Assert.Assert(len(tagUUIDs) > 1)
-
- // Tag to be queried:
- tagID := tagUUIDs[0]
-
- // Tags to be added to the user:
- tagUUIDs = tagUUIDs[1:]
-
- appAssert.TestOnStatus(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/users/:userID/tags/",
- Body: SampleTagIDsFactory(&tagUUIDs),
- Role: &models.Student,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- fiber.StatusCreated,
- )
-
- userTagsBeforeDeletion, err := tag.GetUserTags(appAssert.App.Conn, appAssert.App.TestUser.UUID)
- appAssert.Assert.NilError(&err)
-
- appAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/users/:userID/tags/%s/", tagID),
- Role: &models.Super,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.TesterWithStatus{
- Status: fiber.StatusNoContent,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var dbUser models.User
-
- err := eaa.App.Conn.Where("id = ?", appAssert.App.TestUser.UUID).Preload("Tag").First(&dbUser).Error
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(dbUser.Tag, userTagsBeforeDeletion)
- },
- },
- ).Close()
-}
-
-func TestDeleteUserTagRemovesTagFromUser(t *testing.T) {
- tagUUIDs, appAssert := CreateSetOfTags(h.InitTest(t))
- appAssert.Assert.Assert(len(tagUUIDs) > 1)
-
- tagID := tagUUIDs[0]
-
- appAssert.TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/users/:userID/tags/",
- Body: SampleTagIDsFactory(&tagUUIDs),
- Role: &models.Student,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.TesterWithStatus{
- Status: fiber.StatusCreated,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var dbUser models.User
-
- err := eaa.App.Conn.Where("id = ?", eaa.App.TestUser.UUID).Preload("Tag").First(&dbUser)
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(len(dbUser.Tag), len(tagUUIDs))
-
- var dbTag models.Tag
-
- err = eaa.App.Conn.Where("id = ?", tagID).Preload("User").First(&dbTag)
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(len(dbTag.User), 1)
- },
- },
- ).TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/users/:userID/tags/%s/", tagID),
- Role: &models.Student,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.TesterWithStatus{
- Status: fiber.StatusNoContent,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var dbUser models.User
-
- err := eaa.App.Conn.Where("id = ?", eaa.App.TestUser.UUID).Preload("Tag").First(&dbUser)
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(len(dbUser.Tag), len(tagUUIDs)-1)
-
- var dbTag models.Tag
-
- err = eaa.App.Conn.Where("id = ?", tagID).Preload("User").First(&dbTag)
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(len(dbTag.User), 0)
- },
- },
- )
-}
diff --git a/backend/tests/api/user_test.go b/backend/tests/api/user_test.go
deleted file mode 100644
index 1179dc64b..000000000
--- a/backend/tests/api/user_test.go
+++ /dev/null
@@ -1,589 +0,0 @@
-package tests
-
-import (
- "fmt"
- "net/http"
- "testing"
-
- stdliberrors "errors"
-
- "github.com/GenerateNU/sac/backend/auth"
- "github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/entities/users"
- usersBase "github.com/GenerateNU/sac/backend/entities/users/base"
- "github.com/GenerateNU/sac/backend/errors"
- h "github.com/GenerateNU/sac/backend/tests/api/helpers"
- "github.com/gofiber/fiber/v2"
- "github.com/google/uuid"
- "gorm.io/gorm"
-
- "github.com/goccy/go-json"
-)
-
-func TestGetUsersWorksForSuper(t *testing.T) {
- h.InitTest(t).TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: "/api/v1/users/",
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var users []models.User
-
- err := json.NewDecoder(resp.Body).Decode(&users)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(1, len(users))
-
- respUser := users[0]
-
- eaa.Assert.Equal("SAC", respUser.FirstName)
- eaa.Assert.Equal("Super", respUser.LastName)
- eaa.Assert.Equal("generatesac@gmail.com", respUser.Email)
- eaa.Assert.Equal(models.ComputerScience, respUser.Major0)
- eaa.Assert.Equal(models.Major(""), respUser.Major1)
- eaa.Assert.Equal(models.Major(""), respUser.Major2)
- eaa.Assert.Equal(models.KCCS, respUser.College)
- eaa.Assert.Equal(models.May, respUser.GraduationCycle)
- eaa.Assert.Equal(int16(2025), respUser.GraduationYear)
-
- dbUsers, err := usersBase.GetUsers(eaa.App.Conn, 1, 1)
-
- eaa.Assert.NilError(&err)
-
- eaa.Assert.Equal(1, len(dbUsers))
-
- dbUser := dbUsers[0]
-
- eaa.Assert.Equal(dbUser, respUser)
- },
- },
- ).Close()
-}
-
-func TestGetUsersFailsForStudent(t *testing.T) {
- h.InitTest(t).TestOnError(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: "/api/v1/users/",
- Role: &models.Student,
- },
- errors.Forbidden,
- ).Close()
-}
-
-func TestGetUserWorks(t *testing.T) {
- h.InitTest(t).TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: "/api/v1/users/:userID",
- Role: &models.Student,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var respUser models.User
-
- err := json.NewDecoder(resp.Body).Decode(&respUser)
-
- eaa.Assert.NilError(err)
-
- sampleStudent, rawPassword := h.SampleStudentFactory()
-
- sampleUser := *h.SampleStudentJSONFactory(sampleStudent, rawPassword)
-
- eaa.Assert.Equal(sampleUser["first_name"].(string), respUser.FirstName)
- eaa.Assert.Equal(sampleUser["last_name"].(string), respUser.LastName)
- eaa.Assert.Equal(sampleUser["email"].(string), respUser.Email)
- eaa.Assert.Equal(models.Major(sampleUser["major0"].(string)), respUser.Major0)
- eaa.Assert.Equal(models.Major(sampleUser["major1"].(string)), respUser.Major1)
- eaa.Assert.Equal(models.Major(sampleUser["major2"].(string)), respUser.Major2)
- eaa.Assert.Equal(models.College(sampleUser["college"].(string)), respUser.College)
- eaa.Assert.Equal(models.GraduationCycle(sampleUser["graduation_cycle"].(string)), respUser.GraduationCycle)
- eaa.Assert.Equal(int16(sampleUser["graduation_year"].(int)), respUser.GraduationYear)
-
- dbUser, err := users.GetUser(eaa.App.Conn, eaa.App.TestUser.UUID)
-
- eaa.Assert.NilError(&err)
-
- eaa.Assert.Equal(dbUser, &respUser)
- },
- },
- ).Close()
-}
-
-func TestGetUserFailsBadRequest(t *testing.T) {
- appAssert := h.InitTest(t)
-
- badRequests := []string{
- "0",
- "-1",
- "1.1",
- "foo",
- "null",
- }
-
- for _, badRequest := range badRequests {
- appAssert = appAssert.TestOnError(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/users/%s", badRequest),
- Role: &models.Super,
- },
- errors.FailedToValidateID,
- )
- }
-
- appAssert.Close()
-}
-
-func TestGetUserFailsNotExist(t *testing.T) {
- uuid := uuid.New()
-
- h.InitTest(t).TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodGet,
- Path: fmt.Sprintf("/api/v1/users/%s", uuid),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.UserNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var user models.User
-
- err := eaa.App.Conn.Where("id = ?", uuid).First(&user).Error
-
- eaa.Assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound))
- },
- },
- ).Close()
-}
-
-func TestUpdateUserWorks(t *testing.T) {
- newFirstName := "Michael"
- newLastName := "Brennan"
-
- h.InitTest(t).TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodPatch,
- Path: "/api/v1/users/:userID",
- Body: &map[string]interface{}{
- "first_name": newFirstName,
- "last_name": newLastName,
- },
- Role: &models.Student,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.TesterWithStatus{
- Status: fiber.StatusOK,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var respUser models.User
-
- err := json.NewDecoder(resp.Body).Decode(&respUser)
-
- eaa.Assert.NilError(err)
-
- sampleStudent, rawPassword := h.SampleStudentFactory()
-
- sampleStudentJSON := *h.SampleStudentJSONFactory(sampleStudent, rawPassword)
-
- eaa.Assert.Equal(newFirstName, respUser.FirstName)
- eaa.Assert.Equal(newLastName, respUser.LastName)
- eaa.Assert.Equal((sampleStudentJSON)["email"].(string), respUser.Email)
- eaa.Assert.Equal(models.Major((sampleStudentJSON)["major0"].(string)), respUser.Major0)
- eaa.Assert.Equal(models.Major((sampleStudentJSON)["major1"].(string)), respUser.Major1)
- eaa.Assert.Equal(models.Major((sampleStudentJSON)["major2"].(string)), respUser.Major2)
- eaa.Assert.Equal(models.College((sampleStudentJSON)["college"].(string)), respUser.College)
- eaa.Assert.Equal(models.GraduationCycle(sampleStudentJSON["graduation_cycle"].(string)), respUser.GraduationCycle)
- eaa.Assert.Equal(int16(sampleStudentJSON["graduation_year"].(int)), respUser.GraduationYear)
- var dbUser models.User
-
- err = eaa.App.Conn.First(&dbUser, eaa.App.TestUser.UUID).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(dbUser.FirstName, respUser.FirstName)
- eaa.Assert.Equal(dbUser.LastName, respUser.LastName)
- eaa.Assert.Equal(dbUser.Email, respUser.Email)
- eaa.Assert.Equal(dbUser.Major0, respUser.Major0)
- eaa.Assert.Equal(dbUser.Major1, respUser.Major1)
- eaa.Assert.Equal(dbUser.Major2, respUser.Major2)
- eaa.Assert.Equal(dbUser.College, respUser.College)
- eaa.Assert.Equal(dbUser.GraduationCycle, respUser.GraduationCycle)
- eaa.Assert.Equal(dbUser.GraduationYear, respUser.GraduationYear)
- },
- },
- ).Close()
-}
-
-func TestUpdateUserFailsOnInvalidBody(t *testing.T) {
- for _, invalidData := range []map[string]interface{}{
- {"email": "not.northeastern@gmail.com"},
- {"year": 1963},
- {"college": "UT-Austin"},
- } {
- invalidData := invalidData
-
- h.InitTest(t).TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPatch,
- Path: "/api/v1/users/:userID",
- Body: &invalidData,
- Role: &models.Student,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.ErrorWithTester{
- Error: errors.FailedToValidateUser,
- Tester: TestNumUsersRemainsAt2,
- },
- ).Close()
- }
-}
-
-func TestUpdateUserFailsBadRequest(t *testing.T) {
- badRequests := []string{
- "0",
- "-1",
- "1.1",
- "foo",
- "null",
- }
-
- sampleStudent, rawPassword := h.SampleStudentFactory()
- slightlyDifferentSampleStudentJSON := h.SampleStudentJSONFactory(sampleStudent, rawPassword)
- (*slightlyDifferentSampleStudentJSON)["first_name"] = "John"
-
- for _, badRequest := range badRequests {
- h.InitTest(t).TestOnError(h.TestRequest{
- Method: fiber.MethodPatch,
- Path: fmt.Sprintf("/api/v1/users/%s", badRequest),
- Body: slightlyDifferentSampleStudentJSON,
- Role: &models.Student,
- },
- errors.FailedToValidateID,
- ).Close()
- }
-}
-
-func TestUpdateUserFailsOnIdNotExist(t *testing.T) {
- uuid := uuid.New()
-
- sampleStudent, rawPassword := h.SampleStudentFactory()
-
- h.InitTest(t).TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPatch,
- Path: fmt.Sprintf("/api/v1/users/%s", uuid),
- Body: h.SampleStudentJSONFactory(sampleStudent, rawPassword),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.UserNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var user models.User
-
- err := eaa.App.Conn.Where("id = ?", uuid).First(&user).Error
-
- eaa.Assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound))
- },
- },
- ).Close()
-}
-
-func TestDeleteUserWorks(t *testing.T) {
- h.InitTest(t).TestOnStatusAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: "/api/v1/users/:userID",
- Role: &models.Student,
- TestUserIDReplaces: h.StringToPointer(":userID"),
- },
- h.TesterWithStatus{
- Status: fiber.StatusNoContent,
- Tester: TestNumUsersRemainsAt1,
- },
- ).Close()
-}
-
-func TestDeleteUserNotExist(t *testing.T) {
- uuid := uuid.New()
-
- h.InitTest(t).TestOnErrorAndTester(h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/users/%s", uuid),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.UserNotFound,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- var user models.User
-
- err := eaa.App.Conn.Where("id = ?", uuid).First(&user).Error
-
- eaa.Assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound))
-
- TestNumUsersRemainsAt1(eaa, resp)
- },
- },
- ).Close()
-}
-
-func TestDeleteUserBadRequest(t *testing.T) {
- appAssert := h.InitTest(t)
-
- badRequests := []string{
- "0",
- "-1",
- "1.1",
- "hello",
- "null",
- }
-
- for _, badRequest := range badRequests {
- appAssert = appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodDelete,
- Path: fmt.Sprintf("/api/v1/users/%s", badRequest),
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.FailedToValidateID,
- Tester: TestNumUsersRemainsAt1,
- },
- )
- }
-
- appAssert.Close()
-}
-
-func AssertUserWithIDBodyRespDB(eaa h.ExistingAppAssert, resp *http.Response, body *map[string]interface{}) uuid.UUID {
- var respUser models.User
-
- err := json.NewDecoder(resp.Body).Decode(&respUser)
-
- eaa.Assert.NilError(err)
-
- var dbUsers []models.User
-
- err = eaa.App.Conn.Find(&dbUsers).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(2, len(dbUsers))
-
- dbUser := dbUsers[1]
-
- eaa.Assert.Equal(dbUser.FirstName, respUser.FirstName)
- eaa.Assert.Equal(dbUser.LastName, respUser.LastName)
- eaa.Assert.Equal(dbUser.Email, respUser.Email)
- eaa.Assert.Equal(dbUser.Major0, respUser.Major0)
- eaa.Assert.Equal(dbUser.Major1, respUser.Major1)
- eaa.Assert.Equal(dbUser.Major2, respUser.Major2)
- eaa.Assert.Equal(dbUser.College, respUser.College)
- eaa.Assert.Equal(dbUser.GraduationCycle, respUser.GraduationCycle)
- eaa.Assert.Equal(dbUser.GraduationYear, respUser.GraduationYear)
-
- match, err := auth.CompareHash((*body)["password"].(string), dbUser.PasswordHash)
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Assert(match)
-
- eaa.Assert.Equal((*body)["first_name"].(string), dbUser.FirstName)
- eaa.Assert.Equal((*body)["last_name"].(string), dbUser.LastName)
- eaa.Assert.Equal((*body)["email"].(string), dbUser.Email)
- eaa.Assert.Equal(models.Major((*body)["major0"].(string)), dbUser.Major0)
- eaa.Assert.Equal(models.Major((*body)["major1"].(string)), dbUser.Major1)
- eaa.Assert.Equal(models.Major((*body)["major2"].(string)), dbUser.Major2)
- eaa.Assert.Equal(models.College((*body)["college"].(string)), dbUser.College)
- eaa.Assert.Equal(models.GraduationCycle((*body)["graduation_cycle"].(string)), dbUser.GraduationCycle)
- eaa.Assert.Equal(int16((*body)["graduation_year"].(int)), dbUser.GraduationYear)
-
- return dbUser.ID
-}
-
-func AssertSampleUserBodyRespDB(eaa h.ExistingAppAssert, resp *http.Response) uuid.UUID {
- sampleStudent, rawPassword := h.SampleStudentFactory()
-
- return AssertUserWithIDBodyRespDB(eaa, resp, h.SampleStudentJSONFactory(sampleStudent, rawPassword))
-}
-
-func CreateSampleStudent(t *testing.T, existingAppAssert *h.ExistingAppAssert) (h.ExistingAppAssert, uuid.UUID, *map[string]interface{}) {
- if existingAppAssert == nil {
- newAppAssert := h.InitTest(t)
- existingAppAssert = &newAppAssert
- }
-
- var uuid uuid.UUID
-
- sampleStudent, rawPassword := h.SampleStudentFactory()
-
- existingAppAssert.TestOnStatusAndTester(h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/users/",
- Body: h.SampleStudentJSONFactory(sampleStudent, rawPassword),
- Role: &models.Super,
- },
- h.TesterWithStatus{
- Status: fiber.StatusCreated,
- Tester: func(eaa h.ExistingAppAssert, resp *http.Response) {
- uuid = AssertSampleUserBodyRespDB(eaa, resp)
- },
- },
- )
-
- return *existingAppAssert, uuid, h.SampleStudentJSONFactory(sampleStudent, rawPassword)
-}
-
-func AssertNumUsersRemainsAtN(eaa h.ExistingAppAssert, resp *http.Response, n int) {
- var users []models.User
-
- err := eaa.App.Conn.Find(&users).Error
-
- eaa.Assert.NilError(err)
-
- eaa.Assert.Equal(n, len(users))
-}
-
-var TestNumUsersRemainsAt1 = func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertNumUsersRemainsAtN(eaa, resp, 1)
-}
-
-var TestNumUsersRemainsAt2 = func(eaa h.ExistingAppAssert, resp *http.Response) {
- AssertNumUsersRemainsAtN(eaa, resp, 2)
-}
-
-func TestCreateUserWorks(t *testing.T) {
- appAssert, _, _ := CreateSampleStudent(t, nil)
- appAssert.Close()
-}
-
-func TestCreateUserFailsIfUserWithEmailAlreadyExists(t *testing.T) {
- appAssert, studentUUID, body := CreateSampleStudent(t, nil)
-
- (*body)["id"] = studentUUID
-
- appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/users/",
- Body: body,
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.UserAlreadyExists,
- Tester: TestNumUsersRemainsAt2,
- },
- ).Close()
-}
-
-func AssertCreateBadDataFails(t *testing.T, jsonKey string, badValues []interface{}) {
- appAssert := h.InitTest(t)
-
- sampleStudent, rawPassword := h.SampleStudentFactory()
-
- for _, badValue := range badValues {
- sampleUserPermutation := *h.SampleStudentJSONFactory(sampleStudent, rawPassword)
- sampleUserPermutation[jsonKey] = badValue
-
- appAssert = appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/users/",
- Body: &sampleUserPermutation,
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.FailedToValidateUser,
- Tester: TestNumUsersRemainsAt1,
- },
- )
- }
-
- appAssert.Close()
-}
-
-func TestCreateUserFailsOnInvalidEmail(t *testing.T) {
- AssertCreateBadDataFails(t,
- "email",
- []interface{}{
- "doe.jane@northeastern",
- "doe.jane",
- "doe.jane@",
- "doe.jane@northeastern.",
- "doe.jane@northeastern.e",
- "",
- })
-}
-
-func TestCreateUserFailsOnInvalidPassword(t *testing.T) {
- appAssert := h.InitTest(t)
-
- sampleStudent, rawPassword := h.SampleStudentFactory()
-
- inputsWithDesiredErr := []struct {
- Password string
- Error errors.Error
- }{
- {"0", errors.InvalidPasswordNotLongEnough},
- {"foo", errors.InvalidPasswordNotLongEnough},
- {"abcdefgh", errors.InvalidPasswordNoDigit},
- {"abcdefg0", errors.InvalidPasswordNoSpecialCharacter},
- {"abcdefg@", errors.InvalidPasswordNoDigit},
- }
-
- for _, inputWithDesiredErr := range inputsWithDesiredErr {
- sampleUserPermutation := *h.SampleStudentJSONFactory(sampleStudent, rawPassword)
- sampleUserPermutation["password"] = inputWithDesiredErr.Password
-
- appAssert = appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/users/",
- Body: &sampleUserPermutation,
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: inputWithDesiredErr.Error,
- Tester: TestNumUsersRemainsAt1,
- },
- )
- }
-
- appAssert.Close()
-}
-
-func TestCreateUserFailsOnMissingFields(t *testing.T) {
- appAssert, _, _ := CreateSampleStudent(t, nil)
-
- sampleStudent, rawPassword := h.SampleStudentFactory()
-
- for _, missingField := range []string{
- "first_name",
- "last_name",
- "email",
- "password",
- } {
- sampleUserPermutation := *h.SampleStudentJSONFactory(sampleStudent, rawPassword)
- delete(sampleUserPermutation, missingField)
-
- appAssert = appAssert.TestOnErrorAndTester(
- h.TestRequest{
- Method: fiber.MethodPost,
- Path: "/api/v1/users/",
- Body: &sampleUserPermutation,
- Role: &models.Super,
- },
- h.ErrorWithTester{
- Error: errors.FailedToValidateUser,
- Tester: TestNumUsersRemainsAt2,
- },
- )
- }
-
- appAssert.Close()
-}
diff --git a/backend/tests/domain/recurrence_test.go b/backend/tests/domain/recurrence_test.go
new file mode 100644
index 000000000..a5584658e
--- /dev/null
+++ b/backend/tests/domain/recurrence_test.go
@@ -0,0 +1,95 @@
+package tests
+
+import (
+ "testing"
+ "time"
+
+ "github.com/GenerateNU/sac/backend/protos"
+)
+
+func TestRecurrenceUntilWeekly(t *testing.T) {
+ t.Parallel()
+
+ recurrence, err := protos.NewRecurrence(protos.Weekly, protos.Wednesday)
+ if err != nil {
+ t.Errorf("unexpected error: %v", err)
+ }
+
+ start := time.Date(2024, 1, 3, 6, 30, 0, 0, time.UTC)
+ end := time.Date(2024, 1, 3, 9, 0, 0, 0, time.UTC)
+ termination := time.Date(2024, 2, 1, 0, 0, 0, 0, time.UTC)
+
+ expected := []protos.Occurrence{
+ {Start: start, End: end},
+ {Start: time.Date(2024, 1, 10, 6, 30, 0, 0, time.UTC), End: time.Date(2024, 1, 10, 9, 0, 0, 0, time.UTC)},
+ {Start: time.Date(2024, 1, 17, 6, 30, 0, 0, time.UTC), End: time.Date(2024, 1, 17, 9, 0, 0, 0, time.UTC)},
+ {Start: time.Date(2024, 1, 24, 6, 30, 0, 0, time.UTC), End: time.Date(2024, 1, 24, 9, 0, 0, 0, time.UTC)},
+ {Start: time.Date(2024, 1, 31, 6, 30, 0, 0, time.UTC), End: time.Date(2024, 1, 31, 9, 0, 0, 0, time.UTC)},
+ }
+
+ validateOccurrences(t, recurrence, start, end, termination, expected)
+}
+
+func TestRecurrenceUntilBiweekly(t *testing.T) {
+ t.Parallel()
+
+ recurrence, err := protos.NewRecurrence(protos.Biweekly, protos.Wednesday)
+ if err != nil {
+ t.Errorf("unexpected error: %v", err)
+ }
+
+ start := time.Date(2024, 1, 3, 6, 30, 0, 0, time.UTC)
+ end := time.Date(2024, 1, 3, 9, 0, 0, 0, time.UTC)
+ termination := time.Date(2024, 3, 1, 0, 0, 0, 0, time.UTC)
+
+ expected := []protos.Occurrence{
+ {Start: start, End: end},
+ {Start: time.Date(2024, 1, 17, 6, 30, 0, 0, time.UTC), End: time.Date(2024, 1, 17, 9, 0, 0, 0, time.UTC)},
+ {Start: time.Date(2024, 1, 31, 6, 30, 0, 0, time.UTC), End: time.Date(2024, 1, 31, 9, 0, 0, 0, time.UTC)},
+ {Start: time.Date(2024, 2, 14, 6, 30, 0, 0, time.UTC), End: time.Date(2024, 2, 14, 9, 0, 0, 0, time.UTC)},
+ {Start: time.Date(2024, 2, 28, 6, 30, 0, 0, time.UTC), End: time.Date(2024, 2, 28, 9, 0, 0, 0, time.UTC)},
+ }
+
+ validateOccurrences(t, recurrence, start, end, termination, expected)
+}
+
+func TestRecurrenceUntilMonthly(t *testing.T) {
+ t.Parallel()
+
+ recurrence, err := protos.NewRecurrence(protos.Monthly, protos.Wednesday)
+ if err != nil {
+ t.Errorf("unexpected error: %v", err)
+ }
+
+ start := time.Date(2024, 1, 3, 6, 30, 0, 0, time.UTC)
+ end := time.Date(2024, 1, 3, 9, 0, 0, 0, time.UTC)
+ termination := time.Date(2024, 4, 1, 0, 0, 0, 0, time.UTC)
+
+ expected := []protos.Occurrence{
+ {Start: start, End: end},
+ {Start: time.Date(2024, 2, 3, 6, 30, 0, 0, time.UTC), End: time.Date(2024, 2, 3, 9, 0, 0, 0, time.UTC)},
+ {Start: time.Date(2024, 3, 3, 6, 30, 0, 0, time.UTC), End: time.Date(2024, 3, 3, 9, 0, 0, 0, time.UTC)},
+ }
+
+ validateOccurrences(t, recurrence, start, end, termination, expected)
+}
+
+func validateOccurrences(t *testing.T, recurrence *protos.Recurrence, start, end, termination time.Time, expected []protos.Occurrence) {
+ events, err := recurrence.ReccurUntil(start, end, termination)
+ if err != nil {
+ t.Errorf("unexpected error: %v", err)
+ }
+
+ if len(events) != len(expected) {
+ t.Errorf("expected %d events, got %d", len(expected), len(events))
+ }
+
+ for i, event := range events {
+ if event.Start != expected[i].Start {
+ t.Errorf("expected start time %v, got %v", expected[i].Start, event.Start)
+ }
+ if event.End != expected[i].End {
+ t.Errorf("expected end time %v, got %v", expected[i].End, event.End)
+ }
+ }
+}
diff --git a/backend/types/params.go b/backend/types/params.go
index 6144d6c35..47a65a348 100644
--- a/backend/types/params.go
+++ b/backend/types/params.go
@@ -4,22 +4,45 @@ import (
"github.com/GenerateNU/sac/backend/auth"
"github.com/GenerateNU/sac/backend/config"
"github.com/GenerateNU/sac/backend/integrations"
- "github.com/GenerateNU/sac/backend/middleware"
+ authMiddleware "github.com/GenerateNU/sac/backend/middleware/auth"
+ utilityMiddleware "github.com/GenerateNU/sac/backend/middleware/utility"
"github.com/go-playground/validator/v10"
"github.com/gofiber/fiber/v2"
"gorm.io/gorm"
)
type RouteParams struct {
- Router fiber.Router
- AuthMiddleware *middleware.AuthMiddlewareService
- ServiceParams ServiceParams
+ Router fiber.Router
+ AuthMiddleware *authMiddleware.AuthMiddlewareService
+ UtilityMiddleware *utilityMiddleware.UtilityMiddlewareService
+ ServiceParams ServiceParams
+}
+
+func NewRouteParams(router fiber.Router, authMiddleware *authMiddleware.AuthMiddlewareService, utilityMiddleware *utilityMiddleware.UtilityMiddlewareService, serviceParams ServiceParams) RouteParams {
+ return RouteParams{
+ Router: router,
+ AuthMiddleware: authMiddleware,
+ UtilityMiddleware: utilityMiddleware,
+ ServiceParams: serviceParams,
+ }
}
type ServiceParams struct {
DB *gorm.DB
Validate *validator.Validate
- AuthSettings *config.AuthSettings
+ Auth *config.AuthSettings
JWT auth.JWTClientInterface
+ Calendar *config.CalendarSettings
Integrations integrations.Integrations
}
+
+func NewServiceParams(db *gorm.DB, validate *validator.Validate, auth *config.AuthSettings, jwt auth.JWTClientInterface, calendar *config.CalendarSettings, integrations integrations.Integrations) ServiceParams {
+ return ServiceParams{
+ DB: db,
+ Validate: validate,
+ Auth: auth,
+ JWT: jwt,
+ Calendar: calendar,
+ Integrations: integrations,
+ }
+}
diff --git a/backend/utilities/api_error.go b/backend/utilities/api_error.go
new file mode 100644
index 000000000..7600ff9c3
--- /dev/null
+++ b/backend/utilities/api_error.go
@@ -0,0 +1,98 @@
+package utilities
+
+import (
+ "errors"
+ "fmt"
+ "log/slog"
+ "net/http"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+var (
+ ErrNotFound = errors.New("not found")
+ ErrDuplicate = errors.New("duplicate")
+ ErrExpectedPagination = errors.New("expected pagination. make sure to use the fiberpaginate middleware")
+)
+
+func IsNotFound(err error) bool {
+ return errors.Is(err, ErrNotFound)
+}
+
+func IsDuplicate(err error) bool {
+ return errors.Is(err, ErrDuplicate)
+}
+
+func IsExpectedPagination(err error) bool {
+ return errors.Is(err, ErrExpectedPagination)
+}
+
+type APIError struct {
+ StatusCode int `json:"statusCode"`
+ Message any `json:"msg"`
+}
+
+func (e APIError) Error() string {
+ return fmt.Sprintf("api error: %d", e.StatusCode)
+}
+
+func NewAPIError(statusCode int, err error) APIError {
+ return APIError{
+ StatusCode: statusCode,
+ Message: err.Error(),
+ }
+}
+
+func InvalidRequestData(errors map[string]string) APIError {
+ return APIError{
+ StatusCode: http.StatusUnprocessableEntity,
+ Message: errors,
+ }
+}
+
+func BadRequest(err error) APIError {
+ return NewAPIError(http.StatusBadRequest, err)
+}
+
+func InvalidJSON() APIError {
+ return NewAPIError(http.StatusBadRequest, fmt.Errorf("invalid JSON request data"))
+}
+
+func Unauthorized() APIError {
+ return NewAPIError(http.StatusUnauthorized, fmt.Errorf("unauthorized"))
+}
+
+func Forbidden() APIError {
+ return NewAPIError(http.StatusForbidden, fmt.Errorf("forbidden"))
+}
+
+func Conflict() APIError {
+ return NewAPIError(http.StatusConflict, fmt.Errorf("conflict"))
+}
+
+func InternalServerError() APIError {
+ return NewAPIError(http.StatusInternalServerError, fmt.Errorf("internal server error"))
+}
+
+func ErrorHandler(c *fiber.Ctx, err error) error {
+ var apiErr APIError
+
+ switch err {
+ case ErrNotFound:
+ apiErr = NewAPIError(http.StatusNotFound, err)
+ case ErrDuplicate:
+ apiErr = NewAPIError(http.StatusConflict, err)
+ case ErrExpectedPagination:
+ apiErr = NewAPIError(http.StatusInternalServerError, err)
+ default:
+ if castedErr, ok := err.(APIError); ok {
+ apiErr = castedErr
+ } else {
+ apiErr = InternalServerError()
+ }
+ }
+
+ slog.Error("HTTP API error", "err", err.Error(), "method", c.Method(), "path", c.Path())
+
+ return c.Status(apiErr.StatusCode).JSON(apiErr)
+}
diff --git a/backend/utilities/manipulator.go b/backend/utilities/manipulator.go
index ff0a1d791..9d37e0764 100644
--- a/backend/utilities/manipulator.go
+++ b/backend/utilities/manipulator.go
@@ -1,25 +1,36 @@
package utilities
import (
- "github.com/mitchellh/mapstructure"
+ "fmt"
+ "strings"
+
+ "github.com/go-viper/mapstructure/v2"
)
-// MapRequestToModel maps request data to a target model using mapstructure
-func MapRequestToModel[T any, U any](responseData T, targetModel *U) (*U, error) {
+// MapJsonTags maps request data to a target model using mapstructure
+// NOTE: this function does not correctly map time.Time fields from from to time.Time fields in intoType
+// see the following GitHub issues:
+// https://github.com/mitchellh/mapstructure/issues/334
+// https://github.com/go-viper/mapstructure/issues/20
+func MapJsonTags[From any, Into any](from From, intoType *Into) (*Into, error) {
config := &mapstructure.DecoderConfig{
- Result: targetModel,
+ Result: intoType,
TagName: "json",
}
decoder, err := mapstructure.NewDecoder(config)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("failed to create decoder: %w", err)
}
- err = decoder.Decode(responseData)
+ err = decoder.Decode(from)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("failed to decode data: %w", err)
}
- return targetModel, nil
+ return intoType, nil
+}
+
+func NormalizeEmail(email string) string {
+ return strings.ToLower(email)
}
diff --git a/backend/utilities/map.go b/backend/utilities/map.go
new file mode 100644
index 000000000..653cc6182
--- /dev/null
+++ b/backend/utilities/map.go
@@ -0,0 +1,15 @@
+package utilities
+
+// MergeMaps merges multiple maps into a single map.
+// The keys of maps earlier in the list will take precedence over keys in later maps.
+func MergeMaps[K comparable, V any](maps ...map[K]V) map[K]V {
+ merged := make(map[K]V)
+
+ for index := len(maps) - 1; index >= 0; index-- {
+ for k, v := range maps[index] {
+ merged[k] = v
+ }
+ }
+
+ return merged
+}
diff --git a/backend/utilities/maybe_error.go b/backend/utilities/maybe_error.go
new file mode 100644
index 000000000..a71fcce6b
--- /dev/null
+++ b/backend/utilities/maybe_error.go
@@ -0,0 +1,21 @@
+package utilities
+
+type MaybeError struct {
+ Name string
+ Err error
+}
+
+func NewMaybeError(name string, err error) *MaybeError {
+ return &MaybeError{
+ Name: name,
+ Err: err,
+ }
+}
+
+func (me *MaybeError) Unwrap() error {
+ return me.Err
+}
+
+func (me *MaybeError) IsError() bool {
+ return me.Err != nil
+}
diff --git a/backend/utilities/pagination.go b/backend/utilities/pagination.go
new file mode 100644
index 000000000..462d412db
--- /dev/null
+++ b/backend/utilities/pagination.go
@@ -0,0 +1,12 @@
+package utilities
+
+import (
+ "github.com/garrettladley/fiberpaginate"
+ "gorm.io/gorm"
+)
+
+func IntoScope(p fiberpaginate.PageInfo, db *gorm.DB) func(db *gorm.DB) *gorm.DB {
+ return func(db *gorm.DB) *gorm.DB {
+ return db.Offset(p.Start()).Limit(p.Limit)
+ }
+}
diff --git a/backend/utilities/string.go b/backend/utilities/string.go
new file mode 100644
index 000000000..4ac51703b
--- /dev/null
+++ b/backend/utilities/string.go
@@ -0,0 +1,20 @@
+package utilities
+
+import (
+ "strings"
+ "unicode"
+)
+
+func ToSnakeCase(s string) string {
+ var builder strings.Builder
+ builder.Grow(len(s) * 2) // Preallocate space for efficiency
+
+ for i, c := range s {
+ if i > 0 && unicode.IsUpper(c) {
+ builder.WriteRune('_')
+ }
+ builder.WriteRune(unicode.ToLower(c))
+ }
+
+ return builder.String()
+}
diff --git a/backend/utilities/validator.go b/backend/utilities/validator.go
index b4cb1b611..22edbf8a9 100644
--- a/backend/utilities/validator.go
+++ b/backend/utilities/validator.go
@@ -1,12 +1,11 @@
package utilities
import (
+ "fmt"
"reflect"
- "strconv"
"strings"
"github.com/GenerateNU/sac/backend/entities/models"
- "github.com/GenerateNU/sac/backend/errors"
"github.com/google/uuid"
"github.com/mcnijman/go-emailaddress"
@@ -60,7 +59,10 @@ func validateS3URL(fl validator.FieldLevel) bool {
}
func validateContactPointer(validate *validator.Validate, fl validator.FieldLevel) bool {
- contact, ok := fl.Parent().Interface().(models.PutContactRequestBody)
+ contact, ok := fl.Parent().Interface().(struct {
+ Type models.ContactType
+ Content string
+ })
if !ok {
return false
}
@@ -93,21 +95,48 @@ func validateNotEqualIfNotEmpty(fl validator.FieldLevel) bool {
return field == "" || field != otherField
}
-func ValidateID(id string) (*uuid.UUID, *errors.Error) {
+func ValidateID(id string) (*uuid.UUID, error) {
idAsUUID, err := uuid.Parse(id)
if err != nil {
- return nil, &errors.FailedToValidateID
+ return nil, err
}
return &idAsUUID, nil
}
-func ValidateNonNegative(value string) (*int, *errors.Error) {
- valueAsInt, err := strconv.Atoi(value)
+func Validate(validate *validator.Validate, s any, maybeErrs ...MaybeError) error {
+ hasErrors := false
+ var maybeErrors map[string]string
+
+ for _, maybeErr := range maybeErrs {
+ if maybeErr.Err != nil {
+ if !hasErrors {
+ maybeErrors = make(map[string]string)
+ hasErrors = true
+ }
+ maybeErrors[ToSnakeCase(maybeErr.Name)] = maybeErr.Err.Error()
+ }
+ }
+
+ var validationErrors map[string]string
+ if err := validate.Struct(s); err != nil {
+ validationErrs, ok := err.(validator.ValidationErrors)
+ if ok {
+ if !hasErrors {
+ validationErrors = make(map[string]string)
+ hasErrors = true
+ }
+ for _, validationErr := range validationErrs {
+ validationErrors[ToSnakeCase(validationErr.Field())] = fmt.Sprintf("%s failed %s", validationErr.Field(), validationErr.Tag())
+ }
+ } else {
+ return fmt.Errorf("failed to validate struct: %w", err)
+ }
+ }
- if err != nil || valueAsInt < 0 {
- return nil, &errors.FailedToValidateNonNegativeValue
+ if hasErrors {
+ return InvalidRequestData(MergeMaps(maybeErrors, validationErrors))
}
- return &valueAsInt, nil
+ return nil
}
diff --git a/cli/cmd/lint.go b/cli/cmd/lint.go
index b97d87078..c1115ce4f 100644
--- a/cli/cmd/lint.go
+++ b/cli/cmd/lint.go
@@ -102,7 +102,7 @@ var lintBackendCmd = &cobra.Command{
os.Exit(1)
}
- err = helpers.Execute(exec.Command("golangci-lint", "run", "--fix"), helpers.BACKEND_DIR)
+ err = helpers.Execute(exec.Command("golangci-lint", "run", "--fix", "--timeout=1m"), helpers.BACKEND_DIR)
if err != nil {
fmt.Println(err)
os.Exit(1)
@@ -122,7 +122,7 @@ var lintCliCmd = &cobra.Command{
os.Exit(1)
}
- err = helpers.Execute(exec.Command("golangci-lint", "run", "--fix"), helpers.CLI_DIR)
+ err = helpers.Execute(exec.Command("golangci-lint", "run", "--fix", "--timeout=1m"), helpers.CLI_DIR)
if err != nil {
fmt.Println(err)
os.Exit(1)
diff --git a/cli/cmd/pinecone.go b/cli/cmd/pinecone.go
new file mode 100644
index 000000000..768571e00
--- /dev/null
+++ b/cli/cmd/pinecone.go
@@ -0,0 +1,26 @@
+package cmd
+
+import (
+ "fmt"
+ "os"
+ "os/exec"
+
+ "github.com/GenerateNU/sac/cli/helpers"
+ "github.com/spf13/cobra"
+)
+
+var seedPineconeCmd = &cobra.Command{
+ Use: "seed-pinecone",
+ Short: "Seed Pinecone",
+ Run: func(cmd *cobra.Command, args []string) {
+ err := helpers.Execute(exec.Command("go", "run", "main.go", "seed-pinecone"), helpers.BACKEND_DIR)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ },
+}
+
+func init() {
+ rootCmd.AddCommand(seedPineconeCmd)
+}
diff --git a/cli/cmd/run.go b/cli/cmd/run.go
index a406a99b6..4a125873f 100644
--- a/cli/cmd/run.go
+++ b/cli/cmd/run.go
@@ -19,6 +19,9 @@ func init() {
rootCmd.AddCommand(runCmd)
runCmd.AddCommand(runFeCmd)
runCmd.AddCommand(runBeCmd)
+ runBeCmd.Flags().BoolP("migrate", "m", false, "Specify if you want to only perform the database migration")
+ runBeCmd.Flags().BoolP("seed-pinecone", "s", false, "Specify if you want to only perform the pinecone database seeding")
+ runBeCmd.Flags().BoolP("connect-to-pinecone", "c", false, "Connect to a real Pinecone instance instead of mock")
runFeCmd.AddCommand(runWebCmd)
runFeCmd.AddCommand(runMobileCmd)
@@ -34,10 +37,40 @@ var runBeCmd = &cobra.Command{
Aliases: []string{"be"},
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
- err := helpers.Execute(exec.Command("go", "run", "main.go"), helpers.BACKEND_DIR)
- if err != nil {
- fmt.Println(err)
- os.Exit(1)
+ migrate, _ := cmd.Flags().GetBool("migrate")
+ seedPinecone, _ := cmd.Flags().GetBool("seed-pinecone")
+ connectToPinecone, _ := cmd.Flags().GetBool("connect-to-pinecone")
+
+ if migrate {
+ err := helpers.Execute(exec.Command("go", "run", "main.go", "--only-migrate"), helpers.BACKEND_DIR)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ }
+
+ if seedPinecone {
+ err := helpers.Execute(exec.Command("go", "run", "main.go", "--seed-pinecone"), helpers.BACKEND_DIR)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ }
+
+ if connectToPinecone {
+ err := helpers.Execute(exec.Command("go", "run", "main.go", "--connect-to-pinecone"), helpers.BACKEND_DIR)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ }
+
+ if !migrate && !seedPinecone && !connectToPinecone {
+ err := helpers.Execute(exec.Command("go", "run", "main.go"), helpers.BACKEND_DIR)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
}
},
}
@@ -72,7 +105,13 @@ var runMobileCmd = &cobra.Command{
platform = "run:" + platform
- err := helpers.Execute(exec.Command("npx", "expo", platform), helpers.MOBILE_DIR)
+ output := exec.Command("npx", "expo", platform)
+ output.Dir = helpers.MOBILE_DIR
+ output.Stdout = os.Stdout
+ output.Stderr = os.Stderr
+ output.Stdin = os.Stdin
+
+ err := helpers.Execute(output, helpers.MOBILE_DIR)
if err != nil {
fmt.Println(err)
os.Exit(1)
diff --git a/cli/go.mod b/cli/go.mod
index 699160ebc..720759964 100644
--- a/cli/go.mod
+++ b/cli/go.mod
@@ -13,6 +13,7 @@ require (
github.com/awnumar/memguard v0.22.5 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/garrettladley/mattress v0.4.0 // indirect
+ github.com/google/go-cmp v0.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/joho/godotenv v1.5.1 // indirect
@@ -28,10 +29,11 @@ require (
github.com/spf13/viper v1.18.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
- golang.org/x/crypto v0.22.0 // indirect
+ golang.org/x/crypto v0.23.0 // indirect
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect
- golang.org/x/sys v0.19.0 // indirect
- golang.org/x/text v0.14.0 // indirect
+ golang.org/x/sys v0.20.0 // indirect
+ golang.org/x/text v0.15.0 // indirect
+ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/cli/go.sum b/cli/go.sum
index acccd3ded..b1cae943d 100644
--- a/cli/go.sum
+++ b/cli/go.sum
@@ -15,16 +15,19 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/garrettladley/mattress v0.4.0 h1:ZB3iqyc5q6bqIryNfsh2FMcbMdnV1XEryvqivouceQE=
github.com/garrettladley/mattress v0.4.0/go.mod h1:OWKIRc9wC3gtD3Ng/nUuNEiR1TJvRYLmn/KZYw9nl5Q=
-github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
-github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
@@ -70,18 +73,18 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
-golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
-golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
+golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8=
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
-golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/config/local.yml b/config/local.yml
index 8a88af9b2..2b1afe5fa 100644
--- a/config/local.yml
+++ b/config/local.yml
@@ -13,4 +13,6 @@ superuser:
password: Password#!1
auth:
accesskey: g(r|##*?>\Qp}h37e+,T2
- refreshkey: amk*2!gG}1i"8D9RwJS$p
\ No newline at end of file
+ refreshkey: amk*2!gG}1i"8D9RwJS$p
+calendar:
+ maxterminationdate: 12-31-2024
diff --git a/frontend/.gitignore b/frontend/.gitignore
deleted file mode 100644
index 2187e0dce..000000000
--- a/frontend/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-.expo/
\ No newline at end of file
diff --git a/frontend/dashboard/components.json b/frontend/dashboard/components.json
new file mode 100644
index 000000000..8c574b77e
--- /dev/null
+++ b/frontend/dashboard/components.json
@@ -0,0 +1,17 @@
+{
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "default",
+ "rsc": true,
+ "tsx": true,
+ "tailwind": {
+ "config": "tailwind.config.ts",
+ "css": "src/app/globals.css",
+ "baseColor": "slate",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "aliases": {
+ "components": "@/components",
+ "utils": "@/lib/utils"
+ }
+}
\ No newline at end of file
diff --git a/frontend/dashboard/lib/utils.ts b/frontend/dashboard/lib/utils.ts
new file mode 100644
index 000000000..d084ccade
--- /dev/null
+++ b/frontend/dashboard/lib/utils.ts
@@ -0,0 +1,6 @@
+import { type ClassValue, clsx } from "clsx"
+import { twMerge } from "tailwind-merge"
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs))
+}
diff --git a/frontend/dashboard/package.json b/frontend/dashboard/package.json
index f37b2d22e..a7cb2c850 100644
--- a/frontend/dashboard/package.json
+++ b/frontend/dashboard/package.json
@@ -8,30 +8,42 @@
"start": "next start",
"lint": "next lint",
"format": "prettier --write .",
- "test": "echo \"Woah there, we have no frontend tests as of right now. Let's just say we're passing.\" && exit 0"
+ "test": "jest"
},
"dependencies": {
- "@reduxjs/toolkit": "^2.2.3",
+ "@generatesac/lib": "^0.0.1",
+ "@radix-ui/react-slot": "^1.0.2",
+ "@reduxjs/toolkit": "^2.2.4",
+ "class-variance-authority": "^0.7.0",
+ "clsx": "^2.1.1",
+ "lucide-react": "^0.378.0",
"next": "14.2.3",
"react": "^18",
"react-dom": "^18",
"react-redux": "^9.1.1",
- "@sac/lib": "*",
- "zod": "^3.23.4"
+ "tailwind-merge": "^2.3.0",
+ "tailwindcss-animate": "^1.0.7",
+ "zod": "^3.23.8"
+ },
+ "jest": {
+ "preset": "ts-jest",
+ "testEnvironment": "node"
},
"devDependencies": {
+ "@trivago/prettier-plugin-sort-imports": "^4.3.0",
+ "@types/jest": "^29.5.12",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"autoprefixer": "^10.4.19",
"eslint": "^8",
"eslint-config-next": "14.2.3",
- "jest": "^29.2.1",
+ "eslint-plugin-prettier": "^5.1.3",
+ "jest": "^29.7.0",
"postcss": "^8",
+ "prettier": "^3.2.4",
"tailwindcss": "^3.4.1",
- "typescript": "^5",
- "@trivago/prettier-plugin-sort-imports": "^4.3.0",
- "eslint-plugin-prettier": "^5.1.3",
- "prettier": "^3.2.4"
+ "ts-jest": "^29.1.2",
+ "typescript": "5.4.5"
}
}
diff --git a/frontend/dashboard/src/app/globals.css b/frontend/dashboard/src/app/globals.css
index 875c01e81..b0e6fff59 100644
--- a/frontend/dashboard/src/app/globals.css
+++ b/frontend/dashboard/src/app/globals.css
@@ -1,33 +1,76 @@
@tailwind base;
-@tailwind components;
-@tailwind utilities;
-
-:root {
- --foreground-rgb: 0, 0, 0;
- --background-start-rgb: 214, 219, 220;
- --background-end-rgb: 255, 255, 255;
-}
-
-@media (prefers-color-scheme: dark) {
- :root {
- --foreground-rgb: 255, 255, 255;
- --background-start-rgb: 0, 0, 0;
- --background-end-rgb: 0, 0, 0;
- }
-}
-
-body {
- color: rgb(var(--foreground-rgb));
- background: linear-gradient(
- to bottom,
- transparent,
- rgb(var(--background-end-rgb))
- )
- rgb(var(--background-start-rgb));
-}
-
-@layer utilities {
- .text-balance {
- text-wrap: balance;
+ @tailwind components;
+ @tailwind utilities;
+
+ @layer base {
+ :root {
+ --background: 0 0% 100%;
+ --foreground: 222.2 84% 4.9%;
+
+ --card: 0 0% 100%;
+ --card-foreground: 222.2 84% 4.9%;
+
+ --popover: 0 0% 100%;
+ --popover-foreground: 222.2 84% 4.9%;
+
+ --primary: 222.2 47.4% 11.2%;
+ --primary-foreground: 210 40% 98%;
+
+ --secondary: 210 40% 96.1%;
+ --secondary-foreground: 222.2 47.4% 11.2%;
+
+ --muted: 210 40% 96.1%;
+ --muted-foreground: 215.4 16.3% 46.9%;
+
+ --accent: 210 40% 96.1%;
+ --accent-foreground: 222.2 47.4% 11.2%;
+
+ --destructive: 0 84.2% 60.2%;
+ --destructive-foreground: 210 40% 98%;
+
+ --border: 214.3 31.8% 91.4%;
+ --input: 214.3 31.8% 91.4%;
+ --ring: 222.2 84% 4.9%;
+
+ --radius: 0.5rem;
+ }
+
+ .dark {
+ --background: 222.2 84% 4.9%;
+ --foreground: 210 40% 98%;
+
+ --card: 222.2 84% 4.9%;
+ --card-foreground: 210 40% 98%;
+
+ --popover: 222.2 84% 4.9%;
+ --popover-foreground: 210 40% 98%;
+
+ --primary: 210 40% 98%;
+ --primary-foreground: 222.2 47.4% 11.2%;
+
+ --secondary: 217.2 32.6% 17.5%;
+ --secondary-foreground: 210 40% 98%;
+
+ --muted: 217.2 32.6% 17.5%;
+ --muted-foreground: 215 20.2% 65.1%;
+
+ --accent: 217.2 32.6% 17.5%;
+ --accent-foreground: 210 40% 98%;
+
+ --destructive: 0 62.8% 30.6%;
+ --destructive-foreground: 210 40% 98%;
+
+ --border: 217.2 32.6% 17.5%;
+ --input: 217.2 32.6% 17.5%;
+ --ring: 212.7 26.8% 83.9%;
+ }
}
-}
+
+ @layer base {
+ * {
+ @apply border-border;
+ }
+ body {
+ @apply bg-background text-foreground;
+ }
+ }
\ No newline at end of file
diff --git a/frontend/dashboard/src/app/layout.tsx b/frontend/dashboard/src/app/layout.tsx
index a8d3cca5b..f4e2e85de 100644
--- a/frontend/dashboard/src/app/layout.tsx
+++ b/frontend/dashboard/src/app/layout.tsx
@@ -1,9 +1,13 @@
import type { Metadata } from "next";
-import { Inter } from "next/font/google";
+import { Inter as FontSans } from "next/font/google"
import "./globals.css";
import StoreProvider from "../store/StoreProvider";
+import { cn } from "@/lib/utils"
-const inter = Inter({ subsets: ["latin"] });
+const fontSans = FontSans({
+ subsets: ["latin"],
+ variable: "--font-sans",
+})
export const metadata: Metadata = {
title: "Create Next App",
@@ -18,7 +22,12 @@ export default function RootLayout({
return (
- {children}
+ {children}
);
diff --git a/frontend/dashboard/src/app/page.tsx b/frontend/dashboard/src/app/page.tsx
index 3763448a3..c26fb593c 100644
--- a/frontend/dashboard/src/app/page.tsx
+++ b/frontend/dashboard/src/app/page.tsx
@@ -27,7 +27,6 @@ export default function Home() {
-
-
) {
+ return produce(state, draft => {
+ Object.assign(draft, action.payload);
+ });
+ },
+ updateClub(state, action: PayloadAction) {
+ return produce(state, draft => {
+ Object.assign(draft, action.payload);
+ });
+ },
+ resetClub() {
+ return initialState;
+ }
+ }
+})
+
+export const { setClub, updateClub, resetClub } = clubSlice.actions;
+export const clubReducer = clubSlice.reducer;
\ No newline at end of file
diff --git a/frontend/dashboard/src/app/state/recruitment/recruitmentSlice.ts b/frontend/dashboard/src/app/state/recruitment/recruitmentSlice.ts
new file mode 100644
index 000000000..c2fcce6f9
--- /dev/null
+++ b/frontend/dashboard/src/app/state/recruitment/recruitmentSlice.ts
@@ -0,0 +1,29 @@
+import { createSlice, PayloadAction } from '@reduxjs/toolkit';
+import { Recruitment, RecruitmentCycle } from '../../../types/recruitment';
+
+
+const initialState: Recruitment = {
+ recruitmentCycle: RecruitmentCycle.Always,
+ recruitmentType: [],
+ isRecruiting: false,
+ applications: []
+};
+
+const recruitmentSlice = createSlice({
+ name: 'recruitment',
+ initialState,
+ reducers: {
+ setRecruitment(_, action: PayloadAction) {
+ return action.payload;
+ },
+ updateRecruitment(state, action: PayloadAction>) {
+ return { ...state, ...action.payload };
+ },
+ resetRecruitment() {
+ return initialState;
+ }
+ }
+});
+
+export const { setRecruitment, updateRecruitment, resetRecruitment } = recruitmentSlice.actions;
+export const recruitmentReducer = recruitmentSlice.reducer;
\ No newline at end of file
diff --git a/frontend/dashboard/src/app/tests/clubState.test.ts b/frontend/dashboard/src/app/tests/clubState.test.ts
new file mode 100644
index 000000000..0a5e8fd24
--- /dev/null
+++ b/frontend/dashboard/src/app/tests/clubState.test.ts
@@ -0,0 +1,82 @@
+import { setClub, updateClub, resetClub, clubReducer } from '../state/club/clubSlice';
+import { Club, CreateClubRequestBody, UpdateClubRequestBody } from '../../types/club';
+
+describe('club slice', () => {
+ const initialState: Club = {
+ userId: '',
+ clubId: '',
+ clubName: '',
+ accessToken: '',
+ csrfToken: '',
+ preview: '',
+ description: '',
+ weeklyTimeCommitment: 0,
+ oneWordToDescribeUs: '',
+ logo: '',
+ }
+
+ it('set club', () => {
+ const club: CreateClubRequestBody = {
+ userId: '123',
+ name: 'Generate',
+ preview: 'preview',
+ description: 'description',
+ weeklyTimeCommitment: 10,
+ oneWordToDescribeUs: 'innovative',
+ logo: 'logo.png',
+ }
+
+ const action = setClub(club);
+ const nextState = clubReducer(initialState, action);
+ expect(nextState).toEqual({
+ ...initialState,
+ ...club
+ })
+ })
+
+ it('update club', () => {
+ const currentState: Club = {
+ userId: '123',
+ clubId: '456',
+ clubName: 'Generate Development Studio',
+ accessToken: 'token',
+ csrfToken: 'csrf',
+ preview: 'preview',
+ description: 'description',
+ weeklyTimeCommitment: 20,
+ oneWordToDescribeUs: 'daring',
+ logo: 'logo.png',
+ }
+
+ const updatedFields: UpdateClubRequestBody = {
+ preview: 'new preview',
+ weeklyTimeCommitment: 10,
+ }
+
+ const action = updateClub(updatedFields);
+ const nextState = clubReducer(currentState, action);
+ expect(nextState).toEqual({
+ ...currentState,
+ ...updatedFields,
+ })
+ })
+
+ it('reset club', () => {
+ const currentState: Club = {
+ userId: '123',
+ clubId: '456',
+ clubName: 'Generate Development Studio',
+ accessToken: 'token',
+ csrfToken: 'csrf',
+ preview: 'preview',
+ description: 'description',
+ weeklyTimeCommitment: 20,
+ oneWordToDescribeUs: 'daring',
+ logo: 'logo.png',
+ }
+
+ const action = resetClub();
+ const nextState = clubReducer(currentState, action);
+ expect(nextState).toEqual(initialState);
+ })
+})
\ No newline at end of file
diff --git a/frontend/dashboard/src/app/tests/recruitmentState.test.ts b/frontend/dashboard/src/app/tests/recruitmentState.test.ts
new file mode 100644
index 000000000..89c21ccaa
--- /dev/null
+++ b/frontend/dashboard/src/app/tests/recruitmentState.test.ts
@@ -0,0 +1,60 @@
+import { setRecruitment, updateRecruitment, resetRecruitment, recruitmentReducer } from '../state/recruitment/recruitmentSlice';
+import { Recruitment, RecruitmentCycle, RecruitmentType, UpdateRecruitmentRequestBody } from '../../types/recruitment';
+
+describe('recruitment slice', () => {
+ const initialState: Recruitment = {
+ recruitmentCycle: RecruitmentCycle.Always,
+ recruitmentType: [],
+ isRecruiting: false,
+ applications: []
+ }
+
+ it('set recruitment', () => {
+ const recruitment: Recruitment = {
+ recruitmentCycle: RecruitmentCycle.Spring,
+ recruitmentType: [RecruitmentType.Apply],
+ isRecruiting: true,
+ applications: []
+ }
+
+ const action = setRecruitment(recruitment);
+ const nextState = recruitmentReducer(initialState, action);
+ expect(nextState).toEqual({
+ ...initialState,
+ ...recruitment
+ });
+ })
+
+ it('update recruitment', () => {
+ const currentState: Recruitment = {
+ recruitmentCycle: RecruitmentCycle.Spring,
+ recruitmentType: [RecruitmentType.Apply],
+ isRecruiting: true,
+ applications: []
+ }
+
+ const updatedFields: UpdateRecruitmentRequestBody = {
+ isRecruiting: false,
+ }
+
+ const action = updateRecruitment(updatedFields);
+ const nextState = recruitmentReducer(currentState, action);
+ expect(nextState).toEqual({
+ ...currentState,
+ ...updatedFields,
+ })
+ })
+
+ it('reset recruitment', () => {
+ const currentState: Recruitment = {
+ recruitmentCycle: RecruitmentCycle.Spring,
+ recruitmentType: [RecruitmentType.Apply],
+ isRecruiting: true,
+ applications: []
+ }
+
+ const action = resetRecruitment();
+ const nextState = recruitmentReducer(currentState, action);
+ expect(nextState).toEqual(initialState);
+ });
+})
\ No newline at end of file
diff --git a/frontend/dashboard/src/store/StoreProvider.tsx b/frontend/dashboard/src/store/StoreProvider.tsx
index 429deb39e..4a0881f98 100644
--- a/frontend/dashboard/src/store/StoreProvider.tsx
+++ b/frontend/dashboard/src/store/StoreProvider.tsx
@@ -1,4 +1,4 @@
-"use client";
+'use client'
import { useRef } from "react";
import { AppStore, makeStore } from "./store";
@@ -6,17 +6,21 @@ import { Provider } from "react-redux";
type StoreProviderProps = {
children: React.ReactNode;
-};
+}
/**
* The Redux store provider component. This makes the store accessible globally across the repository
*/
export default function StoreProvider({ children }: StoreProviderProps) {
- const storeRef = useRef();
+ const storeRef = useRef();
- // Instantiate store singleton:
- if (!storeRef.current) {
- storeRef.current = makeStore();
- }
- return {children} ;
+ // Instantiate store singleton:
+ if (!storeRef.current) {
+ storeRef.current = makeStore()
+ }
+ return (
+
+ {children}
+
+ )
}
diff --git a/frontend/dashboard/src/store/store.ts b/frontend/dashboard/src/store/store.ts
index 6aa3d29ac..7e5a536ec 100644
--- a/frontend/dashboard/src/store/store.ts
+++ b/frontend/dashboard/src/store/store.ts
@@ -1,24 +1,28 @@
-import { configureStore } from "@reduxjs/toolkit";
-import { useDispatch, useSelector, useStore } from "react-redux";
-import { baseApi } from "@sac/lib";
+import { baseApi } from '@generatesac/lib';
+import { configureStore } from '@reduxjs/toolkit'
+import { useDispatch, useSelector, useStore } from 'react-redux';
+import { clubReducer } from '../app/state/club/clubSlice';
+import { recruitmentReducer } from '../app/state/recruitment/recruitmentSlice';
export const makeStore = () => {
return configureStore({
reducer: {
[baseApi.reducerPath]: baseApi.reducer,
+ clubReducer: clubReducer,
+ recruitmentReducer: recruitmentReducer,
},
-
middleware: (getDefaultMiddleware) =>
- getDefaultMiddleware().concat(baseApi.middleware),
- });
+ getDefaultMiddleware()
+ .concat(baseApi.middleware)
+ })
};
// Redux types:
-export type AppStore = ReturnType;
-export type RootState = ReturnType;
-export type AppDispatch = AppStore["dispatch"];
+export type AppStore = ReturnType
+export type RootState = ReturnType
+export type AppDispatch = AppStore['dispatch']
// Typed Redux interactive methods:
-export const useAppDispatch = useDispatch.withTypes();
-export const useAppSelector = useSelector.withTypes();
-export const useAppStore = useStore.withTypes();
+export const useAppDispatch = useDispatch.withTypes()
+export const useAppSelector = useSelector.withTypes()
+export const useAppStore = useStore.withTypes()
diff --git a/frontend/dashboard/src/types/application.ts b/frontend/dashboard/src/types/application.ts
new file mode 100644
index 000000000..50356a079
--- /dev/null
+++ b/frontend/dashboard/src/types/application.ts
@@ -0,0 +1,4 @@
+export type Application = {
+ applicationTitle: string
+ applicationLink: string
+}
\ No newline at end of file
diff --git a/frontend/dashboard/src/types/club.ts b/frontend/dashboard/src/types/club.ts
new file mode 100644
index 000000000..b1bb49503
--- /dev/null
+++ b/frontend/dashboard/src/types/club.ts
@@ -0,0 +1,31 @@
+export type Club = {
+ userId: string;
+ clubId: string;
+ parentId?: string;
+ clubName: string;
+ accessToken: string;
+ csrfToken: string;
+ preview: string;
+ description: string;
+ weeklyTimeCommitment: number;
+ oneWordToDescribeUs: string;
+ logo: string;
+}
+
+export interface CreateClubRequestBody {
+ userId: string;
+ name: string;
+ preview: string;
+ description: string;
+ weeklyTimeCommitment: number;
+ oneWordToDescribeUs: string;
+ logo: string;
+}
+
+export interface UpdateClubRequestBody {
+ preview?: string;
+ description?: string;
+ weeklyTimeCommitment?: number;
+ oneWordToDescribeUs?: string;
+ logo?: string;
+}
\ No newline at end of file
diff --git a/frontend/dashboard/src/types/recruitment.ts b/frontend/dashboard/src/types/recruitment.ts
new file mode 100644
index 000000000..9f7e72fc0
--- /dev/null
+++ b/frontend/dashboard/src/types/recruitment.ts
@@ -0,0 +1,29 @@
+import { Application } from "./application";
+
+export enum RecruitmentCycle {
+ Fall = 'fall',
+ FallSpring = 'fallSpring',
+ Spring = 'spring',
+ Always = 'always'
+}
+
+export enum RecruitmentType {
+ Unrestricted = 'unrestricted',
+ Tryout = 'tryout',
+ Apply = 'application'
+}
+
+export type Recruitment = {
+ recruitmentCycle: RecruitmentCycle;
+ recruitmentType: RecruitmentType[];
+ isRecruiting: boolean;
+ applications: Application[];
+}
+
+export type UpdateRecruitmentRequestBody = {
+ recruitmentCycle?: RecruitmentCycle;
+ recruitmentType?: RecruitmentType[];
+ isRecruiting?: boolean;
+ applications?: Application[];
+}
+
diff --git a/frontend/dashboard/tailwind.config.ts b/frontend/dashboard/tailwind.config.ts
index cf5ff5d99..d45370b06 100644
--- a/frontend/dashboard/tailwind.config.ts
+++ b/frontend/dashboard/tailwind.config.ts
@@ -1,20 +1,84 @@
-import type { Config } from "tailwindcss";
+import type { Config } from "tailwindcss"
+const { fontFamily } = require("tailwindcss/defaultTheme")
-const config: Config = {
+const config = {
+ darkMode: ["class"],
content: [
- "./pages/**/*.{js,ts,jsx,tsx,mdx}",
- "./components/**/*.{js,ts,jsx,tsx,mdx}",
- "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
- ],
+ './pages/**/*.{ts,tsx}',
+ './components/**/*.{ts,tsx}',
+ './app/**/*.{ts,tsx}',
+ './src/**/*.{ts,tsx}',
+ ],
+ prefix: "",
theme: {
+ container: {
+ center: true,
+ padding: "2rem",
+ screens: {
+ "2xl": "1400px",
+ },
+ },
extend: {
- backgroundImage: {
- "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
- "gradient-conic":
- "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
+ colors: {
+ border: "hsl(var(--border))",
+ input: "hsl(var(--input))",
+ ring: "hsl(var(--ring))",
+ background: "hsl(var(--background))",
+ foreground: "hsl(var(--foreground))",
+ primary: {
+ DEFAULT: "hsl(var(--primary))",
+ foreground: "hsl(var(--primary-foreground))",
+ },
+ secondary: {
+ DEFAULT: "hsl(var(--secondary))",
+ foreground: "hsl(var(--secondary-foreground))",
+ },
+ destructive: {
+ DEFAULT: "hsl(var(--destructive))",
+ foreground: "hsl(var(--destructive-foreground))",
+ },
+ muted: {
+ DEFAULT: "hsl(var(--muted))",
+ foreground: "hsl(var(--muted-foreground))",
+ },
+ accent: {
+ DEFAULT: "hsl(var(--accent))",
+ foreground: "hsl(var(--accent-foreground))",
+ },
+ popover: {
+ DEFAULT: "hsl(var(--popover))",
+ foreground: "hsl(var(--popover-foreground))",
+ },
+ card: {
+ DEFAULT: "hsl(var(--card))",
+ foreground: "hsl(var(--card-foreground))",
+ },
+ },
+ borderRadius: {
+ lg: "var(--radius)",
+ md: "calc(var(--radius) - 2px)",
+ sm: "calc(var(--radius) - 4px)",
+ },
+ keyframes: {
+ "accordion-down": {
+ from: { height: "0" },
+ to: { height: "var(--radix-accordion-content-height)" },
+ },
+ "accordion-up": {
+ from: { height: "var(--radix-accordion-content-height)" },
+ to: { height: "0" },
+ },
+ },
+ animation: {
+ "accordion-down": "accordion-down 0.2s ease-out",
+ "accordion-up": "accordion-up 0.2s ease-out",
+ },
+ fontFamily: {
+ sans: ["var(--font-sans)", ...fontFamily.sans],
},
},
},
- plugins: [],
-};
-export default config;
+ plugins: [require("tailwindcss-animate")],
+} satisfies Config
+
+export default config
\ No newline at end of file
diff --git a/frontend/dashboard/tsconfig.json b/frontend/dashboard/tsconfig.json
index e7ff90fd2..96c71f61c 100644
--- a/frontend/dashboard/tsconfig.json
+++ b/frontend/dashboard/tsconfig.json
@@ -1,6 +1,10 @@
{
"compilerOptions": {
- "lib": ["dom", "dom.iterable", "esnext"],
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
@@ -11,16 +15,25 @@
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
- "incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
- "@/*": ["./*"]
- }
+ "@/*": [
+ "./*"
+ ]
+ },
+ "incremental": true
},
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
- "exclude": ["node_modules"]
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx",
+ ".next/types/**/*.ts"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
}
diff --git a/frontend/dashboard/yarn.lock b/frontend/dashboard/yarn.lock
index bf1958b63..5845753cf 100644
--- a/frontend/dashboard/yarn.lock
+++ b/frontend/dashboard/yarn.lock
@@ -2,51 +2,101 @@
# yarn lockfile v1
-"@aashutoshrathi/word-wrap@^1.2.3":
- version "1.2.6"
- resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf"
- integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==
-
"@alloc/quick-lru@^5.2.0":
version "5.2.0"
- resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30"
+ resolved "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz"
integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
-"@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.5":
+"@ampproject/remapping@^2.2.0":
+ version "2.3.0"
+ resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz"
+ integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==
+ dependencies:
+ "@jridgewell/gen-mapping" "^0.3.5"
+ "@jridgewell/trace-mapping" "^0.3.24"
+
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.2":
version "7.24.2"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae"
+ resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz"
integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==
dependencies:
"@babel/highlight" "^7.24.2"
picocolors "^1.0.0"
+"@babel/compat-data@^7.23.5":
+ version "7.24.4"
+ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz"
+ integrity sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==
+
+"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9", "@babel/core@^7.8.0", "@babel/core@>=7.0.0-beta.0 <8":
+ version "7.24.5"
+ resolved "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz"
+ integrity sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==
+ dependencies:
+ "@ampproject/remapping" "^2.2.0"
+ "@babel/code-frame" "^7.24.2"
+ "@babel/generator" "^7.24.5"
+ "@babel/helper-compilation-targets" "^7.23.6"
+ "@babel/helper-module-transforms" "^7.24.5"
+ "@babel/helpers" "^7.24.5"
+ "@babel/parser" "^7.24.5"
+ "@babel/template" "^7.24.0"
+ "@babel/traverse" "^7.24.5"
+ "@babel/types" "^7.24.5"
+ convert-source-map "^2.0.0"
+ debug "^4.1.0"
+ gensync "^1.0.0-beta.2"
+ json5 "^2.2.3"
+ semver "^6.3.1"
+
+"@babel/generator@^7.23.0":
+ version "7.24.5"
+ resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz"
+ integrity sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==
+ dependencies:
+ "@babel/types" "^7.24.5"
+ "@jridgewell/gen-mapping" "^0.3.5"
+ "@jridgewell/trace-mapping" "^0.3.25"
+ jsesc "^2.5.1"
+
+"@babel/generator@^7.24.5", "@babel/generator@^7.7.2":
+ version "7.24.5"
+ resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz"
+ integrity sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==
+ dependencies:
+ "@babel/types" "^7.24.5"
+ "@jridgewell/gen-mapping" "^0.3.5"
+ "@jridgewell/trace-mapping" "^0.3.25"
+ jsesc "^2.5.1"
+
"@babel/generator@7.17.7":
version "7.17.7"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad"
+ resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz"
integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==
dependencies:
"@babel/types" "^7.17.0"
jsesc "^2.5.1"
source-map "^0.5.0"
-"@babel/generator@^7.23.0":
- version "7.24.4"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.4.tgz#1fc55532b88adf952025d5d2d1e71f946cb1c498"
- integrity sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==
+"@babel/helper-compilation-targets@^7.23.6":
+ version "7.23.6"
+ resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz"
+ integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==
dependencies:
- "@babel/types" "^7.24.0"
- "@jridgewell/gen-mapping" "^0.3.5"
- "@jridgewell/trace-mapping" "^0.3.25"
- jsesc "^2.5.1"
+ "@babel/compat-data" "^7.23.5"
+ "@babel/helper-validator-option" "^7.23.5"
+ browserslist "^4.22.2"
+ lru-cache "^5.1.1"
+ semver "^6.3.1"
"@babel/helper-environment-visitor@^7.22.20":
version "7.22.20"
- resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
+ resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz"
integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
"@babel/helper-function-name@^7.23.0":
version "7.23.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
+ resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz"
integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
dependencies:
"@babel/template" "^7.22.15"
@@ -54,62 +104,220 @@
"@babel/helper-hoist-variables@^7.22.5":
version "7.22.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
+ resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz"
integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
dependencies:
"@babel/types" "^7.22.5"
-"@babel/helper-split-export-declaration@^7.22.6":
- version "7.22.6"
- resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c"
- integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
+"@babel/helper-module-imports@^7.24.3":
+ version "7.24.3"
+ resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz"
+ integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==
dependencies:
- "@babel/types" "^7.22.5"
+ "@babel/types" "^7.24.0"
+
+"@babel/helper-module-transforms@^7.24.5":
+ version "7.24.5"
+ resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz"
+ integrity sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==
+ dependencies:
+ "@babel/helper-environment-visitor" "^7.22.20"
+ "@babel/helper-module-imports" "^7.24.3"
+ "@babel/helper-simple-access" "^7.24.5"
+ "@babel/helper-split-export-declaration" "^7.24.5"
+ "@babel/helper-validator-identifier" "^7.24.5"
+
+"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.8.0":
+ version "7.24.5"
+ resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz"
+ integrity sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==
+
+"@babel/helper-simple-access@^7.24.5":
+ version "7.24.5"
+ resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz"
+ integrity sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==
+ dependencies:
+ "@babel/types" "^7.24.5"
-"@babel/helper-string-parser@^7.23.4":
+"@babel/helper-split-export-declaration@^7.22.6", "@babel/helper-split-export-declaration@^7.24.5":
+ version "7.24.5"
+ resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz"
+ integrity sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==
+ dependencies:
+ "@babel/types" "^7.24.5"
+
+"@babel/helper-string-parser@^7.24.1":
version "7.24.1"
- resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e"
+ resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz"
integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==
-"@babel/helper-validator-identifier@^7.16.7", "@babel/helper-validator-identifier@^7.22.20":
- version "7.22.20"
- resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
- integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
+"@babel/helper-validator-identifier@^7.16.7", "@babel/helper-validator-identifier@^7.24.5":
+ version "7.24.5"
+ resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz"
+ integrity sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==
+
+"@babel/helper-validator-option@^7.23.5":
+ version "7.23.5"
+ resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz"
+ integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==
+
+"@babel/helpers@^7.24.5":
+ version "7.24.5"
+ resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz"
+ integrity sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==
+ dependencies:
+ "@babel/template" "^7.24.0"
+ "@babel/traverse" "^7.24.5"
+ "@babel/types" "^7.24.5"
"@babel/highlight@^7.24.2":
- version "7.24.2"
- resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.2.tgz#3f539503efc83d3c59080a10e6634306e0370d26"
- integrity sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==
+ version "7.24.5"
+ resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz"
+ integrity sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==
dependencies:
- "@babel/helper-validator-identifier" "^7.22.20"
+ "@babel/helper-validator-identifier" "^7.24.5"
chalk "^2.4.2"
js-tokens "^4.0.0"
picocolors "^1.0.0"
-"@babel/parser@^7.20.5", "@babel/parser@^7.23.0", "@babel/parser@^7.24.0":
- version "7.24.4"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.4.tgz#234487a110d89ad5a3ed4a8a566c36b9453e8c88"
- integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==
+"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.5", "@babel/parser@^7.20.7", "@babel/parser@^7.23.0", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.5":
+ version "7.24.5"
+ resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz"
+ integrity sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==
-"@babel/runtime@^7.23.2":
- version "7.24.4"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.4.tgz#de795accd698007a66ba44add6cc86542aff1edd"
- integrity sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==
+"@babel/plugin-syntax-async-generators@^7.8.4":
+ version "7.8.4"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz"
+ integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-bigint@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz"
+ integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-class-properties@^7.8.3":
+ version "7.12.13"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz"
+ integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.12.13"
+
+"@babel/plugin-syntax-import-meta@^7.8.3":
+ version "7.10.4"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz"
+ integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-syntax-json-strings@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz"
+ integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-jsx@^7.7.2":
+ version "7.24.1"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz"
+ integrity sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.24.0"
+
+"@babel/plugin-syntax-logical-assignment-operators@^7.8.3":
+ version "7.10.4"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz"
+ integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz"
+ integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-numeric-separator@^7.8.3":
+ version "7.10.4"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz"
+ integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-syntax-object-rest-spread@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz"
+ integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-optional-catch-binding@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz"
+ integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-optional-chaining@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz"
+ integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-top-level-await@^7.8.3":
+ version "7.14.5"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz"
+ integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.14.5"
+
+"@babel/plugin-syntax-typescript@^7.7.2":
+ version "7.24.1"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz"
+ integrity sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.24.0"
+
+"@babel/runtime@^7.13.10", "@babel/runtime@^7.20.13", "@babel/runtime@^7.23.2", "@babel/runtime@^7.24.1":
+ version "7.24.5"
+ resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz"
+ integrity sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==
dependencies:
regenerator-runtime "^0.14.0"
-"@babel/template@^7.22.15":
+"@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.3.3":
version "7.24.0"
- resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50"
+ resolved "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz"
integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==
dependencies:
"@babel/code-frame" "^7.23.5"
"@babel/parser" "^7.24.0"
"@babel/types" "^7.24.0"
+"@babel/traverse@^7.24.5":
+ version "7.24.5"
+ resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz"
+ integrity sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==
+ dependencies:
+ "@babel/code-frame" "^7.24.2"
+ "@babel/generator" "^7.24.5"
+ "@babel/helper-environment-visitor" "^7.22.20"
+ "@babel/helper-function-name" "^7.23.0"
+ "@babel/helper-hoist-variables" "^7.22.5"
+ "@babel/helper-split-export-declaration" "^7.24.5"
+ "@babel/parser" "^7.24.5"
+ "@babel/types" "^7.24.5"
+ debug "^4.3.1"
+ globals "^11.1.0"
+
"@babel/traverse@7.23.2":
version "7.23.2"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8"
+ resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz"
integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==
dependencies:
"@babel/code-frame" "^7.22.13"
@@ -123,38 +331,115 @@
debug "^4.1.0"
globals "^11.1.0"
+"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.24.5", "@babel/types@^7.3.3":
+ version "7.24.5"
+ resolved "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz"
+ integrity sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==
+ dependencies:
+ "@babel/helper-string-parser" "^7.24.1"
+ "@babel/helper-validator-identifier" "^7.24.5"
+ to-fast-properties "^2.0.0"
+
+"@babel/types@^7.17.0":
+ version "7.24.5"
+ resolved "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz"
+ integrity sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==
+ dependencies:
+ "@babel/helper-string-parser" "^7.24.1"
+ "@babel/helper-validator-identifier" "^7.24.5"
+ to-fast-properties "^2.0.0"
+
"@babel/types@7.17.0":
version "7.17.0"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b"
+ resolved "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz"
integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==
dependencies:
"@babel/helper-validator-identifier" "^7.16.7"
to-fast-properties "^2.0.0"
-"@babel/types@^7.17.0", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0":
- version "7.24.0"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.0.tgz#3b951f435a92e7333eba05b7566fd297960ea1bf"
- integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==
- dependencies:
- "@babel/helper-string-parser" "^7.23.4"
- "@babel/helper-validator-identifier" "^7.22.20"
- to-fast-properties "^2.0.0"
+"@bcoe/v8-coverage@^0.2.3":
+ version "0.2.3"
+ resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz"
+ integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
+
+"@blocknote/core@^0.12.4":
+ version "0.12.4"
+ resolved "https://registry.npmjs.org/@blocknote/core/-/core-0.12.4.tgz"
+ integrity sha512-njnrEZUZ7sPm0CIwxSfFfnP1IgB+H+Kvk5+2Etr3tozuQgwdQ0X6wn6E+MTCP97Nxl/aPA7S1F/XUoy1L8ICXQ==
+ dependencies:
+ "@tiptap/core" "^2.0.3"
+ "@tiptap/extension-bold" "^2.0.3"
+ "@tiptap/extension-code" "^2.0.3"
+ "@tiptap/extension-collaboration" "^2.0.3"
+ "@tiptap/extension-collaboration-cursor" "^2.0.3"
+ "@tiptap/extension-dropcursor" "^2.0.3"
+ "@tiptap/extension-gapcursor" "^2.0.3"
+ "@tiptap/extension-hard-break" "^2.0.3"
+ "@tiptap/extension-history" "^2.0.3"
+ "@tiptap/extension-horizontal-rule" "^2.0.3"
+ "@tiptap/extension-italic" "^2.0.3"
+ "@tiptap/extension-link" "^2.0.3"
+ "@tiptap/extension-paragraph" "^2.0.3"
+ "@tiptap/extension-strike" "^2.0.3"
+ "@tiptap/extension-table-cell" "^2.0.3"
+ "@tiptap/extension-table-header" "^2.0.3"
+ "@tiptap/extension-table-row" "^2.0.3"
+ "@tiptap/extension-text" "^2.0.3"
+ "@tiptap/extension-underline" "^2.0.3"
+ "@tiptap/pm" "^2.0.3"
+ hast-util-from-dom "^4.2.0"
+ prosemirror-model "^1.18.3"
+ prosemirror-state "^1.4.3"
+ prosemirror-tables "^1.3.4"
+ prosemirror-transform "^1.7.2"
+ prosemirror-view "^1.31.4"
+ rehype-format "^5.0.0"
+ rehype-parse "^8.0.4"
+ rehype-remark "^9.1.2"
+ rehype-stringify "^9.0.3"
+ remark-gfm "^3.0.1"
+ remark-parse "^10.0.1"
+ remark-rehype "^10.1.0"
+ remark-stringify "^10.0.2"
+ unified "^10.1.2"
+ uuid "^8.3.2"
+ y-prosemirror "1.2.1"
+ y-protocols "^1.0.5"
+ yjs "^13.6.1"
+
+"@blocknote/react@^0.12.4":
+ version "0.12.4"
+ resolved "https://registry.npmjs.org/@blocknote/react/-/react-0.12.4.tgz"
+ integrity sha512-cgtQmPUhRmWwHifskhfuwq7SflXTagilblzkfKmkvHYsldeH2WcOHGbgskX5bdx7ulvryrLnTSbXszLuTGd5Hw==
+ dependencies:
+ "@blocknote/core" "^0.12.4"
+ "@floating-ui/react" "^0.26.4"
+ "@mantine/core" "^7.7.1"
+ "@mantine/hooks" "^7.7.1"
+ "@mantine/utils" "^6.0.21"
+ "@tiptap/core" "^2.0.3"
+ "@tiptap/react" "^2.0.3"
+ lodash.merge "^4.6.2"
+ react "^18"
+ react-dom "^18.2.0"
+ react-icons "^4.3.1"
+ use-prefers-color-scheme "^1.1.3"
"@eslint-community/eslint-utils@^4.2.0":
version "4.4.0"
- resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
+ resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz"
integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
dependencies:
eslint-visitor-keys "^3.3.0"
"@eslint-community/regexpp@^4.6.1":
version "4.10.0"
- resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63"
+ resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz"
integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==
"@eslint/eslintrc@^2.1.4":
version "2.1.4"
- resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad"
+ resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz"
integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==
dependencies:
ajv "^6.12.4"
@@ -169,12 +454,63 @@
"@eslint/js@8.57.0":
version "8.57.0"
- resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f"
+ resolved "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz"
integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==
+"@floating-ui/core@^1.0.0":
+ version "1.6.1"
+ resolved "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.1.tgz"
+ integrity sha512-42UH54oPZHPdRHdw6BgoBD6cg/eVTmVrFcgeRDM3jbO7uxSoipVcmcIGFcA5jmOHO5apcyvBhkSKES3fQJnu7A==
+ dependencies:
+ "@floating-ui/utils" "^0.2.0"
+
+"@floating-ui/dom@^1.0.0":
+ version "1.6.5"
+ resolved "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.5.tgz"
+ integrity sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==
+ dependencies:
+ "@floating-ui/core" "^1.0.0"
+ "@floating-ui/utils" "^0.2.0"
+
+"@floating-ui/react-dom@^2.0.0":
+ version "2.0.9"
+ resolved "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.9.tgz"
+ integrity sha512-q0umO0+LQK4+p6aGyvzASqKbKOJcAHJ7ycE9CuUvfx3s9zTHWmGJTPOIlM/hmSBfUfg/XfY5YhLBLR/LHwShQQ==
+ dependencies:
+ "@floating-ui/dom" "^1.0.0"
+
+"@floating-ui/react@^0.26.4", "@floating-ui/react@^0.26.9":
+ version "0.26.13"
+ resolved "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.13.tgz"
+ integrity sha512-kBa9wntpugzrZ8t/4yWelvSmEKZdeTXTJzrxqyrLmcU/n1SM4nvse8yQh2e1b37rJGvtu0EplV9+IkBrCJ1vkw==
+ dependencies:
+ "@floating-ui/react-dom" "^2.0.0"
+ "@floating-ui/utils" "^0.2.0"
+ tabbable "^6.0.0"
+
+"@floating-ui/utils@^0.2.0":
+ version "0.2.2"
+ resolved "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz"
+ integrity sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==
+
+"@generatesac/lib@^0.0.1":
+ version "0.0.1"
+ resolved "https://registry.npmjs.org/@generatesac/lib/-/lib-0.0.1.tgz"
+ integrity sha512-E7Vw3fZlRdxdBUl06H4s/0IzFb7BCAAWP/iHwA/ju0p4ILy0f6mq2hpWvIDqRFLri6NFWdO3eCd23yjN1VQFNQ==
+ dependencies:
+ "@blocknote/core" "^0.12.4"
+ "@blocknote/react" "^0.12.4"
+ "@reduxjs/toolkit" "^2.2.3"
+ "@tiptap/pm" "^2.3.1"
+ react "^18.2.0"
+ react-dom "^18.2.0"
+ react-icons "^5.2.1"
+ react-redux "^9.1.2"
+ zod "^3.23.6"
+
"@humanwhocodes/config-array@^0.11.14":
version "0.11.14"
- resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b"
+ resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz"
integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==
dependencies:
"@humanwhocodes/object-schema" "^2.0.2"
@@ -183,17 +519,17 @@
"@humanwhocodes/module-importer@^1.0.1":
version "1.0.1"
- resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
+ resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz"
integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
"@humanwhocodes/object-schema@^2.0.2":
version "2.0.3"
- resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3"
+ resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz"
integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==
"@isaacs/cliui@^8.0.2":
version "8.0.2"
- resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
+ resolved "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz"
integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==
dependencies:
string-width "^5.1.2"
@@ -203,9 +539,217 @@
wrap-ansi "^8.1.0"
wrap-ansi-cjs "npm:wrap-ansi@^7.0.0"
+"@istanbuljs/load-nyc-config@^1.0.0":
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz"
+ integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==
+ dependencies:
+ camelcase "^5.3.1"
+ find-up "^4.1.0"
+ get-package-type "^0.1.0"
+ js-yaml "^3.13.1"
+ resolve-from "^5.0.0"
+
+"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3":
+ version "0.1.3"
+ resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz"
+ integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==
+
+"@jest/console@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz"
+ integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==
+ dependencies:
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ jest-message-util "^29.7.0"
+ jest-util "^29.7.0"
+ slash "^3.0.0"
+
+"@jest/core@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz"
+ integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==
+ dependencies:
+ "@jest/console" "^29.7.0"
+ "@jest/reporters" "^29.7.0"
+ "@jest/test-result" "^29.7.0"
+ "@jest/transform" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ ansi-escapes "^4.2.1"
+ chalk "^4.0.0"
+ ci-info "^3.2.0"
+ exit "^0.1.2"
+ graceful-fs "^4.2.9"
+ jest-changed-files "^29.7.0"
+ jest-config "^29.7.0"
+ jest-haste-map "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-regex-util "^29.6.3"
+ jest-resolve "^29.7.0"
+ jest-resolve-dependencies "^29.7.0"
+ jest-runner "^29.7.0"
+ jest-runtime "^29.7.0"
+ jest-snapshot "^29.7.0"
+ jest-util "^29.7.0"
+ jest-validate "^29.7.0"
+ jest-watcher "^29.7.0"
+ micromatch "^4.0.4"
+ pretty-format "^29.7.0"
+ slash "^3.0.0"
+ strip-ansi "^6.0.0"
+
+"@jest/environment@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz"
+ integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==
+ dependencies:
+ "@jest/fake-timers" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ jest-mock "^29.7.0"
+
+"@jest/expect-utils@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz"
+ integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==
+ dependencies:
+ jest-get-type "^29.6.3"
+
+"@jest/expect@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz"
+ integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==
+ dependencies:
+ expect "^29.7.0"
+ jest-snapshot "^29.7.0"
+
+"@jest/fake-timers@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz"
+ integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==
+ dependencies:
+ "@jest/types" "^29.6.3"
+ "@sinonjs/fake-timers" "^10.0.2"
+ "@types/node" "*"
+ jest-message-util "^29.7.0"
+ jest-mock "^29.7.0"
+ jest-util "^29.7.0"
+
+"@jest/globals@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz"
+ integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==
+ dependencies:
+ "@jest/environment" "^29.7.0"
+ "@jest/expect" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ jest-mock "^29.7.0"
+
+"@jest/reporters@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz"
+ integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==
+ dependencies:
+ "@bcoe/v8-coverage" "^0.2.3"
+ "@jest/console" "^29.7.0"
+ "@jest/test-result" "^29.7.0"
+ "@jest/transform" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ "@jridgewell/trace-mapping" "^0.3.18"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ collect-v8-coverage "^1.0.0"
+ exit "^0.1.2"
+ glob "^7.1.3"
+ graceful-fs "^4.2.9"
+ istanbul-lib-coverage "^3.0.0"
+ istanbul-lib-instrument "^6.0.0"
+ istanbul-lib-report "^3.0.0"
+ istanbul-lib-source-maps "^4.0.0"
+ istanbul-reports "^3.1.3"
+ jest-message-util "^29.7.0"
+ jest-util "^29.7.0"
+ jest-worker "^29.7.0"
+ slash "^3.0.0"
+ string-length "^4.0.1"
+ strip-ansi "^6.0.0"
+ v8-to-istanbul "^9.0.1"
+
+"@jest/schemas@^29.6.3":
+ version "29.6.3"
+ resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz"
+ integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==
+ dependencies:
+ "@sinclair/typebox" "^0.27.8"
+
+"@jest/source-map@^29.6.3":
+ version "29.6.3"
+ resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz"
+ integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==
+ dependencies:
+ "@jridgewell/trace-mapping" "^0.3.18"
+ callsites "^3.0.0"
+ graceful-fs "^4.2.9"
+
+"@jest/test-result@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz"
+ integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==
+ dependencies:
+ "@jest/console" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ "@types/istanbul-lib-coverage" "^2.0.0"
+ collect-v8-coverage "^1.0.0"
+
+"@jest/test-sequencer@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz"
+ integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==
+ dependencies:
+ "@jest/test-result" "^29.7.0"
+ graceful-fs "^4.2.9"
+ jest-haste-map "^29.7.0"
+ slash "^3.0.0"
+
+"@jest/transform@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz"
+ integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==
+ dependencies:
+ "@babel/core" "^7.11.6"
+ "@jest/types" "^29.6.3"
+ "@jridgewell/trace-mapping" "^0.3.18"
+ babel-plugin-istanbul "^6.1.1"
+ chalk "^4.0.0"
+ convert-source-map "^2.0.0"
+ fast-json-stable-stringify "^2.1.0"
+ graceful-fs "^4.2.9"
+ jest-haste-map "^29.7.0"
+ jest-regex-util "^29.6.3"
+ jest-util "^29.7.0"
+ micromatch "^4.0.4"
+ pirates "^4.0.4"
+ slash "^3.0.0"
+ write-file-atomic "^4.0.2"
+
+"@jest/types@^29.0.0", "@jest/types@^29.6.3":
+ version "29.6.3"
+ resolved "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz"
+ integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==
+ dependencies:
+ "@jest/schemas" "^29.6.3"
+ "@types/istanbul-lib-coverage" "^2.0.0"
+ "@types/istanbul-reports" "^3.0.0"
+ "@types/node" "*"
+ "@types/yargs" "^17.0.8"
+ chalk "^4.0.0"
+
"@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5":
version "0.3.5"
- resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36"
+ resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz"
integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==
dependencies:
"@jridgewell/set-array" "^1.2.1"
@@ -214,100 +758,82 @@
"@jridgewell/resolve-uri@^3.1.0":
version "3.1.2"
- resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
+ resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz"
integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==
"@jridgewell/set-array@^1.2.1":
version "1.2.1"
- resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280"
+ resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz"
integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==
"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14":
version "1.4.15"
- resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
+ resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz"
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
-"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25":
+"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25":
version "0.3.25"
- resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0"
+ resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz"
integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==
dependencies:
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
-"@next/env@14.2.2":
- version "14.2.2"
- resolved "https://registry.yarnpkg.com/@next/env/-/env-14.2.2.tgz#6c36fe0b04a22ea78bd60a645ae77d53cd16d3ca"
- integrity sha512-sk72qRfM1Q90XZWYRoJKu/UWlTgihrASiYw/scb15u+tyzcze3bOuJ/UV6TBOQEeUaxOkRqGeuGUdiiuxc5oqw==
-
-"@next/eslint-plugin-next@14.2.2":
- version "14.2.2"
- resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-14.2.2.tgz#1eaf592ebb961e0b093e4774b0c77298af5e2e0e"
- integrity sha512-q+Ec2648JtBpKiu/FSJm8HAsFXlNvioHeBCbTP12T1SGcHYwhqHULSfQgFkPgHDu3kzNp2Kem4J54bK4rPQ5SQ==
+"@mantine/core@^7.7.1":
+ version "7.9.0"
+ resolved "https://registry.npmjs.org/@mantine/core/-/core-7.9.0.tgz"
+ integrity sha512-EhELO1uYq2s08H69h4BCcvE26mNLPaXUi6RAjApqBIynMcyJlmdluFtvGKFxjpgFZy3moeSYNrjEW//T0uTMZg==
+ dependencies:
+ "@floating-ui/react" "^0.26.9"
+ clsx "2.1.0"
+ react-number-format "^5.3.1"
+ react-remove-scroll "^2.5.7"
+ react-textarea-autosize "8.5.3"
+ type-fest "^4.12.0"
+
+"@mantine/hooks@^7.7.1", "@mantine/hooks@7.9.0":
+ version "7.9.0"
+ resolved "https://registry.npmjs.org/@mantine/hooks/-/hooks-7.9.0.tgz"
+ integrity sha512-LKgyrlaIK0S/gcn/VDbhqLBZOYjvhXfVcH7rMs4MIBVD+wuRo2LvvAYe3cUfQbBCfmlpRjqvewwvsIYYsjSofQ==
+
+"@mantine/utils@^6.0.21":
+ version "6.0.21"
+ resolved "https://registry.npmjs.org/@mantine/utils/-/utils-6.0.21.tgz"
+ integrity sha512-33RVDRop5jiWFao3HKd3Yp7A9mEq4HAJxJPTuYm1NkdqX6aTKOQK7wT8v8itVodBp+sb4cJK6ZVdD1UurK/txQ==
+
+"@next/env@14.2.3":
+ version "14.2.3"
+ resolved "https://registry.npmjs.org/@next/env/-/env-14.2.3.tgz"
+ integrity sha512-W7fd7IbkfmeeY2gXrzJYDx8D2lWKbVoTIj1o1ScPHNzvp30s1AuoEFSdr39bC5sjxJaxTtq3OTCZboNp0lNWHA==
+
+"@next/eslint-plugin-next@14.2.3":
+ version "14.2.3"
+ resolved "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.2.3.tgz"
+ integrity sha512-L3oDricIIjgj1AVnRdRor21gI7mShlSwU/1ZGHmqM3LzHhXXhdkrfeNY5zif25Bi5Dd7fiJHsbhoZCHfXYvlAw==
dependencies:
glob "10.3.10"
-"@next/swc-darwin-arm64@14.2.2":
- version "14.2.2"
- resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.2.tgz#55e395b0db6dd5ea2dc92818260ff3a399f1a056"
- integrity sha512-3iPgMhzbalizGwHNFUcGnDhFPSgVBHQ8aqSTAMxB5BvJG0oYrDf1WOJZlbXBgunOEj/8KMVbejEur/FpvFsgFQ==
-
-"@next/swc-darwin-x64@14.2.2":
- version "14.2.2"
- resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.2.tgz#f96fb65510be798c03b0432129792c6ac8885bc8"
- integrity sha512-x7Afi/jt0ZBRUZHTi49yyej4o8znfIMHO4RvThuoc0P+uli8Jd99y5GKjxoYunPKsXL09xBXEM1+OQy2xEL0Ag==
-
-"@next/swc-linux-arm64-gnu@14.2.2":
- version "14.2.2"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.2.tgz#443f0d4ab9d1aa4338e40f77ca4e182d60e88448"
- integrity sha512-zbfPtkk7L41ODMJwSp5VbmPozPmMMQrzAc0HAUomVeVIIwlDGs/UCqLJvLNDt4jpWgc21SjjyIn762lNGrMaUA==
-
-"@next/swc-linux-arm64-musl@14.2.2":
- version "14.2.2"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.2.tgz#182c00b3d2f3ed4eaacdd385d07b230252c64de9"
- integrity sha512-wPbS3pI/JU16rm3XdLvvTmlsmm1nd+sBa2ohXgBZcShX4TgOjD4R+RqHKlI1cjo/jDZKXt6OxmcU0Iys0OC/yg==
-
-"@next/swc-linux-x64-gnu@14.2.2":
- version "14.2.2"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.2.tgz#e826a08085dcc61685ff42884ad4032e71ac154f"
- integrity sha512-NqWOHqqq8iC9tuHvZxjQ2tX+jWy2X9y8NX2mcB4sj2bIccuCxbIZrU/ThFPZZPauygajZuVQ6zediejQHwZHwQ==
-
-"@next/swc-linux-x64-musl@14.2.2":
- version "14.2.2"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.2.tgz#42f921ca6d93fdfb2b13de70cd8a44ba5526b318"
- integrity sha512-lGepHhwb9sGhCcU7999+iK1ZZT+6rrIoVg40MP7DZski9GIZP80wORSbt5kJzh9v2x2ev2lxC6VgwMQT0PcgTA==
-
-"@next/swc-win32-arm64-msvc@14.2.2":
- version "14.2.2"
- resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.2.tgz#9c8f60da8e3882c4c66f21747abf944a627d05ff"
- integrity sha512-TZSh/48SfcLEQ4rD25VVn2kdIgUWmMflRX3OiyPwGNXn3NiyPqhqei/BaqCYXViIQ+6QsG9R0C8LftMqy8JPMA==
-
-"@next/swc-win32-ia32-msvc@14.2.2":
- version "14.2.2"
- resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.2.tgz#fdb0b5f74e6dc0dcb34b7f7d24775ad034d915e8"
- integrity sha512-M0tBVNMEBJN2ZNQWlcekMn6pvLria7Sa2Fai5znm7CCJz4pP3lrvlSxhKdkCerk0D9E0bqx5yAo3o2Q7RrD4gA==
-
-"@next/swc-win32-x64-msvc@14.2.2":
- version "14.2.2"
- resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.2.tgz#95cc0dad2c7ac5177fa6eeab070dccfa30532353"
- integrity sha512-a/20E/wtTJZ3Ykv3f/8F0l7TtgQa2LWHU2oNB9bsu0VjqGuGGHmm/q6waoUNQYTVPYrrlxxaHjJcDV6aiSTt/w==
+"@next/swc-darwin-arm64@14.2.3":
+ version "14.2.3"
+ resolved "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.3.tgz"
+ integrity sha512-3pEYo/RaGqPP0YzwnlmPN2puaF2WMLM3apt5jLW2fFdXD9+pqcoTzRk+iZsf8ta7+quAe4Q6Ms0nR0SFGFdS1A==
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
+ resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz"
integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
dependencies:
"@nodelib/fs.stat" "2.0.5"
run-parallel "^1.1.9"
-"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
+"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
version "2.0.5"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
+ resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8":
version "1.2.8"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
+ resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz"
integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
dependencies:
"@nodelib/fs.scandir" "2.1.5"
@@ -315,45 +841,232 @@
"@pkgjs/parseargs@^0.11.0":
version "0.11.0"
- resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
+ resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz"
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
"@pkgr/core@^0.1.0":
version "0.1.1"
- resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31"
+ resolved "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz"
integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==
-"@reduxjs/toolkit@^2.2.3":
- version "2.2.3"
- resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-2.2.3.tgz#5ce71cbf162f98c5dafb49bd3f1e11c5486ab9c4"
- integrity sha512-76dll9EnJXg4EVcI5YNxZA/9hSAmZsFqzMmNRHvIlzw2WS/twfcVX3ysYrWGJMClwEmChQFC4yRq74tn6fdzRA==
+"@popperjs/core@^2.9.0":
+ version "2.11.8"
+ resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz"
+ integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
+
+"@radix-ui/react-compose-refs@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz"
+ integrity sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
+"@radix-ui/react-slot@^1.0.2":
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz"
+ integrity sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-compose-refs" "1.0.1"
+
+"@reduxjs/toolkit@^2.2.3", "@reduxjs/toolkit@^2.2.4":
+ version "2.2.5"
+ resolved "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.5.tgz"
+ integrity sha512-aeFA/s5NCG7NoJe/MhmwREJxRkDs0ZaSqt0MxhWUrwCf1UQXpwR87RROJEql0uAkLI6U7snBOYOcKw83ew3FPg==
dependencies:
immer "^10.0.3"
redux "^5.0.1"
redux-thunk "^3.1.0"
- reselect "^5.0.1"
+ reselect "^5.1.0"
+
+"@remirror/core-constants@^2.0.2":
+ version "2.0.2"
+ resolved "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-2.0.2.tgz"
+ integrity sha512-dyHY+sMF0ihPus3O27ODd4+agdHMEmuRdyiZJ2CCWjPV5UFmn17ZbElvk6WOGVE4rdCJKZQCrPV2BcikOMLUGQ==
"@rushstack/eslint-patch@^1.3.3":
version "1.10.2"
- resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.10.2.tgz#053f1540703faa81dea2966b768ee5581c66aeda"
+ resolved "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.2.tgz"
integrity sha512-hw437iINopmQuxWPSUEvqE56NCPsiU8N4AYtfHmJFckclktzK9YQJieD3XkDCDH4OjL+C7zgPUh73R/nrcHrqw==
+"@sinclair/typebox@^0.27.8":
+ version "0.27.8"
+ resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz"
+ integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==
+
+"@sinonjs/commons@^3.0.0":
+ version "3.0.1"
+ resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz"
+ integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==
+ dependencies:
+ type-detect "4.0.8"
+
+"@sinonjs/fake-timers@^10.0.2":
+ version "10.3.0"
+ resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz"
+ integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==
+ dependencies:
+ "@sinonjs/commons" "^3.0.0"
+
"@swc/counter@^0.1.3":
version "0.1.3"
- resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9"
+ resolved "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz"
integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==
"@swc/helpers@0.5.5":
version "0.5.5"
- resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.5.tgz#12689df71bfc9b21c4f4ca00ae55f2f16c8b77c0"
+ resolved "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz"
integrity sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==
dependencies:
"@swc/counter" "^0.1.3"
tslib "^2.4.0"
+"@tiptap/core@^2.0.0", "@tiptap/core@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/core/-/core-2.3.1.tgz"
+ integrity sha512-ycpQlmczAOc05TgB5sc3RUTEEBXAVmS8MR9PqQzg96qidaRfVkgE+2w4k7t83PMHl2duC0MGqOCy96pLYwSpeg==
+
+"@tiptap/extension-bold@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-2.3.1.tgz"
+ integrity sha512-szHDXKOQfrlCzsys401zBtPWE5gyY3LcpPlrn2zBRrBmzU2U/1A7Y3HkoqZo3SSrTY37eG1Vr2J2aHySK6Uj/w==
+
+"@tiptap/extension-bubble-menu@^2.3.1":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.3.1.tgz"
+ integrity sha512-6PGrk65f0eXHcCEe6A2/GpooMsD6RPZY1kWSSWUNfklJO54R/8uAtsSVIBr7wQ34pvrYkNaluRUrDWUokWyBOQ==
+ dependencies:
+ tippy.js "^6.3.7"
+
+"@tiptap/extension-code@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.3.1.tgz"
+ integrity sha512-bVX0EnDZoRXnoA7dyoZe7w2gdRjxmFEcsatHLkcr3R3x4k9oSgZXLe1C2jGbjJWr4j32tYXZ1cpKte6f1WUKzg==
+
+"@tiptap/extension-collaboration-cursor@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-collaboration-cursor/-/extension-collaboration-cursor-2.3.1.tgz"
+ integrity sha512-r4vBfuUiz+o2p62UJUmKruvoHgNS67sOBk2P5zYDljVEg2O8ydZVU2qmBdDgfyqQG3aO/p4tYDCCZeVsoYQngA==
+
+"@tiptap/extension-collaboration@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-collaboration/-/extension-collaboration-2.3.1.tgz"
+ integrity sha512-d/azeir3H2v8epywquDMpDaz0BcLJddwGkSB/MMJe6Q58fEenRCad5/GE3zs0bMEhA0WELq9YtWLO87xrUQg9A==
+
+"@tiptap/extension-dropcursor@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.3.1.tgz"
+ integrity sha512-xDG1Z01ftRI4mIOY+bPuG53xZ9FfVd6hzjNchwFHRlU3E+/2O+DsEBy/pJuHmpnFx1B/1ANbssoidGvK3LIPYw==
+
+"@tiptap/extension-floating-menu@^2.3.1":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.3.1.tgz"
+ integrity sha512-3+dONthHRMFzJjLF9JtRbm9u4XJs8txCoChsZjwD0wBf8XfPtUGZQn9W5xNJG+5pozrOQhj9KC1UZL4tuvSRkg==
+ dependencies:
+ tippy.js "^6.3.7"
+
+"@tiptap/extension-gapcursor@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.3.1.tgz"
+ integrity sha512-jhMw0LtEV/HVovUDRdoH0QLnBWLDyw4Su7UZ0bkMtsnCO9MujLKths3SKsPstuAckZQKR5smokEytxDHH0aglg==
+
+"@tiptap/extension-hard-break@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.3.1.tgz"
+ integrity sha512-HO47iS2KQJLxhZM4ghZz5t2qgESH6D/mKJbjO7jM0eCYEyUfPyYJwV2VgjQP7x+1axcvsrhpzkJrjSg5+KqtQQ==
+
+"@tiptap/extension-history@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.3.1.tgz"
+ integrity sha512-m+W6qTP4V0PHqqKnXw/ma18a62O0Cqp5FDWtSarOuxx6W4FpVr4A3Uxfbp4RigZEYanLcX4UJOWL4nWsFdYWHw==
+
+"@tiptap/extension-horizontal-rule@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.3.1.tgz"
+ integrity sha512-IPgCFkiT6Y5BSFBQMTXS6gq2Ust6otMzRwddoI0RC8tl/tMftFBEPqYKADWVQeQb4C6AQydRjUbmAwHpBH31Eg==
+
+"@tiptap/extension-italic@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-2.3.1.tgz"
+ integrity sha512-yEAn0dT1LH1vAULmZv3L1fs7M1Fn/8wZCw7LDGw2/E+VYbDeXgy7XwMPyzhrzV1oV9Z+3gugCbYV0IJ4PBwudA==
+
+"@tiptap/extension-link@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-2.3.1.tgz"
+ integrity sha512-VE54iLwWcPldqZl7a4E/pmGD7waCWS//VT8jxTuFUroTouIzT+OjB9DQAXMkrRiaz+na3I8Jie1yBE+zYB0gvQ==
+ dependencies:
+ linkifyjs "^4.1.0"
+
+"@tiptap/extension-paragraph@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.3.1.tgz"
+ integrity sha512-bHkkHU012clwCrpzmEHGuF8fwLuFL3x9MJ17wnhwanoIM3MG6ZCdeb9copjDvUpZXLKTUYKotoPGNhxmOrP2bQ==
+
+"@tiptap/extension-strike@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.3.1.tgz"
+ integrity sha512-fpsVewcnaYk37TAF4JHkwH9O6Ml7JooF1v/Eh9p7PSItNcEfg/3RLlJL3c53RzLWdlunjgptM/M0alPV0Zyq4A==
+
+"@tiptap/extension-table-cell@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-table-cell/-/extension-table-cell-2.3.1.tgz"
+ integrity sha512-xjCmpokTRyU4OcUbrXchPkZhUY5ACNyNYPwxWcXlZHG8rFbF/UJFHt22VZzMFLb33iBWgsPR9MfPtSL4+wdm4Q==
+
+"@tiptap/extension-table-header@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-table-header/-/extension-table-header-2.3.1.tgz"
+ integrity sha512-hAQjjPie+QDW851CsmknoPI1hkB54mur0EudHxuEMCTweMZJseiO+IggNdQT3YdlUcV/UZTJdnhtOvmpHHLQ1w==
+
+"@tiptap/extension-table-row@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-table-row/-/extension-table-row-2.3.1.tgz"
+ integrity sha512-TYUj1XXdVGHrQOs1MiErB064Wp6vJeInViuN+fXt/u/Fc4LbQzfXbMsjqALfcfajJdGgqHBNBV25lzCrFGTJ8w==
+
+"@tiptap/extension-text@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.3.1.tgz"
+ integrity sha512-ZM+Bpty9jChEN/VjUP/fX1Fvoz0Z3YLdjj9+pFA0H7woli+TmxWY6yUUTA2SBDb2mJ52yNOUfRE/sYx6gkDuBQ==
+
+"@tiptap/extension-underline@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-2.3.1.tgz"
+ integrity sha512-xgLGr7bM5OAKagUKdL5dWxJHgwEp2fk3D5XCVUBwqgeOZtOFteoqPzb/2617w7qrP+9oM9zRjw6z27hM8YxyvQ==
+
+"@tiptap/pm@^2.0.0", "@tiptap/pm@^2.0.3", "@tiptap/pm@^2.3.1":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/pm/-/pm-2.3.1.tgz"
+ integrity sha512-jdd1PFAFeewcu1rWsiqoCc04u5NCplHVjsGPN4jxUmqKdU0YN/9sp7h8gRG6YN1GZRoC1Y6KD+WPLMdzkwizZQ==
+ dependencies:
+ prosemirror-changeset "^2.2.1"
+ prosemirror-collab "^1.3.1"
+ prosemirror-commands "^1.5.2"
+ prosemirror-dropcursor "^1.8.1"
+ prosemirror-gapcursor "^1.3.2"
+ prosemirror-history "^1.3.2"
+ prosemirror-inputrules "^1.3.0"
+ prosemirror-keymap "^1.2.2"
+ prosemirror-markdown "^1.12.0"
+ prosemirror-menu "^1.2.4"
+ prosemirror-model "^1.19.4"
+ prosemirror-schema-basic "^1.2.2"
+ prosemirror-schema-list "^1.3.0"
+ prosemirror-state "^1.4.3"
+ prosemirror-tables "^1.3.5"
+ prosemirror-trailing-node "^2.0.7"
+ prosemirror-transform "^1.8.0"
+ prosemirror-view "^1.32.7"
+
+"@tiptap/react@^2.0.3":
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/@tiptap/react/-/react-2.3.1.tgz"
+ integrity sha512-MM6UOi5nmdM/dZXYtbBYHJEsVtyyFFnOCXlXmhTlhz0WYI8VkEAY7XWLB96KrqsbRk9PUWwdev7iT1q40zxVeg==
+ dependencies:
+ "@tiptap/extension-bubble-menu" "^2.3.1"
+ "@tiptap/extension-floating-menu" "^2.3.1"
+
"@trivago/prettier-plugin-sort-imports@^4.3.0":
version "4.3.0"
- resolved "https://registry.yarnpkg.com/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.3.0.tgz#725f411646b3942193a37041c84e0b2116339789"
+ resolved "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.3.0.tgz"
integrity sha512-r3n0onD3BTOVUNPhR4lhVK4/pABGpbA7bW3eumZnYdKaHkf1qEC+Mag6DPbGNuuh0eG8AaYj+YqmVHSiGslaTQ==
dependencies:
"@babel/generator" "7.17.7"
@@ -363,46 +1076,183 @@
javascript-natural-sort "0.7.1"
lodash "^4.17.21"
+"@types/babel__core@^7.1.14":
+ version "7.20.5"
+ resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz"
+ integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==
+ dependencies:
+ "@babel/parser" "^7.20.7"
+ "@babel/types" "^7.20.7"
+ "@types/babel__generator" "*"
+ "@types/babel__template" "*"
+ "@types/babel__traverse" "*"
+
+"@types/babel__generator@*":
+ version "7.6.8"
+ resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz"
+ integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==
+ dependencies:
+ "@babel/types" "^7.0.0"
+
+"@types/babel__template@*":
+ version "7.4.4"
+ resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz"
+ integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==
+ dependencies:
+ "@babel/parser" "^7.1.0"
+ "@babel/types" "^7.0.0"
+
+"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6":
+ version "7.20.5"
+ resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz"
+ integrity sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==
+ dependencies:
+ "@babel/types" "^7.20.7"
+
+"@types/debug@^4.0.0":
+ version "4.1.12"
+ resolved "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz"
+ integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==
+ dependencies:
+ "@types/ms" "*"
+
+"@types/extend@^3.0.0":
+ version "3.0.4"
+ resolved "https://registry.npmjs.org/@types/extend/-/extend-3.0.4.tgz"
+ integrity sha512-ArMouDUTJEz1SQRpFsT2rIw7DeqICFv5aaVzLSIYMYQSLcwcGOfT3VyglQs/p7K3F7fT4zxr0NWxYZIdifD6dA==
+
+"@types/graceful-fs@^4.1.3":
+ version "4.1.9"
+ resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz"
+ integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==
+ dependencies:
+ "@types/node" "*"
+
+"@types/hast@^2.0.0":
+ version "2.3.10"
+ resolved "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz"
+ integrity sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==
+ dependencies:
+ "@types/unist" "^2"
+
+"@types/hast@^3.0.0":
+ version "3.0.4"
+ resolved "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz"
+ integrity sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==
+ dependencies:
+ "@types/unist" "*"
+
+"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
+ version "2.0.6"
+ resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz"
+ integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==
+
+"@types/istanbul-lib-report@*":
+ version "3.0.3"
+ resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz"
+ integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==
+ dependencies:
+ "@types/istanbul-lib-coverage" "*"
+
+"@types/istanbul-reports@^3.0.0":
+ version "3.0.4"
+ resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz"
+ integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==
+ dependencies:
+ "@types/istanbul-lib-report" "*"
+
+"@types/jest@^29.5.12":
+ version "29.5.12"
+ resolved "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz"
+ integrity sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==
+ dependencies:
+ expect "^29.0.0"
+ pretty-format "^29.0.0"
+
"@types/json5@^0.0.29":
version "0.0.29"
- resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
+ resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz"
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
-"@types/node@^20":
- version "20.12.7"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.7.tgz#04080362fa3dd6c5822061aa3124f5c152cff384"
- integrity sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==
+"@types/mdast@^3.0.0":
+ version "3.0.15"
+ resolved "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz"
+ integrity sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==
+ dependencies:
+ "@types/unist" "^2"
+
+"@types/ms@*":
+ version "0.7.34"
+ resolved "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz"
+ integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==
+
+"@types/node@*", "@types/node@^20":
+ version "20.12.10"
+ resolved "https://registry.npmjs.org/@types/node/-/node-20.12.10.tgz"
+ integrity sha512-Eem5pH9pmWBHoGAT8Dr5fdc5rYA+4NAovdM4EktRPVAAiJhmWWfQrA0cFhAbOsQdSfIHjAud6YdkbL69+zSKjw==
dependencies:
undici-types "~5.26.4"
+"@types/parse5@^6.0.0":
+ version "6.0.3"
+ resolved "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz"
+ integrity sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==
+
"@types/prop-types@*":
version "15.7.12"
- resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6"
+ resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz"
integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==
"@types/react-dom@^18":
- version "18.2.25"
- resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.25.tgz#2946a30081f53e7c8d585eb138277245caedc521"
- integrity sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==
+ version "18.3.0"
+ resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz"
+ integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==
dependencies:
"@types/react" "*"
-"@types/react@*", "@types/react@^18":
- version "18.2.79"
- resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.79.tgz#c40efb4f255711f554d47b449f796d1c7756d865"
- integrity sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w==
+"@types/react@*", "@types/react@^16.8.0 || ^17.0.0 || ^18.0.0", "@types/react@^16.9.0 || ^17.0.0 || ^18.0.0", "@types/react@^18", "@types/react@^18.2.25":
+ version "18.3.1"
+ resolved "https://registry.npmjs.org/@types/react/-/react-18.3.1.tgz"
+ integrity sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==
dependencies:
"@types/prop-types" "*"
csstype "^3.0.2"
+"@types/stack-utils@^2.0.0":
+ version "2.0.3"
+ resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz"
+ integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==
+
+"@types/unist@*", "@types/unist@^3.0.0":
+ version "3.0.2"
+ resolved "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz"
+ integrity sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==
+
+"@types/unist@^2", "@types/unist@^2.0.0":
+ version "2.0.10"
+ resolved "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz"
+ integrity sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==
+
"@types/use-sync-external-store@^0.0.3":
version "0.0.3"
- resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43"
+ resolved "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz"
integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==
+"@types/yargs-parser@*":
+ version "21.0.3"
+ resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz"
+ integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==
+
+"@types/yargs@^17.0.8":
+ version "17.0.32"
+ resolved "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz"
+ integrity sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==
+ dependencies:
+ "@types/yargs-parser" "*"
+
"@typescript-eslint/parser@^5.4.2 || ^6.0.0 || 7.0.0 - 7.2.0":
version "7.2.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.2.0.tgz#44356312aea8852a3a82deebdacd52ba614ec07a"
+ resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz"
integrity sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==
dependencies:
"@typescript-eslint/scope-manager" "7.2.0"
@@ -413,7 +1263,7 @@
"@typescript-eslint/scope-manager@7.2.0":
version "7.2.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz#cfb437b09a84f95a0930a76b066e89e35d94e3da"
+ resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz"
integrity sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==
dependencies:
"@typescript-eslint/types" "7.2.0"
@@ -421,12 +1271,12 @@
"@typescript-eslint/types@7.2.0":
version "7.2.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.2.0.tgz#0feb685f16de320e8520f13cca30779c8b7c403f"
+ resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.2.0.tgz"
integrity sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==
"@typescript-eslint/typescript-estree@7.2.0":
version "7.2.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz#5beda2876c4137f8440c5a84b4f0370828682556"
+ resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz"
integrity sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==
dependencies:
"@typescript-eslint/types" "7.2.0"
@@ -440,7 +1290,7 @@
"@typescript-eslint/visitor-keys@7.2.0":
version "7.2.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz#5035f177752538a5750cca1af6044b633610bf9e"
+ resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz"
integrity sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==
dependencies:
"@typescript-eslint/types" "7.2.0"
@@ -448,22 +1298,22 @@
"@ungap/structured-clone@^1.2.0":
version "1.2.0"
- resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
+ resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz"
integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
acorn-jsx@^5.3.2:
version "5.3.2"
- resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
+ resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
-acorn@^8.9.0:
+"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.9.0:
version "8.11.3"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a"
+ resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz"
integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==
ajv@^6.12.4:
version "6.12.6"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+ resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
dependencies:
fast-deep-equal "^3.1.1"
@@ -471,43 +1321,55 @@ ajv@^6.12.4:
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
+ansi-escapes@^4.2.1:
+ version "4.3.2"
+ resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz"
+ integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
+ dependencies:
+ type-fest "^0.21.3"
+
ansi-regex@^5.0.1:
version "5.0.1"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
+ resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz"
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
ansi-regex@^6.0.1:
version "6.0.1"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a"
+ resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz"
integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==
ansi-styles@^3.2.1:
version "3.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+ resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz"
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
dependencies:
color-convert "^1.9.0"
ansi-styles@^4.0.0, ansi-styles@^4.1.0:
version "4.3.0"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+ resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz"
integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
dependencies:
color-convert "^2.0.1"
+ansi-styles@^5.0.0:
+ version "5.2.0"
+ resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz"
+ integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
+
ansi-styles@^6.1.0:
version "6.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
+ resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz"
integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
any-promise@^1.0.0:
version "1.3.0"
- resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
+ resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz"
integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==
-anymatch@~3.1.2:
+anymatch@^3.0.3, anymatch@~3.1.2:
version "3.1.3"
- resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
+ resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz"
integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
dependencies:
normalize-path "^3.0.0"
@@ -515,24 +1377,31 @@ anymatch@~3.1.2:
arg@^5.0.2:
version "5.0.2"
- resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
+ resolved "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz"
integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==
+argparse@^1.0.7:
+ version "1.0.10"
+ resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz"
+ integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
+ dependencies:
+ sprintf-js "~1.0.2"
+
argparse@^2.0.1:
version "2.0.1"
- resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
+ resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
aria-query@^5.3.0:
version "5.3.0"
- resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e"
+ resolved "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz"
integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==
dependencies:
dequal "^2.0.3"
array-buffer-byte-length@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f"
+ resolved "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz"
integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==
dependencies:
call-bind "^1.0.5"
@@ -540,7 +1409,7 @@ array-buffer-byte-length@^1.0.1:
array-includes@^3.1.6, array-includes@^3.1.7:
version "3.1.8"
- resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d"
+ resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz"
integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==
dependencies:
call-bind "^1.0.7"
@@ -552,12 +1421,12 @@ array-includes@^3.1.6, array-includes@^3.1.7:
array-union@^2.1.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
+ resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz"
integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
array.prototype.findlast@^1.2.4:
version "1.2.5"
- resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904"
+ resolved "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz"
integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==
dependencies:
call-bind "^1.0.7"
@@ -569,7 +1438,7 @@ array.prototype.findlast@^1.2.4:
array.prototype.findlastindex@^1.2.3:
version "1.2.5"
- resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d"
+ resolved "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz"
integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==
dependencies:
call-bind "^1.0.7"
@@ -581,7 +1450,7 @@ array.prototype.findlastindex@^1.2.3:
array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.2:
version "1.3.2"
- resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18"
+ resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz"
integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==
dependencies:
call-bind "^1.0.2"
@@ -591,7 +1460,7 @@ array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.2:
array.prototype.flatmap@^1.3.2:
version "1.3.2"
- resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527"
+ resolved "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz"
integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==
dependencies:
call-bind "^1.0.2"
@@ -601,7 +1470,7 @@ array.prototype.flatmap@^1.3.2:
array.prototype.toreversed@^1.1.2:
version "1.1.2"
- resolved "https://registry.yarnpkg.com/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz#b989a6bf35c4c5051e1dc0325151bf8088954eba"
+ resolved "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz"
integrity sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==
dependencies:
call-bind "^1.0.2"
@@ -611,7 +1480,7 @@ array.prototype.toreversed@^1.1.2:
array.prototype.tosorted@^1.1.3:
version "1.1.3"
- resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz#c8c89348337e51b8a3c48a9227f9ce93ceedcba8"
+ resolved "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz"
integrity sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==
dependencies:
call-bind "^1.0.5"
@@ -622,7 +1491,7 @@ array.prototype.tosorted@^1.1.3:
arraybuffer.prototype.slice@^1.0.3:
version "1.0.3"
- resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6"
+ resolved "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz"
integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==
dependencies:
array-buffer-byte-length "^1.0.1"
@@ -636,12 +1505,12 @@ arraybuffer.prototype.slice@^1.0.3:
ast-types-flow@^0.0.8:
version "0.0.8"
- resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.8.tgz#0a85e1c92695769ac13a428bb653e7538bea27d6"
+ resolved "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz"
integrity sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==
autoprefixer@^10.4.19:
version "10.4.19"
- resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.19.tgz#ad25a856e82ee9d7898c59583c1afeb3fa65f89f"
+ resolved "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz"
integrity sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==
dependencies:
browserslist "^4.23.0"
@@ -653,36 +1522,101 @@ autoprefixer@^10.4.19:
available-typed-arrays@^1.0.7:
version "1.0.7"
- resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846"
+ resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz"
integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==
dependencies:
possible-typed-array-names "^1.0.0"
axe-core@=4.7.0:
version "4.7.0"
- resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf"
+ resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz"
integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==
axobject-query@^3.2.1:
version "3.2.1"
- resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.2.1.tgz#39c378a6e3b06ca679f29138151e45b2b32da62a"
+ resolved "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz"
integrity sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==
dependencies:
dequal "^2.0.3"
-balanced-match@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
- integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+babel-jest@^29.0.0, babel-jest@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz"
+ integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==
+ dependencies:
+ "@jest/transform" "^29.7.0"
+ "@types/babel__core" "^7.1.14"
+ babel-plugin-istanbul "^6.1.1"
+ babel-preset-jest "^29.6.3"
+ chalk "^4.0.0"
+ graceful-fs "^4.2.9"
+ slash "^3.0.0"
-binary-extensions@^2.0.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522"
+babel-plugin-istanbul@^6.1.1:
+ version "6.1.1"
+ resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz"
+ integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.0.0"
+ "@istanbuljs/load-nyc-config" "^1.0.0"
+ "@istanbuljs/schema" "^0.1.2"
+ istanbul-lib-instrument "^5.0.4"
+ test-exclude "^6.0.0"
+
+babel-plugin-jest-hoist@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz"
+ integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==
+ dependencies:
+ "@babel/template" "^7.3.3"
+ "@babel/types" "^7.3.3"
+ "@types/babel__core" "^7.1.14"
+ "@types/babel__traverse" "^7.0.6"
+
+babel-preset-current-node-syntax@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz"
+ integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==
+ dependencies:
+ "@babel/plugin-syntax-async-generators" "^7.8.4"
+ "@babel/plugin-syntax-bigint" "^7.8.3"
+ "@babel/plugin-syntax-class-properties" "^7.8.3"
+ "@babel/plugin-syntax-import-meta" "^7.8.3"
+ "@babel/plugin-syntax-json-strings" "^7.8.3"
+ "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3"
+ "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
+ "@babel/plugin-syntax-numeric-separator" "^7.8.3"
+ "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
+ "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
+ "@babel/plugin-syntax-optional-chaining" "^7.8.3"
+ "@babel/plugin-syntax-top-level-await" "^7.8.3"
+
+babel-preset-jest@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz"
+ integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==
+ dependencies:
+ babel-plugin-jest-hoist "^29.6.3"
+ babel-preset-current-node-syntax "^1.0.0"
+
+bail@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz"
+ integrity sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==
+
+balanced-match@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
+binary-extensions@^2.0.0:
+ version "2.3.0"
+ resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz"
integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
brace-expansion@^1.1.7:
version "1.1.11"
- resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz"
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
dependencies:
balanced-match "^1.0.0"
@@ -690,21 +1624,21 @@ brace-expansion@^1.1.7:
brace-expansion@^2.0.1:
version "2.0.1"
- resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
+ resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz"
integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
dependencies:
balanced-match "^1.0.0"
braces@^3.0.2, braces@~3.0.2:
version "3.0.2"
- resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+ resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
dependencies:
fill-range "^7.0.1"
-browserslist@^4.23.0:
+browserslist@^4.22.2, browserslist@^4.23.0, "browserslist@>= 4.21.0":
version "4.23.0"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab"
+ resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz"
integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==
dependencies:
caniuse-lite "^1.0.30001587"
@@ -712,16 +1646,35 @@ browserslist@^4.23.0:
node-releases "^2.0.14"
update-browserslist-db "^1.0.13"
+bs-logger@0.x:
+ version "0.2.6"
+ resolved "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz"
+ integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==
+ dependencies:
+ fast-json-stable-stringify "2.x"
+
+bser@2.1.1:
+ version "2.1.1"
+ resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz"
+ integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==
+ dependencies:
+ node-int64 "^0.4.0"
+
+buffer-from@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz"
+ integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
+
busboy@1.6.0:
version "1.6.0"
- resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
+ resolved "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz"
integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==
dependencies:
streamsearch "^1.1.0"
call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7:
version "1.0.7"
- resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
+ resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz"
integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
dependencies:
es-define-property "^1.0.0"
@@ -732,22 +1685,37 @@ call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7:
callsites@^3.0.0:
version "3.1.0"
- resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
+ resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz"
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
camelcase-css@^2.0.1:
version "2.0.1"
- resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5"
+ resolved "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz"
integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
+camelcase@^5.3.1:
+ version "5.3.1"
+ resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz"
+ integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
+
+camelcase@^6.2.0:
+ version "6.3.0"
+ resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz"
+ integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
+
caniuse-lite@^1.0.30001579, caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001599:
- version "1.0.30001612"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz#d34248b4ec1f117b70b24ad9ee04c90e0b8a14ae"
- integrity sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==
+ version "1.0.30001616"
+ resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001616.tgz"
+ integrity sha512-RHVYKov7IcdNjVHJFNY/78RdG4oGVjbayxv8u5IO74Wv7Hlq4PnJE6mo/OjFijjVFNy5ijnCt6H3IIo4t+wfEw==
+
+ccount@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz"
+ integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==
chalk@^2.4.2:
version "2.4.2"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+ resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
dependencies:
ansi-styles "^3.2.1"
@@ -756,15 +1724,35 @@ chalk@^2.4.2:
chalk@^4.0.0:
version "4.1.2"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
+ resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
dependencies:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
+char-regex@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz"
+ integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==
+
+character-entities-html4@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz"
+ integrity sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==
+
+character-entities-legacy@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz"
+ integrity sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==
+
+character-entities@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz"
+ integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==
+
chokidar@^3.5.3:
version "3.6.0"
- resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
+ resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz"
integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
dependencies:
anymatch "~3.1.2"
@@ -777,48 +1765,127 @@ chokidar@^3.5.3:
optionalDependencies:
fsevents "~2.3.2"
+ci-info@^3.2.0:
+ version "3.9.0"
+ resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz"
+ integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==
+
+cjs-module-lexer@^1.0.0:
+ version "1.3.1"
+ resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz"
+ integrity sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==
+
+class-variance-authority@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz"
+ integrity sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==
+ dependencies:
+ clsx "2.0.0"
+
client-only@0.0.1:
version "0.0.1"
- resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1"
+ resolved "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz"
integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==
+cliui@^8.0.1:
+ version "8.0.1"
+ resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz"
+ integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.1"
+ wrap-ansi "^7.0.0"
+
+clsx@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz"
+ integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==
+
+clsx@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz"
+ integrity sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==
+
+clsx@2.1.0:
+ version "2.1.0"
+ resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz"
+ integrity sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==
+
+co@^4.6.0:
+ version "4.6.0"
+ resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz"
+ integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==
+
+collect-v8-coverage@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz"
+ integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==
+
color-convert@^1.9.0:
version "1.9.3"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+ resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz"
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
dependencies:
color-name "1.1.3"
color-convert@^2.0.1:
version "2.0.1"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+ resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"
integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
dependencies:
color-name "~1.1.4"
+color-name@~1.1.4:
+ version "1.1.4"
+ resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
+ integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
color-name@1.1.3:
version "1.1.3"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+ resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
-color-name@~1.1.4:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
- integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+comma-separated-tokens@^2.0.0:
+ version "2.0.3"
+ resolved "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz"
+ integrity sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==
commander@^4.0.0:
version "4.1.1"
- resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
+ resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz"
integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
concat-map@0.0.1:
version "0.0.1"
- resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
-cross-spawn@^7.0.0, cross-spawn@^7.0.2:
+convert-source-map@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz"
+ integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
+
+create-jest@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz"
+ integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==
+ dependencies:
+ "@jest/types" "^29.6.3"
+ chalk "^4.0.0"
+ exit "^0.1.2"
+ graceful-fs "^4.2.9"
+ jest-config "^29.7.0"
+ jest-util "^29.7.0"
+ prompts "^2.0.1"
+
+crelt@^1.0.0:
+ version "1.0.6"
+ resolved "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz"
+ integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==
+
+cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
- resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
+ resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
dependencies:
path-key "^3.1.0"
@@ -827,22 +1894,22 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2:
cssesc@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
+ resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz"
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
csstype@^3.0.2:
version "3.1.3"
- resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
+ resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz"
integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
damerau-levenshtein@^1.0.8:
version "1.0.8"
- resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
+ resolved "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz"
integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==
data-view-buffer@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2"
+ resolved "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz"
integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==
dependencies:
call-bind "^1.0.6"
@@ -851,7 +1918,7 @@ data-view-buffer@^1.0.1:
data-view-byte-length@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2"
+ resolved "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz"
integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==
dependencies:
call-bind "^1.0.7"
@@ -860,7 +1927,7 @@ data-view-byte-length@^1.0.1:
data-view-byte-offset@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a"
+ resolved "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz"
integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==
dependencies:
call-bind "^1.0.6"
@@ -869,108 +1936,162 @@ data-view-byte-offset@^1.0.0:
debug@^3.2.7:
version "3.2.7"
- resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
+ resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz"
integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
dependencies:
ms "^2.1.1"
-debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
+debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
version "4.3.4"
- resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
+ resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"
+decode-named-character-reference@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz"
+ integrity sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==
+ dependencies:
+ character-entities "^2.0.0"
+
+dedent@^1.0.0:
+ version "1.5.3"
+ resolved "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz"
+ integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==
+
deep-is@^0.1.3:
version "0.1.4"
- resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
+ resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
+deepmerge@^4.2.2:
+ version "4.3.1"
+ resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz"
+ integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
+
define-data-property@^1.0.1, define-data-property@^1.1.4:
version "1.1.4"
- resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
+ resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz"
integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
dependencies:
es-define-property "^1.0.0"
es-errors "^1.3.0"
gopd "^1.0.1"
-define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1:
+define-properties@^1.2.0, define-properties@^1.2.1:
version "1.2.1"
- resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c"
+ resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz"
integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==
dependencies:
define-data-property "^1.0.1"
has-property-descriptors "^1.0.0"
object-keys "^1.1.1"
-dequal@^2.0.3:
+dequal@^2.0.0, dequal@^2.0.3:
version "2.0.3"
- resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be"
+ resolved "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz"
integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==
+detect-newline@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz"
+ integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==
+
+detect-node-es@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz"
+ integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==
+
didyoumean@^1.2.2:
version "1.2.2"
- resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
+ resolved "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz"
integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==
+diff-sequences@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz"
+ integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==
+
+diff@^5.0.0:
+ version "5.2.0"
+ resolved "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz"
+ integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==
+
dir-glob@^3.0.1:
version "3.0.1"
- resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
+ resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz"
integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
dependencies:
path-type "^4.0.0"
dlv@^1.1.3:
version "1.1.3"
- resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79"
+ resolved "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz"
integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
doctrine@^2.1.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
+ resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz"
integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==
dependencies:
esutils "^2.0.2"
doctrine@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
+ resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz"
integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
dependencies:
esutils "^2.0.2"
eastasianwidth@^0.2.0:
version "0.2.0"
- resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
+ resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz"
integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
electron-to-chromium@^1.4.668:
- version "1.4.745"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.745.tgz#9c202ce9cbf18a5b5e0ca47145fd127cc4dd2290"
- integrity sha512-tRbzkaRI5gbUn5DEvF0dV4TQbMZ5CLkWeTAXmpC9IrYT+GE+x76i9p+o3RJ5l9XmdQlI1pPhVtE9uNcJJ0G0EA==
+ version "1.4.757"
+ resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.757.tgz"
+ integrity sha512-jftDaCknYSSt/+KKeXzH3LX5E2CvRLm75P3Hj+J/dv3CL0qUYcOt13d5FN1NiL5IJbbhzHrb3BomeG2tkSlZmw==
+
+emittery@^0.13.1:
+ version "0.13.1"
+ resolved "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz"
+ integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==
emoji-regex@^8.0.0:
version "8.0.0"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+ resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
emoji-regex@^9.2.2:
version "9.2.2"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
+ resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz"
integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
enhanced-resolve@^5.12.0:
version "5.16.0"
- resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz#65ec88778083056cb32487faa9aef82ed0864787"
+ resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz"
integrity sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==
dependencies:
graceful-fs "^4.2.4"
tapable "^2.2.0"
-es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.1, es-abstract@^1.23.2:
+entities@^4.4.0:
+ version "4.5.0"
+ resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz"
+ integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
+
+error-ex@^1.3.1:
+ version "1.3.2"
+ resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz"
+ integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
+ dependencies:
+ is-arrayish "^0.2.1"
+
+es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.1, es-abstract@^1.23.2, es-abstract@^1.23.3:
version "1.23.3"
- resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0"
+ resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz"
integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==
dependencies:
array-buffer-byte-length "^1.0.1"
@@ -1022,24 +2143,24 @@ es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23
es-define-property@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845"
+ resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz"
integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
dependencies:
get-intrinsic "^1.2.4"
es-errors@^1.1.0, es-errors@^1.2.1, es-errors@^1.3.0:
version "1.3.0"
- resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
+ resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz"
integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
es-iterator-helpers@^1.0.15, es-iterator-helpers@^1.0.17:
- version "1.0.18"
- resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz#4d3424f46b24df38d064af6fbbc89274e29ea69d"
- integrity sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==
+ version "1.0.19"
+ resolved "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz"
+ integrity sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==
dependencies:
call-bind "^1.0.7"
define-properties "^1.2.1"
- es-abstract "^1.23.0"
+ es-abstract "^1.23.3"
es-errors "^1.3.0"
es-set-tostringtag "^2.0.3"
function-bind "^1.1.2"
@@ -1054,14 +2175,14 @@ es-iterator-helpers@^1.0.15, es-iterator-helpers@^1.0.17:
es-object-atoms@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941"
+ resolved "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz"
integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==
dependencies:
es-errors "^1.3.0"
es-set-tostringtag@^2.0.3:
version "2.0.3"
- resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777"
+ resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz"
integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==
dependencies:
get-intrinsic "^1.2.4"
@@ -1070,41 +2191,51 @@ es-set-tostringtag@^2.0.3:
es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763"
+ resolved "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz"
integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==
dependencies:
hasown "^2.0.0"
es-to-primitive@^1.2.1:
version "1.2.1"
- resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
+ resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz"
integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
dependencies:
is-callable "^1.1.4"
is-date-object "^1.0.1"
is-symbol "^1.0.2"
-escalade@^3.1.1:
+escalade@^3.1.1, escalade@^3.1.2:
version "3.1.2"
- resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
+ resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz"
integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
escape-string-regexp@^1.0.5:
version "1.0.5"
- resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+ resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
+escape-string-regexp@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz"
+ integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
+
escape-string-regexp@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
+ resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
-eslint-config-next@14.2.2:
- version "14.2.2"
- resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-14.2.2.tgz#c79f935fa63859303056778b88848b2af0d052ab"
- integrity sha512-12/uFc0KX+wUs7EDpOUGKMXBXZJiBVGdK5/m/QgXOCg2mQ0bQWoKSWNrCeOg7Vum6Kw1d1TW453W6xh+GbHquw==
+escape-string-regexp@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz"
+ integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==
+
+eslint-config-next@14.2.3:
+ version "14.2.3"
+ resolved "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.2.3.tgz"
+ integrity sha512-ZkNztm3Q7hjqvB1rRlOX8P9E/cXRL9ajRcs8jufEtwMfTVYRqnmtnaSu57QqHyBlovMuiB8LEzfLBkh5RYV6Fg==
dependencies:
- "@next/eslint-plugin-next" "14.2.2"
+ "@next/eslint-plugin-next" "14.2.3"
"@rushstack/eslint-patch" "^1.3.3"
"@typescript-eslint/parser" "^5.4.2 || ^6.0.0 || 7.0.0 - 7.2.0"
eslint-import-resolver-node "^0.3.6"
@@ -1116,7 +2247,7 @@ eslint-config-next@14.2.2:
eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.9:
version "0.3.9"
- resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac"
+ resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz"
integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==
dependencies:
debug "^3.2.7"
@@ -1125,7 +2256,7 @@ eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.9:
eslint-import-resolver-typescript@^3.5.2:
version "3.6.1"
- resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz#7b983680edd3f1c5bce1a5829ae0bc2d57fe9efa"
+ resolved "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz"
integrity sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==
dependencies:
debug "^4.3.4"
@@ -1138,14 +2269,14 @@ eslint-import-resolver-typescript@^3.5.2:
eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0:
version "2.8.1"
- resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz#52f2404300c3bd33deece9d7372fb337cc1d7c34"
+ resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz"
integrity sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==
dependencies:
debug "^3.2.7"
-eslint-plugin-import@^2.28.1:
+eslint-plugin-import@*, eslint-plugin-import@^2.28.1:
version "2.29.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz#d45b37b5ef5901d639c15270d74d46d161150643"
+ resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz"
integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==
dependencies:
array-includes "^3.1.7"
@@ -1168,7 +2299,7 @@ eslint-plugin-import@^2.28.1:
eslint-plugin-jsx-a11y@^6.7.1:
version "6.8.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz#2fa9c701d44fcd722b7c771ec322432857fcbad2"
+ resolved "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz"
integrity sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==
dependencies:
"@babel/runtime" "^7.23.2"
@@ -1190,20 +2321,20 @@ eslint-plugin-jsx-a11y@^6.7.1:
eslint-plugin-prettier@^5.1.3:
version "5.1.3"
- resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz#17cfade9e732cef32b5f5be53bd4e07afd8e67e1"
+ resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz"
integrity sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==
dependencies:
prettier-linter-helpers "^1.0.0"
synckit "^0.8.6"
"eslint-plugin-react-hooks@^4.5.0 || 5.0.0-canary-7118f5dd7-20230705":
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3"
- integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==
+ version "4.6.2"
+ resolved "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz"
+ integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==
eslint-plugin-react@^7.33.2:
version "7.34.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz#6806b70c97796f5bbfb235a5d3379ece5f4da997"
+ resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz"
integrity sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==
dependencies:
array-includes "^3.1.7"
@@ -1227,7 +2358,7 @@ eslint-plugin-react@^7.33.2:
eslint-scope@^7.2.2:
version "7.2.2"
- resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f"
+ resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz"
integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==
dependencies:
esrecurse "^4.3.0"
@@ -1235,12 +2366,12 @@ eslint-scope@^7.2.2:
eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3:
version "3.4.3"
- resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
+ resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz"
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
-eslint@^8:
+eslint@*, "eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8", "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8", "eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^7.23.0 || ^8.0.0", eslint@^8, eslint@^8.56.0, eslint@>=8.0.0:
version "8.57.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668"
+ resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz"
integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
@@ -1284,50 +2415,91 @@ eslint@^8:
espree@^9.6.0, espree@^9.6.1:
version "9.6.1"
- resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f"
+ resolved "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz"
integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==
dependencies:
acorn "^8.9.0"
acorn-jsx "^5.3.2"
eslint-visitor-keys "^3.4.1"
+esprima@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz"
+ integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
+
esquery@^1.4.2:
version "1.5.0"
- resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b"
+ resolved "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz"
integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==
dependencies:
estraverse "^5.1.0"
esrecurse@^4.3.0:
version "4.3.0"
- resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
+ resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz"
integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
dependencies:
estraverse "^5.2.0"
estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0:
version "5.3.0"
- resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
+ resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz"
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
esutils@^2.0.2:
version "2.0.3"
- resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
+ resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
+execa@^5.0.0:
+ version "5.1.1"
+ resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz"
+ integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
+ dependencies:
+ cross-spawn "^7.0.3"
+ get-stream "^6.0.0"
+ human-signals "^2.1.0"
+ is-stream "^2.0.0"
+ merge-stream "^2.0.0"
+ npm-run-path "^4.0.1"
+ onetime "^5.1.2"
+ signal-exit "^3.0.3"
+ strip-final-newline "^2.0.0"
+
+exit@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz"
+ integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==
+
+expect@^29.0.0, expect@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz"
+ integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==
+ dependencies:
+ "@jest/expect-utils" "^29.7.0"
+ jest-get-type "^29.6.3"
+ jest-matcher-utils "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-util "^29.7.0"
+
+extend@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz"
+ integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
+
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
- resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
+ resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
fast-diff@^1.1.2:
version "1.3.0"
- resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0"
+ resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz"
integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==
fast-glob@^3.2.9, fast-glob@^3.3.0, fast-glob@^3.3.1:
version "3.3.2"
- resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
+ resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz"
integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
@@ -1336,40 +2508,55 @@ fast-glob@^3.2.9, fast-glob@^3.3.0, fast-glob@^3.3.1:
merge2 "^1.3.0"
micromatch "^4.0.4"
-fast-json-stable-stringify@^2.0.0:
+fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0, fast-json-stable-stringify@2.x:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+ resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
fast-levenshtein@^2.0.6:
version "2.0.6"
- resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+ resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz"
integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
fastq@^1.6.0:
version "1.17.1"
- resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47"
+ resolved "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz"
integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==
dependencies:
reusify "^1.0.4"
+fb-watchman@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz"
+ integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==
+ dependencies:
+ bser "2.1.1"
+
file-entry-cache@^6.0.1:
version "6.0.1"
- resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
+ resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz"
integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==
dependencies:
flat-cache "^3.0.4"
fill-range@^7.0.1:
version "7.0.1"
- resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+ resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
dependencies:
to-regex-range "^5.0.1"
+find-up@^4.0.0, find-up@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz"
+ integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
+ dependencies:
+ locate-path "^5.0.0"
+ path-exists "^4.0.0"
+
find-up@^5.0.0:
version "5.0.0"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
+ resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz"
integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
dependencies:
locate-path "^6.0.0"
@@ -1377,7 +2564,7 @@ find-up@^5.0.0:
flat-cache@^3.0.4:
version "3.2.0"
- resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee"
+ resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz"
integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==
dependencies:
flatted "^3.2.9"
@@ -1386,19 +2573,19 @@ flat-cache@^3.0.4:
flatted@^3.2.9:
version "3.3.1"
- resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a"
+ resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz"
integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==
for-each@^0.3.3:
version "0.3.3"
- resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
+ resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz"
integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==
dependencies:
is-callable "^1.1.3"
foreground-child@^3.1.0:
version "3.1.1"
- resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d"
+ resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz"
integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==
dependencies:
cross-spawn "^7.0.0"
@@ -1406,27 +2593,27 @@ foreground-child@^3.1.0:
fraction.js@^4.3.7:
version "4.3.7"
- resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7"
+ resolved "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz"
integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==
fs.realpath@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+ resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
-fsevents@~2.3.2:
+fsevents@^2.3.2, fsevents@~2.3.2:
version "2.3.3"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
+ resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
function-bind@^1.1.2:
version "1.1.2"
- resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
+ resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
function.prototype.name@^1.1.5, function.prototype.name@^1.1.6:
version "1.1.6"
- resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd"
+ resolved "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz"
integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==
dependencies:
call-bind "^1.0.2"
@@ -1436,12 +2623,22 @@ function.prototype.name@^1.1.5, function.prototype.name@^1.1.6:
functions-have-names@^1.2.3:
version "1.2.3"
- resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
+ resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz"
integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
+gensync@^1.0.0-beta.2:
+ version "1.0.0-beta.2"
+ resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz"
+ integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
+
+get-caller-file@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz"
+ integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+
get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4:
version "1.2.4"
- resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
+ resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz"
integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
dependencies:
es-errors "^1.3.0"
@@ -1450,9 +2647,24 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@
has-symbols "^1.0.3"
hasown "^2.0.0"
+get-nonce@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz"
+ integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==
+
+get-package-type@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz"
+ integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==
+
+get-stream@^6.0.0:
+ version "6.0.1"
+ resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz"
+ integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
+
get-symbol-description@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5"
+ resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz"
integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==
dependencies:
call-bind "^1.0.5"
@@ -1460,40 +2672,29 @@ get-symbol-description@^1.0.2:
get-intrinsic "^1.2.4"
get-tsconfig@^4.5.0:
- version "4.7.3"
- resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.3.tgz#0498163d98f7b58484dd4906999c0c9d5f103f83"
- integrity sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==
+ version "4.7.4"
+ resolved "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.4.tgz"
+ integrity sha512-ofbkKj+0pjXjhejr007J/fLf+sW+8H7K5GCm+msC8q3IpvgjobpyPqSRFemNyIMxklC0zeJpi7VDFna19FacvQ==
dependencies:
resolve-pkg-maps "^1.0.0"
glob-parent@^5.1.2, glob-parent@~5.1.2:
version "5.1.2"
- resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+ resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz"
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
dependencies:
is-glob "^4.0.1"
glob-parent@^6.0.2:
version "6.0.2"
- resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
+ resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz"
integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
dependencies:
is-glob "^4.0.3"
-glob@10.3.10:
- version "10.3.10"
- resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b"
- integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==
- dependencies:
- foreground-child "^3.1.0"
- jackspeak "^2.3.5"
- minimatch "^9.0.1"
- minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
- path-scurry "^1.10.1"
-
glob@^10.3.10:
version "10.3.12"
- resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.12.tgz#3a65c363c2e9998d220338e88a5f6ac97302960b"
+ resolved "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz"
integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==
dependencies:
foreground-child "^3.1.0"
@@ -1502,9 +2703,9 @@ glob@^10.3.10:
minipass "^7.0.4"
path-scurry "^1.10.2"
-glob@^7.1.3:
+glob@^7.1.3, glob@^7.1.4:
version "7.2.3"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
+ resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz"
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
dependencies:
fs.realpath "^1.0.0"
@@ -1514,28 +2715,40 @@ glob@^7.1.3:
once "^1.3.0"
path-is-absolute "^1.0.0"
+glob@10.3.10:
+ version "10.3.10"
+ resolved "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz"
+ integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==
+ dependencies:
+ foreground-child "^3.1.0"
+ jackspeak "^2.3.5"
+ minimatch "^9.0.1"
+ minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
+ path-scurry "^1.10.1"
+
globals@^11.1.0:
version "11.12.0"
- resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
+ resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz"
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
globals@^13.19.0:
version "13.24.0"
- resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171"
+ resolved "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz"
integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==
dependencies:
type-fest "^0.20.2"
globalthis@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf"
- integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==
+ version "1.0.4"
+ resolved "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz"
+ integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==
dependencies:
- define-properties "^1.1.3"
+ define-properties "^1.2.1"
+ gopd "^1.0.1"
globby@^11.1.0:
version "11.1.0"
- resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
+ resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz"
integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
dependencies:
array-union "^2.1.0"
@@ -1547,93 +2760,329 @@ globby@^11.1.0:
gopd@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
+ resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz"
integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
dependencies:
get-intrinsic "^1.1.3"
-graceful-fs@^4.2.11, graceful-fs@^4.2.4:
+graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.9:
version "4.2.11"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
+ resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz"
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
graphemer@^1.4.0:
version "1.4.0"
- resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
+ resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz"
integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
has-bigints@^1.0.1, has-bigints@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa"
+ resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz"
integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==
has-flag@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+ resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz"
integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
has-flag@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+ resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
+ resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz"
integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
dependencies:
es-define-property "^1.0.0"
has-proto@^1.0.1, has-proto@^1.0.3:
version "1.0.3"
- resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd"
+ resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz"
integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==
has-symbols@^1.0.2, has-symbols@^1.0.3:
version "1.0.3"
- resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
+ resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz"
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
has-tostringtag@^1.0.0, has-tostringtag@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
+ resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz"
integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==
dependencies:
has-symbols "^1.0.3"
hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2:
version "2.0.2"
- resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
+ resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz"
integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
dependencies:
function-bind "^1.1.2"
+hast-util-embedded@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.npmjs.org/hast-util-embedded/-/hast-util-embedded-2.0.1.tgz"
+ integrity sha512-QUdSOP1/o+/TxXtpPFXR2mUg2P+ySrmlX7QjwHZCXqMFyYk7YmcGSvqRW+4XgXAoHifdE1t2PwFaQK33TqVjSw==
+ dependencies:
+ hast-util-is-element "^2.0.0"
+
+hast-util-embedded@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/hast-util-embedded/-/hast-util-embedded-3.0.0.tgz"
+ integrity sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==
+ dependencies:
+ "@types/hast" "^3.0.0"
+ hast-util-is-element "^3.0.0"
+
+hast-util-from-dom@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.npmjs.org/hast-util-from-dom/-/hast-util-from-dom-4.2.0.tgz"
+ integrity sha512-t1RJW/OpJbCAJQeKi3Qrj1cAOLA0+av/iPFori112+0X7R3wng+jxLA+kXec8K4szqPRGI8vPxbbpEYvvpwaeQ==
+ dependencies:
+ hastscript "^7.0.0"
+ web-namespaces "^2.0.0"
+
+hast-util-from-parse5@^7.0.0:
+ version "7.1.2"
+ resolved "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-7.1.2.tgz"
+ integrity sha512-Nz7FfPBuljzsN3tCQ4kCBKqdNhQE2l0Tn+X1ubgKBPRoiDIu1mL08Cfw4k7q71+Duyaw7DXDN+VTAp4Vh3oCOw==
+ dependencies:
+ "@types/hast" "^2.0.0"
+ "@types/unist" "^2.0.0"
+ hastscript "^7.0.0"
+ property-information "^6.0.0"
+ vfile "^5.0.0"
+ vfile-location "^4.0.0"
+ web-namespaces "^2.0.0"
+
+hast-util-has-property@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-2.0.1.tgz"
+ integrity sha512-X2+RwZIMTMKpXUzlotatPzWj8bspCymtXH3cfG3iQKV+wPF53Vgaqxi/eLqGck0wKq1kS9nvoB1wchbCPEL8sg==
+
+hast-util-has-property@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-3.0.0.tgz"
+ integrity sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==
+ dependencies:
+ "@types/hast" "^3.0.0"
+
+hast-util-is-body-ok-link@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/hast-util-is-body-ok-link/-/hast-util-is-body-ok-link-2.0.0.tgz"
+ integrity sha512-S58hCexyKdD31vMsErvgLfflW6vYWo/ixRLPJTtkOvLld24vyI8vmYmkgLA5LG3la2ME7nm7dLGdm48gfLRBfw==
+ dependencies:
+ "@types/hast" "^2.0.0"
+ hast-util-has-property "^2.0.0"
+ hast-util-is-element "^2.0.0"
+
+hast-util-is-body-ok-link@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/hast-util-is-body-ok-link/-/hast-util-is-body-ok-link-3.0.0.tgz"
+ integrity sha512-VFHY5bo2nY8HiV6nir2ynmEB1XkxzuUffhEGeVx7orbu/B1KaGyeGgMZldvMVx5xWrDlLLG/kQ6YkJAMkBEx0w==
+ dependencies:
+ "@types/hast" "^3.0.0"
+
+hast-util-is-element@^2.0.0:
+ version "2.1.3"
+ resolved "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-2.1.3.tgz"
+ integrity sha512-O1bKah6mhgEq2WtVMk+Ta5K7pPMqsBBlmzysLdcwKVrqzZQ0CHqUPiIVspNhAG1rvxpvJjtGee17XfauZYKqVA==
+ dependencies:
+ "@types/hast" "^2.0.0"
+ "@types/unist" "^2.0.0"
+
+hast-util-is-element@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz"
+ integrity sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==
+ dependencies:
+ "@types/hast" "^3.0.0"
+
+hast-util-parse-selector@^3.0.0:
+ version "3.1.1"
+ resolved "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz"
+ integrity sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==
+ dependencies:
+ "@types/hast" "^2.0.0"
+
+hast-util-phrasing@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.npmjs.org/hast-util-phrasing/-/hast-util-phrasing-2.0.2.tgz"
+ integrity sha512-yGkCfPkkfCyiLfK6KEl/orMDr/zgCnq/NaO9HfULx6/Zga5fso5eqQA5Ov/JZVqACygvw9shRYWgXNcG2ilo7w==
+ dependencies:
+ "@types/hast" "^2.0.0"
+ hast-util-embedded "^2.0.0"
+ hast-util-has-property "^2.0.0"
+ hast-util-is-body-ok-link "^2.0.0"
+ hast-util-is-element "^2.0.0"
+
+hast-util-phrasing@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.npmjs.org/hast-util-phrasing/-/hast-util-phrasing-3.0.1.tgz"
+ integrity sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==
+ dependencies:
+ "@types/hast" "^3.0.0"
+ hast-util-embedded "^3.0.0"
+ hast-util-has-property "^3.0.0"
+ hast-util-is-body-ok-link "^3.0.0"
+ hast-util-is-element "^3.0.0"
+
+hast-util-raw@^7.0.0:
+ version "7.2.3"
+ resolved "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-7.2.3.tgz"
+ integrity sha512-RujVQfVsOrxzPOPSzZFiwofMArbQke6DJjnFfceiEbFh7S05CbPt0cYN+A5YeD3pso0JQk6O1aHBnx9+Pm2uqg==
+ dependencies:
+ "@types/hast" "^2.0.0"
+ "@types/parse5" "^6.0.0"
+ hast-util-from-parse5 "^7.0.0"
+ hast-util-to-parse5 "^7.0.0"
+ html-void-elements "^2.0.0"
+ parse5 "^6.0.0"
+ unist-util-position "^4.0.0"
+ unist-util-visit "^4.0.0"
+ vfile "^5.0.0"
+ web-namespaces "^2.0.0"
+ zwitch "^2.0.0"
+
+hast-util-to-html@^8.0.0:
+ version "8.0.4"
+ resolved "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-8.0.4.tgz"
+ integrity sha512-4tpQTUOr9BMjtYyNlt0P50mH7xj0Ks2xpo8M943Vykljf99HW6EzulIoJP1N3eKOSScEHzyzi9dm7/cn0RfGwA==
+ dependencies:
+ "@types/hast" "^2.0.0"
+ "@types/unist" "^2.0.0"
+ ccount "^2.0.0"
+ comma-separated-tokens "^2.0.0"
+ hast-util-raw "^7.0.0"
+ hast-util-whitespace "^2.0.0"
+ html-void-elements "^2.0.0"
+ property-information "^6.0.0"
+ space-separated-tokens "^2.0.0"
+ stringify-entities "^4.0.0"
+ zwitch "^2.0.4"
+
+hast-util-to-mdast@^8.3.0:
+ version "8.4.1"
+ resolved "https://registry.npmjs.org/hast-util-to-mdast/-/hast-util-to-mdast-8.4.1.tgz"
+ integrity sha512-tfmBLASuCgyhCzpkTXM5kU8xeuS5jkMZ17BYm2YftGT5wvgc7uHXTZ/X8WfNd6F5NV/IGmrLsuahZ+jXQir4zQ==
+ dependencies:
+ "@types/extend" "^3.0.0"
+ "@types/hast" "^2.0.0"
+ "@types/mdast" "^3.0.0"
+ "@types/unist" "^2.0.0"
+ extend "^3.0.0"
+ hast-util-has-property "^2.0.0"
+ hast-util-is-element "^2.0.0"
+ hast-util-phrasing "^2.0.0"
+ hast-util-to-text "^3.0.0"
+ mdast-util-phrasing "^3.0.0"
+ mdast-util-to-string "^3.0.0"
+ rehype-minify-whitespace "^5.0.0"
+ trim-trailing-lines "^2.0.0"
+ unist-util-is "^5.0.0"
+ unist-util-visit "^4.0.0"
+
+hast-util-to-parse5@^7.0.0:
+ version "7.1.0"
+ resolved "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-7.1.0.tgz"
+ integrity sha512-YNRgAJkH2Jky5ySkIqFXTQiaqcAtJyVE+D5lkN6CdtOqrnkLfGYYrEcKuHOJZlp+MwjSwuD3fZuawI+sic/RBw==
+ dependencies:
+ "@types/hast" "^2.0.0"
+ comma-separated-tokens "^2.0.0"
+ property-information "^6.0.0"
+ space-separated-tokens "^2.0.0"
+ web-namespaces "^2.0.0"
+ zwitch "^2.0.0"
+
+hast-util-to-text@^3.0.0:
+ version "3.1.2"
+ resolved "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-3.1.2.tgz"
+ integrity sha512-tcllLfp23dJJ+ju5wCCZHVpzsQQ43+moJbqVX3jNWPB7z/KFC4FyZD6R7y94cHL6MQ33YtMZL8Z0aIXXI4XFTw==
+ dependencies:
+ "@types/hast" "^2.0.0"
+ "@types/unist" "^2.0.0"
+ hast-util-is-element "^2.0.0"
+ unist-util-find-after "^4.0.0"
+
+hast-util-whitespace@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz"
+ integrity sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==
+
+hast-util-whitespace@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz"
+ integrity sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==
+ dependencies:
+ "@types/hast" "^3.0.0"
+
+hastscript@^7.0.0:
+ version "7.2.0"
+ resolved "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz"
+ integrity sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==
+ dependencies:
+ "@types/hast" "^2.0.0"
+ comma-separated-tokens "^2.0.0"
+ hast-util-parse-selector "^3.0.0"
+ property-information "^6.0.0"
+ space-separated-tokens "^2.0.0"
+
+html-escaper@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz"
+ integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
+
+html-void-elements@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz"
+ integrity sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==
+
+html-whitespace-sensitive-tag-names@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/html-whitespace-sensitive-tag-names/-/html-whitespace-sensitive-tag-names-3.0.0.tgz"
+ integrity sha512-KlClZ3/Qy5UgvpvVvDomGhnQhNWH5INE8GwvSIQ9CWt1K0zbbXrl7eN5bWaafOZgtmO3jMPwUqmrmEwinhPq1w==
+
+human-signals@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz"
+ integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
+
ignore@^5.2.0:
version "5.3.1"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef"
+ resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz"
integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==
immer@^10.0.3:
- version "10.0.4"
- resolved "https://registry.yarnpkg.com/immer/-/immer-10.0.4.tgz#09af41477236b99449f9d705369a4daaf780362b"
- integrity sha512-cuBuGK40P/sk5IzWa9QPUaAdvPHjkk1c+xYsd9oZw+YQQEV+10G0P5uMpGctZZKnyQ+ibRO08bD25nWLmYi2pw==
+ version "10.1.1"
+ resolved "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz"
+ integrity sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==
import-fresh@^3.2.1:
version "3.3.0"
- resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
+ resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz"
integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
dependencies:
parent-module "^1.0.0"
resolve-from "^4.0.0"
+import-local@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz"
+ integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==
+ dependencies:
+ pkg-dir "^4.2.0"
+ resolve-cwd "^3.0.0"
+
imurmurhash@^0.1.4:
version "0.1.4"
- resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+ resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz"
integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
inflight@^1.0.4:
version "1.0.6"
- resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz"
integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
dependencies:
once "^1.3.0"
@@ -1641,142 +3090,169 @@ inflight@^1.0.4:
inherits@2:
version "2.0.4"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+ resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
internal-slot@^1.0.7:
version "1.0.7"
- resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802"
+ resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz"
integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==
dependencies:
es-errors "^1.3.0"
hasown "^2.0.0"
side-channel "^1.0.4"
+invariant@^2.2.4:
+ version "2.2.4"
+ resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz"
+ integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
+ dependencies:
+ loose-envify "^1.0.0"
+
is-array-buffer@^3.0.4:
version "3.0.4"
- resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98"
+ resolved "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz"
integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==
dependencies:
call-bind "^1.0.2"
get-intrinsic "^1.2.1"
+is-arrayish@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz"
+ integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
+
is-async-function@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646"
+ resolved "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz"
integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==
dependencies:
has-tostringtag "^1.0.0"
is-bigint@^1.0.1:
version "1.0.4"
- resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
+ resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz"
integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==
dependencies:
has-bigints "^1.0.1"
is-binary-path@~2.1.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
+ resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz"
integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
dependencies:
binary-extensions "^2.0.0"
is-boolean-object@^1.1.0:
version "1.1.2"
- resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719"
+ resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz"
integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==
dependencies:
call-bind "^1.0.2"
has-tostringtag "^1.0.0"
+is-buffer@^2.0.0:
+ version "2.0.5"
+ resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz"
+ integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==
+
is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7:
version "1.2.7"
- resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
+ resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz"
integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.13.1:
version "2.13.1"
- resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384"
+ resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz"
integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==
dependencies:
hasown "^2.0.0"
is-data-view@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f"
+ resolved "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz"
integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==
dependencies:
is-typed-array "^1.1.13"
is-date-object@^1.0.1, is-date-object@^1.0.5:
version "1.0.5"
- resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f"
+ resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz"
integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==
dependencies:
has-tostringtag "^1.0.0"
is-extglob@^2.1.1:
version "2.1.1"
- resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+ resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz"
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
is-finalizationregistry@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz#c8749b65f17c133313e661b1289b95ad3dbd62e6"
+ resolved "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz"
integrity sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==
dependencies:
call-bind "^1.0.2"
is-fullwidth-code-point@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+ resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz"
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+is-generator-fn@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz"
+ integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==
+
is-generator-function@^1.0.10:
version "1.0.10"
- resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72"
+ resolved "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz"
integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==
dependencies:
has-tostringtag "^1.0.0"
is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
version "4.0.3"
- resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
+ resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz"
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
dependencies:
is-extglob "^2.1.1"
is-map@^2.0.3:
version "2.0.3"
- resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e"
+ resolved "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz"
integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==
is-negative-zero@^2.0.3:
version "2.0.3"
- resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747"
+ resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz"
integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==
is-number-object@^1.0.4:
version "1.0.7"
- resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc"
+ resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz"
integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==
dependencies:
has-tostringtag "^1.0.0"
is-number@^7.0.0:
version "7.0.0"
- resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+ resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
is-path-inside@^3.0.3:
version "3.0.3"
- resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
+ resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz"
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
+is-plain-obj@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz"
+ integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==
+
is-regex@^1.1.4:
version "1.1.4"
- resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958"
+ resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz"
integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
dependencies:
call-bind "^1.0.2"
@@ -1784,52 +3260,57 @@ is-regex@^1.1.4:
is-set@^2.0.3:
version "2.0.3"
- resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d"
+ resolved "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz"
integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==
is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3:
version "1.0.3"
- resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688"
+ resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz"
integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==
dependencies:
call-bind "^1.0.7"
+is-stream@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz"
+ integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
+
is-string@^1.0.5, is-string@^1.0.7:
version "1.0.7"
- resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd"
+ resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz"
integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==
dependencies:
has-tostringtag "^1.0.0"
is-symbol@^1.0.2, is-symbol@^1.0.3:
version "1.0.4"
- resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c"
+ resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz"
integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==
dependencies:
has-symbols "^1.0.2"
is-typed-array@^1.1.13:
version "1.1.13"
- resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229"
+ resolved "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz"
integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==
dependencies:
which-typed-array "^1.1.14"
is-weakmap@^2.0.2:
version "2.0.2"
- resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd"
+ resolved "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz"
integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==
is-weakref@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2"
+ resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz"
integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==
dependencies:
call-bind "^1.0.2"
is-weakset@^2.0.3:
version "2.0.3"
- resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.3.tgz#e801519df8c0c43e12ff2834eead84ec9e624007"
+ resolved "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz"
integrity sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==
dependencies:
call-bind "^1.0.7"
@@ -1837,17 +3318,75 @@ is-weakset@^2.0.3:
isarray@^2.0.5:
version "2.0.5"
- resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723"
+ resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz"
integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==
isexe@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+ resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
+isomorphic.js@^0.2.4:
+ version "0.2.5"
+ resolved "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz"
+ integrity sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==
+
+istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0:
+ version "3.2.2"
+ resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz"
+ integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==
+
+istanbul-lib-instrument@^5.0.4:
+ version "5.2.1"
+ resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz"
+ integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==
+ dependencies:
+ "@babel/core" "^7.12.3"
+ "@babel/parser" "^7.14.7"
+ "@istanbuljs/schema" "^0.1.2"
+ istanbul-lib-coverage "^3.2.0"
+ semver "^6.3.0"
+
+istanbul-lib-instrument@^6.0.0:
+ version "6.0.2"
+ resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz"
+ integrity sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==
+ dependencies:
+ "@babel/core" "^7.23.9"
+ "@babel/parser" "^7.23.9"
+ "@istanbuljs/schema" "^0.1.3"
+ istanbul-lib-coverage "^3.2.0"
+ semver "^7.5.4"
+
+istanbul-lib-report@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz"
+ integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==
+ dependencies:
+ istanbul-lib-coverage "^3.0.0"
+ make-dir "^4.0.0"
+ supports-color "^7.1.0"
+
+istanbul-lib-source-maps@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz"
+ integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==
+ dependencies:
+ debug "^4.1.1"
+ istanbul-lib-coverage "^3.0.0"
+ source-map "^0.6.1"
+
+istanbul-reports@^3.1.3:
+ version "3.1.7"
+ resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz"
+ integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==
+ dependencies:
+ html-escaper "^2.0.0"
+ istanbul-lib-report "^3.0.0"
+
iterator.prototype@^1.1.2:
version "1.1.2"
- resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0"
+ resolved "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz"
integrity sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==
dependencies:
define-properties "^1.2.1"
@@ -1858,7 +3397,7 @@ iterator.prototype@^1.1.2:
jackspeak@^2.3.5, jackspeak@^2.3.6:
version "2.3.6"
- resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8"
+ resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz"
integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==
dependencies:
"@isaacs/cliui" "^8.0.2"
@@ -1867,56 +3406,432 @@ jackspeak@^2.3.5, jackspeak@^2.3.6:
javascript-natural-sort@0.7.1:
version "0.7.1"
- resolved "https://registry.yarnpkg.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59"
+ resolved "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz"
integrity sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==
+jest-changed-files@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz"
+ integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==
+ dependencies:
+ execa "^5.0.0"
+ jest-util "^29.7.0"
+ p-limit "^3.1.0"
+
+jest-circus@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz"
+ integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==
+ dependencies:
+ "@jest/environment" "^29.7.0"
+ "@jest/expect" "^29.7.0"
+ "@jest/test-result" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ co "^4.6.0"
+ dedent "^1.0.0"
+ is-generator-fn "^2.0.0"
+ jest-each "^29.7.0"
+ jest-matcher-utils "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-runtime "^29.7.0"
+ jest-snapshot "^29.7.0"
+ jest-util "^29.7.0"
+ p-limit "^3.1.0"
+ pretty-format "^29.7.0"
+ pure-rand "^6.0.0"
+ slash "^3.0.0"
+ stack-utils "^2.0.3"
+
+jest-cli@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz"
+ integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==
+ dependencies:
+ "@jest/core" "^29.7.0"
+ "@jest/test-result" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ chalk "^4.0.0"
+ create-jest "^29.7.0"
+ exit "^0.1.2"
+ import-local "^3.0.2"
+ jest-config "^29.7.0"
+ jest-util "^29.7.0"
+ jest-validate "^29.7.0"
+ yargs "^17.3.1"
+
+jest-config@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz"
+ integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==
+ dependencies:
+ "@babel/core" "^7.11.6"
+ "@jest/test-sequencer" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ babel-jest "^29.7.0"
+ chalk "^4.0.0"
+ ci-info "^3.2.0"
+ deepmerge "^4.2.2"
+ glob "^7.1.3"
+ graceful-fs "^4.2.9"
+ jest-circus "^29.7.0"
+ jest-environment-node "^29.7.0"
+ jest-get-type "^29.6.3"
+ jest-regex-util "^29.6.3"
+ jest-resolve "^29.7.0"
+ jest-runner "^29.7.0"
+ jest-util "^29.7.0"
+ jest-validate "^29.7.0"
+ micromatch "^4.0.4"
+ parse-json "^5.2.0"
+ pretty-format "^29.7.0"
+ slash "^3.0.0"
+ strip-json-comments "^3.1.1"
+
+jest-diff@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz"
+ integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==
+ dependencies:
+ chalk "^4.0.0"
+ diff-sequences "^29.6.3"
+ jest-get-type "^29.6.3"
+ pretty-format "^29.7.0"
+
+jest-docblock@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz"
+ integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==
+ dependencies:
+ detect-newline "^3.0.0"
+
+jest-each@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz"
+ integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==
+ dependencies:
+ "@jest/types" "^29.6.3"
+ chalk "^4.0.0"
+ jest-get-type "^29.6.3"
+ jest-util "^29.7.0"
+ pretty-format "^29.7.0"
+
+jest-environment-node@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz"
+ integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==
+ dependencies:
+ "@jest/environment" "^29.7.0"
+ "@jest/fake-timers" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ jest-mock "^29.7.0"
+ jest-util "^29.7.0"
+
+jest-get-type@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz"
+ integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==
+
+jest-haste-map@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz"
+ integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==
+ dependencies:
+ "@jest/types" "^29.6.3"
+ "@types/graceful-fs" "^4.1.3"
+ "@types/node" "*"
+ anymatch "^3.0.3"
+ fb-watchman "^2.0.0"
+ graceful-fs "^4.2.9"
+ jest-regex-util "^29.6.3"
+ jest-util "^29.7.0"
+ jest-worker "^29.7.0"
+ micromatch "^4.0.4"
+ walker "^1.0.8"
+ optionalDependencies:
+ fsevents "^2.3.2"
+
+jest-leak-detector@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz"
+ integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==
+ dependencies:
+ jest-get-type "^29.6.3"
+ pretty-format "^29.7.0"
+
+jest-matcher-utils@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz"
+ integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==
+ dependencies:
+ chalk "^4.0.0"
+ jest-diff "^29.7.0"
+ jest-get-type "^29.6.3"
+ pretty-format "^29.7.0"
+
+jest-message-util@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz"
+ integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==
+ dependencies:
+ "@babel/code-frame" "^7.12.13"
+ "@jest/types" "^29.6.3"
+ "@types/stack-utils" "^2.0.0"
+ chalk "^4.0.0"
+ graceful-fs "^4.2.9"
+ micromatch "^4.0.4"
+ pretty-format "^29.7.0"
+ slash "^3.0.0"
+ stack-utils "^2.0.3"
+
+jest-mock@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz"
+ integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==
+ dependencies:
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ jest-util "^29.7.0"
+
+jest-pnp-resolver@^1.2.2:
+ version "1.2.3"
+ resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz"
+ integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==
+
+jest-regex-util@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz"
+ integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==
+
+jest-resolve-dependencies@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz"
+ integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==
+ dependencies:
+ jest-regex-util "^29.6.3"
+ jest-snapshot "^29.7.0"
+
+jest-resolve@*, jest-resolve@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz"
+ integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==
+ dependencies:
+ chalk "^4.0.0"
+ graceful-fs "^4.2.9"
+ jest-haste-map "^29.7.0"
+ jest-pnp-resolver "^1.2.2"
+ jest-util "^29.7.0"
+ jest-validate "^29.7.0"
+ resolve "^1.20.0"
+ resolve.exports "^2.0.0"
+ slash "^3.0.0"
+
+jest-runner@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz"
+ integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==
+ dependencies:
+ "@jest/console" "^29.7.0"
+ "@jest/environment" "^29.7.0"
+ "@jest/test-result" "^29.7.0"
+ "@jest/transform" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ emittery "^0.13.1"
+ graceful-fs "^4.2.9"
+ jest-docblock "^29.7.0"
+ jest-environment-node "^29.7.0"
+ jest-haste-map "^29.7.0"
+ jest-leak-detector "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-resolve "^29.7.0"
+ jest-runtime "^29.7.0"
+ jest-util "^29.7.0"
+ jest-watcher "^29.7.0"
+ jest-worker "^29.7.0"
+ p-limit "^3.1.0"
+ source-map-support "0.5.13"
+
+jest-runtime@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz"
+ integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==
+ dependencies:
+ "@jest/environment" "^29.7.0"
+ "@jest/fake-timers" "^29.7.0"
+ "@jest/globals" "^29.7.0"
+ "@jest/source-map" "^29.6.3"
+ "@jest/test-result" "^29.7.0"
+ "@jest/transform" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ cjs-module-lexer "^1.0.0"
+ collect-v8-coverage "^1.0.0"
+ glob "^7.1.3"
+ graceful-fs "^4.2.9"
+ jest-haste-map "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-mock "^29.7.0"
+ jest-regex-util "^29.6.3"
+ jest-resolve "^29.7.0"
+ jest-snapshot "^29.7.0"
+ jest-util "^29.7.0"
+ slash "^3.0.0"
+ strip-bom "^4.0.0"
+
+jest-snapshot@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz"
+ integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==
+ dependencies:
+ "@babel/core" "^7.11.6"
+ "@babel/generator" "^7.7.2"
+ "@babel/plugin-syntax-jsx" "^7.7.2"
+ "@babel/plugin-syntax-typescript" "^7.7.2"
+ "@babel/types" "^7.3.3"
+ "@jest/expect-utils" "^29.7.0"
+ "@jest/transform" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ babel-preset-current-node-syntax "^1.0.0"
+ chalk "^4.0.0"
+ expect "^29.7.0"
+ graceful-fs "^4.2.9"
+ jest-diff "^29.7.0"
+ jest-get-type "^29.6.3"
+ jest-matcher-utils "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-util "^29.7.0"
+ natural-compare "^1.4.0"
+ pretty-format "^29.7.0"
+ semver "^7.5.3"
+
+jest-util@^29.0.0, jest-util@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz"
+ integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==
+ dependencies:
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ ci-info "^3.2.0"
+ graceful-fs "^4.2.9"
+ picomatch "^2.2.3"
+
+jest-validate@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz"
+ integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==
+ dependencies:
+ "@jest/types" "^29.6.3"
+ camelcase "^6.2.0"
+ chalk "^4.0.0"
+ jest-get-type "^29.6.3"
+ leven "^3.1.0"
+ pretty-format "^29.7.0"
+
+jest-watcher@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz"
+ integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==
+ dependencies:
+ "@jest/test-result" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ ansi-escapes "^4.2.1"
+ chalk "^4.0.0"
+ emittery "^0.13.1"
+ jest-util "^29.7.0"
+ string-length "^4.0.1"
+
+jest-worker@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz"
+ integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==
+ dependencies:
+ "@types/node" "*"
+ jest-util "^29.7.0"
+ merge-stream "^2.0.0"
+ supports-color "^8.0.0"
+
+jest@^29.0.0, jest@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz"
+ integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==
+ dependencies:
+ "@jest/core" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ import-local "^3.0.2"
+ jest-cli "^29.7.0"
+
jiti@^1.21.0:
version "1.21.0"
- resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d"
+ resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz"
integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+ resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+js-yaml@^3.13.1:
+ version "3.14.1"
+ resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz"
+ integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
+ dependencies:
+ argparse "^1.0.7"
+ esprima "^4.0.0"
+
js-yaml@^4.1.0:
version "4.1.0"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
+ resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
dependencies:
argparse "^2.0.1"
jsesc@^2.5.1:
version "2.5.2"
- resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
+ resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz"
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
json-buffer@3.0.1:
version "3.0.1"
- resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
+ resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz"
integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
+json-parse-even-better-errors@^2.3.0:
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz"
+ integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
+
json-schema-traverse@^0.4.1:
version "0.4.1"
- resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+ resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json-stable-stringify-without-jsonify@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
+ resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz"
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
json5@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593"
+ resolved "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz"
integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==
dependencies:
minimist "^1.2.0"
+json5@^2.2.3:
+ version "2.2.3"
+ resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz"
+ integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
+
"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.5:
version "3.3.5"
- resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a"
+ resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz"
integrity sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==
dependencies:
array-includes "^3.1.6"
@@ -1926,139 +3841,669 @@ json5@^1.0.2:
keyv@^4.5.3:
version "4.5.4"
- resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
+ resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz"
integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
dependencies:
json-buffer "3.0.1"
+kleur@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz"
+ integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
+
+kleur@^4.0.3:
+ version "4.1.5"
+ resolved "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz"
+ integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==
+
language-subtag-registry@^0.3.20:
version "0.3.22"
- resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d"
+ resolved "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz"
integrity sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==
language-tags@^1.0.9:
version "1.0.9"
- resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.9.tgz#1ffdcd0ec0fafb4b1be7f8b11f306ad0f9c08777"
+ resolved "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz"
integrity sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==
dependencies:
language-subtag-registry "^0.3.20"
+leven@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz"
+ integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==
+
levn@^0.4.1:
version "0.4.1"
- resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
+ resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz"
integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
dependencies:
prelude-ls "^1.2.1"
type-check "~0.4.0"
+lib0@^0.2.42, lib0@^0.2.85, lib0@^0.2.86:
+ version "0.2.93"
+ resolved "https://registry.npmjs.org/lib0/-/lib0-0.2.93.tgz"
+ integrity sha512-M5IKsiFJYulS+8Eal8f+zAqf5ckm1vffW0fFDxfgxJ+uiVopvDdd3PxJmz0GsVi3YNO7QCFSq0nAsiDmNhLj9Q==
+ dependencies:
+ isomorphic.js "^0.2.4"
+
lilconfig@^2.1.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52"
+ resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz"
integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==
lilconfig@^3.0.0:
version "3.1.1"
- resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.1.tgz#9d8a246fa753106cfc205fd2d77042faca56e5e3"
+ resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz"
integrity sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==
lines-and-columns@^1.1.6:
version "1.2.4"
- resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
+ resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz"
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
+linkify-it@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz"
+ integrity sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==
+ dependencies:
+ uc.micro "^2.0.0"
+
+linkifyjs@^4.1.0:
+ version "4.1.3"
+ resolved "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.1.3.tgz"
+ integrity sha512-auMesunaJ8yfkHvK4gfg1K0SaKX/6Wn9g2Aac/NwX+l5VdmFZzo/hdPGxEOETj+ryRa4/fiOPjeeKURSAJx1sg==
+
+locate-path@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz"
+ integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
+ dependencies:
+ p-locate "^4.1.0"
+
locate-path@^6.0.0:
version "6.0.0"
- resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
+ resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz"
integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
dependencies:
p-locate "^5.0.0"
+lodash.memoize@4.x:
+ version "4.1.2"
+ resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz"
+ integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==
+
lodash.merge@^4.6.2:
version "4.6.2"
- resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
+ resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
lodash@^4.17.21:
version "4.17.21"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+ resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
-loose-envify@^1.1.0, loose-envify@^1.4.0:
+longest-streak@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz"
+ integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==
+
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
version "1.4.0"
- resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+ resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
lru-cache@^10.2.0:
- version "10.2.0"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3"
- integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==
+ version "10.2.2"
+ resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz"
+ integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==
+
+lru-cache@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz"
+ integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
+ dependencies:
+ yallist "^3.0.2"
lru-cache@^6.0.0:
version "6.0.0"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
+ resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"
+lucide-react@^0.378.0:
+ version "0.378.0"
+ resolved "https://registry.npmjs.org/lucide-react/-/lucide-react-0.378.0.tgz"
+ integrity sha512-u6EPU8juLUk9ytRcyapkWI18epAv3RU+6+TC23ivjR0e+glWKBobFeSgRwOIJihzktILQuy6E0E80P2jVTDR5g==
+
+make-dir@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz"
+ integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==
+ dependencies:
+ semver "^7.5.3"
+
+make-error@1.x:
+ version "1.3.6"
+ resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz"
+ integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
+
+makeerror@1.0.12:
+ version "1.0.12"
+ resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz"
+ integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==
+ dependencies:
+ tmpl "1.0.5"
+
+markdown-it@^14.0.0:
+ version "14.1.0"
+ resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz"
+ integrity sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==
+ dependencies:
+ argparse "^2.0.1"
+ entities "^4.4.0"
+ linkify-it "^5.0.0"
+ mdurl "^2.0.0"
+ punycode.js "^2.3.1"
+ uc.micro "^2.1.0"
+
+markdown-table@^3.0.0:
+ version "3.0.3"
+ resolved "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz"
+ integrity sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==
+
+mdast-util-definitions@^5.0.0:
+ version "5.1.2"
+ resolved "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz"
+ integrity sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==
+ dependencies:
+ "@types/mdast" "^3.0.0"
+ "@types/unist" "^2.0.0"
+ unist-util-visit "^4.0.0"
+
+mdast-util-find-and-replace@^2.0.0:
+ version "2.2.2"
+ resolved "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.2.2.tgz"
+ integrity sha512-MTtdFRz/eMDHXzeK6W3dO7mXUlF82Gom4y0oOgvHhh/HXZAGvIQDUvQ0SuUx+j2tv44b8xTHOm8K/9OoRFnXKw==
+ dependencies:
+ "@types/mdast" "^3.0.0"
+ escape-string-regexp "^5.0.0"
+ unist-util-is "^5.0.0"
+ unist-util-visit-parents "^5.0.0"
+
+mdast-util-from-markdown@^1.0.0:
+ version "1.3.1"
+ resolved "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz"
+ integrity sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==
+ dependencies:
+ "@types/mdast" "^3.0.0"
+ "@types/unist" "^2.0.0"
+ decode-named-character-reference "^1.0.0"
+ mdast-util-to-string "^3.1.0"
+ micromark "^3.0.0"
+ micromark-util-decode-numeric-character-reference "^1.0.0"
+ micromark-util-decode-string "^1.0.0"
+ micromark-util-normalize-identifier "^1.0.0"
+ micromark-util-symbol "^1.0.0"
+ micromark-util-types "^1.0.0"
+ unist-util-stringify-position "^3.0.0"
+ uvu "^0.5.0"
+
+mdast-util-gfm-autolink-literal@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.3.tgz"
+ integrity sha512-My8KJ57FYEy2W2LyNom4n3E7hKTuQk/0SES0u16tjA9Z3oFkF4RrC/hPAPgjlSpezsOvI8ObcXcElo92wn5IGA==
+ dependencies:
+ "@types/mdast" "^3.0.0"
+ ccount "^2.0.0"
+ mdast-util-find-and-replace "^2.0.0"
+ micromark-util-character "^1.0.0"
+
+mdast-util-gfm-footnote@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.2.tgz"
+ integrity sha512-56D19KOGbE00uKVj3sgIykpwKL179QsVFwx/DCW0u/0+URsryacI4MAdNJl0dh+u2PSsD9FtxPFbHCzJ78qJFQ==
+ dependencies:
+ "@types/mdast" "^3.0.0"
+ mdast-util-to-markdown "^1.3.0"
+ micromark-util-normalize-identifier "^1.0.0"
+
+mdast-util-gfm-strikethrough@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.3.tgz"
+ integrity sha512-DAPhYzTYrRcXdMjUtUjKvW9z/FNAMTdU0ORyMcbmkwYNbKocDpdk+PX1L1dQgOID/+vVs1uBQ7ElrBQfZ0cuiQ==
+ dependencies:
+ "@types/mdast" "^3.0.0"
+ mdast-util-to-markdown "^1.3.0"
+
+mdast-util-gfm-table@^1.0.0:
+ version "1.0.7"
+ resolved "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.7.tgz"
+ integrity sha512-jjcpmNnQvrmN5Vx7y7lEc2iIOEytYv7rTvu+MeyAsSHTASGCCRA79Igg2uKssgOs1i1po8s3plW0sTu1wkkLGg==
+ dependencies:
+ "@types/mdast" "^3.0.0"
+ markdown-table "^3.0.0"
+ mdast-util-from-markdown "^1.0.0"
+ mdast-util-to-markdown "^1.3.0"
+
+mdast-util-gfm-task-list-item@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.2.tgz"
+ integrity sha512-PFTA1gzfp1B1UaiJVyhJZA1rm0+Tzn690frc/L8vNX1Jop4STZgOE6bxUhnzdVSB+vm2GU1tIsuQcA9bxTQpMQ==
+ dependencies:
+ "@types/mdast" "^3.0.0"
+ mdast-util-to-markdown "^1.3.0"
+
+mdast-util-gfm@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-2.0.2.tgz"
+ integrity sha512-qvZ608nBppZ4icQlhQQIAdc6S3Ffj9RGmzwUKUWuEICFnd1LVkN3EktF7ZHAgfcEdvZB5owU9tQgt99e2TlLjg==
+ dependencies:
+ mdast-util-from-markdown "^1.0.0"
+ mdast-util-gfm-autolink-literal "^1.0.0"
+ mdast-util-gfm-footnote "^1.0.0"
+ mdast-util-gfm-strikethrough "^1.0.0"
+ mdast-util-gfm-table "^1.0.0"
+ mdast-util-gfm-task-list-item "^1.0.0"
+ mdast-util-to-markdown "^1.0.0"
+
+mdast-util-phrasing@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-3.0.1.tgz"
+ integrity sha512-WmI1gTXUBJo4/ZmSk79Wcb2HcjPJBzM1nlI/OUWA8yk2X9ik3ffNbBGsU+09BFmXaL1IBb9fiuvq6/KMiNycSg==
+ dependencies:
+ "@types/mdast" "^3.0.0"
+ unist-util-is "^5.0.0"
+
+mdast-util-to-hast@^12.1.0:
+ version "12.3.0"
+ resolved "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.3.0.tgz"
+ integrity sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw==
+ dependencies:
+ "@types/hast" "^2.0.0"
+ "@types/mdast" "^3.0.0"
+ mdast-util-definitions "^5.0.0"
+ micromark-util-sanitize-uri "^1.1.0"
+ trim-lines "^3.0.0"
+ unist-util-generated "^2.0.0"
+ unist-util-position "^4.0.0"
+ unist-util-visit "^4.0.0"
+
+mdast-util-to-markdown@^1.0.0, mdast-util-to-markdown@^1.3.0:
+ version "1.5.0"
+ resolved "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.5.0.tgz"
+ integrity sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==
+ dependencies:
+ "@types/mdast" "^3.0.0"
+ "@types/unist" "^2.0.0"
+ longest-streak "^3.0.0"
+ mdast-util-phrasing "^3.0.0"
+ mdast-util-to-string "^3.0.0"
+ micromark-util-decode-string "^1.0.0"
+ unist-util-visit "^4.0.0"
+ zwitch "^2.0.0"
+
+mdast-util-to-string@^3.0.0, mdast-util-to-string@^3.1.0:
+ version "3.2.0"
+ resolved "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz"
+ integrity sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==
+ dependencies:
+ "@types/mdast" "^3.0.0"
+
+mdurl@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz"
+ integrity sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==
+
+merge-stream@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz"
+ integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
+
merge2@^1.3.0, merge2@^1.4.1:
version "1.4.1"
- resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
+ resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+micromark-core-commonmark@^1.0.0, micromark-core-commonmark@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz"
+ integrity sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==
+ dependencies:
+ decode-named-character-reference "^1.0.0"
+ micromark-factory-destination "^1.0.0"
+ micromark-factory-label "^1.0.0"
+ micromark-factory-space "^1.0.0"
+ micromark-factory-title "^1.0.0"
+ micromark-factory-whitespace "^1.0.0"
+ micromark-util-character "^1.0.0"
+ micromark-util-chunked "^1.0.0"
+ micromark-util-classify-character "^1.0.0"
+ micromark-util-html-tag-name "^1.0.0"
+ micromark-util-normalize-identifier "^1.0.0"
+ micromark-util-resolve-all "^1.0.0"
+ micromark-util-subtokenize "^1.0.0"
+ micromark-util-symbol "^1.0.0"
+ micromark-util-types "^1.0.1"
+ uvu "^0.5.0"
+
+micromark-extension-gfm-autolink-literal@^1.0.0:
+ version "1.0.5"
+ resolved "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.5.tgz"
+ integrity sha512-z3wJSLrDf8kRDOh2qBtoTRD53vJ+CWIyo7uyZuxf/JAbNJjiHsOpG1y5wxk8drtv3ETAHutCu6N3thkOOgueWg==
+ dependencies:
+ micromark-util-character "^1.0.0"
+ micromark-util-sanitize-uri "^1.0.0"
+ micromark-util-symbol "^1.0.0"
+ micromark-util-types "^1.0.0"
+
+micromark-extension-gfm-footnote@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.1.2.tgz"
+ integrity sha512-Yxn7z7SxgyGWRNa4wzf8AhYYWNrwl5q1Z8ii+CSTTIqVkmGZF1CElX2JI8g5yGoM3GAman9/PVCUFUSJ0kB/8Q==
+ dependencies:
+ micromark-core-commonmark "^1.0.0"
+ micromark-factory-space "^1.0.0"
+ micromark-util-character "^1.0.0"
+ micromark-util-normalize-identifier "^1.0.0"
+ micromark-util-sanitize-uri "^1.0.0"
+ micromark-util-symbol "^1.0.0"
+ micromark-util-types "^1.0.0"
+ uvu "^0.5.0"
+
+micromark-extension-gfm-strikethrough@^1.0.0:
+ version "1.0.7"
+ resolved "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.7.tgz"
+ integrity sha512-sX0FawVE1o3abGk3vRjOH50L5TTLr3b5XMqnP9YDRb34M0v5OoZhG+OHFz1OffZ9dlwgpTBKaT4XW/AsUVnSDw==
+ dependencies:
+ micromark-util-chunked "^1.0.0"
+ micromark-util-classify-character "^1.0.0"
+ micromark-util-resolve-all "^1.0.0"
+ micromark-util-symbol "^1.0.0"
+ micromark-util-types "^1.0.0"
+ uvu "^0.5.0"
+
+micromark-extension-gfm-table@^1.0.0:
+ version "1.0.7"
+ resolved "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.7.tgz"
+ integrity sha512-3ZORTHtcSnMQEKtAOsBQ9/oHp9096pI/UvdPtN7ehKvrmZZ2+bbWhi0ln+I9drmwXMt5boocn6OlwQzNXeVeqw==
+ dependencies:
+ micromark-factory-space "^1.0.0"
+ micromark-util-character "^1.0.0"
+ micromark-util-symbol "^1.0.0"
+ micromark-util-types "^1.0.0"
+ uvu "^0.5.0"
+
+micromark-extension-gfm-tagfilter@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.2.tgz"
+ integrity sha512-5XWB9GbAUSHTn8VPU8/1DBXMuKYT5uOgEjJb8gN3mW0PNW5OPHpSdojoqf+iq1xo7vWzw/P8bAHY0n6ijpXF7g==
+ dependencies:
+ micromark-util-types "^1.0.0"
+
+micromark-extension-gfm-task-list-item@^1.0.0:
+ version "1.0.5"
+ resolved "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.5.tgz"
+ integrity sha512-RMFXl2uQ0pNQy6Lun2YBYT9g9INXtWJULgbt01D/x8/6yJ2qpKyzdZD3pi6UIkzF++Da49xAelVKUeUMqd5eIQ==
+ dependencies:
+ micromark-factory-space "^1.0.0"
+ micromark-util-character "^1.0.0"
+ micromark-util-symbol "^1.0.0"
+ micromark-util-types "^1.0.0"
+ uvu "^0.5.0"
+
+micromark-extension-gfm@^2.0.0:
+ version "2.0.3"
+ resolved "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-2.0.3.tgz"
+ integrity sha512-vb9OoHqrhCmbRidQv/2+Bc6pkP0FrtlhurxZofvOEy5o8RtuuvTq+RQ1Vw5ZDNrVraQZu3HixESqbG+0iKk/MQ==
+ dependencies:
+ micromark-extension-gfm-autolink-literal "^1.0.0"
+ micromark-extension-gfm-footnote "^1.0.0"
+ micromark-extension-gfm-strikethrough "^1.0.0"
+ micromark-extension-gfm-table "^1.0.0"
+ micromark-extension-gfm-tagfilter "^1.0.0"
+ micromark-extension-gfm-task-list-item "^1.0.0"
+ micromark-util-combine-extensions "^1.0.0"
+ micromark-util-types "^1.0.0"
+
+micromark-factory-destination@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz"
+ integrity sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==
+ dependencies:
+ micromark-util-character "^1.0.0"
+ micromark-util-symbol "^1.0.0"
+ micromark-util-types "^1.0.0"
+
+micromark-factory-label@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz"
+ integrity sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==
+ dependencies:
+ micromark-util-character "^1.0.0"
+ micromark-util-symbol "^1.0.0"
+ micromark-util-types "^1.0.0"
+ uvu "^0.5.0"
+
+micromark-factory-space@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz"
+ integrity sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==
+ dependencies:
+ micromark-util-character "^1.0.0"
+ micromark-util-types "^1.0.0"
+
+micromark-factory-title@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz"
+ integrity sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==
+ dependencies:
+ micromark-factory-space "^1.0.0"
+ micromark-util-character "^1.0.0"
+ micromark-util-symbol "^1.0.0"
+ micromark-util-types "^1.0.0"
+
+micromark-factory-whitespace@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz"
+ integrity sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==
+ dependencies:
+ micromark-factory-space "^1.0.0"
+ micromark-util-character "^1.0.0"
+ micromark-util-symbol "^1.0.0"
+ micromark-util-types "^1.0.0"
+
+micromark-util-character@^1.0.0:
+ version "1.2.0"
+ resolved "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz"
+ integrity sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==
+ dependencies:
+ micromark-util-symbol "^1.0.0"
+ micromark-util-types "^1.0.0"
+
+micromark-util-chunked@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz"
+ integrity sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==
+ dependencies:
+ micromark-util-symbol "^1.0.0"
+
+micromark-util-classify-character@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz"
+ integrity sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==
+ dependencies:
+ micromark-util-character "^1.0.0"
+ micromark-util-symbol "^1.0.0"
+ micromark-util-types "^1.0.0"
+
+micromark-util-combine-extensions@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz"
+ integrity sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==
+ dependencies:
+ micromark-util-chunked "^1.0.0"
+ micromark-util-types "^1.0.0"
+
+micromark-util-decode-numeric-character-reference@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz"
+ integrity sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==
+ dependencies:
+ micromark-util-symbol "^1.0.0"
+
+micromark-util-decode-string@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz"
+ integrity sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==
+ dependencies:
+ decode-named-character-reference "^1.0.0"
+ micromark-util-character "^1.0.0"
+ micromark-util-decode-numeric-character-reference "^1.0.0"
+ micromark-util-symbol "^1.0.0"
+
+micromark-util-encode@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz"
+ integrity sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==
+
+micromark-util-html-tag-name@^1.0.0:
+ version "1.2.0"
+ resolved "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz"
+ integrity sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==
+
+micromark-util-normalize-identifier@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz"
+ integrity sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==
+ dependencies:
+ micromark-util-symbol "^1.0.0"
+
+micromark-util-resolve-all@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz"
+ integrity sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==
+ dependencies:
+ micromark-util-types "^1.0.0"
+
+micromark-util-sanitize-uri@^1.0.0, micromark-util-sanitize-uri@^1.1.0:
+ version "1.2.0"
+ resolved "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz"
+ integrity sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==
+ dependencies:
+ micromark-util-character "^1.0.0"
+ micromark-util-encode "^1.0.0"
+ micromark-util-symbol "^1.0.0"
+
+micromark-util-subtokenize@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz"
+ integrity sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==
+ dependencies:
+ micromark-util-chunked "^1.0.0"
+ micromark-util-symbol "^1.0.0"
+ micromark-util-types "^1.0.0"
+ uvu "^0.5.0"
+
+micromark-util-symbol@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz"
+ integrity sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==
+
+micromark-util-types@^1.0.0, micromark-util-types@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz"
+ integrity sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==
+
+micromark@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz"
+ integrity sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==
+ dependencies:
+ "@types/debug" "^4.0.0"
+ debug "^4.0.0"
+ decode-named-character-reference "^1.0.0"
+ micromark-core-commonmark "^1.0.1"
+ micromark-factory-space "^1.0.0"
+ micromark-util-character "^1.0.0"
+ micromark-util-chunked "^1.0.0"
+ micromark-util-combine-extensions "^1.0.0"
+ micromark-util-decode-numeric-character-reference "^1.0.0"
+ micromark-util-encode "^1.0.0"
+ micromark-util-normalize-identifier "^1.0.0"
+ micromark-util-resolve-all "^1.0.0"
+ micromark-util-sanitize-uri "^1.0.0"
+ micromark-util-subtokenize "^1.0.0"
+ micromark-util-symbol "^1.0.0"
+ micromark-util-types "^1.0.1"
+ uvu "^0.5.0"
+
micromatch@^4.0.4, micromatch@^4.0.5:
version "4.0.5"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
+ resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz"
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
dependencies:
braces "^3.0.2"
picomatch "^2.3.1"
-minimatch@9.0.3:
- version "9.0.3"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825"
- integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==
- dependencies:
- brace-expansion "^2.0.1"
+mimic-fn@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz"
+ integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
-minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
+minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
version "3.1.2"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+ resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
minimatch@^9.0.1:
version "9.0.4"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51"
+ resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz"
integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==
dependencies:
brace-expansion "^2.0.1"
+minimatch@9.0.3:
+ version "9.0.3"
+ resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz"
+ integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==
+ dependencies:
+ brace-expansion "^2.0.1"
+
minimist@^1.2.0, minimist@^1.2.6:
version "1.2.8"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
+ resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4:
- version "7.0.4"
- resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c"
- integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==
+ version "7.1.0"
+ resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.0.tgz"
+ integrity sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig==
-ms@2.1.2:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
- integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+mri@^1.1.0:
+ version "1.2.0"
+ resolved "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz"
+ integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==
ms@^2.1.1:
version "2.1.3"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+ resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+ms@2.1.2:
+ version "2.1.2"
+ resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
+ integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
mz@^2.7.0:
version "2.7.0"
- resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
+ resolved "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz"
integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==
dependencies:
any-promise "^1.0.0"
@@ -2067,20 +4512,20 @@ mz@^2.7.0:
nanoid@^3.3.6, nanoid@^3.3.7:
version "3.3.7"
- resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
+ resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz"
integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
natural-compare@^1.4.0:
version "1.4.0"
- resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+ resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz"
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
-next@14.2.2:
- version "14.2.2"
- resolved "https://registry.yarnpkg.com/next/-/next-14.2.2.tgz#707311b5e4bf973ada2305233f322bdd0cd9d579"
- integrity sha512-oGwUaa2bCs47FbuxWMpOoXtBMPYpvTPgdZr3UAo+pu7Ns00z9otmYpoeV1HEiYL06AlRQQIA/ypK526KjJfaxg==
+next@14.2.3:
+ version "14.2.3"
+ resolved "https://registry.npmjs.org/next/-/next-14.2.3.tgz"
+ integrity sha512-dowFkFTR8v79NPJO4QsBUtxv0g9BrS/phluVpMAt2ku7H+cbcBJlopXjkWlwxrk/xGqMemr7JkGPGemPrLLX7A==
dependencies:
- "@next/env" "14.2.2"
+ "@next/env" "14.2.3"
"@swc/helpers" "0.5.5"
busboy "1.6.0"
caniuse-lite "^1.0.30001579"
@@ -2088,54 +4533,66 @@ next@14.2.2:
postcss "8.4.31"
styled-jsx "5.1.1"
optionalDependencies:
- "@next/swc-darwin-arm64" "14.2.2"
- "@next/swc-darwin-x64" "14.2.2"
- "@next/swc-linux-arm64-gnu" "14.2.2"
- "@next/swc-linux-arm64-musl" "14.2.2"
- "@next/swc-linux-x64-gnu" "14.2.2"
- "@next/swc-linux-x64-musl" "14.2.2"
- "@next/swc-win32-arm64-msvc" "14.2.2"
- "@next/swc-win32-ia32-msvc" "14.2.2"
- "@next/swc-win32-x64-msvc" "14.2.2"
+ "@next/swc-darwin-arm64" "14.2.3"
+ "@next/swc-darwin-x64" "14.2.3"
+ "@next/swc-linux-arm64-gnu" "14.2.3"
+ "@next/swc-linux-arm64-musl" "14.2.3"
+ "@next/swc-linux-x64-gnu" "14.2.3"
+ "@next/swc-linux-x64-musl" "14.2.3"
+ "@next/swc-win32-arm64-msvc" "14.2.3"
+ "@next/swc-win32-ia32-msvc" "14.2.3"
+ "@next/swc-win32-x64-msvc" "14.2.3"
+
+node-int64@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz"
+ integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==
node-releases@^2.0.14:
version "2.0.14"
- resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b"
+ resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz"
integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==
normalize-path@^3.0.0, normalize-path@~3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+ resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
normalize-range@^0.1.2:
version "0.1.2"
- resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
+ resolved "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz"
integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==
+npm-run-path@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz"
+ integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
+ dependencies:
+ path-key "^3.0.0"
+
object-assign@^4.0.1, object-assign@^4.1.1:
version "4.1.1"
- resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+ resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
object-hash@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9"
+ resolved "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz"
integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==
object-inspect@^1.13.1:
version "1.13.1"
- resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2"
+ resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz"
integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==
object-keys@^1.1.1:
version "1.1.1"
- resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
+ resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz"
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
object.assign@^4.1.4, object.assign@^4.1.5:
version "4.1.5"
- resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0"
+ resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz"
integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==
dependencies:
call-bind "^1.0.5"
@@ -2145,7 +4602,7 @@ object.assign@^4.1.4, object.assign@^4.1.5:
object.entries@^1.1.7:
version "1.1.8"
- resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.8.tgz#bffe6f282e01f4d17807204a24f8edd823599c41"
+ resolved "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz"
integrity sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==
dependencies:
call-bind "^1.0.7"
@@ -2154,7 +4611,7 @@ object.entries@^1.1.7:
object.fromentries@^2.0.7:
version "2.0.8"
- resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65"
+ resolved "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz"
integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==
dependencies:
call-bind "^1.0.7"
@@ -2164,7 +4621,7 @@ object.fromentries@^2.0.7:
object.groupby@^1.0.1:
version "1.0.3"
- resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e"
+ resolved "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz"
integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==
dependencies:
call-bind "^1.0.7"
@@ -2173,7 +4630,7 @@ object.groupby@^1.0.1:
object.hasown@^1.1.3:
version "1.1.4"
- resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.4.tgz#e270ae377e4c120cdcb7656ce66884a6218283dc"
+ resolved "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz"
integrity sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==
dependencies:
define-properties "^1.2.1"
@@ -2182,7 +4639,7 @@ object.hasown@^1.1.3:
object.values@^1.1.6, object.values@^1.1.7:
version "1.2.0"
- resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b"
+ resolved "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz"
integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==
dependencies:
call-bind "^1.0.7"
@@ -2191,67 +4648,113 @@ object.values@^1.1.6, object.values@^1.1.7:
once@^1.3.0:
version "1.4.0"
- resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
dependencies:
wrappy "1"
+onetime@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz"
+ integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
+ dependencies:
+ mimic-fn "^2.1.0"
+
optionator@^0.9.3:
- version "0.9.3"
- resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64"
- integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==
+ version "0.9.4"
+ resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz"
+ integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==
dependencies:
- "@aashutoshrathi/word-wrap" "^1.2.3"
deep-is "^0.1.3"
fast-levenshtein "^2.0.6"
levn "^0.4.1"
prelude-ls "^1.2.1"
type-check "^0.4.0"
+ word-wrap "^1.2.5"
+
+orderedmap@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz"
+ integrity sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==
-p-limit@^3.0.2:
+p-limit@^2.2.0:
+ version "2.3.0"
+ resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz"
+ integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
+ dependencies:
+ p-try "^2.0.0"
+
+p-limit@^3.0.2, p-limit@^3.1.0:
version "3.1.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
+ resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz"
integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
dependencies:
yocto-queue "^0.1.0"
+p-locate@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz"
+ integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
+ dependencies:
+ p-limit "^2.2.0"
+
p-locate@^5.0.0:
version "5.0.0"
- resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
+ resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz"
integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
dependencies:
p-limit "^3.0.2"
+p-try@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz"
+ integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+
parent-module@^1.0.0:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+ resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz"
integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
dependencies:
callsites "^3.0.0"
+parse-json@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz"
+ integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ error-ex "^1.3.1"
+ json-parse-even-better-errors "^2.3.0"
+ lines-and-columns "^1.1.6"
+
+parse5@^6.0.0:
+ version "6.0.1"
+ resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz"
+ integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
+
path-exists@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
+ resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz"
integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
path-is-absolute@^1.0.0:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+ resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz"
integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
-path-key@^3.1.0:
+path-key@^3.0.0, path-key@^3.1.0:
version "3.1.1"
- resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
+ resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
path-parse@^1.0.7:
version "1.0.7"
- resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+ resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
path-scurry@^1.10.1, path-scurry@^1.10.2:
version "1.10.2"
- resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.2.tgz#8f6357eb1239d5fa1da8b9f70e9c080675458ba7"
+ resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz"
integrity sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==
dependencies:
lru-cache "^10.2.0"
@@ -2259,37 +4762,44 @@ path-scurry@^1.10.1, path-scurry@^1.10.2:
path-type@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
+ resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
picocolors@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
+ resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
-picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
+picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1:
version "2.3.1"
- resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+ resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
pify@^2.3.0:
version "2.3.0"
- resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+ resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz"
integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==
-pirates@^4.0.1:
+pirates@^4.0.1, pirates@^4.0.4:
version "4.0.6"
- resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9"
+ resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz"
integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==
+pkg-dir@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz"
+ integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
+ dependencies:
+ find-up "^4.0.0"
+
possible-typed-array-names@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f"
+ resolved "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz"
integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==
postcss-import@^15.1.0:
version "15.1.0"
- resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-15.1.0.tgz#41c64ed8cc0e23735a9698b3249ffdbf704adc70"
+ resolved "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz"
integrity sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==
dependencies:
postcss-value-parser "^4.0.0"
@@ -2298,14 +4808,14 @@ postcss-import@^15.1.0:
postcss-js@^4.0.1:
version "4.0.1"
- resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2"
+ resolved "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz"
integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==
dependencies:
camelcase-css "^2.0.1"
postcss-load-config@^4.0.1:
version "4.0.2"
- resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.2.tgz#7159dcf626118d33e299f485d6afe4aff7c4a3e3"
+ resolved "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz"
integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==
dependencies:
lilconfig "^3.0.0"
@@ -2313,14 +4823,14 @@ postcss-load-config@^4.0.1:
postcss-nested@^6.0.1:
version "6.0.1"
- resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.0.1.tgz#f83dc9846ca16d2f4fa864f16e9d9f7d0961662c"
+ resolved "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz"
integrity sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==
dependencies:
postcss-selector-parser "^6.0.11"
postcss-selector-parser@^6.0.11:
version "6.0.16"
- resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz#3b88b9f5c5abd989ef4e2fc9ec8eedd34b20fb04"
+ resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz"
integrity sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==
dependencies:
cssesc "^3.0.0"
@@ -2328,118 +4838,362 @@ postcss-selector-parser@^6.0.11:
postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0:
version "4.2.0"
- resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
+ resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
+postcss@^8, postcss@^8.0.0, postcss@^8.1.0, postcss@^8.2.14, postcss@^8.4.21, postcss@^8.4.23, postcss@>=8.0.9:
+ version "8.4.38"
+ resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz"
+ integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==
+ dependencies:
+ nanoid "^3.3.7"
+ picocolors "^1.0.0"
+ source-map-js "^1.2.0"
+
postcss@8.4.31:
version "8.4.31"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d"
+ resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz"
integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==
dependencies:
nanoid "^3.3.6"
picocolors "^1.0.0"
source-map-js "^1.0.2"
-postcss@^8, postcss@^8.4.23:
- version "8.4.38"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.38.tgz#b387d533baf2054288e337066d81c6bee9db9e0e"
- integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==
- dependencies:
- nanoid "^3.3.7"
- picocolors "^1.0.0"
- source-map-js "^1.2.0"
-
prelude-ls@^1.2.1:
version "1.2.1"
- resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
+ resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
prettier-linter-helpers@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b"
+ resolved "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz"
integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==
dependencies:
fast-diff "^1.1.2"
-prettier@^3.2.4:
+prettier@^3.2.4, prettier@>=3.0.0, "prettier@2.x - 3.x":
version "3.2.5"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368"
+ resolved "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz"
integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==
-prop-types@^15.8.1:
+pretty-format@^29.0.0, pretty-format@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz"
+ integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==
+ dependencies:
+ "@jest/schemas" "^29.6.3"
+ ansi-styles "^5.0.0"
+ react-is "^18.0.0"
+
+prompts@^2.0.1:
+ version "2.4.2"
+ resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz"
+ integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==
+ dependencies:
+ kleur "^3.0.3"
+ sisteransi "^1.0.5"
+
+prop-types@^15.7.2, prop-types@^15.8.1:
version "15.8.1"
- resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
+ resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
dependencies:
loose-envify "^1.4.0"
object-assign "^4.1.1"
react-is "^16.13.1"
+property-information@^6.0.0:
+ version "6.5.0"
+ resolved "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz"
+ integrity sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==
+
+prosemirror-changeset@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.2.1.tgz"
+ integrity sha512-J7msc6wbxB4ekDFj+n9gTW/jav/p53kdlivvuppHsrZXCaQdVgRghoZbSS3kwrRyAstRVQ4/+u5k7YfLgkkQvQ==
+ dependencies:
+ prosemirror-transform "^1.0.0"
+
+prosemirror-collab@^1.3.1:
+ version "1.3.1"
+ resolved "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz"
+ integrity sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==
+ dependencies:
+ prosemirror-state "^1.0.0"
+
+prosemirror-commands@^1.0.0, prosemirror-commands@^1.5.2:
+ version "1.5.2"
+ resolved "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.5.2.tgz"
+ integrity sha512-hgLcPaakxH8tu6YvVAaILV2tXYsW3rAdDR8WNkeKGcgeMVQg3/TMhPdVoh7iAmfgVjZGtcOSjKiQaoeKjzd2mQ==
+ dependencies:
+ prosemirror-model "^1.0.0"
+ prosemirror-state "^1.0.0"
+ prosemirror-transform "^1.0.0"
+
+prosemirror-dropcursor@^1.8.1:
+ version "1.8.1"
+ resolved "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.1.tgz"
+ integrity sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==
+ dependencies:
+ prosemirror-state "^1.0.0"
+ prosemirror-transform "^1.1.0"
+ prosemirror-view "^1.1.0"
+
+prosemirror-gapcursor@^1.3.2:
+ version "1.3.2"
+ resolved "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.3.2.tgz"
+ integrity sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==
+ dependencies:
+ prosemirror-keymap "^1.0.0"
+ prosemirror-model "^1.0.0"
+ prosemirror-state "^1.0.0"
+ prosemirror-view "^1.0.0"
+
+prosemirror-history@^1.0.0, prosemirror-history@^1.3.2:
+ version "1.4.0"
+ resolved "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.4.0.tgz"
+ integrity sha512-UUiGzDVcqo1lovOPdi9YxxUps3oBFWAIYkXLu3Ot+JPv1qzVogRbcizxK3LhHmtaUxclohgiOVesRw5QSlMnbQ==
+ dependencies:
+ prosemirror-state "^1.2.2"
+ prosemirror-transform "^1.0.0"
+ prosemirror-view "^1.31.0"
+ rope-sequence "^1.3.0"
+
+prosemirror-inputrules@^1.3.0:
+ version "1.4.0"
+ resolved "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.4.0.tgz"
+ integrity sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==
+ dependencies:
+ prosemirror-state "^1.0.0"
+ prosemirror-transform "^1.0.0"
+
+prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.1.2, prosemirror-keymap@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.2.tgz"
+ integrity sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==
+ dependencies:
+ prosemirror-state "^1.0.0"
+ w3c-keyname "^2.2.0"
+
+prosemirror-markdown@^1.12.0:
+ version "1.12.0"
+ resolved "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.12.0.tgz"
+ integrity sha512-6F5HS8Z0HDYiS2VQDZzfZP6A0s/I0gbkJy8NCzzDMtcsz3qrfqyroMMeoSjAmOhDITyon11NbXSzztfKi+frSQ==
+ dependencies:
+ markdown-it "^14.0.0"
+ prosemirror-model "^1.0.0"
+
+prosemirror-menu@^1.2.4:
+ version "1.2.4"
+ resolved "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.2.4.tgz"
+ integrity sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==
+ dependencies:
+ crelt "^1.0.0"
+ prosemirror-commands "^1.0.0"
+ prosemirror-history "^1.0.0"
+ prosemirror-state "^1.0.0"
+
+prosemirror-model@^1.0.0, prosemirror-model@^1.18.3, prosemirror-model@^1.19.0, prosemirror-model@^1.19.4, prosemirror-model@^1.20.0, prosemirror-model@^1.21.0, prosemirror-model@^1.7.1, prosemirror-model@^1.8.1:
+ version "1.21.0"
+ resolved "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.21.0.tgz"
+ integrity sha512-zLpS1mVCZLA7VTp82P+BfMiYVPcX1/z0Mf3gsjKZtzMWubwn2pN7CceMV0DycjlgE5JeXPR7UF4hJPbBV98oWA==
+ dependencies:
+ orderedmap "^2.0.0"
+
+prosemirror-schema-basic@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.2.tgz"
+ integrity sha512-/dT4JFEGyO7QnNTe9UaKUhjDXbTNkiWTq/N4VpKaF79bBjSExVV2NXmJpcM7z/gD7mbqNjxbmWW5nf1iNSSGnw==
+ dependencies:
+ prosemirror-model "^1.19.0"
+
+prosemirror-schema-list@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.3.0.tgz"
+ integrity sha512-Hz/7gM4skaaYfRPNgr421CU4GSwotmEwBVvJh5ltGiffUJwm7C8GfN/Bc6DR1EKEp5pDKhODmdXXyi9uIsZl5A==
+ dependencies:
+ prosemirror-model "^1.0.0"
+ prosemirror-state "^1.0.0"
+ prosemirror-transform "^1.7.3"
+
+prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.2.3, prosemirror-state@^1.3.1, prosemirror-state@^1.4.2, prosemirror-state@^1.4.3:
+ version "1.4.3"
+ resolved "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.3.tgz"
+ integrity sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==
+ dependencies:
+ prosemirror-model "^1.0.0"
+ prosemirror-transform "^1.0.0"
+ prosemirror-view "^1.27.0"
+
+prosemirror-tables@^1.3.4, prosemirror-tables@^1.3.5:
+ version "1.3.7"
+ resolved "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.3.7.tgz"
+ integrity sha512-oEwX1wrziuxMtwFvdDWSFHVUWrFJWt929kVVfHvtTi8yvw+5ppxjXZkMG/fuTdFo+3DXyIPSKfid+Be1npKXDA==
+ dependencies:
+ prosemirror-keymap "^1.1.2"
+ prosemirror-model "^1.8.1"
+ prosemirror-state "^1.3.1"
+ prosemirror-transform "^1.2.1"
+ prosemirror-view "^1.13.3"
+
+prosemirror-trailing-node@^2.0.7:
+ version "2.0.8"
+ resolved "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-2.0.8.tgz"
+ integrity sha512-ujRYhSuhQb1Jsarh1IHqb2KoSnRiD7wAMDGucP35DN7j5af6X7B18PfdPIrbwsPTqIAj0fyOvxbuPsWhNvylmA==
+ dependencies:
+ "@remirror/core-constants" "^2.0.2"
+ escape-string-regexp "^4.0.0"
+
+prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.2.1, prosemirror-transform@^1.7.2, prosemirror-transform@^1.7.3, prosemirror-transform@^1.8.0:
+ version "1.9.0"
+ resolved "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.9.0.tgz"
+ integrity sha512-5UXkr1LIRx3jmpXXNKDhv8OyAOeLTGuXNwdVfg8x27uASna/wQkr9p6fD3eupGOi4PLJfbezxTyi/7fSJypXHg==
+ dependencies:
+ prosemirror-model "^1.21.0"
+
+prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, prosemirror-view@^1.27.0, prosemirror-view@^1.31.0, prosemirror-view@^1.31.2, prosemirror-view@^1.31.4, prosemirror-view@^1.32.7, prosemirror-view@^1.9.10:
+ version "1.33.6"
+ resolved "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.33.6.tgz"
+ integrity sha512-zRLUNgLIQfd8IfGprsXxWTjdA8xEAFJe8cDNrOptj6Mop9sj+BMeVbJvceyAYCm5G2dOdT2prctH7K9dfnpIMw==
+ dependencies:
+ prosemirror-model "^1.20.0"
+ prosemirror-state "^1.0.0"
+ prosemirror-transform "^1.1.0"
+
+punycode.js@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz"
+ integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==
+
punycode@^2.1.0:
version "2.3.1"
- resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
+ resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz"
integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
+pure-rand@^6.0.0:
+ version "6.1.0"
+ resolved "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz"
+ integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==
+
queue-microtask@^1.2.2:
version "1.2.3"
- resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
+ resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
-react-dom@^18:
- version "18.2.0"
- resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
- integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
+"react-dom@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^17.0.0 || ^18.0.0", react-dom@^18, react-dom@^18.2.0, react-dom@>=16.8.0:
+ version "18.3.1"
+ resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz"
+ integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==
dependencies:
loose-envify "^1.1.0"
- scheduler "^0.23.0"
+ scheduler "^0.23.2"
+
+react-icons@^4.3.1:
+ version "4.12.0"
+ resolved "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz"
+ integrity sha512-IBaDuHiShdZqmfc/TwHu6+d6k2ltNCf3AszxNmjJc1KUfXdEeRJOKyNvLmAHaarhzGmTSVygNdyu8/opXv2gaw==
+
+react-icons@^5.2.1:
+ version "5.2.1"
+ resolved "https://registry.npmjs.org/react-icons/-/react-icons-5.2.1.tgz"
+ integrity sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==
react-is@^16.13.1:
version "16.13.1"
- resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
+ resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
-react-redux@^9.1.1:
- version "9.1.1"
- resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-9.1.1.tgz#852ec13084bd7375e26db697d2fc9027ffada204"
- integrity sha512-5ynfGDzxxsoV73+4czQM56qF43vsmgJsO22rmAvU5tZT2z5Xow/A2uhhxwXuGTxgdReF3zcp7A80gma2onRs1A==
+react-is@^18.0.0:
+ version "18.3.1"
+ resolved "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz"
+ integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
+
+react-number-format@^5.3.1:
+ version "5.3.4"
+ resolved "https://registry.npmjs.org/react-number-format/-/react-number-format-5.3.4.tgz"
+ integrity sha512-2hHN5mbLuCDUx19bv0Q8wet67QqYK6xmtLQeY5xx+h7UXiMmRtaCwqko4mMPoKXLc6xAzwRrutg8XbTRlsfjRg==
+ dependencies:
+ prop-types "^15.7.2"
+
+"react-redux@^7.2.1 || ^8.1.3 || ^9.0.0", react-redux@^9.1.1, react-redux@^9.1.2:
+ version "9.1.2"
+ resolved "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz"
+ integrity sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==
dependencies:
"@types/use-sync-external-store" "^0.0.3"
use-sync-external-store "^1.0.0"
-react@^18:
- version "18.2.0"
- resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
- integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
+react-remove-scroll-bar@^2.3.6:
+ version "2.3.6"
+ resolved "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz"
+ integrity sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==
+ dependencies:
+ react-style-singleton "^2.2.1"
+ tslib "^2.0.0"
+
+react-remove-scroll@^2.5.7:
+ version "2.5.9"
+ resolved "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.9.tgz"
+ integrity sha512-bvHCLBrFfM2OgcrpPY2YW84sPdS2o2HKWJUf1xGyGLnSoEnOTOBpahIarjRuYtN0ryahCeP242yf+5TrBX/pZA==
+ dependencies:
+ react-remove-scroll-bar "^2.3.6"
+ react-style-singleton "^2.2.1"
+ tslib "^2.1.0"
+ use-callback-ref "^1.3.0"
+ use-sidecar "^1.1.2"
+
+react-style-singleton@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz"
+ integrity sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==
+ dependencies:
+ get-nonce "^1.0.0"
+ invariant "^2.2.4"
+ tslib "^2.0.0"
+
+react-textarea-autosize@8.5.3:
+ version "8.5.3"
+ resolved "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.5.3.tgz"
+ integrity sha512-XT1024o2pqCuZSuBt9FwHlaDeNtVrtCXu0Rnz88t1jUGheCLa3PhjE1GH8Ctm2axEtvdCl5SUHYschyQ0L5QHQ==
+ dependencies:
+ "@babel/runtime" "^7.20.13"
+ use-composed-ref "^1.3.0"
+ use-latest "^1.2.1"
+
+react@*, "react@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.5.1 || ^17.0.0 || ^18.0.0", "react@^16.8 || ^17.0 || ^18.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.9.0 || ^17.0.0 || ^18", "react@^17.0.0 || ^18.0.0", react@^18, react@^18.0, react@^18.2.0, react@^18.3.1, "react@>= 16.8.0", "react@>= 16.8.0 || 17.x.x || ^18.0.0-0", react@>=16.8.0:
+ version "18.3.1"
+ resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz"
+ integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==
dependencies:
loose-envify "^1.1.0"
read-cache@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
+ resolved "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz"
integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==
dependencies:
pify "^2.3.0"
readdirp@~3.6.0:
version "3.6.0"
- resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
+ resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz"
integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
dependencies:
picomatch "^2.2.1"
redux-thunk@^3.1.0:
version "3.1.0"
- resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-3.1.0.tgz#94aa6e04977c30e14e892eae84978c1af6058ff3"
+ resolved "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz"
integrity sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==
-redux@^5.0.1:
+redux@^5.0.0, redux@^5.0.1:
version "5.0.1"
- resolved "https://registry.yarnpkg.com/redux/-/redux-5.0.1.tgz#97fa26881ce5746500125585d5642c77b6e9447b"
+ resolved "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz"
integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==
reflect.getprototypeof@^1.0.4:
version "1.0.6"
- resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz#3ab04c32a8390b770712b7a8633972702d278859"
+ resolved "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz"
integrity sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==
dependencies:
call-bind "^1.0.7"
@@ -2452,12 +5206,12 @@ reflect.getprototypeof@^1.0.4:
regenerator-runtime@^0.14.0:
version "0.14.1"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
+ resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz"
integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
regexp.prototype.flags@^1.5.2:
version "1.5.2"
- resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334"
+ resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz"
integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==
dependencies:
call-bind "^1.0.6"
@@ -2465,24 +5219,150 @@ regexp.prototype.flags@^1.5.2:
es-errors "^1.3.0"
set-function-name "^2.0.1"
-reselect@^5.0.1:
+rehype-format@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.npmjs.org/rehype-format/-/rehype-format-5.0.0.tgz"
+ integrity sha512-kM4II8krCHmUhxrlvzFSptvaWh280Fr7UGNJU5DCMuvmAwGCNmGfi9CvFAQK6JDjsNoRMWQStglK3zKJH685Wg==
+ dependencies:
+ "@types/hast" "^3.0.0"
+ hast-util-embedded "^3.0.0"
+ hast-util-is-element "^3.0.0"
+ hast-util-phrasing "^3.0.0"
+ hast-util-whitespace "^3.0.0"
+ html-whitespace-sensitive-tag-names "^3.0.0"
+ rehype-minify-whitespace "^6.0.0"
+ unist-util-visit-parents "^6.0.0"
+
+rehype-minify-whitespace@^5.0.0:
+ version "5.0.1"
+ resolved "https://registry.npmjs.org/rehype-minify-whitespace/-/rehype-minify-whitespace-5.0.1.tgz"
+ integrity sha512-PPp4lWJiBPlePI/dv1BeYktbwkfgXkrK59MUa+tYbMPgleod+4DvFK2PLU0O0O60/xuhHfiR9GUIUlXTU8sRIQ==
+ dependencies:
+ "@types/hast" "^2.0.0"
+ hast-util-embedded "^2.0.0"
+ hast-util-is-element "^2.0.0"
+ hast-util-whitespace "^2.0.0"
+ unified "^10.0.0"
+ unist-util-is "^5.0.0"
+
+rehype-minify-whitespace@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.npmjs.org/rehype-minify-whitespace/-/rehype-minify-whitespace-6.0.0.tgz"
+ integrity sha512-i9It4YHR0Sf3GsnlR5jFUKXRr9oayvEk9GKQUkwZv6hs70OH9q3OCZrq9PpLvIGKt3W+JxBOxCidNVpH/6rWdA==
+ dependencies:
+ "@types/hast" "^3.0.0"
+ hast-util-embedded "^3.0.0"
+ hast-util-is-element "^3.0.0"
+ hast-util-whitespace "^3.0.0"
+ unist-util-is "^6.0.0"
+
+rehype-parse@^8.0.4:
+ version "8.0.5"
+ resolved "https://registry.npmjs.org/rehype-parse/-/rehype-parse-8.0.5.tgz"
+ integrity sha512-Ds3RglaY/+clEX2U2mHflt7NlMA72KspZ0JLUJgBBLpRddBcEw3H8uYZQliQriku22NZpYMfjDdSgHcjxue24A==
+ dependencies:
+ "@types/hast" "^2.0.0"
+ hast-util-from-parse5 "^7.0.0"
+ parse5 "^6.0.0"
+ unified "^10.0.0"
+
+rehype-remark@^9.1.2:
+ version "9.1.2"
+ resolved "https://registry.npmjs.org/rehype-remark/-/rehype-remark-9.1.2.tgz"
+ integrity sha512-c0fG3/CrJ95zAQ07xqHSkdpZybwdsY7X5dNWvgL2XqLKZuqmG3+vk6kP/4miCnp+R+x/0uKKRSpfXb9aGR8Z5w==
+ dependencies:
+ "@types/hast" "^2.0.0"
+ "@types/mdast" "^3.0.0"
+ hast-util-to-mdast "^8.3.0"
+ unified "^10.0.0"
+
+rehype-stringify@^9.0.3:
+ version "9.0.4"
+ resolved "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-9.0.4.tgz"
+ integrity sha512-Uk5xu1YKdqobe5XpSskwPvo1XeHUUucWEQSl8hTrXt5selvca1e8K1EZ37E6YoZ4BT8BCqCdVfQW7OfHfthtVQ==
+ dependencies:
+ "@types/hast" "^2.0.0"
+ hast-util-to-html "^8.0.0"
+ unified "^10.0.0"
+
+remark-gfm@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz"
+ integrity sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==
+ dependencies:
+ "@types/mdast" "^3.0.0"
+ mdast-util-gfm "^2.0.0"
+ micromark-extension-gfm "^2.0.0"
+ unified "^10.0.0"
+
+remark-parse@^10.0.1:
+ version "10.0.2"
+ resolved "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.2.tgz"
+ integrity sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw==
+ dependencies:
+ "@types/mdast" "^3.0.0"
+ mdast-util-from-markdown "^1.0.0"
+ unified "^10.0.0"
+
+remark-rehype@^10.1.0:
+ version "10.1.0"
+ resolved "https://registry.npmjs.org/remark-rehype/-/remark-rehype-10.1.0.tgz"
+ integrity sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==
+ dependencies:
+ "@types/hast" "^2.0.0"
+ "@types/mdast" "^3.0.0"
+ mdast-util-to-hast "^12.1.0"
+ unified "^10.0.0"
+
+remark-stringify@^10.0.2:
+ version "10.0.3"
+ resolved "https://registry.npmjs.org/remark-stringify/-/remark-stringify-10.0.3.tgz"
+ integrity sha512-koyOzCMYoUHudypbj4XpnAKFbkddRMYZHwghnxd7ue5210WzGw6kOBwauJTRUMq16jsovXx8dYNvSSWP89kZ3A==
+ dependencies:
+ "@types/mdast" "^3.0.0"
+ mdast-util-to-markdown "^1.0.0"
+ unified "^10.0.0"
+
+require-directory@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz"
+ integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
+
+reselect@^5.1.0:
version "5.1.0"
- resolved "https://registry.yarnpkg.com/reselect/-/reselect-5.1.0.tgz#c479139ab9dd91be4d9c764a7f3868210ef8cd21"
+ resolved "https://registry.npmjs.org/reselect/-/reselect-5.1.0.tgz"
integrity sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg==
+resolve-cwd@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz"
+ integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==
+ dependencies:
+ resolve-from "^5.0.0"
+
resolve-from@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+ resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+resolve-from@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz"
+ integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
+
resolve-pkg-maps@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f"
+ resolved "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz"
integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==
-resolve@^1.1.7, resolve@^1.22.2, resolve@^1.22.4:
+resolve.exports@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz"
+ integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==
+
+resolve@^1.1.7, resolve@^1.20.0, resolve@^1.22.2, resolve@^1.22.4:
version "1.22.8"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
+ resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz"
integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
dependencies:
is-core-module "^2.13.0"
@@ -2491,7 +5371,7 @@ resolve@^1.1.7, resolve@^1.22.2, resolve@^1.22.4:
resolve@^2.0.0-next.5:
version "2.0.0-next.5"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c"
+ resolved "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz"
integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==
dependencies:
is-core-module "^2.13.0"
@@ -2500,26 +5380,38 @@ resolve@^2.0.0-next.5:
reusify@^1.0.4:
version "1.0.4"
- resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+ resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
rimraf@^3.0.2:
version "3.0.2"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+ resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
dependencies:
glob "^7.1.3"
+rope-sequence@^1.3.0:
+ version "1.3.4"
+ resolved "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz"
+ integrity sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==
+
run-parallel@^1.1.9:
version "1.2.0"
- resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
+ resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz"
integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
dependencies:
queue-microtask "^1.2.2"
+sade@^1.7.3:
+ version "1.8.1"
+ resolved "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz"
+ integrity sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==
+ dependencies:
+ mri "^1.1.0"
+
safe-array-concat@^1.1.2:
version "1.1.2"
- resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb"
+ resolved "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz"
integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==
dependencies:
call-bind "^1.0.7"
@@ -2529,35 +5421,42 @@ safe-array-concat@^1.1.2:
safe-regex-test@^1.0.3:
version "1.0.3"
- resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377"
+ resolved "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz"
integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==
dependencies:
call-bind "^1.0.6"
es-errors "^1.3.0"
is-regex "^1.1.4"
-scheduler@^0.23.0:
- version "0.23.0"
- resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
- integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
+scheduler@^0.23.2:
+ version "0.23.2"
+ resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz"
+ integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==
dependencies:
loose-envify "^1.1.0"
-semver@^6.3.1:
+semver@^6.3.0, semver@^6.3.1:
version "6.3.1"
- resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
+ resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
+semver@^7.5.3:
+ version "7.6.0"
+ resolved "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz"
+ integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==
+ dependencies:
+ lru-cache "^6.0.0"
+
semver@^7.5.4:
version "7.6.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d"
+ resolved "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz"
integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==
dependencies:
lru-cache "^6.0.0"
set-function-length@^1.2.1:
version "1.2.2"
- resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
+ resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz"
integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
dependencies:
define-data-property "^1.1.4"
@@ -2569,7 +5468,7 @@ set-function-length@^1.2.1:
set-function-name@^2.0.1, set-function-name@^2.0.2:
version "2.0.2"
- resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985"
+ resolved "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz"
integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==
dependencies:
define-data-property "^1.1.4"
@@ -2579,19 +5478,19 @@ set-function-name@^2.0.1, set-function-name@^2.0.2:
shebang-command@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+ resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz"
integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
dependencies:
shebang-regex "^3.0.0"
shebang-regex@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+ resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
side-channel@^1.0.4, side-channel@^1.0.6:
version "1.0.6"
- resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
+ resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz"
integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==
dependencies:
call-bind "^1.0.7"
@@ -2599,43 +5498,100 @@ side-channel@^1.0.4, side-channel@^1.0.6:
get-intrinsic "^1.2.4"
object-inspect "^1.13.1"
+signal-exit@^3.0.3, signal-exit@^3.0.7:
+ version "3.0.7"
+ resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz"
+ integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
+
signal-exit@^4.0.1:
version "4.1.0"
- resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
+ resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz"
integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
+sisteransi@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz"
+ integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==
+
slash@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
+ resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
source-map-js@^1.0.2, source-map-js@^1.2.0:
version "1.2.0"
- resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"
+ resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz"
integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==
+source-map-support@0.5.13:
+ version "0.5.13"
+ resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz"
+ integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==
+ dependencies:
+ buffer-from "^1.0.0"
+ source-map "^0.6.0"
+
source-map@^0.5.0:
version "0.5.7"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+ resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz"
integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
+source-map@^0.6.0, source-map@^0.6.1:
+ version "0.6.1"
+ resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
+ integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+space-separated-tokens@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz"
+ integrity sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==
+
+sprintf-js@~1.0.2:
+ version "1.0.3"
+ resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
+ integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
+
+stack-utils@^2.0.3:
+ version "2.0.6"
+ resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz"
+ integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==
+ dependencies:
+ escape-string-regexp "^2.0.0"
+
streamsearch@^1.1.0:
version "1.1.0"
- resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
+ resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz"
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
+string-length@^4.0.1:
+ version "4.0.2"
+ resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz"
+ integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==
+ dependencies:
+ char-regex "^1.0.2"
+ strip-ansi "^6.0.0"
+
"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+ resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.1"
+
+string-width@^4.1.0, string-width@^4.2.0:
+ version "4.2.3"
+ resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
-string-width@^4.1.0:
+string-width@^4.2.3:
version "4.2.3"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+ resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
@@ -2644,7 +5600,7 @@ string-width@^4.1.0:
string-width@^5.0.1, string-width@^5.1.2:
version "5.1.2"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
+ resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz"
integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==
dependencies:
eastasianwidth "^0.2.0"
@@ -2653,7 +5609,7 @@ string-width@^5.0.1, string-width@^5.1.2:
string.prototype.matchall@^4.0.10:
version "4.0.11"
- resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz#1092a72c59268d2abaad76582dccc687c0297e0a"
+ resolved "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz"
integrity sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==
dependencies:
call-bind "^1.0.7"
@@ -2671,7 +5627,7 @@ string.prototype.matchall@^4.0.10:
string.prototype.trim@^1.2.9:
version "1.2.9"
- resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4"
+ resolved "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz"
integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==
dependencies:
call-bind "^1.0.7"
@@ -2681,7 +5637,7 @@ string.prototype.trim@^1.2.9:
string.prototype.trimend@^1.0.8:
version "1.0.8"
- resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229"
+ resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz"
integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==
dependencies:
call-bind "^1.0.7"
@@ -2690,54 +5646,72 @@ string.prototype.trimend@^1.0.8:
string.prototype.trimstart@^1.0.8:
version "1.0.8"
- resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde"
+ resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz"
integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==
dependencies:
call-bind "^1.0.7"
define-properties "^1.2.1"
es-object-atoms "^1.0.0"
+stringify-entities@^4.0.0:
+ version "4.0.4"
+ resolved "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz"
+ integrity sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==
+ dependencies:
+ character-entities-html4 "^2.0.0"
+ character-entities-legacy "^3.0.0"
+
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+ resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+ resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^7.0.1:
version "7.1.0"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
+ resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz"
integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==
dependencies:
ansi-regex "^6.0.1"
strip-bom@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+ resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz"
integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==
+strip-bom@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz"
+ integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==
+
+strip-final-newline@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz"
+ integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
+
strip-json-comments@^3.1.1:
version "3.1.1"
- resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
+ resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
styled-jsx@5.1.1:
version "5.1.1"
- resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.1.tgz#839a1c3aaacc4e735fed0781b8619ea5d0009d1f"
+ resolved "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz"
integrity sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==
dependencies:
client-only "0.0.1"
sucrase@^3.32.0:
version "3.35.0"
- resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263"
+ resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz"
integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==
dependencies:
"@jridgewell/gen-mapping" "^0.3.2"
@@ -2750,34 +5724,58 @@ sucrase@^3.32.0:
supports-color@^5.3.0:
version "5.5.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+ resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
dependencies:
has-flag "^3.0.0"
supports-color@^7.1.0:
version "7.2.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+ resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz"
integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
dependencies:
has-flag "^4.0.0"
+supports-color@^8.0.0:
+ version "8.1.1"
+ resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz"
+ integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
+ dependencies:
+ has-flag "^4.0.0"
+
supports-preserve-symlinks-flag@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
+ resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
synckit@^0.8.6:
version "0.8.8"
- resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.8.tgz#fe7fe446518e3d3d49f5e429f443cf08b6edfcd7"
+ resolved "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz"
integrity sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==
dependencies:
"@pkgr/core" "^0.1.0"
tslib "^2.6.2"
-tailwindcss@^3.4.1:
+tabbable@^6.0.0:
+ version "6.2.0"
+ resolved "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz"
+ integrity sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==
+
+tailwind-merge@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.3.0.tgz"
+ integrity sha512-vkYrLpIP+lgR0tQCG6AP7zZXCTLc1Lnv/CCRT3BqJ9CZ3ui2++GPaGb1x/ILsINIMSYqqvrpqjUFsMNLlW99EA==
+ dependencies:
+ "@babel/runtime" "^7.24.1"
+
+tailwindcss-animate@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz"
+ integrity sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==
+
+tailwindcss@^3.4.1, "tailwindcss@>=3.0.0 || insiders":
version "3.4.3"
- resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.3.tgz#be48f5283df77dfced705451319a5dffb8621519"
+ resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz"
integrity sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==
dependencies:
"@alloc/quick-lru" "^5.2.0"
@@ -2805,53 +5803,103 @@ tailwindcss@^3.4.1:
tapable@^2.2.0:
version "2.2.1"
- resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
+ resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz"
integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
+test-exclude@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz"
+ integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==
+ dependencies:
+ "@istanbuljs/schema" "^0.1.2"
+ glob "^7.1.4"
+ minimatch "^3.0.4"
+
text-table@^0.2.0:
version "0.2.0"
- resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
+ resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
thenify-all@^1.0.0:
version "1.6.0"
- resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726"
+ resolved "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz"
integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==
dependencies:
thenify ">= 3.1.0 < 4"
"thenify@>= 3.1.0 < 4":
version "3.3.1"
- resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f"
+ resolved "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz"
integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==
dependencies:
any-promise "^1.0.0"
+tippy.js@^6.3.7:
+ version "6.3.7"
+ resolved "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz"
+ integrity sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==
+ dependencies:
+ "@popperjs/core" "^2.9.0"
+
+tmpl@1.0.5:
+ version "1.0.5"
+ resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz"
+ integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==
+
to-fast-properties@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
+ resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz"
integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
to-regex-range@^5.0.1:
version "5.0.1"
- resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+ resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz"
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
dependencies:
is-number "^7.0.0"
+trim-lines@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz"
+ integrity sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==
+
+trim-trailing-lines@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-2.1.0.tgz"
+ integrity sha512-5UR5Biq4VlVOtzqkm2AZlgvSlDJtME46uV0br0gENbwN4l5+mMKT4b9gJKqWtuL2zAIqajGJGuvbCbcAJUZqBg==
+
+trough@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz"
+ integrity sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==
+
ts-api-utils@^1.0.1:
version "1.3.0"
- resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1"
+ resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz"
integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==
ts-interface-checker@^0.1.9:
version "0.1.13"
- resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699"
+ resolved "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz"
integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==
+ts-jest@^29.1.2:
+ version "29.1.2"
+ resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.2.tgz"
+ integrity sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==
+ dependencies:
+ bs-logger "0.x"
+ fast-json-stable-stringify "2.x"
+ jest-util "^29.0.0"
+ json5 "^2.2.3"
+ lodash.memoize "4.x"
+ make-error "1.x"
+ semver "^7.5.3"
+ yargs-parser "^21.0.1"
+
tsconfig-paths@^3.15.0:
version "3.15.0"
- resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4"
+ resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz"
integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==
dependencies:
"@types/json5" "^0.0.29"
@@ -2859,26 +5907,41 @@ tsconfig-paths@^3.15.0:
minimist "^1.2.6"
strip-bom "^3.0.0"
-tslib@^2.4.0, tslib@^2.6.2:
+tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.6.2:
version "2.6.2"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
+ resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz"
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
- resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
+ resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz"
integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
dependencies:
prelude-ls "^1.2.1"
+type-detect@4.0.8:
+ version "4.0.8"
+ resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz"
+ integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
+
type-fest@^0.20.2:
version "0.20.2"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
+ resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz"
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
+type-fest@^0.21.3:
+ version "0.21.3"
+ resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz"
+ integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
+
+type-fest@^4.12.0:
+ version "4.18.2"
+ resolved "https://registry.npmjs.org/type-fest/-/type-fest-4.18.2.tgz"
+ integrity sha512-+suCYpfJLAe4OXS6+PPXjW3urOS4IoP9waSiLuXfLgqZODKw/aWwASvzqE886wA0kQgGy0mIWyhd87VpqIy6Xg==
+
typed-array-buffer@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3"
+ resolved "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz"
integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==
dependencies:
call-bind "^1.0.7"
@@ -2887,7 +5950,7 @@ typed-array-buffer@^1.0.2:
typed-array-byte-length@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67"
+ resolved "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz"
integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==
dependencies:
call-bind "^1.0.7"
@@ -2898,7 +5961,7 @@ typed-array-byte-length@^1.0.1:
typed-array-byte-offset@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063"
+ resolved "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz"
integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==
dependencies:
available-typed-arrays "^1.0.7"
@@ -2910,7 +5973,7 @@ typed-array-byte-offset@^1.0.2:
typed-array-length@^1.0.6:
version "1.0.6"
- resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3"
+ resolved "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz"
integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==
dependencies:
call-bind "^1.0.7"
@@ -2920,14 +5983,19 @@ typed-array-length@^1.0.6:
is-typed-array "^1.1.13"
possible-typed-array-names "^1.0.0"
-typescript@^5:
+typescript@>=3.3.1, typescript@>=4.2.0, "typescript@>=4.3 <6", typescript@5.4.5:
version "5.4.5"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611"
+ resolved "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz"
integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==
+uc.micro@^2.0.0, uc.micro@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz"
+ integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==
+
unbox-primitive@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
+ resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz"
integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==
dependencies:
call-bind "^1.0.2"
@@ -2937,37 +6005,220 @@ unbox-primitive@^1.0.2:
undici-types@~5.26.4:
version "5.26.5"
- resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
+ resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz"
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
+unified@^10.0.0, unified@^10.1.2:
+ version "10.1.2"
+ resolved "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz"
+ integrity sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==
+ dependencies:
+ "@types/unist" "^2.0.0"
+ bail "^2.0.0"
+ extend "^3.0.0"
+ is-buffer "^2.0.0"
+ is-plain-obj "^4.0.0"
+ trough "^2.0.0"
+ vfile "^5.0.0"
+
+unist-util-find-after@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-4.0.1.tgz"
+ integrity sha512-QO/PuPMm2ERxC6vFXEPtmAutOopy5PknD+Oq64gGwxKtk4xwo9Z97t9Av1obPmGU0IyTa6EKYUfTrK2QJS3Ozw==
+ dependencies:
+ "@types/unist" "^2.0.0"
+ unist-util-is "^5.0.0"
+
+unist-util-generated@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.1.tgz"
+ integrity sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A==
+
+unist-util-is@^5.0.0:
+ version "5.2.1"
+ resolved "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz"
+ integrity sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==
+ dependencies:
+ "@types/unist" "^2.0.0"
+
+unist-util-is@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz"
+ integrity sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==
+ dependencies:
+ "@types/unist" "^3.0.0"
+
+unist-util-position@^4.0.0:
+ version "4.0.4"
+ resolved "https://registry.npmjs.org/unist-util-position/-/unist-util-position-4.0.4.tgz"
+ integrity sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==
+ dependencies:
+ "@types/unist" "^2.0.0"
+
+unist-util-stringify-position@^3.0.0:
+ version "3.0.3"
+ resolved "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz"
+ integrity sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==
+ dependencies:
+ "@types/unist" "^2.0.0"
+
+unist-util-visit-parents@^5.0.0, unist-util-visit-parents@^5.1.1:
+ version "5.1.3"
+ resolved "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz"
+ integrity sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==
+ dependencies:
+ "@types/unist" "^2.0.0"
+ unist-util-is "^5.0.0"
+
+unist-util-visit-parents@^6.0.0:
+ version "6.0.1"
+ resolved "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz"
+ integrity sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==
+ dependencies:
+ "@types/unist" "^3.0.0"
+ unist-util-is "^6.0.0"
+
+unist-util-visit@^4.0.0:
+ version "4.1.2"
+ resolved "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz"
+ integrity sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==
+ dependencies:
+ "@types/unist" "^2.0.0"
+ unist-util-is "^5.0.0"
+ unist-util-visit-parents "^5.1.1"
+
update-browserslist-db@^1.0.13:
- version "1.0.13"
- resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4"
- integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==
+ version "1.0.15"
+ resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.15.tgz"
+ integrity sha512-K9HWH62x3/EalU1U6sjSZiylm9C8tgq2mSvshZpqc7QE69RaA2qjhkW2HlNA0tFpEbtyFz7HTqbSdN4MSwUodA==
dependencies:
- escalade "^3.1.1"
+ escalade "^3.1.2"
picocolors "^1.0.0"
uri-js@^4.2.2:
version "4.4.1"
- resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
+ resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz"
integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
dependencies:
punycode "^2.1.0"
+use-callback-ref@^1.3.0:
+ version "1.3.2"
+ resolved "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz"
+ integrity sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==
+ dependencies:
+ tslib "^2.0.0"
+
+use-composed-ref@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.3.0.tgz"
+ integrity sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==
+
+use-isomorphic-layout-effect@^1.1.1:
+ version "1.1.2"
+ resolved "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz"
+ integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==
+
+use-latest@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.npmjs.org/use-latest/-/use-latest-1.2.1.tgz"
+ integrity sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==
+ dependencies:
+ use-isomorphic-layout-effect "^1.1.1"
+
+use-prefers-color-scheme@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.npmjs.org/use-prefers-color-scheme/-/use-prefers-color-scheme-1.1.3.tgz"
+ integrity sha512-ZRgDfb5BFLum/Sud4SpZ+d1YcV+lRbsupw0qQ/rGy5kGrpE3KMUQgEQOKiQQSa4Wslex46n5fKFO+9FGMTosUQ==
+
+use-sidecar@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz"
+ integrity sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==
+ dependencies:
+ detect-node-es "^1.1.0"
+ tslib "^2.0.0"
+
use-sync-external-store@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
- integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
+ version "1.2.2"
+ resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz"
+ integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==
util-deprecate@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+ resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
+uuid@^8.3.2:
+ version "8.3.2"
+ resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz"
+ integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
+
+uvu@^0.5.0:
+ version "0.5.6"
+ resolved "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz"
+ integrity sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==
+ dependencies:
+ dequal "^2.0.0"
+ diff "^5.0.0"
+ kleur "^4.0.3"
+ sade "^1.7.3"
+
+v8-to-istanbul@^9.0.1:
+ version "9.2.0"
+ resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz"
+ integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==
+ dependencies:
+ "@jridgewell/trace-mapping" "^0.3.12"
+ "@types/istanbul-lib-coverage" "^2.0.1"
+ convert-source-map "^2.0.0"
+
+vfile-location@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.npmjs.org/vfile-location/-/vfile-location-4.1.0.tgz"
+ integrity sha512-YF23YMyASIIJXpktBa4vIGLJ5Gs88UB/XePgqPmTa7cDA+JeO3yclbpheQYCHjVHBn/yePzrXuygIL+xbvRYHw==
+ dependencies:
+ "@types/unist" "^2.0.0"
+ vfile "^5.0.0"
+
+vfile-message@^3.0.0:
+ version "3.1.4"
+ resolved "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz"
+ integrity sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==
+ dependencies:
+ "@types/unist" "^2.0.0"
+ unist-util-stringify-position "^3.0.0"
+
+vfile@^5.0.0:
+ version "5.3.7"
+ resolved "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz"
+ integrity sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==
+ dependencies:
+ "@types/unist" "^2.0.0"
+ is-buffer "^2.0.0"
+ unist-util-stringify-position "^3.0.0"
+ vfile-message "^3.0.0"
+
+w3c-keyname@^2.2.0:
+ version "2.2.8"
+ resolved "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz"
+ integrity sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==
+
+walker@^1.0.8:
+ version "1.0.8"
+ resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz"
+ integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==
+ dependencies:
+ makeerror "1.0.12"
+
+web-namespaces@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz"
+ integrity sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==
+
which-boxed-primitive@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"
+ resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz"
integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==
dependencies:
is-bigint "^1.0.1"
@@ -2978,7 +6229,7 @@ which-boxed-primitive@^1.0.2:
which-builtin-type@^1.1.3:
version "1.1.3"
- resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.3.tgz#b1b8443707cc58b6e9bf98d32110ff0c2cbd029b"
+ resolved "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz"
integrity sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==
dependencies:
function.prototype.name "^1.1.5"
@@ -2996,7 +6247,7 @@ which-builtin-type@^1.1.3:
which-collection@^1.0.1:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0"
+ resolved "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz"
integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==
dependencies:
is-map "^2.0.3"
@@ -3006,7 +6257,7 @@ which-collection@^1.0.1:
which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.9:
version "1.1.15"
- resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d"
+ resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz"
integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==
dependencies:
available-typed-arrays "^1.0.7"
@@ -3017,14 +6268,28 @@ which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.9:
which@^2.0.1:
version "2.0.2"
- resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+ resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz"
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
dependencies:
isexe "^2.0.0"
+word-wrap@^1.2.5:
+ version "1.2.5"
+ resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz"
+ integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
+
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
version "7.0.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+ resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
+wrap-ansi@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
@@ -3033,7 +6298,7 @@ which@^2.0.1:
wrap-ansi@^8.1.0:
version "8.1.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
+ resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz"
integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==
dependencies:
ansi-styles "^6.1.0"
@@ -3042,25 +6307,92 @@ wrap-ansi@^8.1.0:
wrappy@1:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
+write-file-atomic@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz"
+ integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==
+ dependencies:
+ imurmurhash "^0.1.4"
+ signal-exit "^3.0.7"
+
+y-prosemirror@^1.2.1, y-prosemirror@1.2.1:
+ version "1.2.1"
+ resolved "https://registry.npmjs.org/y-prosemirror/-/y-prosemirror-1.2.1.tgz"
+ integrity sha512-czMBfB1eL2awqmOSxQM8cS/fsUOGE6fjvyPLInrh4crPxFiw67wDpwIW+EGBYKRa04sYbS0ScGj7ZgvWuDrmBQ==
+ dependencies:
+ lib0 "^0.2.42"
+
+y-protocols@^1.0.1, y-protocols@^1.0.5:
+ version "1.0.6"
+ resolved "https://registry.npmjs.org/y-protocols/-/y-protocols-1.0.6.tgz"
+ integrity sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==
+ dependencies:
+ lib0 "^0.2.85"
+
+y18n@^5.0.5:
+ version "5.0.8"
+ resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz"
+ integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
+
+yallist@^3.0.2:
+ version "3.1.1"
+ resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz"
+ integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
+
yallist@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
+ resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yaml@^2.3.4:
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.1.tgz#2e57e0b5e995292c25c75d2658f0664765210eed"
- integrity sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==
+ version "2.4.2"
+ resolved "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz"
+ integrity sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==
+
+yargs-parser@^21.0.1, yargs-parser@^21.1.1:
+ version "21.1.1"
+ resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz"
+ integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
+
+yargs@^17.3.1:
+ version "17.7.2"
+ resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz"
+ integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
+ dependencies:
+ cliui "^8.0.1"
+ escalade "^3.1.1"
+ get-caller-file "^2.0.5"
+ require-directory "^2.1.1"
+ string-width "^4.2.3"
+ y18n "^5.0.5"
+ yargs-parser "^21.1.1"
+
+yjs@^13.0.0, yjs@^13.5.38, yjs@^13.6.1:
+ version "13.6.15"
+ resolved "https://registry.npmjs.org/yjs/-/yjs-13.6.15.tgz"
+ integrity sha512-moFv4uNYhp8BFxIk3AkpoAnnjts7gwdpiG8RtyFiKbMtxKCS0zVZ5wPaaGpwC3V2N/K8TK8MwtSI3+WO9CHWjQ==
+ dependencies:
+ lib0 "^0.2.86"
yocto-queue@^0.1.0:
version "0.1.0"
- resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
+ resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
-zod@^3.23.3:
- version "3.23.3"
- resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.3.tgz#eeb068f83acb55310174673dee631dfa0be5510d"
- integrity sha512-tPvq1B/2Yu/dh2uAIH2/BhUlUeLIUvAjr6dpL/75I0pCYefHgjhXk1o1Kob3kTU8C7yU1j396jFHlsVWFi9ogg==
+zod@^3.23.6:
+ version "3.23.7"
+ resolved "https://registry.npmjs.org/zod/-/zod-3.23.7.tgz"
+ integrity sha512-NBeIoqbtOiUMomACV/y+V3Qfs9+Okr18vR5c/5pHClPpufWOrsx8TENboDPe265lFdfewX2yBtNTLPvnmCxwog==
+
+zod@^3.23.8:
+ version "3.23.8"
+ resolved "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz"
+ integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==
+
+zwitch@^2.0.0, zwitch@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz"
+ integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==
diff --git a/frontend/lib/.eslintrc.cjs b/frontend/lib/.eslintrc.cjs
new file mode 100644
index 000000000..6e8698b72
--- /dev/null
+++ b/frontend/lib/.eslintrc.cjs
@@ -0,0 +1,18 @@
+module.exports = {
+ root: true,
+ env: { browser: true, es2020: true },
+ extends: [
+ "eslint:recommended",
+ "plugin:@typescript-eslint/recommended",
+ "plugin:react-hooks/recommended",
+ ],
+ ignorePatterns: ["dist", ".eslintrc.cjs"],
+ parser: "@typescript-eslint/parser",
+ plugins: ["react-refresh"],
+ rules: {
+ "react-refresh/only-export-components": [
+ "warn",
+ { allowConstantExport: true },
+ ],
+ },
+};
diff --git a/frontend/lib/.eslintrc.json b/frontend/lib/.eslintrc.json
deleted file mode 100644
index be1138c28..000000000
--- a/frontend/lib/.eslintrc.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "plugins": ["prettier"]
-}
diff --git a/frontend/lib/.gitignore b/frontend/lib/.gitignore
index 40b878db5..a547bf36d 100644
--- a/frontend/lib/.gitignore
+++ b/frontend/lib/.gitignore
@@ -1 +1,24 @@
-node_modules/
\ No newline at end of file
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/frontend/lib/README.md b/frontend/lib/README.md
new file mode 100644
index 000000000..0af595e9d
--- /dev/null
+++ b/frontend/lib/README.md
@@ -0,0 +1,30 @@
+# Generate SAC Frontend Library:
+
+This repository holds the common types, apis, and components for frontend library used by the Student Activity Calendar.
+
+To install the page, navigate to the target repo and initiate the following command:
+
+- `yarn add @generatesac/blocks`
+
+## Development / Testing
+
+When contributing to the package, you will likely want to test your code locally before pushing to remote. To link it with real-time updates, following the steps below:
+
+1. Navigate to `/frontend/lib` and run `yarn link`
+2. Mavigate to the target repo, ppen a second terminal and run `yarn link "@generatesac/blocks"`
+3. Navigate back to `/frontend/lib` and run `yarn watch`.
+
+When you are ready to finish local development:
+
+1. Exit out of "watch mode" using `ctrl + C`
+1. Navigate to `/frontend/lib` and run `yarn unlink`
+1. Navigate to the target repo and run `yarn link "@generatesac/blocks"`
+
+## Contributing
+
+When you are ready to push new code to the library, make sure to bump the version in the `package.json`. We are using semantic versioning. If you forget to do this, the `frontend/lib` GitHub Action will fail on push.
+
+Once the code is merged into `main`, a new version of the package will automatically be built and deployed. Monitor GitHub Actions to ensure a proper release. In the event that the workflow fails, you can manually release the package using the commands below:
+
+1. `yarn build`
+2. `yarn publish`
diff --git a/frontend/lib/api/authApi.ts b/frontend/lib/api/authApi.ts
deleted file mode 100644
index 8452eb392..000000000
--- a/frontend/lib/api/authApi.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-import { LoginRequestBody, RefreshTokenRequestBody } from '../types/auth';
-import { User, userSchema } from '../types/user';
-import {
- EmailRequestBody,
- VerifyEmailRequestBody,
- VerifyPasswordResetTokenRequestBody
-} from '../types/verification';
-
-import { baseApi } from '../api/base';
-
-const AUTH_API_BASE_URL = '/auth';
-
-export const authApi = baseApi.injectEndpoints({
- endpoints: (builder) => ({
- login: builder.mutation({
- query: (body) => ({
- url: `${AUTH_API_BASE_URL}/login`,
- method: 'POST',
- body
- }),
- transformResponse: (response: User) => {
- return userSchema.parse(response);
- }
- }),
- logout: builder.mutation({
- query: () => ({
- url: `${AUTH_API_BASE_URL}/logout`,
- method: 'POST'
- })
- }),
- refresh: builder.mutation({
- query: (body) => ({
- url: 'refresh',
- method: 'POST',
- body
- })
- }),
- forgotPassword: builder.mutation({
- query: (body) => ({
- url: `${AUTH_API_BASE_URL}/forgot-password`,
- method: 'POST',
- body
- })
- }),
- verifyPasswordResetToken: builder.mutation<
- void,
- VerifyPasswordResetTokenRequestBody
- >({
- query: (body) => ({
- url: `${AUTH_API_BASE_URL}/verify-reset`,
- method: 'POST',
- body
- })
- }),
- sendCode: builder.mutation({
- query: (body) => ({
- url: `${AUTH_API_BASE_URL}/send-code`,
- method: 'POST',
- body
- })
- }),
- verifyEmail: builder.mutation({
- query: (body) => ({
- url: `${AUTH_API_BASE_URL}/verify-email`,
- method: 'POST',
- body
- })
- })
- })
-});
-
-export const {
- useLoginMutation,
- useLogoutMutation,
- useRefreshMutation,
- useForgotPasswordMutation,
- useVerifyPasswordResetTokenMutation,
- useSendCodeMutation,
- useVerifyEmailMutation
-} = authApi;
diff --git a/frontend/lib/api/base.ts b/frontend/lib/api/base.ts
deleted file mode 100644
index 3a67a6d66..000000000
--- a/frontend/lib/api/base.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
-
-export const API_BASE_URL = 'http://127.0.0.1:8080/api/v1';
-
-// BaseAPI for the entire application:
-export const baseApi = createApi({
- baseQuery: fetchBaseQuery({
- baseUrl: API_BASE_URL,
- credentials: 'include',
- prepareHeaders: async (headers, { getState }) => {
- const token = (getState() as { auth: { token: string } })?.auth
- .token;
- if (token) {
- headers.set('Authorization', `Bearer ${token}`);
- }
- return headers;
- }
- }),
- tagTypes: [
- 'User',
- 'Tag',
- 'Category',
- 'Club',
- 'Contact',
- 'Event',
- 'PointOfContact',
- 'File',
- 'Follower',
- 'Member'
- ],
- endpoints: () => ({})
-});
-
-// Add query params to a request:
-export function handleQueryParams(
- baseUrl: string,
- queryParams?: Record
-): string {
- const url = new URL(baseUrl);
- if (queryParams) {
- Object.entries(queryParams).forEach(([key, value]) => {
- url.searchParams.append(key, value.toString());
- });
- }
- return url.toString();
-}
diff --git a/frontend/lib/api/categoryApi.ts b/frontend/lib/api/categoryApi.ts
deleted file mode 100644
index 161e307dc..000000000
--- a/frontend/lib/api/categoryApi.ts
+++ /dev/null
@@ -1,115 +0,0 @@
-import { z } from 'zod';
-
-import {
- Category,
- CreateCategoryRequestBody,
- categorySchema
-} from '../types/category';
-import { PaginationQueryParams } from '../types/root';
-import { Tag } from '../types/tag';
-
-import { baseApi, handleQueryParams } from '../api/base';
-
-const CATEGORY_API_BASE_URL = '/categories';
-
-export const categoryApi = baseApi.injectEndpoints({
- endpoints: (builder) => ({
- createCategory: builder.mutation({
- query: (body) => ({
- url: CATEGORY_API_BASE_URL,
- method: 'POST',
- body
- }),
- transformResponse: (response: Category) => {
- return categorySchema.parse(response);
- },
- invalidatesTags: ['Category']
- }),
- categories: builder.query({
- query: (queryParams) => ({
- url: handleQueryParams(
- `${CATEGORY_API_BASE_URL}/`,
- queryParams
- ),
- method: 'GET'
- }),
- transformResponse: (response: Category[]) => {
- return z.array(categorySchema).parse(response);
- },
- providesTags: (result, _, _arg) =>
- result
- ? result.map((category) => ({
- type: 'Category',
- id: category.id
- }))
- : ['Category']
- }),
- category: builder.query({
- query: (id) => ({
- url: `${CATEGORY_API_BASE_URL}/${id}/`,
- method: 'GET'
- }),
- transformResponse: (response: Category) => {
- return categorySchema.parse(response);
- },
- providesTags: (result, _, id) =>
- result ? [{ type: 'Category', id }] : []
- }),
- deleteCategory: builder.mutation({
- query: (id) => ({
- url: `${CATEGORY_API_BASE_URL}/${id}/`,
- method: 'DELETE'
- }),
- invalidatesTags: (_result, _, id) => [{ type: 'Category', id }]
- }),
- updateCategory: builder.mutation<
- Category,
- { id: string; body: CreateCategoryRequestBody }
- >({
- query: ({ id, body }) => ({
- url: `${CATEGORY_API_BASE_URL}/${id}/`,
- method: 'PUT',
- body
- }),
- transformResponse: (response: Category) => {
- return categorySchema.parse(response);
- },
- invalidatesTags: (result, _, { id }) =>
- result ? [{ type: 'Category', id }] : []
- }),
- categoryTags: builder.query<
- Tag[],
- { id: string; queryParams?: PaginationQueryParams }
- >({
- query: ({ id, queryParams }) => ({
- url: handleQueryParams(
- `${CATEGORY_API_BASE_URL}/${id}/tags/`,
- queryParams
- ),
- method: 'GET'
- }),
- providesTags: (result, _, _arg) =>
- result
- ? result.map((tag) => ({ type: 'Tag', id: tag.id }))
- : ['Tag']
- }),
- categoryTag: builder.query({
- query: ({ categoryID, tagID }) => ({
- url: `${CATEGORY_API_BASE_URL}/${categoryID}/tags/${tagID}/`,
- method: 'GET'
- }),
- providesTags: (result, _, { tagID }) =>
- result ? [{ type: 'Tag', id: tagID }] : []
- })
- })
-});
-
-export const {
- useCreateCategoryMutation,
- useCategoriesQuery,
- useCategoryQuery,
- useDeleteCategoryMutation,
- useUpdateCategoryMutation,
- useCategoryTagsQuery,
- useCategoryTagQuery
-} = categoryApi;
diff --git a/frontend/lib/api/clubApi.ts b/frontend/lib/api/clubApi.ts
deleted file mode 100644
index 3481f835b..000000000
--- a/frontend/lib/api/clubApi.ts
+++ /dev/null
@@ -1,333 +0,0 @@
-import { z } from 'zod';
-
-import {
- Club,
- CreateClubRequestBody,
- CreateClubTagsRequestBody,
- UpdateClubRequestBody,
- clubSchema
-} from '../types/club';
-import {
- Contact,
- CreateContactRequestBody,
- contactSchema
-} from '../types/contact';
-import { Event, eventSchema } from '../types/event';
-import {
- PointOfContact,
- UpdatePointOfContactRequestBody,
- pointOfContactSchema
-} from '../types/pointOfContact';
-import { PaginationQueryParams } from '../types/root';
-import { Tag, tagSchema } from '../types/tag';
-import { User, userSchema } from '../types/user';
-
-import { baseApi, handleQueryParams } from '../api/base';
-
-export const CLUB_API_BASE_URL = '/clubs';
-
-export const clubApi = baseApi.injectEndpoints({
- endpoints: (builder) => ({
- createClub: builder.mutation({
- query: (body) => ({
- url: `${CLUB_API_BASE_URL}/`,
- method: 'POST',
- body
- }),
- invalidatesTags: ['Club'],
- transformResponse: (response: Club) => {
- return clubSchema.parse(response);
- }
- }),
- clubs: builder.query({
- query: (queryParams) => ({
- url: handleQueryParams(`${CLUB_API_BASE_URL}/`, queryParams),
- method: 'GET'
- }),
- providesTags: (result, _, _arg) =>
- result
- ? result.map((club) => ({ type: 'Club', id: club.id }))
- : ['Club'],
- transformResponse: (response: Club) => {
- return z.array(clubSchema).parse(response);
- }
- }),
- club: builder.query({
- query: (id) => ({
- url: `${CLUB_API_BASE_URL}/${id}/`,
- method: 'GET'
- }),
- providesTags: (result, _, id) =>
- result ? [{ type: 'Club', id }] : [],
- transformResponse: (response: Club) => {
- return clubSchema.parse(response);
- }
- }),
- updateClub: builder.mutation<
- Club,
- { id: string; body: UpdateClubRequestBody }
- >({
- query: ({ id, body }) => ({
- url: `${CLUB_API_BASE_URL}/${id}/`,
- method: 'PATCH',
- body
- }),
- invalidatesTags: (result, _, { id }) =>
- result ? [{ type: 'Club', id }] : [],
- transformResponse: (response: Club) => {
- return clubSchema.parse(response);
- }
- }),
- deleteClub: builder.mutation({
- query: (id) => ({
- url: `${CLUB_API_BASE_URL}/${id}/`,
- method: 'DELETE'
- }),
- invalidatesTags: (_result, _, id) => [{ type: 'Club', id }]
- }),
- clubContacts: builder.query({
- query: (id) => ({
- url: `${CLUB_API_BASE_URL}/${id}/contacts/`,
- method: 'GET'
- }),
- providesTags: (result, _, _arg) =>
- result
- ? result.map((contact) => ({
- type: 'Contact',
- id: contact.id
- }))
- : ['Contact'],
- transformResponse: (response: Contact) => {
- return z.array(contactSchema).parse(response);
- }
- }),
- createContact: builder.mutation<
- Contact,
- { id: string; body: CreateContactRequestBody }
- >({
- query: ({ id, body }) => ({
- url: `${CLUB_API_BASE_URL}/${id}/contacts/`,
- method: 'PUT',
- body
- }),
- invalidatesTags: ['Contact'],
- transformResponse: (response: Contact) => {
- return contactSchema.parse(response);
- }
- }),
- clubEvents: builder.query<
- Event[],
- { id: string; queryParams?: PaginationQueryParams }
- >({
- query: ({ id, queryParams }) => ({
- url: handleQueryParams(
- `${CLUB_API_BASE_URL}/${id}/events/`,
- queryParams
- ),
- method: 'GET'
- }),
- providesTags: (result, _, _arg) =>
- result
- ? result.map((event) => ({ type: 'Event', id: event.id }))
- : ['Event'],
- transformResponse: (response) => {
- return z.array(eventSchema).parse(response);
- }
- }),
- clubFollowers: builder.query<
- User[],
- { id: string; queryParams?: PaginationQueryParams }
- >({
- query: ({ id, queryParams }) => ({
- url: handleQueryParams(
- `${CLUB_API_BASE_URL}/${id}/followers/`,
- queryParams
- ),
- method: 'GET'
- }),
- providesTags: (result, _, _arg) =>
- result
- ? result.map((follower) => ({
- type: 'Follower',
- id: follower.id
- }))
- : ['Follower'],
- transformResponse: (response) => {
- return z.array(userSchema).parse(response);
- }
- }),
- clubMembers: builder.query<
- User[],
- { id: string; queryParams?: PaginationQueryParams }
- >({
- query: ({ id, queryParams }) => ({
- url: handleQueryParams(
- `${CLUB_API_BASE_URL}/${id}/members/`,
- queryParams
- ),
- method: 'GET'
- }),
- providesTags: (result, _, _arg) =>
- result
- ? result.map((member) => ({ type: 'User', id: member.id }))
- : ['User'],
- transformResponse: (response) => {
- return z.array(userSchema).parse(response);
- }
- }),
- clubPointOfContacts: builder.query({
- query: (id) => ({
- url: `${CLUB_API_BASE_URL}/${id}/pocs/`,
- method: 'GET'
- }),
- providesTags: (result, _, _arg) =>
- result
- ? result.map((poc) => ({
- type: 'PointOfContact',
- id: poc.id
- }))
- : ['PointOfContact'],
- transformResponse: (response) => {
- return z.array(pointOfContactSchema).parse(response);
- }
- }),
- clubPointOfContact: builder.query<
- PointOfContact,
- { clubId: string; pocId: string }
- >({
- query: ({ clubId, pocId }) => ({
- url: `${CLUB_API_BASE_URL}/${clubId}/pocs/${pocId}`,
- method: 'GET'
- }),
- providesTags: (result, _, { pocId }) =>
- result ? [{ type: 'PointOfContact', id: pocId }] : [],
- transformResponse: (response) => {
- return pointOfContactSchema.parse(response);
- }
- }),
- createClubPointOfContact: builder.mutation<
- PointOfContact,
- { id: string; body: FormData }
- >({
- query: ({ id, body }) => ({
- url: `${CLUB_API_BASE_URL}/${id}/pocs/`,
- method: 'POST',
- body
- }),
- invalidatesTags: ['PointOfContact'],
- transformResponse: (response) => {
- return pointOfContactSchema.parse(response);
- }
- }),
- updateClubPointOfContactPhoto: builder.mutation<
- PointOfContact,
- { clubId: string; pocId: string; body: FormData }
- >({
- query: ({ clubId, pocId, body }) => ({
- url: `${CLUB_API_BASE_URL}/${clubId}/pocs/${pocId}/photo`,
- method: 'PATCH',
- body
- }),
- invalidatesTags: (result, _, { pocId }) =>
- result ? [{ type: 'PointOfContact', id: pocId }] : [],
- transformResponse: (response) => {
- return pointOfContactSchema.parse(response);
- }
- }),
- updateClubPointOfContact: builder.mutation<
- PointOfContact,
- {
- clubId: string;
- pocId: string;
- body: UpdatePointOfContactRequestBody;
- }
- >({
- query: ({ clubId, pocId, body }) => ({
- url: `${CLUB_API_BASE_URL}/${clubId}/pocs/${pocId}`,
- method: 'PATCH',
- body
- }),
- invalidatesTags: (result, _, { pocId }) =>
- result ? [{ type: 'PointOfContact', id: pocId }] : [],
- transformResponse: (response) => {
- return pointOfContactSchema.parse(response);
- }
- }),
- deleteClubPointOfContact: builder.mutation<
- void,
- { clubId: string; pocId: string }
- >({
- query: ({ clubId, pocId }) => ({
- url: `${CLUB_API_BASE_URL}/${clubId}/pocs/${pocId}`,
- method: 'DELETE'
- }),
- invalidatesTags: (_result, _, { pocId }) => [
- { type: 'PointOfContact', id: pocId }
- ]
- }),
- createClubTags: builder.mutation<
- Tag[],
- { id: string; body: CreateClubTagsRequestBody }
- >({
- query: ({ id, body }) => ({
- url: `${CLUB_API_BASE_URL}/${id}/tags/`,
- method: 'POST',
- body
- }),
- invalidatesTags: (result, _, _arg) =>
- result
- ? result.map((tag) => ({ type: 'Tag', id: tag.id }))
- : ['Tag'],
- transformResponse: (response) => {
- return z.array(tagSchema).parse(response);
- }
- }),
- clubTags: builder.query({
- query: (id) => ({
- url: `${CLUB_API_BASE_URL}/${id}/tags/`,
- method: 'GET'
- }),
- providesTags: (result, _, _arg) =>
- result
- ? result.map((tag) => ({ type: 'Tag', id: tag.id }))
- : ['Tag'],
- transformResponse: (response) => {
- return z.array(tagSchema).parse(response);
- }
- }),
- deleteClubTag: builder.mutation<
- void,
- { clubId: string; tagId: string }
- >({
- query: ({ clubId, tagId }) => ({
- url: `${CLUB_API_BASE_URL}/${clubId}/tags/${tagId}`,
- method: 'DELETE'
- }),
- invalidatesTags: (_result, _, { tagId }) => [
- { type: 'Tag', id: tagId }
- ]
- })
- })
-});
-
-export const {
- useCreateClubMutation,
- useClubsQuery,
- useClubQuery,
- useUpdateClubMutation,
- useDeleteClubMutation,
- useClubContactsQuery,
- useCreateContactMutation,
- useClubEventsQuery,
- useClubFollowersQuery,
- useClubMembersQuery,
- useClubPointOfContactsQuery,
- useClubPointOfContactQuery,
- useCreateClubPointOfContactMutation,
- useUpdateClubPointOfContactPhotoMutation,
- useUpdateClubPointOfContactMutation,
- useDeleteClubPointOfContactMutation,
- useCreateClubTagsMutation,
- useClubTagsQuery,
- useDeleteClubTagMutation
-} = clubApi;
diff --git a/frontend/lib/api/contactApi.ts b/frontend/lib/api/contactApi.ts
deleted file mode 100644
index 396d94089..000000000
--- a/frontend/lib/api/contactApi.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import { z } from 'zod';
-
-import { Contact, contactSchema } from '../types/contact';
-import { PaginationQueryParams } from '../types/root';
-
-import { baseApi, handleQueryParams } from '../api/base';
-
-const CONTACT_API_BASE_URL = '/contacts';
-
-export const contactApi = baseApi.injectEndpoints({
- endpoints: (builder) => ({
- contact: builder.query({
- query: (id) => ({
- url: `${CONTACT_API_BASE_URL}/${id}`,
- method: 'GET'
- }),
- providesTags: (result, _, id) =>
- result ? [{ type: 'Contact', id }] : [],
- transformResponse: (response) => {
- return contactSchema.parse(response);
- }
- }),
- contacts: builder.query({
- query: (queryParams) => ({
- url: handleQueryParams(`${CONTACT_API_BASE_URL}/`, queryParams),
- method: 'GET'
- }),
- providesTags: (result) =>
- result
- ? result.map(({ id }) => ({ type: 'Contact', id }))
- : ['Contact'],
- transformResponse: (response) => {
- return z.array(contactSchema).parse(response);
- }
- }),
- deleteContact: builder.mutation({
- query: (id) => ({
- url: `${CONTACT_API_BASE_URL}/${id}`,
- method: 'DELETE'
- }),
- invalidatesTags: (_result, _, id) => [{ type: 'Contact', id }]
- })
- })
-});
-
-export const { useContactQuery, useContactsQuery, useDeleteContactMutation } =
- contactApi;
diff --git a/frontend/lib/api/eventApi.ts b/frontend/lib/api/eventApi.ts
deleted file mode 100644
index ee8e29618..000000000
--- a/frontend/lib/api/eventApi.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-import { z } from 'zod';
-
-import { Club, clubSchema } from '../types/club';
-import {
- CreateEventRequestBody,
- Event,
- UpdateEventRequestBody,
- eventSchema
-} from '../types/event';
-import { PaginationQueryParams } from '../types/root';
-import { Tag } from '../types/tag';
-
-import { baseApi, handleQueryParams } from '../api/base';
-
-const EVENT_API_BASE_URL = '/events';
-
-export const eventApi = baseApi.injectEndpoints({
- endpoints: (builder) => ({
- events: builder.query({
- query: (queryParams) => ({
- url: handleQueryParams(`${EVENT_API_BASE_URL}/`, queryParams),
- method: 'GET'
- }),
- providesTags: (result, _, _arg) =>
- result
- ? result.map((event) => ({ type: 'Event', id: event.id }))
- : ['Event'],
- transformResponse: (response) => {
- return z.array(eventSchema).parse(response);
- }
- }),
- event: builder.query({
- query: (id) => ({
- url: `${EVENT_API_BASE_URL}/${id}/`,
- method: 'GET'
- }),
- providesTags: (result, _, id) =>
- result ? [{ type: 'Event', id }] : [],
- transformResponse: (response: Event) => {
- return eventSchema.parse(response);
- }
- }),
- createEvent: builder.mutation({
- query: (body) => ({
- url: `${EVENT_API_BASE_URL}/`,
- method: 'POST',
- body
- }),
- invalidatesTags: ['Event'],
- transformResponse: (response) => {
- return eventSchema.parse(response);
- }
- }),
- updateEvent: builder.mutation<
- Event,
- { id: string; body: UpdateEventRequestBody }
- >({
- query: ({ id, body }) => ({
- url: `${EVENT_API_BASE_URL}/${id}`,
- method: 'PATCH',
- body
- }),
- invalidatesTags: (result, _, { id }) =>
- result ? [{ type: 'Event', id }] : [],
- transformResponse: (response) => {
- return eventSchema.parse(response);
- }
- }),
- deleteEvent: builder.mutation({
- query: (id) => ({
- url: `${EVENT_API_BASE_URL}/${id}`,
- method: 'DELETE'
- }),
- invalidatesTags: (result, _, id) =>
- result ? [{ type: 'Event', id }] : []
- }),
- eventHosts: builder.query({
- query: (id) => ({
- url: `${EVENT_API_BASE_URL}/${id}/hosts`,
- method: 'GET'
- }),
- providesTags: (result, _, id) =>
- result ? [{ type: 'Event', id }, 'Club'] : ['Event'],
- transformResponse: (response) => {
- return z.array(clubSchema).parse(response);
- }
- }),
- eventTags: builder.query({
- query: (id) => ({
- url: `${EVENT_API_BASE_URL}/${id}/tags`,
- method: 'GET'
- }),
- providesTags: (result, _, _arg) =>
- result
- ? result.map((tag) => ({ type: 'Tag', id: tag.id }))
- : ['Tag']
- })
- })
-});
-
-export const {
- useEventsQuery,
- useEventQuery,
- useCreateEventMutation,
- useUpdateEventMutation,
- useDeleteEventMutation,
- useEventHostsQuery,
- useEventTagsQuery
-} = eventApi;
diff --git a/frontend/lib/api/fileApi.ts b/frontend/lib/api/fileApi.ts
deleted file mode 100644
index 9df28d1ee..000000000
--- a/frontend/lib/api/fileApi.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import { z } from 'zod';
-
-import { File, fileSchema } from '../types/file';
-import { PaginationQueryParams } from '../types/root';
-
-import { baseApi, handleQueryParams } from '../api/base';
-
-const FILE_API_BASE_URL = '/files';
-
-export const fileApi = baseApi.injectEndpoints({
- endpoints: (builder) => ({
- files: builder.query({
- query: (queryParams) => ({
- url: handleQueryParams(`${FILE_API_BASE_URL}/`, queryParams),
- method: 'GET'
- }),
- providesTags: (result) =>
- result
- ? result.map(({ id }) => ({ type: 'File', id }))
- : ['File'],
- transformResponse: (response) => {
- return z.array(fileSchema).parse(response);
- }
- }),
- file: builder.query({
- query: (id) => ({
- url: `${FILE_API_BASE_URL}/${id}`,
- method: 'GET'
- }),
- providesTags: (result, _, id) =>
- result ? [{ type: 'File', id }] : [],
- transformResponse: (response) => {
- return fileSchema.parse(response);
- }
- }),
- createFile: builder.mutation({
- query: (body) => ({
- url: `${FILE_API_BASE_URL}/`,
- method: 'POST',
- body
- }),
- invalidatesTags: ['File'],
- transformResponse: (response) => {
- return fileSchema.parse(response);
- }
- }),
- deleteFile: builder.mutation({
- query: (id) => ({
- url: `${FILE_API_BASE_URL}/${id}`,
- method: 'DELETE'
- }),
- invalidatesTags: (_result, _, id) => [{ type: 'File', id }]
- })
- })
-});
-
-export const {
- useFilesQuery,
- useFileQuery,
- useCreateFileMutation,
- useDeleteFileMutation
-} = fileApi;
diff --git a/frontend/lib/api/index.ts b/frontend/lib/api/index.ts
deleted file mode 100644
index d9f91448e..000000000
--- a/frontend/lib/api/index.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-export * from './tagApi';
-export * from './userApi';
-export * from './eventApi';
-export * from './contactApi';
-export * from './clubApi';
-export * from './categoryApi';
-export * from './pointOfContactApi';
-export * from './fileApi';
-export * from './authApi';
-export * from './base';
diff --git a/frontend/lib/api/pointOfContactApi.ts b/frontend/lib/api/pointOfContactApi.ts
deleted file mode 100644
index 905a6a499..000000000
--- a/frontend/lib/api/pointOfContactApi.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { z } from 'zod';
-
-import { PointOfContact, pointOfContactSchema } from '../types/pointOfContact';
-import { PaginationQueryParams } from '../types/root';
-
-import { baseApi, handleQueryParams } from '../api/base';
-
-const POC_API_BASE_URL = '/pocs';
-
-export const pointOfContactApi = baseApi.injectEndpoints({
- endpoints: (builder) => ({
- pointOfContacts: builder.query(
- {
- query: (queryParams) => ({
- url: handleQueryParams(`${POC_API_BASE_URL}/`, queryParams),
- method: 'GET'
- }),
- providesTags: (result) =>
- result
- ? result.map(({ id }) => ({
- type: 'PointOfContact',
- id
- }))
- : ['PointOfContact'],
- transformResponse: (response) => {
- return z.array(pointOfContactSchema).parse(response);
- }
- }
- ),
- pointOfContact: builder.query({
- query: (id) => ({
- url: `${POC_API_BASE_URL}/${id}`,
- method: 'GET'
- }),
- providesTags: (result, _, id) =>
- result ? [{ type: 'PointOfContact', id }] : [],
- transformResponse: (response) => {
- return pointOfContactSchema.parse(response);
- }
- })
- })
-});
-
-export const { usePointOfContactsQuery, usePointOfContactQuery } =
- pointOfContactApi;
diff --git a/frontend/lib/api/tagApi.ts b/frontend/lib/api/tagApi.ts
deleted file mode 100644
index c302b2d3a..000000000
--- a/frontend/lib/api/tagApi.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-import { z } from 'zod';
-
-import { PaginationQueryParams } from '../types/root';
-import {
- CreateTagRequestBody,
- Tag,
- UpdateTagRequestBody,
- tagSchema
-} from '../types/tag';
-
-import { baseApi, handleQueryParams } from '../api/base';
-
-const TAG_API_BASE_URL = '/tags';
-
-export const tagApi = baseApi.injectEndpoints({
- endpoints: (builder) => ({
- tags: builder.query({
- query: (queryParams) => ({
- url: handleQueryParams(`${TAG_API_BASE_URL}/`, queryParams),
- method: 'GET'
- }),
- providesTags: (result) =>
- result
- ? result.map(({ id }) => ({ type: 'Tag', id }))
- : ['Tag'],
- transformResponse: (response) => {
- return z.array(tagSchema).parse(response);
- }
- }),
- tag: builder.query({
- query: (id) => ({
- url: `${TAG_API_BASE_URL}/${id}/`,
- method: 'GET'
- }),
- providesTags: (result, _, id) =>
- result ? [{ type: 'Tag', id }] : [],
- transformResponse: (response) => {
- return tagSchema.parse(response);
- }
- }),
- createTag: builder.mutation({
- query: (body) => ({
- url: `${TAG_API_BASE_URL}/`,
- method: 'POST',
- body
- }),
- invalidatesTags: ['Tag'],
- transformResponse: (response) => {
- return tagSchema.parse(response);
- }
- }),
- updateTag: builder.mutation<
- Tag,
- { id: string; body: UpdateTagRequestBody }
- >({
- query: ({ id, body }) => ({
- url: `${TAG_API_BASE_URL}/${id}/`,
- method: 'PATCH',
- body
- }),
- invalidatesTags: (result, _, { id }) =>
- result ? [{ type: 'Tag', id }] : [],
- transformResponse: (response) => {
- return tagSchema.parse(response);
- }
- }),
- deleteTag: builder.mutation({
- query: (id) => ({
- url: `${TAG_API_BASE_URL}/${id}/`,
- method: 'DELETE'
- }),
- invalidatesTags: (_result, _, id) => [{ type: 'Tag', id }]
- })
- })
-});
-
-export const {
- useTagsQuery,
- useTagQuery,
- useCreateTagMutation,
- useUpdateTagMutation,
- useDeleteTagMutation
-} = tagApi;
diff --git a/frontend/lib/api/userApi.ts b/frontend/lib/api/userApi.ts
deleted file mode 100644
index 3092daa01..000000000
--- a/frontend/lib/api/userApi.ts
+++ /dev/null
@@ -1,228 +0,0 @@
-import { z } from 'zod';
-
-import { UpdatePasswordRequestBody } from '../types/auth';
-import { Club, clubSchema } from '../types/club';
-import { PaginationQueryParams } from '../types/root';
-import { Tag, tagSchema } from '../types/tag';
-import {
- CreateUserRequestBody,
- CreateUserTagsRequestBody,
- UpdateUserRequestBody,
- User,
- userSchema
-} from '../types/user';
-
-import { baseApi, handleQueryParams } from '../api/base';
-
-const USER_API_BASE_URL = '/users';
-
-export const userApi = baseApi.injectEndpoints({
- endpoints: (builder) => ({
- users: builder.query({
- query: (queryParams) => ({
- url: handleQueryParams(`${USER_API_BASE_URL}/`, queryParams),
- method: 'GET'
- }),
- providesTags: (result) =>
- result
- ? result.map(({ id }) => ({ type: 'User', id }))
- : ['User'],
- transformResponse: (response) => {
- return z.array(userSchema).parse(response);
- }
- }),
- user: builder.query({
- query: (id) => ({
- url: `${USER_API_BASE_URL}/${id}/`,
- method: 'GET'
- }),
- providesTags: (result, _, id) =>
- result ? [{ type: 'User', id }] : [],
- transformResponse: (response) => {
- return userSchema.parse(response);
- }
- }),
- currentUser: builder.query({
- query: () => ({
- url: `${USER_API_BASE_URL}/me`,
- method: 'GET'
- }),
- providesTags: (result) =>
- result ? [{ type: 'User', id: result.id }] : [],
- transformResponse: (response) => {
- return userSchema.parse(response);
- }
- }),
- createUser: builder.mutation({
- query: (body) => ({
- url: `${USER_API_BASE_URL}/`,
- method: 'POST',
- body
- }),
- invalidatesTags: ['User'],
- transformResponse: (response) => {
- return userSchema.parse(response);
- }
- }),
- updateUser: builder.mutation<
- User,
- { id: string; body: UpdateUserRequestBody }
- >({
- query: ({ id, body }) => ({
- url: `${USER_API_BASE_URL}/${id}/`,
- method: 'PATCH',
- body
- }),
- invalidatesTags: (result, _, { id }) =>
- result ? [{ type: 'User', id }] : [],
- transformResponse: (response) => {
- return userSchema.parse(response);
- }
- }),
- deleteUser: builder.mutation({
- query: (id) => ({
- url: `${USER_API_BASE_URL}/${id}/`,
- method: 'DELETE'
- }),
- invalidatesTags: (_result, _, id) => [{ type: 'User', id }]
- }),
- updatePassword: builder.mutation<
- void,
- { id: string; body: UpdatePasswordRequestBody }
- >({
- query: ({ id, body }) => ({
- url: `${USER_API_BASE_URL}/${id}/password`,
- method: 'PATCH',
- body
- })
- }),
- userFollowing: builder.query({
- query: (id) => ({
- url: `${USER_API_BASE_URL}/${id}/follower/`,
- method: 'GET'
- }),
- providesTags: (result, _, id) =>
- result
- ? [{ type: 'Follower', id }, 'Club']
- : [{ type: 'Follower', id }],
- transformResponse: (response) => {
- return z.array(clubSchema).parse(response);
- }
- }),
- createUserFollowing: builder.mutation<
- void,
- { userID: string; clubID: string }
- >({
- query: ({ userID, clubID }) => ({
- url: `${USER_API_BASE_URL}/${userID}/follower/${clubID}`,
- method: 'POST'
- }),
- invalidatesTags: (_result, _, { userID }) => [
- { type: 'Follower', id: userID }
- ]
- }),
- deleteUserFollowing: builder.mutation<
- void,
- { userID: string; clubID: string }
- >({
- query: ({ userID, clubID }) => ({
- url: `${USER_API_BASE_URL}/${userID}/follower/${clubID}`,
- method: 'DELETE'
- }),
- invalidatesTags: (_result, _, { userID }) => [
- { type: 'Follower', id: userID }
- ]
- }),
- userMembership: builder.query({
- query: (id) => ({
- url: `${USER_API_BASE_URL}/${id}/member/`,
- method: 'GET'
- }),
- providesTags: (result, _, id) =>
- result
- ? [{ type: 'Member', id }, 'Club']
- : [{ type: 'Member', id }],
- transformResponse: (response) => {
- return z.array(clubSchema).parse(response);
- }
- }),
- createUserMembership: builder.mutation<
- void,
- { userID: string; clubID: string }
- >({
- query: ({ userID, clubID }) => ({
- url: `${USER_API_BASE_URL}/${userID}/member/${clubID}`,
- method: 'POST'
- }),
- invalidatesTags: (_result, _, { userID }) => [
- { type: 'Follower', id: userID },
- { type: 'Member', id: userID }
- ]
- }),
- deleteUserMembership: builder.mutation<
- void,
- { userID: string; clubID: string }
- >({
- query: ({ userID, clubID }) => ({
- url: `${USER_API_BASE_URL}/${userID}/member/${clubID}`,
- method: 'DELETE'
- }),
- invalidatesTags: (_result, _, { userID }) => [
- { type: 'Member', id: userID }
- ]
- }),
- userTags: builder.query({
- query: () => ({
- url: `${USER_API_BASE_URL}/tags/`,
- method: 'GET'
- }),
- providesTags: (result) =>
- result
- ? result.map((tag) => ({ type: 'Tag', id: tag.id }))
- : ['Tag'],
- transformResponse: (response) => {
- return z.array(tagSchema).parse(response);
- }
- }),
- createUserTags: builder.mutation({
- query: (body) => ({
- url: `${USER_API_BASE_URL}/tags/`,
- method: 'POST',
- body
- }),
- invalidatesTags: (result, _, _arg) =>
- result
- ? result.map((tag) => ({ type: 'Tag', id: tag.id }))
- : ['Tag'],
- transformResponse: (response) => {
- return z.array(tagSchema).parse(response);
- }
- }),
- deleteUserTag: builder.mutation({
- query: (id) => ({
- url: `${USER_API_BASE_URL}/tags/${id}/`,
- method: 'DELETE'
- }),
- invalidatesTags: (_result, _, id) => [{ type: 'Tag', id }]
- })
- })
-});
-
-export const {
- useUsersQuery,
- useUserQuery,
- useCurrentUserQuery,
- useCreateUserMutation,
- useUpdateUserMutation,
- useDeleteUserMutation,
- useUpdatePasswordMutation,
- useUserFollowingQuery,
- useCreateUserFollowingMutation,
- useDeleteUserFollowingMutation,
- useUserMembershipQuery,
- useCreateUserMembershipMutation,
- useDeleteUserMembershipMutation,
- useUserTagsQuery,
- useCreateUserTagsMutation,
- useDeleteUserTagMutation
-} = userApi;
diff --git a/frontend/lib/const.ts b/frontend/lib/const.ts
deleted file mode 100644
index 75dab23f5..000000000
--- a/frontend/lib/const.ts
+++ /dev/null
@@ -1 +0,0 @@
-export const API_BASE_URL = 'http://127.0.0.1:8080/api/v1';
diff --git a/frontend/lib/index.ts b/frontend/lib/index.ts
deleted file mode 100644
index 4d4b4e299..000000000
--- a/frontend/lib/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from './api';
-export * from './types';
diff --git a/frontend/lib/package.json b/frontend/lib/package.json
index 116e230ac..35c09da62 100644
--- a/frontend/lib/package.json
+++ b/frontend/lib/package.json
@@ -1,19 +1,56 @@
{
- "name": "@sac/lib",
- "main": "index.ts",
- "version": "0.1.0",
- "scripts": {
- "test": "echo \"Woah there, we have no frontend tests as of right now. Let's just say we're passing.\" && exit 0",
- "lint": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
- "format": "prettier --write ."
- },
- "private": true,
- "dependencies": {
- "@reduxjs/toolkit": "^2.2.3",
- "zod": "^3.23.4"
- },
- "devDependencies": {
- "eslint-plugin-prettier": "^5.1.3",
- "prettier": "^3.2.4"
- }
+ "name": "@generatesac/lib",
+ "version": "0.0.1",
+ "type": "module",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "files": [
+ "dist"
+ ],
+ "description": "This repository holds the common types, apis, and components for frontend library used by the Student Activity Calendar.",
+ "repository": {
+ "url": "https://github.com/GenerateNU/sac"
+ },
+ "license": "ISC",
+ "scripts": {
+ "dev": "vite",
+ "format": "prettier --write .",
+ "build": "tsc && vite build",
+ "watch": "yarn build --watch",
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
+ "test": "echo \"Woah there, we have no frontend tests as of right now. Let's just say we're passing.\" && exit 0"
+ },
+ "dependencies": {
+ "@reduxjs/toolkit": "^2.2.3",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-icons": "^5.2.1",
+ "react-redux": "^9.1.2",
+ "zod": "^3.23.6"
+ },
+ "devDependencies": {
+ "@trivago/prettier-plugin-sort-imports": "^4.3.0",
+ "@types/node": "^20.12.10",
+ "@types/react": "^18.2.66",
+ "@types/react-dom": "^18.2.22",
+ "@typescript-eslint/eslint-plugin": "^7.2.0",
+ "@typescript-eslint/parser": "^7.2.0",
+ "@vitejs/plugin-react-swc": "^3.5.0",
+ "eslint": "^8.57.0",
+ "eslint-plugin-react-hooks": "^4.6.0",
+ "eslint-plugin-react-refresh": "^0.4.6",
+ "glob": "^10.3.12",
+ "prettier": "^3.2.5",
+ "typescript": "^5.2.2",
+ "vite": "^5.2.0",
+ "vite-plugin-dts": "^3.9.1",
+ "vite-plugin-lib-inject-css": "^2.0.1"
+ },
+ "peerDependencies": {
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "publishConfig": {
+ "@generatesac:registry": "https://npm.pkg.github.com"
+ }
}
diff --git a/frontend/lib/src/api/authApi.ts b/frontend/lib/src/api/authApi.ts
new file mode 100644
index 000000000..e16cd6fef
--- /dev/null
+++ b/frontend/lib/src/api/authApi.ts
@@ -0,0 +1,69 @@
+import { LoginRequestBody, RefreshTokenRequestBody } from "../types/auth";
+import { User, userSchema } from "../types/user";
+import {
+ EmailRequestBody,
+ VerifyEmailRequestBody,
+ VerifyPasswordResetTokenRequestBody,
+} from "../types/verification";
+import { baseApi } from "./base";
+
+const AUTH_API_BASE_URL = "/auth";
+
+export const authApi = baseApi.injectEndpoints({
+ endpoints: (builder) => ({
+ login: builder.mutation({
+ query: (body) => ({
+ url: `${AUTH_API_BASE_URL}/login`,
+ method: "POST",
+ body,
+ }),
+ transformResponse: (response: User) => {
+ return userSchema.parse(response);
+ },
+ }),
+ logout: builder.mutation({
+ query: () => ({
+ url: `${AUTH_API_BASE_URL}/logout`,
+ method: "POST",
+ }),
+ }),
+ refresh: builder.mutation({
+ query: (body) => ({
+ url: "refresh",
+ method: "POST",
+ body,
+ }),
+ }),
+ forgotPassword: builder.mutation({
+ query: (body) => ({
+ url: `${AUTH_API_BASE_URL}/forgot-password`,
+ method: "POST",
+ body,
+ }),
+ }),
+ verifyPasswordResetToken: builder.mutation<
+ void,
+ VerifyPasswordResetTokenRequestBody
+ >({
+ query: (body) => ({
+ url: `${AUTH_API_BASE_URL}/verify-reset`,
+ method: "POST",
+ body,
+ }),
+ }),
+ sendCode: builder.mutation({
+ query: (body) => ({
+ url: `${AUTH_API_BASE_URL}/send-code`,
+ method: "POST",
+ body,
+ }),
+ }),
+ verifyEmail: builder.mutation({
+ query: (body) => ({
+ url: `${AUTH_API_BASE_URL}/verify-email`,
+ method: "POST",
+ body,
+ }),
+ }),
+ }),
+});
diff --git a/frontend/lib/src/api/base.ts b/frontend/lib/src/api/base.ts
new file mode 100644
index 000000000..f4171fc23
--- /dev/null
+++ b/frontend/lib/src/api/base.ts
@@ -0,0 +1,45 @@
+import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
+
+export const API_BASE_URL = "http://127.0.0.1:8080/api/v1";
+
+// BaseAPI for the entire application:
+export const baseApi = createApi({
+ baseQuery: fetchBaseQuery({
+ baseUrl: API_BASE_URL,
+ credentials: "include",
+ prepareHeaders: async (headers, { getState }) => {
+ const token = (getState() as { auth: { token: string } })?.auth.token;
+ if (token) {
+ headers.set("Authorization", `Bearer ${token}`);
+ }
+ return headers;
+ },
+ }),
+ tagTypes: [
+ "User",
+ "Tag",
+ "Category",
+ "Club",
+ "Contact",
+ "Event",
+ "PointOfContact",
+ "File",
+ "Follower",
+ "Member",
+ ],
+ endpoints: () => ({}),
+});
+
+// Add query params to a request:
+export function handleQueryParams(
+ baseUrl: string,
+ queryParams?: Record,
+): string {
+ const url = new URL(baseUrl);
+ if (queryParams) {
+ Object.entries(queryParams).forEach(([key, value]) => {
+ url.searchParams.append(key, value.toString());
+ });
+ }
+ return url.toString();
+}
diff --git a/frontend/lib/src/api/categoryApi.ts b/frontend/lib/src/api/categoryApi.ts
new file mode 100644
index 000000000..d2f5e9259
--- /dev/null
+++ b/frontend/lib/src/api/categoryApi.ts
@@ -0,0 +1,99 @@
+import { z } from "zod";
+
+import {
+ Category,
+ CreateCategoryRequestBody,
+ categorySchema,
+} from "../types/category";
+import { PaginationQueryParams } from "../types/root";
+import { Tag } from "../types/tag";
+import { baseApi, handleQueryParams } from "./base";
+
+const CATEGORY_API_BASE_URL = "/categories";
+
+export const categoryApi = baseApi.injectEndpoints({
+ endpoints: (builder) => ({
+ createCategory: builder.mutation({
+ query: (body) => ({
+ url: CATEGORY_API_BASE_URL,
+ method: "POST",
+ body,
+ }),
+ transformResponse: (response: Category) => {
+ return categorySchema.parse(response);
+ },
+ invalidatesTags: ["Category"],
+ }),
+ categories: builder.query({
+ query: (queryParams) => ({
+ url: handleQueryParams(`${CATEGORY_API_BASE_URL}/`, queryParams),
+ method: "GET",
+ }),
+ transformResponse: (response: Category[]) => {
+ return z.array(categorySchema).parse(response);
+ },
+ providesTags: (result, _, _arg) =>
+ result
+ ? result.map((category) => ({
+ type: "Category",
+ id: category.id,
+ }))
+ : ["Category"],
+ }),
+ category: builder.query({
+ query: (id) => ({
+ url: `${CATEGORY_API_BASE_URL}/${id}/`,
+ method: "GET",
+ }),
+ transformResponse: (response: Category) => {
+ return categorySchema.parse(response);
+ },
+ providesTags: (result, _, id) =>
+ result ? [{ type: "Category", id }] : [],
+ }),
+ deleteCategory: builder.mutation({
+ query: (id) => ({
+ url: `${CATEGORY_API_BASE_URL}/${id}/`,
+ method: "DELETE",
+ }),
+ invalidatesTags: (_result, _, id) => [{ type: "Category", id }],
+ }),
+ updateCategory: builder.mutation<
+ Category,
+ { id: string; body: CreateCategoryRequestBody }
+ >({
+ query: ({ id, body }) => ({
+ url: `${CATEGORY_API_BASE_URL}/${id}/`,
+ method: "PUT",
+ body,
+ }),
+ transformResponse: (response: Category) => {
+ return categorySchema.parse(response);
+ },
+ invalidatesTags: (result, _, { id }) =>
+ result ? [{ type: "Category", id }] : [],
+ }),
+ categoryTags: builder.query<
+ Tag[],
+ { id: string; queryParams?: PaginationQueryParams }
+ >({
+ query: ({ id, queryParams }) => ({
+ url: handleQueryParams(
+ `${CATEGORY_API_BASE_URL}/${id}/tags/`,
+ queryParams,
+ ),
+ method: "GET",
+ }),
+ providesTags: (result, _, _arg) =>
+ result ? result.map((tag) => ({ type: "Tag", id: tag.id })) : ["Tag"],
+ }),
+ categoryTag: builder.query({
+ query: ({ categoryID, tagID }) => ({
+ url: `${CATEGORY_API_BASE_URL}/${categoryID}/tags/${tagID}/`,
+ method: "GET",
+ }),
+ providesTags: (result, _, { tagID }) =>
+ result ? [{ type: "Tag", id: tagID }] : [],
+ }),
+ }),
+});
diff --git a/frontend/lib/src/api/clubApi.ts b/frontend/lib/src/api/clubApi.ts
new file mode 100644
index 000000000..278836379
--- /dev/null
+++ b/frontend/lib/src/api/clubApi.ts
@@ -0,0 +1,322 @@
+import { z } from "zod";
+
+import {
+ Club,
+ CreateClubRequestBody,
+ CreateClubTagsRequestBody,
+ UpdateClubRequestBody,
+ clubSchema,
+} from "../types/club";
+import {
+ Contact,
+ CreateContactRequestBody,
+ contactSchema,
+} from "../types/contact";
+import { Event, eventSchema } from "../types/event";
+import {
+ PointOfContact,
+ UpdatePointOfContactRequestBody,
+ pointOfContactSchema,
+} from "../types/pointOfContact";
+import { PaginationQueryParams } from "../types/root";
+import { Tag, tagSchema } from "../types/tag";
+import { User, userSchema } from "../types/user";
+import { baseApi, handleQueryParams } from "./base";
+
+export const CLUB_API_BASE_URL = "/clubs";
+
+export const clubApi = baseApi.injectEndpoints({
+ endpoints: (builder) => ({
+ createClub: builder.mutation({
+ query: (body) => ({
+ url: `${CLUB_API_BASE_URL}/`,
+ method: "POST",
+ body,
+ }),
+ invalidatesTags: ["Club"],
+ transformResponse: (response: Club) => {
+ return clubSchema.parse(response);
+ },
+ }),
+ clubs: builder.query({
+ query: (queryParams) => ({
+ url: handleQueryParams(`${CLUB_API_BASE_URL}/`, queryParams),
+ method: "GET",
+ }),
+ providesTags: (result, _, _arg) =>
+ result
+ ? result.map((club) => ({ type: "Club", id: club.id }))
+ : ["Club"],
+ transformResponse: (response: Club) => {
+ return z.array(clubSchema).parse(response);
+ },
+ }),
+ club: builder.query({
+ query: (id) => ({
+ url: `${CLUB_API_BASE_URL}/${id}/`,
+ method: "GET",
+ }),
+ providesTags: (result, _, id) => (result ? [{ type: "Club", id }] : []),
+ transformResponse: (response: Club) => {
+ return clubSchema.parse(response);
+ },
+ }),
+ updateClub: builder.mutation<
+ Club,
+ { id: string; body: UpdateClubRequestBody }
+ >({
+ query: ({ id, body }) => ({
+ url: `${CLUB_API_BASE_URL}/${id}/`,
+ method: "PATCH",
+ body,
+ }),
+ invalidatesTags: (result, _, { id }) =>
+ result ? [{ type: "Club", id }] : [],
+ transformResponse: (response: Club) => {
+ return clubSchema.parse(response);
+ },
+ }),
+ deleteClub: builder.mutation({
+ query: (id) => ({
+ url: `${CLUB_API_BASE_URL}/${id}/`,
+ method: "DELETE",
+ }),
+ invalidatesTags: (_result, _, id) => [{ type: "Club", id }],
+ }),
+ clubContacts: builder.query({
+ query: (id) => ({
+ url: `${CLUB_API_BASE_URL}/${id}/contacts/`,
+ method: "GET",
+ }),
+ providesTags: (result, _, _arg) =>
+ result
+ ? result.map((contact) => ({
+ type: "Contact",
+ id: contact.id,
+ }))
+ : ["Contact"],
+ transformResponse: (response: Contact) => {
+ return z.array(contactSchema).parse(response);
+ },
+ }),
+ createContact: builder.mutation<
+ Contact,
+ { id: string; body: CreateContactRequestBody }
+ >({
+ query: ({ id, body }) => ({
+ url: `${CLUB_API_BASE_URL}/${id}/contacts/`,
+ method: "PUT",
+ body,
+ }),
+ invalidatesTags: ["Contact"],
+ transformResponse: (response: Contact) => {
+ return contactSchema.parse(response);
+ },
+ }),
+ clubEvents: builder.query<
+ Event[],
+ { id: string; queryParams?: PaginationQueryParams }
+ >({
+ query: ({ id, queryParams }) => ({
+ url: handleQueryParams(
+ `${CLUB_API_BASE_URL}/${id}/events/`,
+ queryParams,
+ ),
+ method: "GET",
+ }),
+ providesTags: (result, _, _arg) =>
+ result
+ ? result.map((event) => ({ type: "Event", id: event.id }))
+ : ["Event"],
+ transformResponse: (response) => {
+ return z.array(eventSchema).parse(response);
+ },
+ }),
+ clubFollowers: builder.query<
+ User[],
+ { id: string; queryParams?: PaginationQueryParams }
+ >({
+ query: ({ id, queryParams }) => ({
+ url: handleQueryParams(
+ `${CLUB_API_BASE_URL}/${id}/followers/`,
+ queryParams,
+ ),
+ method: "GET",
+ }),
+ providesTags: (result, _, _arg) =>
+ result
+ ? result.map((follower) => ({
+ type: "Follower",
+ id: follower.id,
+ }))
+ : ["Follower"],
+ transformResponse: (response) => {
+ return z.array(userSchema).parse(response);
+ },
+ }),
+ clubMembers: builder.query<
+ User[],
+ { id: string; queryParams?: PaginationQueryParams }
+ >({
+ query: ({ id, queryParams }) => ({
+ url: handleQueryParams(
+ `${CLUB_API_BASE_URL}/${id}/members/`,
+ queryParams,
+ ),
+ method: "GET",
+ }),
+ providesTags: (result, _, _arg) =>
+ result
+ ? result.map((member) => ({ type: "User", id: member.id }))
+ : ["User"],
+ transformResponse: (response) => {
+ return z.array(userSchema).parse(response);
+ },
+ }),
+ createClubMember: builder.mutation<
+ User,
+ { clubID: string; userID: string }
+ >({
+ query: ({ clubID, userID }) => ({
+ url: `${CLUB_API_BASE_URL}/${clubID}/members/${userID}`,
+ method: "POST",
+ }),
+ invalidatesTags: (result, _, { userID }) =>
+ result ? [{ type: "User", id: userID }] : [],
+ }),
+ deleteClubMember: builder.mutation<
+ void,
+ { clubID: string; userID: string }
+ >({
+ query: ({ clubID, userID }) => ({
+ url: `${CLUB_API_BASE_URL}/${clubID}/members/${userID}`,
+ method: "DELETE",
+ }),
+ invalidatesTags: (result, _, { userID }) =>
+ result ? [{ type: "User", id: userID }] : [],
+ }),
+ clubPointOfContacts: builder.query({
+ query: (id) => ({
+ url: `${CLUB_API_BASE_URL}/${id}/pocs/`,
+ method: "GET",
+ }),
+ providesTags: (result, _, _arg) =>
+ result
+ ? result.map((poc) => ({
+ type: "PointOfContact",
+ id: poc.id,
+ }))
+ : ["PointOfContact"],
+ transformResponse: (response) => {
+ return z.array(pointOfContactSchema).parse(response);
+ },
+ }),
+ clubPointOfContact: builder.query<
+ PointOfContact,
+ { clubID: string; pocId: string }
+ >({
+ query: ({ clubID, pocId }) => ({
+ url: `${CLUB_API_BASE_URL}/${clubID}/pocs/${pocId}`,
+ method: "GET",
+ }),
+ providesTags: (result, _, { pocId }) =>
+ result ? [{ type: "PointOfContact", id: pocId }] : [],
+ transformResponse: (response) => {
+ return pointOfContactSchema.parse(response);
+ },
+ }),
+ createClubPointOfContact: builder.mutation<
+ PointOfContact,
+ { id: string; body: FormData }
+ >({
+ query: ({ id, body }) => ({
+ url: `${CLUB_API_BASE_URL}/${id}/pocs/`,
+ method: "POST",
+ body,
+ }),
+ invalidatesTags: ["PointOfContact"],
+ transformResponse: (response) => {
+ return pointOfContactSchema.parse(response);
+ },
+ }),
+ updateClubPointOfContactPhoto: builder.mutation<
+ PointOfContact,
+ { clubID: string; pocId: string; body: FormData }
+ >({
+ query: ({ clubID, pocId, body }) => ({
+ url: `${CLUB_API_BASE_URL}/${clubID}/pocs/${pocId}/photo`,
+ method: "PATCH",
+ body,
+ }),
+ invalidatesTags: (result, _, { pocId }) =>
+ result ? [{ type: "PointOfContact", id: pocId }] : [],
+ transformResponse: (response) => {
+ return pointOfContactSchema.parse(response);
+ },
+ }),
+ updateClubPointOfContact: builder.mutation<
+ PointOfContact,
+ {
+ clubID: string;
+ pocId: string;
+ body: UpdatePointOfContactRequestBody;
+ }
+ >({
+ query: ({ clubID, pocId, body }) => ({
+ url: `${CLUB_API_BASE_URL}/${clubID}/pocs/${pocId}`,
+ method: "PATCH",
+ body,
+ }),
+ invalidatesTags: (result, _, { pocId }) =>
+ result ? [{ type: "PointOfContact", id: pocId }] : [],
+ transformResponse: (response) => {
+ return pointOfContactSchema.parse(response);
+ },
+ }),
+ deleteClubPointOfContact: builder.mutation<
+ void,
+ { clubID: string; pocId: string }
+ >({
+ query: ({ clubID, pocId }) => ({
+ url: `${CLUB_API_BASE_URL}/${clubID}/pocs/${pocId}`,
+ method: "DELETE",
+ }),
+ invalidatesTags: (_result, _, { pocId }) => [
+ { type: "PointOfContact", id: pocId },
+ ],
+ }),
+ createClubTags: builder.mutation<
+ Tag[],
+ { id: string; body: CreateClubTagsRequestBody }
+ >({
+ query: ({ id, body }) => ({
+ url: `${CLUB_API_BASE_URL}/${id}/tags/`,
+ method: "POST",
+ body,
+ }),
+ invalidatesTags: (result, _, _arg) =>
+ result ? result.map((tag) => ({ type: "Tag", id: tag.id })) : ["Tag"],
+ transformResponse: (response) => {
+ return z.array(tagSchema).parse(response);
+ },
+ }),
+ clubTags: builder.query({
+ query: (id) => ({
+ url: `${CLUB_API_BASE_URL}/${id}/tags/`,
+ method: "GET",
+ }),
+ providesTags: (result, _, _arg) =>
+ result ? result.map((tag) => ({ type: "Tag", id: tag.id })) : ["Tag"],
+ transformResponse: (response) => {
+ return z.array(tagSchema).parse(response);
+ },
+ }),
+ deleteClubTag: builder.mutation({
+ query: ({ clubID, tagId }) => ({
+ url: `${CLUB_API_BASE_URL}/${clubID}/tags/${tagId}`,
+ method: "DELETE",
+ }),
+ invalidatesTags: (_result, _, { tagId }) => [{ type: "Tag", id: tagId }],
+ }),
+ }),
+});
diff --git a/frontend/lib/src/api/contactApi.ts b/frontend/lib/src/api/contactApi.ts
new file mode 100644
index 000000000..1f49c01e7
--- /dev/null
+++ b/frontend/lib/src/api/contactApi.ts
@@ -0,0 +1,43 @@
+import { z } from "zod";
+
+import { Contact, contactSchema } from "../types/contact";
+import { PaginationQueryParams } from "../types/root";
+import { baseApi, handleQueryParams } from "./base";
+
+const CONTACT_API_BASE_URL = "/contacts";
+
+export const contactApi = baseApi.injectEndpoints({
+ endpoints: (builder) => ({
+ contact: builder.query({
+ query: (id) => ({
+ url: `${CONTACT_API_BASE_URL}/${id}`,
+ method: "GET",
+ }),
+ providesTags: (result, _, id) =>
+ result ? [{ type: "Contact", id }] : [],
+ transformResponse: (response) => {
+ return contactSchema.parse(response);
+ },
+ }),
+ contacts: builder.query({
+ query: (queryParams) => ({
+ url: handleQueryParams(`${CONTACT_API_BASE_URL}/`, queryParams),
+ method: "GET",
+ }),
+ providesTags: (result) =>
+ result
+ ? result.map(({ id }) => ({ type: "Contact", id }))
+ : ["Contact"],
+ transformResponse: (response) => {
+ return z.array(contactSchema).parse(response);
+ },
+ }),
+ deleteContact: builder.mutation({
+ query: (id) => ({
+ url: `${CONTACT_API_BASE_URL}/${id}`,
+ method: "DELETE",
+ }),
+ invalidatesTags: (_result, _, id) => [{ type: "Contact", id }],
+ }),
+ }),
+});
diff --git a/frontend/lib/src/api/eventApi.ts b/frontend/lib/src/api/eventApi.ts
new file mode 100644
index 000000000..6a20e8b28
--- /dev/null
+++ b/frontend/lib/src/api/eventApi.ts
@@ -0,0 +1,95 @@
+import { z } from "zod";
+
+import { Club, clubSchema } from "../types/club";
+import {
+ CreateEventRequestBody,
+ Event,
+ UpdateEventRequestBody,
+ eventSchema,
+} from "../types/event";
+import { PaginationQueryParams } from "../types/root";
+import { Tag } from "../types/tag";
+import { baseApi, handleQueryParams } from "./base";
+
+const EVENT_API_BASE_URL = "/events";
+
+export const eventApi = baseApi.injectEndpoints({
+ endpoints: (builder) => ({
+ events: builder.query({
+ query: (queryParams) => ({
+ url: handleQueryParams(`${EVENT_API_BASE_URL}/`, queryParams),
+ method: "GET",
+ }),
+ providesTags: (result, _, _arg) =>
+ result
+ ? result.map((event) => ({ type: "Event", id: event.id }))
+ : ["Event"],
+ transformResponse: (response) => {
+ return z.array(eventSchema).parse(response);
+ },
+ }),
+ event: builder.query({
+ query: (id) => ({
+ url: `${EVENT_API_BASE_URL}/${id}/`,
+ method: "GET",
+ }),
+ providesTags: (result, _, id) => (result ? [{ type: "Event", id }] : []),
+ transformResponse: (response: Event) => {
+ return eventSchema.parse(response);
+ },
+ }),
+ createEvent: builder.mutation({
+ query: (body) => ({
+ url: `${EVENT_API_BASE_URL}/`,
+ method: "POST",
+ body,
+ }),
+ invalidatesTags: ["Event"],
+ transformResponse: (response) => {
+ return eventSchema.parse(response);
+ },
+ }),
+ updateEvent: builder.mutation<
+ Event,
+ { id: string; body: UpdateEventRequestBody }
+ >({
+ query: ({ id, body }) => ({
+ url: `${EVENT_API_BASE_URL}/${id}`,
+ method: "PATCH",
+ body,
+ }),
+ invalidatesTags: (result, _, { id }) =>
+ result ? [{ type: "Event", id }] : [],
+ transformResponse: (response) => {
+ return eventSchema.parse(response);
+ },
+ }),
+ deleteEvent: builder.mutation({
+ query: (id) => ({
+ url: `${EVENT_API_BASE_URL}/${id}`,
+ method: "DELETE",
+ }),
+ invalidatesTags: (result, _, id) =>
+ result ? [{ type: "Event", id }] : [],
+ }),
+ eventHosts: builder.query({
+ query: (id) => ({
+ url: `${EVENT_API_BASE_URL}/${id}/hosts`,
+ method: "GET",
+ }),
+ providesTags: (result, _, id) =>
+ result ? [{ type: "Event", id }, "Club"] : ["Event"],
+ transformResponse: (response) => {
+ return z.array(clubSchema).parse(response);
+ },
+ }),
+ eventTags: builder.query({
+ query: (id) => ({
+ url: `${EVENT_API_BASE_URL}/${id}/tags`,
+ method: "GET",
+ }),
+ providesTags: (result, _, _arg) =>
+ result ? result.map((tag) => ({ type: "Tag", id: tag.id })) : ["Tag"],
+ }),
+ }),
+});
diff --git a/frontend/lib/src/api/fileApi.ts b/frontend/lib/src/api/fileApi.ts
new file mode 100644
index 000000000..9725b7fb3
--- /dev/null
+++ b/frontend/lib/src/api/fileApi.ts
@@ -0,0 +1,51 @@
+import { z } from "zod";
+
+import { File, fileSchema } from "../types/file";
+import { PaginationQueryParams } from "../types/root";
+import { baseApi, handleQueryParams } from "./base";
+
+const FILE_API_BASE_URL = "/files";
+
+export const fileApi = baseApi.injectEndpoints({
+ endpoints: (builder) => ({
+ files: builder.query({
+ query: (queryParams) => ({
+ url: handleQueryParams(`${FILE_API_BASE_URL}/`, queryParams),
+ method: "GET",
+ }),
+ providesTags: (result) =>
+ result ? result.map(({ id }) => ({ type: "File", id })) : ["File"],
+ transformResponse: (response) => {
+ return z.array(fileSchema).parse(response);
+ },
+ }),
+ file: builder.query({
+ query: (id) => ({
+ url: `${FILE_API_BASE_URL}/${id}`,
+ method: "GET",
+ }),
+ providesTags: (result, _, id) => (result ? [{ type: "File", id }] : []),
+ transformResponse: (response) => {
+ return fileSchema.parse(response);
+ },
+ }),
+ createFile: builder.mutation({
+ query: (body) => ({
+ url: `${FILE_API_BASE_URL}/`,
+ method: "POST",
+ body,
+ }),
+ invalidatesTags: ["File"],
+ transformResponse: (response) => {
+ return fileSchema.parse(response);
+ },
+ }),
+ deleteFile: builder.mutation({
+ query: (id) => ({
+ url: `${FILE_API_BASE_URL}/${id}`,
+ method: "DELETE",
+ }),
+ invalidatesTags: (_result, _, id) => [{ type: "File", id }],
+ }),
+ }),
+});
diff --git a/frontend/lib/src/api/index.ts b/frontend/lib/src/api/index.ts
new file mode 100644
index 000000000..36963c18c
--- /dev/null
+++ b/frontend/lib/src/api/index.ts
@@ -0,0 +1,10 @@
+export * from "./tagApi";
+export * from "./userApi";
+export * from "./eventApi";
+export * from "./contactApi";
+export * from "./clubApi";
+export * from "./categoryApi";
+export * from "./pointOfContactApi";
+export * from "./fileApi";
+export * from "./authApi";
+export * from "./base";
diff --git a/frontend/lib/src/api/pointOfContactApi.ts b/frontend/lib/src/api/pointOfContactApi.ts
new file mode 100644
index 000000000..4ce7630ca
--- /dev/null
+++ b/frontend/lib/src/api/pointOfContactApi.ts
@@ -0,0 +1,39 @@
+import { z } from "zod";
+
+import { PointOfContact, pointOfContactSchema } from "../types/pointOfContact";
+import { PaginationQueryParams } from "../types/root";
+import { baseApi, handleQueryParams } from "./base";
+
+const POC_API_BASE_URL = "/pocs";
+
+export const pointOfContactApi = baseApi.injectEndpoints({
+ endpoints: (builder) => ({
+ pointOfContacts: builder.query({
+ query: (queryParams) => ({
+ url: handleQueryParams(`${POC_API_BASE_URL}/`, queryParams),
+ method: "GET",
+ }),
+ providesTags: (result) =>
+ result
+ ? result.map(({ id }) => ({
+ type: "PointOfContact",
+ id,
+ }))
+ : ["PointOfContact"],
+ transformResponse: (response) => {
+ return z.array(pointOfContactSchema).parse(response);
+ },
+ }),
+ pointOfContact: builder.query({
+ query: (id) => ({
+ url: `${POC_API_BASE_URL}/${id}`,
+ method: "GET",
+ }),
+ providesTags: (result, _, id) =>
+ result ? [{ type: "PointOfContact", id }] : [],
+ transformResponse: (response) => {
+ return pointOfContactSchema.parse(response);
+ },
+ }),
+ }),
+});
diff --git a/frontend/lib/src/api/tagApi.ts b/frontend/lib/src/api/tagApi.ts
new file mode 100644
index 000000000..aed91c8c7
--- /dev/null
+++ b/frontend/lib/src/api/tagApi.ts
@@ -0,0 +1,71 @@
+import { z } from "zod";
+
+import { PaginationQueryParams } from "../types/root";
+import {
+ CreateTagRequestBody,
+ Tag,
+ UpdateTagRequestBody,
+ tagSchema,
+} from "../types/tag";
+import { baseApi, handleQueryParams } from "./base";
+
+const TAG_API_BASE_URL = "/tags";
+
+export const tagApi = baseApi.injectEndpoints({
+ endpoints: (builder) => ({
+ tags: builder.query({
+ query: (queryParams) => ({
+ url: handleQueryParams(`${TAG_API_BASE_URL}/`, queryParams),
+ method: "GET",
+ }),
+ providesTags: (result) =>
+ result ? result.map(({ id }) => ({ type: "Tag", id })) : ["Tag"],
+ transformResponse: (response) => {
+ return z.array(tagSchema).parse(response);
+ },
+ }),
+ tag: builder.query({
+ query: (id) => ({
+ url: `${TAG_API_BASE_URL}/${id}/`,
+ method: "GET",
+ }),
+ providesTags: (result, _, id) => (result ? [{ type: "Tag", id }] : []),
+ transformResponse: (response) => {
+ return tagSchema.parse(response);
+ },
+ }),
+ createTag: builder.mutation({
+ query: (body) => ({
+ url: `${TAG_API_BASE_URL}/`,
+ method: "POST",
+ body,
+ }),
+ invalidatesTags: ["Tag"],
+ transformResponse: (response) => {
+ return tagSchema.parse(response);
+ },
+ }),
+ updateTag: builder.mutation<
+ Tag,
+ { id: string; body: UpdateTagRequestBody }
+ >({
+ query: ({ id, body }) => ({
+ url: `${TAG_API_BASE_URL}/${id}/`,
+ method: "PATCH",
+ body,
+ }),
+ invalidatesTags: (result, _, { id }) =>
+ result ? [{ type: "Tag", id }] : [],
+ transformResponse: (response) => {
+ return tagSchema.parse(response);
+ },
+ }),
+ deleteTag: builder.mutation({
+ query: (id) => ({
+ url: `${TAG_API_BASE_URL}/${id}/`,
+ method: "DELETE",
+ }),
+ invalidatesTags: (_result, _, id) => [{ type: "Tag", id }],
+ }),
+ }),
+});
diff --git a/frontend/lib/src/api/userApi.ts b/frontend/lib/src/api/userApi.ts
new file mode 100644
index 000000000..76ff03c62
--- /dev/null
+++ b/frontend/lib/src/api/userApi.ts
@@ -0,0 +1,174 @@
+import { z } from "zod";
+
+import { UpdatePasswordRequestBody } from "../types/auth";
+import { Club, clubSchema } from "../types/club";
+import { PaginationQueryParams } from "../types/root";
+import { Tag, tagSchema } from "../types/tag";
+import {
+ CreateUserRequestBody,
+ CreateUserTagsRequestBody,
+ UpdateUserRequestBody,
+ User,
+ userSchema,
+} from "../types/user";
+import { baseApi, handleQueryParams } from "./base";
+
+const USER_API_BASE_URL = "/users";
+
+export const userApi = baseApi.injectEndpoints({
+ endpoints: (builder) => ({
+ users: builder.query({
+ query: (queryParams) => ({
+ url: handleQueryParams(`${USER_API_BASE_URL}/`, queryParams),
+ method: "GET",
+ }),
+ providesTags: (result) =>
+ result ? result.map(({ id }) => ({ type: "User", id })) : ["User"],
+ transformResponse: (response) => {
+ return z.array(userSchema).parse(response);
+ },
+ }),
+ user: builder.query({
+ query: (id) => ({
+ url: `${USER_API_BASE_URL}/${id}/`,
+ method: "GET",
+ }),
+ providesTags: (result, _, id) => (result ? [{ type: "User", id }] : []),
+ transformResponse: (response) => {
+ return userSchema.parse(response);
+ },
+ }),
+ currentUser: builder.query({
+ query: () => ({
+ url: `${USER_API_BASE_URL}/me`,
+ method: "GET",
+ }),
+ providesTags: (result) =>
+ result ? [{ type: "User", id: result.id }] : [],
+ transformResponse: (response) => {
+ return userSchema.parse(response);
+ },
+ }),
+ createUser: builder.mutation({
+ query: (body) => ({
+ url: `${USER_API_BASE_URL}/`,
+ method: "POST",
+ body,
+ }),
+ invalidatesTags: ["User"],
+ transformResponse: (response) => {
+ return userSchema.parse(response);
+ },
+ }),
+ updateUser: builder.mutation<
+ User,
+ { id: string; body: UpdateUserRequestBody }
+ >({
+ query: ({ id, body }) => ({
+ url: `${USER_API_BASE_URL}/${id}/`,
+ method: "PATCH",
+ body,
+ }),
+ invalidatesTags: (result, _, { id }) =>
+ result ? [{ type: "User", id }] : [],
+ transformResponse: (response) => {
+ return userSchema.parse(response);
+ },
+ }),
+ deleteUser: builder.mutation({
+ query: (id) => ({
+ url: `${USER_API_BASE_URL}/${id}/`,
+ method: "DELETE",
+ }),
+ invalidatesTags: (_result, _, id) => [{ type: "User", id }],
+ }),
+ updatePassword: builder.mutation<
+ void,
+ { id: string; body: UpdatePasswordRequestBody }
+ >({
+ query: ({ id, body }) => ({
+ url: `${USER_API_BASE_URL}/${id}/password`,
+ method: "PATCH",
+ body,
+ }),
+ }),
+ userFollowing: builder.query({
+ query: (id) => ({
+ url: `${USER_API_BASE_URL}/${id}/follower/`,
+ method: "GET",
+ }),
+ providesTags: (result, _, id) =>
+ result
+ ? [{ type: "Follower", id }, "Club"]
+ : [{ type: "Follower", id }],
+ transformResponse: (response) => {
+ return z.array(clubSchema).parse(response);
+ },
+ }),
+ createUserFollowing: builder.mutation<
+ void,
+ { userID: string; clubID: string }
+ >({
+ query: ({ userID, clubID }) => ({
+ url: `${USER_API_BASE_URL}/${userID}/follower/${clubID}`,
+ method: "POST",
+ }),
+ invalidatesTags: (_result, _, { userID }) => [
+ { type: "Follower", id: userID },
+ ],
+ }),
+ deleteUserFollowing: builder.mutation<
+ void,
+ { userID: string; clubID: string }
+ >({
+ query: ({ userID, clubID }) => ({
+ url: `${USER_API_BASE_URL}/${userID}/follower/${clubID}`,
+ method: "DELETE",
+ }),
+ invalidatesTags: (_result, _, { userID }) => [
+ { type: "Follower", id: userID },
+ ],
+ }),
+ userMembership: builder.query({
+ query: (id) => ({
+ url: `${USER_API_BASE_URL}/${id}/member/`,
+ method: "GET",
+ }),
+ providesTags: (result, _, id) =>
+ result ? [{ type: "Member", id }, "Club"] : [{ type: "Member", id }],
+ transformResponse: (response) => {
+ return z.array(clubSchema).parse(response);
+ },
+ }),
+ userTags: builder.query({
+ query: () => ({
+ url: `${USER_API_BASE_URL}/tags/`,
+ method: "GET",
+ }),
+ providesTags: (result) =>
+ result ? result.map((tag) => ({ type: "Tag", id: tag.id })) : ["Tag"],
+ transformResponse: (response) => {
+ return z.array(tagSchema).parse(response);
+ },
+ }),
+ createUserTags: builder.mutation({
+ query: (body) => ({
+ url: `${USER_API_BASE_URL}/tags/`,
+ method: "POST",
+ body,
+ }),
+ invalidatesTags: (result, _, _arg) =>
+ result ? result.map((tag) => ({ type: "Tag", id: tag.id })) : ["Tag"],
+ transformResponse: (response) => {
+ return z.array(tagSchema).parse(response);
+ },
+ }),
+ deleteUserTag: builder.mutation({
+ query: (id) => ({
+ url: `${USER_API_BASE_URL}/tags/${id}/`,
+ method: "DELETE",
+ }),
+ invalidatesTags: (_result, _, id) => [{ type: "Tag", id }],
+ }),
+ }),
+});
diff --git a/frontend/lib/src/index.ts b/frontend/lib/src/index.ts
new file mode 100644
index 000000000..1d58e1a79
--- /dev/null
+++ b/frontend/lib/src/index.ts
@@ -0,0 +1,2 @@
+export * from "./api";
+export * from "./types";
diff --git a/frontend/lib/types/auth.ts b/frontend/lib/src/types/auth.ts
similarity index 58%
rename from frontend/lib/types/auth.ts
rename to frontend/lib/src/types/auth.ts
index f9191dc5a..e45d7af5f 100644
--- a/frontend/lib/types/auth.ts
+++ b/frontend/lib/src/types/auth.ts
@@ -1,31 +1,31 @@
-import { z } from 'zod';
+import { z } from "zod";
// Schemas:
export const loginRequestBodySchema = z.object({
- email: z.string().email(),
- password: z.string().min(8)
+ email: z.string().email(),
+ password: z.string().min(8),
});
export const updatePasswordRequestBodySchema = z.object({
- old_password: z.string().min(8),
- new_password: z.string().min(8)
+ old_password: z.string().min(8),
+ new_password: z.string().min(8),
});
export const refreshTokenRequestBodySchema = z.object({
- refresh_token: z.string()
+ refresh_token: z.string(),
});
export const tokensSchema = z.object({
- access_token: z.string(),
- refresh_token: z.string()
+ access_token: z.string(),
+ refresh_token: z.string(),
});
// Types:
export type LoginRequestBody = z.infer;
export type UpdatePasswordRequestBody = z.infer<
- typeof updatePasswordRequestBodySchema
+ typeof updatePasswordRequestBodySchema
>;
export type RefreshTokenRequestBody = z.infer<
- typeof refreshTokenRequestBodySchema
+ typeof refreshTokenRequestBodySchema
>;
export type Tokens = z.infer;
diff --git a/frontend/lib/types/category.ts b/frontend/lib/src/types/category.ts
similarity index 59%
rename from frontend/lib/types/category.ts
rename to frontend/lib/src/types/category.ts
index f400b4d70..6577d5693 100644
--- a/frontend/lib/types/category.ts
+++ b/frontend/lib/src/types/category.ts
@@ -1,22 +1,22 @@
-import { z } from 'zod';
+import { z } from "zod";
-import { rootModelSchema } from './root';
-import { tagSchema } from './tag';
+import { rootModelSchema } from "./root";
+import { tagSchema } from "./tag";
// Schemas:
export const createCategoryRequestBodySchema = z.object({
- name: z.string().min(1)
+ name: z.string().min(1),
});
export const categorySchemaIntermediate = z.object({
- name: z.string(),
- tags: z.array(tagSchema)
+ name: z.string(),
+ tags: z.array(tagSchema),
});
export const categorySchema = categorySchemaIntermediate.merge(rootModelSchema);
// Types:
export type CreateCategoryRequestBody = z.infer<
- typeof createCategoryRequestBodySchema
+ typeof createCategoryRequestBodySchema
>;
export type Category = z.infer;
diff --git a/frontend/lib/src/types/club.ts b/frontend/lib/src/types/club.ts
new file mode 100644
index 000000000..1f1705ca5
--- /dev/null
+++ b/frontend/lib/src/types/club.ts
@@ -0,0 +1,65 @@
+import { z } from "zod";
+
+import { rootModelSchema } from "./root";
+
+// Enums:
+const recruitmentCycleEnum = z.enum(["fall", "spring", "fallSpring", "always"]);
+const recruitmentTypeEnum = z.enum(["unrestricted", "tryout", "application"]);
+
+// Schemas:
+export const createClubRequestBodySchema = z.object({
+ user_id: z.string().uuid(),
+ name: z.string(),
+ preview: z.string(),
+ description: z.string(),
+ is_recruiting: z.boolean(),
+ recruitment_cycle: recruitmentCycleEnum,
+ recruitment_type: recruitmentTypeEnum,
+ application_link: z.string(),
+ logo: z.string().optional(),
+ weekly_time_committment: z.number().optional(),
+ one_word_to_describe_us: z.string().max(20).optional(),
+});
+
+export const updateClubRequestBodySchema = z.object({
+ name: z.string().optional(),
+ preview: z.string().optional(),
+ description: z.string().optional(),
+ is_recruiting: z.boolean().optional(),
+ recruitment_cycle: recruitmentCycleEnum.optional(),
+ recruitment_type: recruitmentTypeEnum.optional(),
+ application_link: z.string().optional(),
+ logo: z.string().optional(),
+ weekly_time_committment: z.number().optional(),
+ one_word_to_describe_us: z.string().max(20).optional(),
+});
+
+export const createClubTagsRequestBodySchema = z.object({
+ tags: z.array(z.string().uuid()),
+});
+
+const clubSchemaIntermediate = z.object({
+ name: z.string().max(255),
+ preview: z.string().max(255),
+ description: z.string().max(255),
+ num_members: z.number(),
+ is_recruiting: z.boolean(),
+ recruitment_cycle: recruitmentCycleEnum,
+ recruitment_type: recruitmentTypeEnum,
+ application_link: z.string().max(255),
+ logo: z.string().max(255).optional(),
+ weekly_time_committment: z.number().optional(),
+ one_word_to_describe_us: z.string().max(20).optional(),
+});
+
+export const clubSchema = clubSchemaIntermediate.merge(rootModelSchema);
+
+// Types:
+export type RecruitmentCycle = z.infer;
+export type RecruitmentType = z.infer;
+export type CreateClubRequestBody = z.infer;
+export type UpdateClubRequestBody = z.infer;
+export type CreateClubTagsRequestBody = z.infer<
+ typeof createClubTagsRequestBodySchema
+>;
+export type Club = z.infer;
diff --git a/frontend/lib/src/types/contact.ts b/frontend/lib/src/types/contact.ts
new file mode 100644
index 000000000..7ec56c109
--- /dev/null
+++ b/frontend/lib/src/types/contact.ts
@@ -0,0 +1,33 @@
+import { z } from "zod";
+
+import { rootModelSchema } from "./root";
+
+// Enums:
+const contactTypeEnum = z.enum([
+ "facebook",
+ "instagram",
+ "x",
+ "linkedin",
+ "youtube",
+ "github",
+ "slack",
+ "discord",
+ "email",
+ "customSite",
+]);
+
+// Schemas:
+export const createContactRequestBodySchema = z.object({
+ type: contactTypeEnum,
+ content: z.string().max(255),
+});
+
+export const contactSchema =
+ createContactRequestBodySchema.merge(rootModelSchema);
+
+// Types:
+export type ContactType = z.infer;
+export type CreateContactRequestBody = z.infer<
+ typeof createContactRequestBodySchema
+>;
+export type Contact = z.infer;
diff --git a/frontend/lib/types/error.ts b/frontend/lib/src/types/error.ts
similarity index 63%
rename from frontend/lib/types/error.ts
rename to frontend/lib/src/types/error.ts
index aa50e46ac..6bfb33c7d 100644
--- a/frontend/lib/types/error.ts
+++ b/frontend/lib/src/types/error.ts
@@ -1,3 +1,3 @@
export type ErrorResponse = {
- error: string;
+ error: string;
};
diff --git a/frontend/lib/src/types/event.ts b/frontend/lib/src/types/event.ts
new file mode 100644
index 000000000..594a01c5d
--- /dev/null
+++ b/frontend/lib/src/types/event.ts
@@ -0,0 +1,57 @@
+import { z } from "zod";
+
+import { rootModelSchema } from "./root";
+
+/**
+ * TODO: Re-Write After BE Fixes
+ */
+
+// Enums:
+const eventTypeEnum = z.enum(["open", "membersOnly"]);
+
+// Schemas:
+const createEventRequestBodySchema = z.object({
+ name: z.string(),
+ preview: z.string(),
+ content: z.string(),
+ start_time: z.date(),
+ end_time: z.date(),
+ location: z.string(),
+ event_type: eventTypeEnum,
+ is_recurring: z.boolean(),
+});
+
+const updateEventRequestBodySchema = z.object({
+ name: z.string().optional(),
+ preview: z.string().optional(),
+ content: z.string().optional(),
+ start_time: z.date().optional(),
+ end_time: z.date().optional(),
+ location: z.string().optional(),
+ event_type: eventTypeEnum.optional(),
+ host: z.string().uuid().optional(),
+});
+
+const eventSchemaIntermediate = z.object({
+ name: z.string().max(255),
+ preview: z.string().max(255),
+ content: z.string().max(255),
+ start_time: z.date(),
+ end_time: z.date(),
+ location: z.string().max(255),
+ meeting_link: z.string().max(255).optional(),
+ event_type: eventTypeEnum,
+ is_recurring: z.boolean(),
+ host: z.string().uuid(),
+});
+
+export const eventSchema = eventSchemaIntermediate.merge(rootModelSchema);
+
+// Types:
+export type CreateEventRequestBody = z.infer<
+ typeof createEventRequestBodySchema
+>;
+export type UpdateEventRequestBody = z.infer<
+ typeof updateEventRequestBodySchema
+>;
+export type Event = z.infer;
diff --git a/frontend/lib/src/types/file.ts b/frontend/lib/src/types/file.ts
new file mode 100644
index 000000000..87716e371
--- /dev/null
+++ b/frontend/lib/src/types/file.ts
@@ -0,0 +1,25 @@
+import { z } from "zod";
+
+import { rootModelSchema } from "./root";
+
+// Schemas:
+export const createFileRequestBodySchema = z.object({
+ owner_id: z.string().uuid(),
+ owner_type: z.string().max(255),
+});
+
+const fileSchemaIntermediate = z.object({
+ owner_id: z.string().uuid(),
+ owner_type: z.string().max(255),
+ file_name: z.string().max(255),
+ file_type: z.string().max(255),
+ file_size: z.number().min(1),
+ file_url: z.string().max(255),
+ object_key: z.string().max(255),
+});
+
+export const fileSchema = fileSchemaIntermediate.merge(rootModelSchema);
+
+// Types:
+export type CreateFileRequestBody = z.infer;
+export type File = z.infer;
diff --git a/frontend/lib/src/types/index.ts b/frontend/lib/src/types/index.ts
new file mode 100644
index 000000000..693dbacf2
--- /dev/null
+++ b/frontend/lib/src/types/index.ts
@@ -0,0 +1,12 @@
+export * from "./auth";
+export * from "./error";
+export * from "./root";
+export * from "./club";
+export * from "./contact";
+export * from "./user";
+export * from "./tag";
+export * from "./category";
+export * from "./event";
+export * from "./file";
+export * from "./pointOfContact";
+export * from "./verification";
diff --git a/frontend/lib/src/types/pointOfContact.ts b/frontend/lib/src/types/pointOfContact.ts
new file mode 100644
index 000000000..b21072c3b
--- /dev/null
+++ b/frontend/lib/src/types/pointOfContact.ts
@@ -0,0 +1,36 @@
+import { z } from "zod";
+
+import { fileSchema } from "./file";
+import { rootModelSchema } from "./root";
+
+// Schemas:
+const createPointOfContactRequestBodySchema = z.object({
+ name: z.string(),
+ email: z.string().email(),
+ position: z.string(),
+});
+
+const updatePointOfContactRequestBodySchema = z.object({
+ name: z.string().optional(),
+ email: z.string().email().optional(),
+ position: z.string().optional(),
+});
+
+const pointOfContactSchemaIntermediate = z.object({
+ name: z.string().max(255),
+ email: z.string().email(),
+ position: z.string().max(255),
+ photo_file: fileSchema,
+});
+
+export const pointOfContactSchema =
+ pointOfContactSchemaIntermediate.merge(rootModelSchema);
+
+// Types:
+export type CreatePointOfContactRequestBody = z.infer<
+ typeof createPointOfContactRequestBodySchema
+>;
+export type UpdatePointOfContactRequestBody = z.infer<
+ typeof updatePointOfContactRequestBodySchema
+>;
+export type PointOfContact = z.infer;
diff --git a/frontend/lib/src/types/root.ts b/frontend/lib/src/types/root.ts
new file mode 100644
index 000000000..eba7ca968
--- /dev/null
+++ b/frontend/lib/src/types/root.ts
@@ -0,0 +1,18 @@
+import { z } from "zod";
+
+export type uuid = string;
+
+export const rootModelSchema = z.object({
+ id: z.string().uuid(),
+ created_at: z.date(),
+ updated_at: z.date(),
+});
+
+const paginationQueryParams = z
+ .object({
+ page: z.number().int().positive().optional(),
+ limit: z.number().int().positive().optional(),
+ })
+ .optional();
+
+export type PaginationQueryParams = z.infer;
diff --git a/frontend/lib/types/tag.ts b/frontend/lib/src/types/tag.ts
similarity index 63%
rename from frontend/lib/types/tag.ts
rename to frontend/lib/src/types/tag.ts
index 88a978719..4a350be13 100644
--- a/frontend/lib/types/tag.ts
+++ b/frontend/lib/src/types/tag.ts
@@ -1,21 +1,21 @@
-import { z } from 'zod';
+import { z } from "zod";
-import { rootModelSchema } from './root';
+import { rootModelSchema } from "./root";
// Schemas:
export const createTagRequestBodySchema = z.object({
- name: z.string(),
- categoryID: z.string().uuid()
+ name: z.string(),
+ categoryID: z.string().uuid(),
});
export const updateTagRequestBodySchema = z.object({
- name: z.string().optional(),
- categoryID: z.string().uuid().optional()
+ name: z.string().optional(),
+ categoryID: z.string().uuid().optional(),
});
export const tagSchemaIntermediate = z.object({
- name: z.string().max(255),
- category_id: z.string().uuid()
+ name: z.string().max(255),
+ category_id: z.string().uuid(),
});
export const tagSchema = tagSchemaIntermediate.merge(rootModelSchema);
diff --git a/frontend/lib/src/types/user.ts b/frontend/lib/src/types/user.ts
new file mode 100644
index 000000000..b2e9b1572
--- /dev/null
+++ b/frontend/lib/src/types/user.ts
@@ -0,0 +1,184 @@
+import { z } from "zod";
+
+import { rootModelSchema } from "./root";
+
+// Enums:
+export const userRoleEnum = z.enum(["super", "student"]);
+
+export const collegeEnum = z.enum([
+ "CAMD",
+ "DMSB",
+ "KCCS",
+ "CE",
+ "BCHS",
+ "SL",
+ "CPS",
+ "CS",
+ "CSSH",
+]);
+
+export const majorEnum = z.enum([
+ "africanaStudies",
+ "americanSignLanguage",
+ "americanSignLanguage-EnglishInterpreting",
+ "appliedPhysics",
+ "architecturalStudies",
+ "architecture",
+ "art:ArtVisualStudies",
+ "behavioralNeuroscience",
+ "biochemistry",
+ "bioengineering",
+ "biology",
+ "biomedicalPhysics",
+ "businessAdministration",
+ "businessAdministration:Accounting",
+ "businessAdministration:AccountingAndAdvisoryServices",
+ "businessAdministration:BrandManagement",
+ "businessAdministration:BusinessAnalytics",
+ "businessAdministration:CorporateInnovation",
+ "businessAdministration:EntrepreneurialStartups",
+ "businessAdministration:FamilyBusiness",
+ "businessAdministration:Finance",
+ "businessAdministration:Fintech",
+ "businessAdministration:HealthcareManagementAndConsulting",
+ "businessAdministration:Management",
+ "businessAdministration:ManagementInformationSystems",
+ "businessAdministration:Marketing",
+ "businessAdministration:MarketingAnalytics",
+ "businessAdministration:SocialInnovationAndEntrepreneurship",
+ "businessAdministration:SupplyChainManagement",
+ "cellAndMolecularBiology",
+ "chemicalEngineering",
+ "chemistry",
+ "civilEngineering",
+ "communicationStudies",
+ "computerEngineering",
+ "computerScience",
+ "computingAndLaw",
+ "criminologyAndCriminalJustice",
+ "culturalAnthropology",
+ "cybersecurity",
+ "dataScience",
+ "design",
+ "economics",
+ "electricalEngineering",
+ "english",
+ "environmentalAndSustainabilityStudies",
+ "environmentalEngineering",
+ "environmentalScience",
+ "environmentalStudies",
+ "gameArtAndAnimation",
+ "gameDesign",
+ "globalAsianStudies",
+ "healthScience",
+ "history",
+ "historyCultureAndLaw",
+ "humanServices",
+ "industrialEngineering",
+ "internationalAffairs",
+ "internationalBusiness",
+ "internationalBusiness:Accounting",
+ "internationalBusiness:AccountingAndAdvisoryServices",
+ "internationalBusiness:BrandManagement",
+ "internationalBusiness:BusinessAnalytics",
+ "internationalBusiness:CorporateInnovation",
+ "internationalBusiness:EntrepreneurialStartups",
+ "internationalBusiness:FamilyBusiness",
+ "internationalBusiness:Finance",
+ "internationalBusiness:Fintech",
+ "internationalBusiness:HealthcareManagementAndConsulting",
+ "internationalBusiness:Management",
+ "internationalBusiness:ManagementInformationSystems",
+ "internationalBusiness:Marketing",
+ "internationalBusiness:MarketingAnalytics",
+ "internationalBusiness:SocialInnovationAndEntrepreneurship",
+ "internationalBusiness:SupplyChainManagement",
+ "journalism",
+ "landscapeArchitecture",
+ "linguistics",
+ "marineBiology",
+ "mathematics",
+ "mechanicalEngineering",
+ "mediaAndScreenStudies",
+ "mediaArts",
+ "music",
+ "musicTechnology",
+ "nursing",
+ "pharmaceuticalSciences",
+ "pharmacy(PharmD)",
+ "philosophy",
+ "physics",
+ "politicalScience",
+ "politicsPhilosophyEconomics",
+ "psychology",
+ "publicHealth",
+ "publicRelations",
+ "religiousStudies",
+ "sociology",
+ "spanish",
+ "speechLanguagePathologyAndAudiology",
+ "theatre",
+]);
+
+export const graduationCycleEnum = z.enum(["december", "may"]);
+
+export const yearEnum = z.enum(["1", "2", "3", "4", "5"]);
+
+// Schemas:
+export const createUserRequestBodySchema = z.object({
+ first_name: z.string().min(1),
+ last_name: z.string().min(1),
+ email: z.string().email(),
+ password: z.string().min(8),
+ major0: majorEnum.optional(),
+ major1: majorEnum.optional(),
+ major2: majorEnum.optional(),
+ college: collegeEnum,
+ graduation_cycle: graduationCycleEnum.optional(),
+ graduation_year: z.number().optional(),
+});
+
+export const updateUserRequestBodySchema = z.object({
+ first_name: z.string().min(1).optional(),
+ last_name: z.string().min(1).optional(),
+ major0: majorEnum.optional(),
+ major1: majorEnum.optional(),
+ major2: majorEnum.optional(),
+ college: collegeEnum.optional(),
+ graduation_cycle: graduationCycleEnum.optional(),
+ graduation_year: z.number().optional(),
+});
+
+export const createUserTagsRequestBodySchema = z.object({
+ tags: z.array(z.string().uuid()),
+});
+
+const userSchemaIntermediate = z.object({
+ role: userRoleEnum,
+ first_name: z.string().min(1),
+ last_name: z.string().min(1),
+ email: z.string().email(),
+ major0: majorEnum.optional(),
+ major1: majorEnum.optional(),
+ major2: majorEnum.optional(),
+ college: collegeEnum.optional(),
+ graduation_cycle: graduationCycleEnum.optional(),
+ graduation_year: z.number().optional(),
+ is_verified: z.boolean(),
+});
+
+export const userSchema = userSchemaIntermediate.merge(rootModelSchema);
+
+// Types:
+export type UserRole = z.infer;
+export type College = z.infer;
+export type Major = z.infer;
+export type GraduationCycle = z.infer;
+export type Year = z.infer;
+
+export type CreateUserRequestBody = z.infer;
+export type UpdateUserRequestBody = z.infer;
+export type CreateUserTagsRequestBody = z.infer<
+ typeof createUserTagsRequestBodySchema
+>;
+export type User = z.infer;
diff --git a/frontend/lib/types/verification.ts b/frontend/lib/src/types/verification.ts
similarity index 52%
rename from frontend/lib/types/verification.ts
rename to frontend/lib/src/types/verification.ts
index fc26ad025..8b4cd0880 100644
--- a/frontend/lib/types/verification.ts
+++ b/frontend/lib/src/types/verification.ts
@@ -1,38 +1,38 @@
-import { z } from 'zod';
+import { z } from "zod";
// Enums:
-const verificationTypeEnum = z.enum(['email_verification', 'password_reset']);
+const verificationTypeEnum = z.enum(["email_verification", "password_reset"]);
// Schemas:
const emailRequestBodySchema = z.object({
- email: z.string().email()
+ email: z.string().email(),
});
const verifyEmailRequestBodySchema = z.object({
- email: z.string().email(),
- token: z.string().length(6)
+ email: z.string().email(),
+ token: z.string().length(6),
});
const verifyPasswordResetTokenRequestBodySchema = z.object({
- token: z.string(),
- new_password: z.string().min(8),
- verify_new_password: z.string().min(8)
+ token: z.string(),
+ new_password: z.string().min(8),
+ verify_new_password: z.string().min(8),
});
const verificationSchema = z.object({
- user_id: z.string().uuid(),
- token: z.string(),
- expires_at: z.date(),
- type: verificationTypeEnum
+ user_id: z.string().uuid(),
+ token: z.string(),
+ expires_at: z.date(),
+ type: verificationTypeEnum,
});
// Types:
export type VerificationType = z.infer;
export type EmailRequestBody = z.infer;
export type VerifyEmailRequestBody = z.infer<
- typeof verifyEmailRequestBodySchema
+ typeof verifyEmailRequestBodySchema
>;
export type VerifyPasswordResetTokenRequestBody = z.infer<
- typeof verifyPasswordResetTokenRequestBodySchema
+ typeof verifyPasswordResetTokenRequestBodySchema
>;
export type Verification = z.infer;
diff --git a/frontend/lib/src/vite-env.d.ts b/frontend/lib/src/vite-env.d.ts
new file mode 100644
index 000000000..11f02fe2a
--- /dev/null
+++ b/frontend/lib/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/frontend/lib/store.ts b/frontend/lib/store.ts
deleted file mode 100644
index 03038174f..000000000
--- a/frontend/lib/store.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { configureStore } from '@reduxjs/toolkit';
-import { setupListeners } from '@reduxjs/toolkit/query';
-
-import { categoriesApi } from './api/category';
-import { clubsApi } from './api/club';
-import { contactsApi } from './api/contact';
-import { eventsApi } from './api/event';
-import { tagsApi } from './api/tag';
-import { usersApi } from './api/user';
-
-export const store = configureStore({
- reducer: {
- [usersApi.reducerPath]: usersApi.reducer,
- [clubsApi.reducerPath]: clubsApi.reducer,
- [eventsApi.reducerPath]: eventsApi.reducer,
- [categoriesApi.reducerPath]: categoriesApi.reducer,
- [contactsApi.reducerPath]: contactsApi.reducer,
- [tagsApi.reducerPath]: tagsApi.reducer
- },
-
- middleware: (getDefaultMiddleware) =>
- getDefaultMiddleware()
- .concat(usersApi.middleware)
- .concat(clubsApi.middleware)
- .concat(eventsApi.middleware)
- .concat(categoriesApi.middleware)
- .concat(contactsApi.middleware)
- .concat(tagsApi.middleware)
-});
-
-setupListeners(store.dispatch);
-
-export type RootState = ReturnType;
-export type AppDispatch = typeof store.dispatch;
diff --git a/frontend/lib/tsconfig.json b/frontend/lib/tsconfig.json
index 4998af8a0..aa2736782 100644
--- a/frontend/lib/tsconfig.json
+++ b/frontend/lib/tsconfig.json
@@ -1,28 +1,26 @@
{
- "compilerOptions": {
- "target": "es5",
- "lib": ["dom", "dom.iterable", "esnext"],
- "allowJs": true,
- "skipLibCheck": true,
- "strict": true,
- "noEmit": true,
- "esModuleInterop": true,
- "module": "esnext",
- "moduleResolution": "bundler",
- "resolveJsonModule": true,
- "isolatedModules": true,
- "jsx": "preserve",
- "incremental": true,
- "plugins": [
- {
- "name": "next"
- }
- ],
- "baseUrl": ".",
- "paths": {
- "@/*": ["./*"]
- }
- },
- "include": ["**/*.ts", "**/*.tsx", "types/index.ts"],
- "exclude": ["node_modules"]
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["test", "src"],
+ "exclude": ["node_modules", "dist"],
+ "references": [{ "path": "./tsconfig.node.json" }]
}
diff --git a/frontend/lib/tsconfig.node.json b/frontend/lib/tsconfig.node.json
new file mode 100644
index 000000000..97ede7ee6
--- /dev/null
+++ b/frontend/lib/tsconfig.node.json
@@ -0,0 +1,11 @@
+{
+ "compilerOptions": {
+ "composite": true,
+ "skipLibCheck": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "allowSyntheticDefaultImports": true,
+ "strict": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/frontend/lib/types/club.ts b/frontend/lib/types/club.ts
deleted file mode 100644
index b43bc9c63..000000000
--- a/frontend/lib/types/club.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-import { z } from 'zod';
-
-import { rootModelSchema } from './root';
-
-// Enums:
-const recruitmentCycleEnum = z.enum(['fall', 'spring', 'fallSpring', 'always']);
-const recruitmentTypeEnum = z.enum(['unrestricted', 'tryout', 'application']);
-
-// Schemas:
-export const createClubRequestBodySchema = z.object({
- user_id: z.string().uuid(),
- name: z.string(),
- preview: z.string(),
- description: z.string(),
- is_recruiting: z.boolean(),
- recruitment_cycle: recruitmentCycleEnum,
- recruitment_type: recruitmentTypeEnum,
- application_link: z.string(),
- logo: z.string().optional(),
- weekly_time_committment: z.number().optional(),
- one_word_to_describe_us: z.string().max(20).optional()
-});
-
-export const updateClubRequestBodySchema = z.object({
- name: z.string().optional(),
- preview: z.string().optional(),
- description: z.string().optional(),
- is_recruiting: z.boolean().optional(),
- recruitment_cycle: recruitmentCycleEnum.optional(),
- recruitment_type: recruitmentTypeEnum.optional(),
- application_link: z.string().optional(),
- logo: z.string().optional(),
- weekly_time_committment: z.number().optional(),
- one_word_to_describe_us: z.string().max(20).optional()
-});
-
-export const createClubTagsRequestBodySchema = z.object({
- tags: z.array(z.string().uuid())
-});
-
-const clubSchemaIntermediate = z.object({
- name: z.string().max(255),
- preview: z.string().max(255),
- description: z.string().max(255),
- num_members: z.number(),
- is_recruiting: z.boolean(),
- recruitment_cycle: recruitmentCycleEnum,
- recruitment_type: recruitmentTypeEnum,
- application_link: z.string().max(255),
- logo: z.string().max(255).optional(),
- weekly_time_committment: z.number().optional(),
- one_word_to_describe_us: z.string().max(20).optional()
-});
-
-export const clubSchema = clubSchemaIntermediate.merge(rootModelSchema);
-
-// Types:
-export type RecruitmentCycle = z.infer;
-export type RecruitmentType = z.infer;
-export type CreateClubRequestBody = z.infer;
-export type UpdateClubRequestBody = z.infer;
-export type CreateClubTagsRequestBody = z.infer<
- typeof createClubTagsRequestBodySchema
->;
-export type Club = z.infer;
diff --git a/frontend/lib/types/contact.ts b/frontend/lib/types/contact.ts
deleted file mode 100644
index 664284e93..000000000
--- a/frontend/lib/types/contact.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { z } from 'zod';
-
-import { rootModelSchema } from './root';
-
-// Enums:
-const contactTypeEnum = z.enum([
- 'facebook',
- 'instagram',
- 'x',
- 'linkedin',
- 'youtube',
- 'github',
- 'slack',
- 'discord',
- 'email',
- 'customSite'
-]);
-
-// Schemas:
-export const createContactRequestBodySchema = z.object({
- type: contactTypeEnum,
- content: z.string().max(255)
-});
-
-export const contactSchema =
- createContactRequestBodySchema.merge(rootModelSchema);
-
-// Types:
-export type ContactType = z.infer;
-export type CreateContactRequestBody = z.infer<
- typeof createContactRequestBodySchema
->;
-export type Contact = z.infer;
diff --git a/frontend/lib/types/event.ts b/frontend/lib/types/event.ts
deleted file mode 100644
index 515066238..000000000
--- a/frontend/lib/types/event.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import { z } from 'zod';
-
-import { rootModelSchema } from './root';
-
-/**
- * TODO: Re-Write After BE Fixes
- */
-
-// Enums:
-const eventTypeEnum = z.enum(['open', 'membersOnly']);
-
-// Schemas:
-const createEventRequestBodySchema = z.object({
- name: z.string(),
- preview: z.string(),
- content: z.string(),
- start_time: z.date(),
- end_time: z.date(),
- location: z.string(),
- event_type: eventTypeEnum,
- is_recurring: z.boolean()
-});
-
-const updateEventRequestBodySchema = z.object({
- name: z.string().optional(),
- preview: z.string().optional(),
- content: z.string().optional(),
- start_time: z.date().optional(),
- end_time: z.date().optional(),
- location: z.string().optional(),
- event_type: eventTypeEnum.optional(),
- host: z.string().uuid().optional()
-});
-
-const eventSchemaIntermediate = z.object({
- name: z.string().max(255),
- preview: z.string().max(255),
- content: z.string().max(255),
- start_time: z.date(),
- end_time: z.date(),
- location: z.string().max(255),
- meeting_link: z.string().max(255).optional(),
- event_type: eventTypeEnum,
- is_recurring: z.boolean(),
- host: z.string().uuid()
-});
-
-export const eventSchema = eventSchemaIntermediate.merge(rootModelSchema);
-
-// Types:
-export type CreateEventRequestBody = z.infer<
- typeof createEventRequestBodySchema
->;
-export type UpdateEventRequestBody = z.infer<
- typeof updateEventRequestBodySchema
->;
-export type Event = z.infer;
diff --git a/frontend/lib/types/file.ts b/frontend/lib/types/file.ts
deleted file mode 100644
index b7b3101d8..000000000
--- a/frontend/lib/types/file.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { z } from 'zod';
-
-import { rootModelSchema } from './root';
-
-// Schemas:
-export const createFileRequestBodySchema = z.object({
- owner_id: z.string().uuid(),
- owner_type: z.string().max(255)
-});
-
-const fileSchemaIntermediate = z.object({
- owner_id: z.string().uuid(),
- owner_type: z.string().max(255),
- file_name: z.string().max(255),
- file_type: z.string().max(255),
- file_size: z.number().min(1),
- file_url: z.string().max(255),
- object_key: z.string().max(255)
-});
-
-export const fileSchema = fileSchemaIntermediate.merge(rootModelSchema);
-
-// Types:
-export type CreateFileRequestBody = z.infer;
-export type File = z.infer;
diff --git a/frontend/lib/types/index.ts b/frontend/lib/types/index.ts
deleted file mode 100644
index a247cd707..000000000
--- a/frontend/lib/types/index.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-export * from './auth';
-export * from './error';
-
-export * from './root';
-export * from './club';
-export * from './contact';
-export * from './user';
-export * from './tag';
-export * from './category';
-export * from './event';
-export * from './file';
-export * from './pointOfContact';
-export * from './verification';
diff --git a/frontend/lib/types/item.ts b/frontend/lib/types/item.ts
deleted file mode 100644
index 763910602..000000000
--- a/frontend/lib/types/item.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export type Item = {
- label: string;
- value: string;
-};
diff --git a/frontend/lib/types/pointOfContact.ts b/frontend/lib/types/pointOfContact.ts
deleted file mode 100644
index 1bc6008ce..000000000
--- a/frontend/lib/types/pointOfContact.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { z } from 'zod';
-
-import { fileSchema } from './file';
-import { rootModelSchema } from './root';
-
-// Schemas:
-const createPointOfContactRequestBodySchema = z.object({
- name: z.string(),
- email: z.string().email(),
- position: z.string()
-});
-
-const updatePointOfContactRequestBodySchema = z.object({
- name: z.string().optional(),
- email: z.string().email().optional(),
- position: z.string().optional()
-});
-
-const pointOfContactSchemaIntermediate = z.object({
- name: z.string().max(255),
- email: z.string().email(),
- position: z.string().max(255),
- photo_file: fileSchema
-});
-
-export const pointOfContactSchema =
- pointOfContactSchemaIntermediate.merge(rootModelSchema);
-
-// Types:
-export type CreatePointOfContactRequestBody = z.infer<
- typeof createPointOfContactRequestBodySchema
->;
-export type UpdatePointOfContactRequestBody = z.infer<
- typeof updatePointOfContactRequestBodySchema
->;
-export type PointOfContact = z.infer;
diff --git a/frontend/lib/types/root.ts b/frontend/lib/types/root.ts
deleted file mode 100644
index 27c0ee4c0..000000000
--- a/frontend/lib/types/root.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { z } from 'zod';
-
-export type uuid = string;
-
-export const rootModelSchema = z.object({
- id: z.string().uuid(),
- created_at: z.date(),
- updated_at: z.date()
-});
-
-const paginationQueryParams = z
- .object({
- page: z.number().int().positive().optional(),
- limit: z.number().int().positive().optional()
- })
- .optional();
-
-export type PaginationQueryParams = z.infer;
diff --git a/frontend/lib/types/user.ts b/frontend/lib/types/user.ts
deleted file mode 100644
index 6093fbac4..000000000
--- a/frontend/lib/types/user.ts
+++ /dev/null
@@ -1,184 +0,0 @@
-import { z } from 'zod';
-
-import { rootModelSchema } from './root';
-
-// Enums:
-export const userRoleEnum = z.enum(['super', 'student']);
-
-export const collegeEnum = z.enum([
- 'CAMD',
- 'DMSB',
- 'KCCS',
- 'CE',
- 'BCHS',
- 'SL',
- 'CPS',
- 'CS',
- 'CSSH'
-]);
-
-export const majorEnum = z.enum([
- 'africanaStudies',
- 'americanSignLanguage',
- 'americanSignLanguage-EnglishInterpreting',
- 'appliedPhysics',
- 'architecturalStudies',
- 'architecture',
- 'art:ArtVisualStudies',
- 'behavioralNeuroscience',
- 'biochemistry',
- 'bioengineering',
- 'biology',
- 'biomedicalPhysics',
- 'businessAdministration',
- 'businessAdministration:Accounting',
- 'businessAdministration:AccountingAndAdvisoryServices',
- 'businessAdministration:BrandManagement',
- 'businessAdministration:BusinessAnalytics',
- 'businessAdministration:CorporateInnovation',
- 'businessAdministration:EntrepreneurialStartups',
- 'businessAdministration:FamilyBusiness',
- 'businessAdministration:Finance',
- 'businessAdministration:Fintech',
- 'businessAdministration:HealthcareManagementAndConsulting',
- 'businessAdministration:Management',
- 'businessAdministration:ManagementInformationSystems',
- 'businessAdministration:Marketing',
- 'businessAdministration:MarketingAnalytics',
- 'businessAdministration:SocialInnovationAndEntrepreneurship',
- 'businessAdministration:SupplyChainManagement',
- 'cellAndMolecularBiology',
- 'chemicalEngineering',
- 'chemistry',
- 'civilEngineering',
- 'communicationStudies',
- 'computerEngineering',
- 'computerScience',
- 'computingAndLaw',
- 'criminologyAndCriminalJustice',
- 'culturalAnthropology',
- 'cybersecurity',
- 'dataScience',
- 'design',
- 'economics',
- 'electricalEngineering',
- 'english',
- 'environmentalAndSustainabilityStudies',
- 'environmentalEngineering',
- 'environmentalScience',
- 'environmentalStudies',
- 'gameArtAndAnimation',
- 'gameDesign',
- 'globalAsianStudies',
- 'healthScience',
- 'history',
- 'historyCultureAndLaw',
- 'humanServices',
- 'industrialEngineering',
- 'internationalAffairs',
- 'internationalBusiness',
- 'internationalBusiness:Accounting',
- 'internationalBusiness:AccountingAndAdvisoryServices',
- 'internationalBusiness:BrandManagement',
- 'internationalBusiness:BusinessAnalytics',
- 'internationalBusiness:CorporateInnovation',
- 'internationalBusiness:EntrepreneurialStartups',
- 'internationalBusiness:FamilyBusiness',
- 'internationalBusiness:Finance',
- 'internationalBusiness:Fintech',
- 'internationalBusiness:HealthcareManagementAndConsulting',
- 'internationalBusiness:Management',
- 'internationalBusiness:ManagementInformationSystems',
- 'internationalBusiness:Marketing',
- 'internationalBusiness:MarketingAnalytics',
- 'internationalBusiness:SocialInnovationAndEntrepreneurship',
- 'internationalBusiness:SupplyChainManagement',
- 'journalism',
- 'landscapeArchitecture',
- 'linguistics',
- 'marineBiology',
- 'mathematics',
- 'mechanicalEngineering',
- 'mediaAndScreenStudies',
- 'mediaArts',
- 'music',
- 'musicTechnology',
- 'nursing',
- 'pharmaceuticalSciences',
- 'pharmacy(PharmD)',
- 'philosophy',
- 'physics',
- 'politicalScience',
- 'politicsPhilosophyEconomics',
- 'psychology',
- 'publicHealth',
- 'publicRelations',
- 'religiousStudies',
- 'sociology',
- 'spanish',
- 'speechLanguagePathologyAndAudiology',
- 'theatre'
-]);
-
-export const graduationCycleEnum = z.enum(['december', 'may']);
-
-export const yearEnum = z.enum(['1', '2', '3', '4', '5']);
-
-// Schemas:
-export const createUserRequestBodySchema = z.object({
- first_name: z.string().min(1),
- last_name: z.string().min(1),
- email: z.string().email(),
- password: z.string().min(8),
- major0: majorEnum.optional(),
- major1: majorEnum.optional(),
- major2: majorEnum.optional(),
- college: collegeEnum,
- graduation_cycle: graduationCycleEnum.optional(),
- graduation_year: z.number().optional()
-});
-
-export const updateUserRequestBodySchema = z.object({
- first_name: z.string().min(1).optional(),
- last_name: z.string().min(1).optional(),
- major0: majorEnum.optional(),
- major1: majorEnum.optional(),
- major2: majorEnum.optional(),
- college: collegeEnum.optional(),
- graduation_cycle: graduationCycleEnum.optional(),
- graduation_year: z.number().optional()
-});
-
-export const createUserTagsRequestBodySchema = z.object({
- tags: z.array(z.string().uuid())
-});
-
-const userSchemaIntermediate = z.object({
- role: userRoleEnum,
- first_name: z.string().min(1),
- last_name: z.string().min(1),
- email: z.string().email(),
- major0: majorEnum.optional(),
- major1: majorEnum.optional(),
- major2: majorEnum.optional(),
- college: collegeEnum.optional(),
- graduation_cycle: graduationCycleEnum.optional(),
- graduation_year: z.number().optional(),
- is_verified: z.boolean()
-});
-
-export const userSchema = userSchemaIntermediate.merge(rootModelSchema);
-
-// Types:
-export type UserRole = z.infer;
-export type College = z.infer;
-export type Major = z.infer;
-export type GraduationCycle = z.infer;
-export type Year = z.infer;
-
-export type CreateUserRequestBody = z.infer;
-export type UpdateUserRequestBody = z.infer;
-export type CreateUserTagsRequestBody = z.infer<
- typeof createUserTagsRequestBodySchema
->;
-export type User = z.infer;
diff --git a/frontend/lib/types/uuid.ts b/frontend/lib/types/uuid.ts
deleted file mode 100644
index d0ea1399d..000000000
--- a/frontend/lib/types/uuid.ts
+++ /dev/null
@@ -1 +0,0 @@
-export type uuid = string;
diff --git a/frontend/lib/vite.config.ts b/frontend/lib/vite.config.ts
new file mode 100644
index 000000000..22d2a58d6
--- /dev/null
+++ b/frontend/lib/vite.config.ts
@@ -0,0 +1,22 @@
+import { defineConfig } from "vite";
+import { resolve } from "path";
+import dts from "vite-plugin-dts";
+import { libInjectCss } from "vite-plugin-lib-inject-css";
+import react from "@vitejs/plugin-react-swc";
+
+export default defineConfig({
+ plugins: [react(), libInjectCss(), dts({ include: ["src"] })],
+ build: {
+ lib: {
+ entry: resolve(__dirname, "src/index.ts"),
+ formats: ["es"],
+ },
+ rollupOptions: {
+ external: ["react", "react/jsx-runtime"],
+ output: {
+ assetFileNames: "assets/[name][extname]",
+ entryFileNames: "[name].js",
+ },
+ },
+ },
+});
diff --git a/frontend/lib/yarn.lock b/frontend/lib/yarn.lock
index 5ff57ae27..63d5c4405 100644
--- a/frontend/lib/yarn.lock
+++ b/frontend/lib/yarn.lock
@@ -2,6 +2,406 @@
# yarn lockfile v1
+"@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.5":
+ version "7.24.2"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae"
+ integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==
+ dependencies:
+ "@babel/highlight" "^7.24.2"
+ picocolors "^1.0.0"
+
+"@babel/generator@7.17.7":
+ version "7.17.7"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad"
+ integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==
+ dependencies:
+ "@babel/types" "^7.17.0"
+ jsesc "^2.5.1"
+ source-map "^0.5.0"
+
+"@babel/generator@^7.23.0":
+ version "7.24.5"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.5.tgz#e5afc068f932f05616b66713e28d0f04e99daeb3"
+ integrity sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==
+ dependencies:
+ "@babel/types" "^7.24.5"
+ "@jridgewell/gen-mapping" "^0.3.5"
+ "@jridgewell/trace-mapping" "^0.3.25"
+ jsesc "^2.5.1"
+
+"@babel/helper-environment-visitor@^7.22.20":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
+ integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
+
+"@babel/helper-function-name@^7.23.0":
+ version "7.23.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
+ integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
+ dependencies:
+ "@babel/template" "^7.22.15"
+ "@babel/types" "^7.23.0"
+
+"@babel/helper-hoist-variables@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
+ integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
+"@babel/helper-split-export-declaration@^7.22.6":
+ version "7.24.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz#b9a67f06a46b0b339323617c8c6213b9055a78b6"
+ integrity sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==
+ dependencies:
+ "@babel/types" "^7.24.5"
+
+"@babel/helper-string-parser@^7.24.1":
+ version "7.24.1"
+ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e"
+ integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==
+
+"@babel/helper-validator-identifier@^7.16.7", "@babel/helper-validator-identifier@^7.24.5":
+ version "7.24.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz#918b1a7fa23056603506370089bd990d8720db62"
+ integrity sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==
+
+"@babel/highlight@^7.24.2":
+ version "7.24.5"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.5.tgz#bc0613f98e1dd0720e99b2a9ee3760194a704b6e"
+ integrity sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.24.5"
+ chalk "^2.4.2"
+ js-tokens "^4.0.0"
+ picocolors "^1.0.0"
+
+"@babel/parser@^7.20.5", "@babel/parser@^7.23.0", "@babel/parser@^7.24.0", "@babel/parser@^7.24.4":
+ version "7.24.5"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.5.tgz#4a4d5ab4315579e5398a82dcf636ca80c3392790"
+ integrity sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==
+
+"@babel/template@^7.22.15":
+ version "7.24.0"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50"
+ integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==
+ dependencies:
+ "@babel/code-frame" "^7.23.5"
+ "@babel/parser" "^7.24.0"
+ "@babel/types" "^7.24.0"
+
+"@babel/traverse@7.23.2":
+ version "7.23.2"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8"
+ integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==
+ dependencies:
+ "@babel/code-frame" "^7.22.13"
+ "@babel/generator" "^7.23.0"
+ "@babel/helper-environment-visitor" "^7.22.20"
+ "@babel/helper-function-name" "^7.23.0"
+ "@babel/helper-hoist-variables" "^7.22.5"
+ "@babel/helper-split-export-declaration" "^7.22.6"
+ "@babel/parser" "^7.23.0"
+ "@babel/types" "^7.23.0"
+ debug "^4.1.0"
+ globals "^11.1.0"
+
+"@babel/types@7.17.0":
+ version "7.17.0"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b"
+ integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.16.7"
+ to-fast-properties "^2.0.0"
+
+"@babel/types@^7.17.0", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.24.5":
+ version "7.24.5"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.5.tgz#7661930afc638a5383eb0c4aee59b74f38db84d7"
+ integrity sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==
+ dependencies:
+ "@babel/helper-string-parser" "^7.24.1"
+ "@babel/helper-validator-identifier" "^7.24.5"
+ to-fast-properties "^2.0.0"
+
+"@esbuild/aix-ppc64@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz#a70f4ac11c6a1dfc18b8bbb13284155d933b9537"
+ integrity sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==
+
+"@esbuild/android-arm64@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz#db1c9202a5bc92ea04c7b6840f1bbe09ebf9e6b9"
+ integrity sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==
+
+"@esbuild/android-arm@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.20.2.tgz#3b488c49aee9d491c2c8f98a909b785870d6e995"
+ integrity sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==
+
+"@esbuild/android-x64@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.20.2.tgz#3b1628029e5576249d2b2d766696e50768449f98"
+ integrity sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==
+
+"@esbuild/darwin-arm64@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz#6e8517a045ddd86ae30c6608c8475ebc0c4000bb"
+ integrity sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==
+
+"@esbuild/darwin-x64@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz#90ed098e1f9dd8a9381695b207e1cff45540a0d0"
+ integrity sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==
+
+"@esbuild/freebsd-arm64@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz#d71502d1ee89a1130327e890364666c760a2a911"
+ integrity sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==
+
+"@esbuild/freebsd-x64@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz#aa5ea58d9c1dd9af688b8b6f63ef0d3d60cea53c"
+ integrity sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==
+
+"@esbuild/linux-arm64@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz#055b63725df678379b0f6db9d0fa85463755b2e5"
+ integrity sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==
+
+"@esbuild/linux-arm@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz#76b3b98cb1f87936fbc37f073efabad49dcd889c"
+ integrity sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==
+
+"@esbuild/linux-ia32@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz#c0e5e787c285264e5dfc7a79f04b8b4eefdad7fa"
+ integrity sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==
+
+"@esbuild/linux-loong64@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz#a6184e62bd7cdc63e0c0448b83801001653219c5"
+ integrity sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==
+
+"@esbuild/linux-mips64el@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz#d08e39ce86f45ef8fc88549d29c62b8acf5649aa"
+ integrity sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==
+
+"@esbuild/linux-ppc64@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz#8d252f0b7756ffd6d1cbde5ea67ff8fd20437f20"
+ integrity sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==
+
+"@esbuild/linux-riscv64@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz#19f6dcdb14409dae607f66ca1181dd4e9db81300"
+ integrity sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==
+
+"@esbuild/linux-s390x@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz#3c830c90f1a5d7dd1473d5595ea4ebb920988685"
+ integrity sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==
+
+"@esbuild/linux-x64@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz#86eca35203afc0d9de0694c64ec0ab0a378f6fff"
+ integrity sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==
+
+"@esbuild/netbsd-x64@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz#e771c8eb0e0f6e1877ffd4220036b98aed5915e6"
+ integrity sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==
+
+"@esbuild/openbsd-x64@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz#9a795ae4b4e37e674f0f4d716f3e226dd7c39baf"
+ integrity sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==
+
+"@esbuild/sunos-x64@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz#7df23b61a497b8ac189def6e25a95673caedb03f"
+ integrity sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==
+
+"@esbuild/win32-arm64@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz#f1ae5abf9ca052ae11c1bc806fb4c0f519bacf90"
+ integrity sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==
+
+"@esbuild/win32-ia32@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz#241fe62c34d8e8461cd708277813e1d0ba55ce23"
+ integrity sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==
+
+"@esbuild/win32-x64@0.20.2":
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz#9c907b21e30a52db959ba4f80bb01a0cc403d5cc"
+ integrity sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==
+
+"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
+ integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
+ dependencies:
+ eslint-visitor-keys "^3.3.0"
+
+"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1":
+ version "4.10.0"
+ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63"
+ integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==
+
+"@eslint/eslintrc@^2.1.4":
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad"
+ integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==
+ dependencies:
+ ajv "^6.12.4"
+ debug "^4.3.2"
+ espree "^9.6.0"
+ globals "^13.19.0"
+ ignore "^5.2.0"
+ import-fresh "^3.2.1"
+ js-yaml "^4.1.0"
+ minimatch "^3.1.2"
+ strip-json-comments "^3.1.1"
+
+"@eslint/js@8.57.0":
+ version "8.57.0"
+ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f"
+ integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==
+
+"@humanwhocodes/config-array@^0.11.14":
+ version "0.11.14"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b"
+ integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==
+ dependencies:
+ "@humanwhocodes/object-schema" "^2.0.2"
+ debug "^4.3.1"
+ minimatch "^3.0.5"
+
+"@humanwhocodes/module-importer@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
+ integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
+
+"@humanwhocodes/object-schema@^2.0.2":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3"
+ integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==
+
+"@isaacs/cliui@^8.0.2":
+ version "8.0.2"
+ resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
+ integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==
+ dependencies:
+ string-width "^5.1.2"
+ string-width-cjs "npm:string-width@^4.2.0"
+ strip-ansi "^7.0.1"
+ strip-ansi-cjs "npm:strip-ansi@^6.0.1"
+ wrap-ansi "^8.1.0"
+ wrap-ansi-cjs "npm:wrap-ansi@^7.0.0"
+
+"@jridgewell/gen-mapping@^0.3.5":
+ version "0.3.5"
+ resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36"
+ integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==
+ dependencies:
+ "@jridgewell/set-array" "^1.2.1"
+ "@jridgewell/sourcemap-codec" "^1.4.10"
+ "@jridgewell/trace-mapping" "^0.3.24"
+
+"@jridgewell/resolve-uri@^3.1.0":
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
+ integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==
+
+"@jridgewell/set-array@^1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280"
+ integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==
+
+"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15":
+ version "1.4.15"
+ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
+ integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
+
+"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25":
+ version "0.3.25"
+ resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0"
+ integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==
+ dependencies:
+ "@jridgewell/resolve-uri" "^3.1.0"
+ "@jridgewell/sourcemap-codec" "^1.4.14"
+
+"@microsoft/api-extractor-model@7.28.13":
+ version "7.28.13"
+ resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.28.13.tgz#96fbc52155e0d07e0eabbd9699065b77702fe33a"
+ integrity sha512-39v/JyldX4MS9uzHcdfmjjfS6cYGAoXV+io8B5a338pkHiSt+gy2eXQ0Q7cGFJ7quSa1VqqlMdlPrB6sLR/cAw==
+ dependencies:
+ "@microsoft/tsdoc" "0.14.2"
+ "@microsoft/tsdoc-config" "~0.16.1"
+ "@rushstack/node-core-library" "4.0.2"
+
+"@microsoft/api-extractor@7.43.0":
+ version "7.43.0"
+ resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.43.0.tgz#41c42677bc71cd8e0f23c63c56802d85044e65cd"
+ integrity sha512-GFhTcJpB+MI6FhvXEI9b2K0snulNLWHqC/BbcJtyNYcKUiw7l3Lgis5ApsYncJ0leALX7/of4XfmXk+maT111w==
+ dependencies:
+ "@microsoft/api-extractor-model" "7.28.13"
+ "@microsoft/tsdoc" "0.14.2"
+ "@microsoft/tsdoc-config" "~0.16.1"
+ "@rushstack/node-core-library" "4.0.2"
+ "@rushstack/rig-package" "0.5.2"
+ "@rushstack/terminal" "0.10.0"
+ "@rushstack/ts-command-line" "4.19.1"
+ lodash "~4.17.15"
+ minimatch "~3.0.3"
+ resolve "~1.22.1"
+ semver "~7.5.4"
+ source-map "~0.6.1"
+ typescript "5.4.2"
+
+"@microsoft/tsdoc-config@~0.16.1":
+ version "0.16.2"
+ resolved "https://registry.yarnpkg.com/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz#b786bb4ead00d54f53839a458ce626c8548d3adf"
+ integrity sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==
+ dependencies:
+ "@microsoft/tsdoc" "0.14.2"
+ ajv "~6.12.6"
+ jju "~1.4.0"
+ resolve "~1.19.0"
+
+"@microsoft/tsdoc@0.14.2":
+ version "0.14.2"
+ resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz#c3ec604a0b54b9a9b87e9735dfc59e1a5da6a5fb"
+ integrity sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==
+
+"@nodelib/fs.scandir@2.1.5":
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
+ integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
+ dependencies:
+ "@nodelib/fs.stat" "2.0.5"
+ run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
+ integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
+
+"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8":
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
+ integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
+ dependencies:
+ "@nodelib/fs.scandir" "2.1.5"
+ fastq "^1.6.0"
+
+"@pkgjs/parseargs@^0.11.0":
+ version "0.11.0"
+ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
+ integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
+
"@reduxjs/toolkit@^2.2.3":
version "2.2.3"
resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-2.2.3.tgz#5ce71cbf162f98c5dafb49bd3f1e11c5486ab9c4"
@@ -12,10 +412,1408 @@
redux-thunk "^3.1.0"
reselect "^5.0.1"
+"@rollup/pluginutils@^5.1.0":
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.0.tgz#7e53eddc8c7f483a4ad0b94afb1f7f5fd3c771e0"
+ integrity sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==
+ dependencies:
+ "@types/estree" "^1.0.0"
+ estree-walker "^2.0.2"
+ picomatch "^2.3.1"
+
+"@rollup/rollup-android-arm-eabi@4.17.2":
+ version "4.17.2"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.2.tgz#1a32112822660ee104c5dd3a7c595e26100d4c2d"
+ integrity sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==
+
+"@rollup/rollup-android-arm64@4.17.2":
+ version "4.17.2"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.2.tgz#5aeef206d65ff4db423f3a93f71af91b28662c5b"
+ integrity sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==
+
+"@rollup/rollup-darwin-arm64@4.17.2":
+ version "4.17.2"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.2.tgz#6b66aaf003c70454c292cd5f0236ebdc6ffbdf1a"
+ integrity sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==
+
+"@rollup/rollup-darwin-x64@4.17.2":
+ version "4.17.2"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.2.tgz#f64fc51ed12b19f883131ccbcea59fc68cbd6c0b"
+ integrity sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==
+
+"@rollup/rollup-linux-arm-gnueabihf@4.17.2":
+ version "4.17.2"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.2.tgz#1a7641111be67c10111f7122d1e375d1226cbf14"
+ integrity sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==
+
+"@rollup/rollup-linux-arm-musleabihf@4.17.2":
+ version "4.17.2"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.2.tgz#c93fd632923e0fee25aacd2ae414288d0b7455bb"
+ integrity sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==
+
+"@rollup/rollup-linux-arm64-gnu@4.17.2":
+ version "4.17.2"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.2.tgz#fa531425dd21d058a630947527b4612d9d0b4a4a"
+ integrity sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==
+
+"@rollup/rollup-linux-arm64-musl@4.17.2":
+ version "4.17.2"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.2.tgz#8acc16f095ceea5854caf7b07e73f7d1802ac5af"
+ integrity sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==
+
+"@rollup/rollup-linux-powerpc64le-gnu@4.17.2":
+ version "4.17.2"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.2.tgz#94e69a8499b5cf368911b83a44bb230782aeb571"
+ integrity sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==
+
+"@rollup/rollup-linux-riscv64-gnu@4.17.2":
+ version "4.17.2"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.2.tgz#7ef1c781c7e59e85a6ce261cc95d7f1e0b56db0f"
+ integrity sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==
+
+"@rollup/rollup-linux-s390x-gnu@4.17.2":
+ version "4.17.2"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.2.tgz#f15775841c3232fca9b78cd25a7a0512c694b354"
+ integrity sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==
+
+"@rollup/rollup-linux-x64-gnu@4.17.2":
+ version "4.17.2"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.2.tgz#b521d271798d037ad70c9f85dd97d25f8a52e811"
+ integrity sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==
+
+"@rollup/rollup-linux-x64-musl@4.17.2":
+ version "4.17.2"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.2.tgz#9254019cc4baac35800991315d133cc9fd1bf385"
+ integrity sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==
+
+"@rollup/rollup-win32-arm64-msvc@4.17.2":
+ version "4.17.2"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.2.tgz#27f65a89f6f52ee9426ec11e3571038e4671790f"
+ integrity sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==
+
+"@rollup/rollup-win32-ia32-msvc@4.17.2":
+ version "4.17.2"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.2.tgz#a2fbf8246ed0bb014f078ca34ae6b377a90cb411"
+ integrity sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==
+
+"@rollup/rollup-win32-x64-msvc@4.17.2":
+ version "4.17.2"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.2.tgz#5a2d08b81e8064b34242d5cc9973ef8dd1e60503"
+ integrity sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==
+
+"@rushstack/node-core-library@4.0.2":
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/@rushstack/node-core-library/-/node-core-library-4.0.2.tgz#e26854a3314b279d57e8abdb4acce7797d02f554"
+ integrity sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==
+ dependencies:
+ fs-extra "~7.0.1"
+ import-lazy "~4.0.0"
+ jju "~1.4.0"
+ resolve "~1.22.1"
+ semver "~7.5.4"
+ z-schema "~5.0.2"
+
+"@rushstack/rig-package@0.5.2":
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/@rushstack/rig-package/-/rig-package-0.5.2.tgz#0e23a115904678717a74049661931c0b37dd5495"
+ integrity sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA==
+ dependencies:
+ resolve "~1.22.1"
+ strip-json-comments "~3.1.1"
+
+"@rushstack/terminal@0.10.0":
+ version "0.10.0"
+ resolved "https://registry.yarnpkg.com/@rushstack/terminal/-/terminal-0.10.0.tgz#e81909fa0e5c8016b6df4739f0f381f44358269f"
+ integrity sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw==
+ dependencies:
+ "@rushstack/node-core-library" "4.0.2"
+ supports-color "~8.1.1"
+
+"@rushstack/ts-command-line@4.19.1":
+ version "4.19.1"
+ resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-4.19.1.tgz#288ee54dd607e558a8be07705869c16c31b5c3ef"
+ integrity sha512-J7H768dgcpG60d7skZ5uSSwyCZs/S2HrWP1Ds8d1qYAyaaeJmpmmLr9BVw97RjFzmQPOYnoXcKA4GkqDCkduQg==
+ dependencies:
+ "@rushstack/terminal" "0.10.0"
+ "@types/argparse" "1.0.38"
+ argparse "~1.0.9"
+ string-argv "~0.3.1"
+
+"@swc/core-darwin-arm64@1.5.3":
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.5.3.tgz#37267be4dc76426073f66ca0177a10c9b1237326"
+ integrity sha512-kRmmV2XqWegzGXvJfVVOj10OXhLgaVOOBjaX3p3Aqg7Do5ksg+bY5wi1gAN/Eul7B08Oqf7GG7WJevjDQGWPOg==
+
+"@swc/core-darwin-x64@1.5.3":
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.5.3.tgz#d914ad5c28022913550ef75efc78b9220a03fa1e"
+ integrity sha512-EYs0+ovaRw6ZN9GBr2nIeC7gUXWA0q4RYR+Og3Vo0Qgv2Mt/XudF44A2lPK9X7M3JIfu6JjnxnTuvsK1Lqojfw==
+
+"@swc/core-linux-arm-gnueabihf@1.5.3":
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.5.3.tgz#b03d82237bb6cfbcb62815ab65e371fe0f7db622"
+ integrity sha512-RBVUTidSf4wgPdv98VrgJ4rMzMDN/3LBWdT7l+R7mNFH+mtID7ZAhTON0o/m1HkECgAgi1xcbTOVAw1xgd5KLA==
+
+"@swc/core-linux-arm64-gnu@1.5.3":
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.5.3.tgz#6fb6a91a400825b3ecf27083e6c670a677c40356"
+ integrity sha512-DCC6El3MiTYfv98CShxz/g2s4Pxn6tV0mldCQ0UdRqaN2ApUn7E+zTrqaj5bk7yII3A43WhE9Mr6wNPbXUeVyg==
+
+"@swc/core-linux-arm64-musl@1.5.3":
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.5.3.tgz#5f32b7535420973ee55d8e5abf0682bba390df60"
+ integrity sha512-p04ysjYXEyaCGpJvwHm0T0nkPawXtdKBTThWnlh8M5jYULVNVA1YmC9azG2Avs1GDaLgBPVUgodmFYpdSupOYA==
+
+"@swc/core-linux-x64-gnu@1.5.3":
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.5.3.tgz#50510af9f466890a61d6ec9821c52e83b8be8633"
+ integrity sha512-/l4KJu0xwYm6tcVSOvF8RbXrIeIHJAhWnKvuX4ZnYKFkON968kB8Ghx+1yqBQcZf36tMzSuZUC5xBUA9u66lGA==
+
+"@swc/core-linux-x64-musl@1.5.3":
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.5.3.tgz#da2a0cf23e67991c77b1d05328f5afb3408dad07"
+ integrity sha512-54DmSnrTXq4fYEKNR0nFAImG3+FxsHlQ6Tol/v3l+rxmg2K0FeeDOpH7wTXeWhMGhFlGrLIyLSnA+SzabfoDIA==
+
+"@swc/core-win32-arm64-msvc@1.5.3":
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.5.3.tgz#d4314763ff14814eb59d967921bfc30307f6afd4"
+ integrity sha512-piUMqoHNwDXChBfaaFIMzYgoxepfd8Ci1uXXNVEnuiRKz3FiIcNLmvXaBD7lKUwKcnGgVziH/CrndX6SldKQNQ==
+
+"@swc/core-win32-ia32-msvc@1.5.3":
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.5.3.tgz#7c2bda8aee04a162a5bfcad19de9ebaed9f9037d"
+ integrity sha512-zV5utPYBUzYhBOomCByAjKAvfVBcOCJtnszx7Zlfz7SAv/cGm8D1QzPDCvv6jDhIlUtLj6KyL8JXeFr+f95Fjw==
+
+"@swc/core-win32-x64-msvc@1.5.3":
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.5.3.tgz#677da96e52b9d5f4c374a03033970fe67b7c0594"
+ integrity sha512-QmUiXiPIV5gBADfDh8e2jKynEhyRC+dcKP/zF9y5KqDUErYzlhocLd68uYS4uIegP6AylYlmigHgcaktGEE9VQ==
+
+"@swc/core@^1.3.107":
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.5.3.tgz#57add517711dbc7373cd438da1ddcaa4b2ae540d"
+ integrity sha512-pSEglypnBGLHBoBcv3aYS7IM2t2LRinubYMyP88UoFIcD2pear2CeB15CbjJ2IzuvERD0ZL/bthM7cDSR9g+aQ==
+ dependencies:
+ "@swc/counter" "^0.1.2"
+ "@swc/types" "^0.1.5"
+ optionalDependencies:
+ "@swc/core-darwin-arm64" "1.5.3"
+ "@swc/core-darwin-x64" "1.5.3"
+ "@swc/core-linux-arm-gnueabihf" "1.5.3"
+ "@swc/core-linux-arm64-gnu" "1.5.3"
+ "@swc/core-linux-arm64-musl" "1.5.3"
+ "@swc/core-linux-x64-gnu" "1.5.3"
+ "@swc/core-linux-x64-musl" "1.5.3"
+ "@swc/core-win32-arm64-msvc" "1.5.3"
+ "@swc/core-win32-ia32-msvc" "1.5.3"
+ "@swc/core-win32-x64-msvc" "1.5.3"
+
+"@swc/counter@^0.1.2", "@swc/counter@^0.1.3":
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9"
+ integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==
+
+"@swc/types@^0.1.5":
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.6.tgz#2f13f748995b247d146de2784d3eb7195410faba"
+ integrity sha512-/JLo/l2JsT/LRd80C3HfbmVpxOAJ11FO2RCEslFrgzLltoP9j8XIbsyDcfCt2WWyX+CM96rBoNM+IToAkFOugg==
+ dependencies:
+ "@swc/counter" "^0.1.3"
+
+"@trivago/prettier-plugin-sort-imports@^4.3.0":
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.3.0.tgz#725f411646b3942193a37041c84e0b2116339789"
+ integrity sha512-r3n0onD3BTOVUNPhR4lhVK4/pABGpbA7bW3eumZnYdKaHkf1qEC+Mag6DPbGNuuh0eG8AaYj+YqmVHSiGslaTQ==
+ dependencies:
+ "@babel/generator" "7.17.7"
+ "@babel/parser" "^7.20.5"
+ "@babel/traverse" "7.23.2"
+ "@babel/types" "7.17.0"
+ javascript-natural-sort "0.7.1"
+ lodash "^4.17.21"
+
+"@types/argparse@1.0.38":
+ version "1.0.38"
+ resolved "https://registry.yarnpkg.com/@types/argparse/-/argparse-1.0.38.tgz#a81fd8606d481f873a3800c6ebae4f1d768a56a9"
+ integrity sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==
+
+"@types/estree@1.0.5", "@types/estree@^1.0.0":
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4"
+ integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
+
+"@types/json-schema@^7.0.15":
+ version "7.0.15"
+ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
+ integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
+
+"@types/node@^20.12.10":
+ version "20.12.10"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.10.tgz#8f0c3f12b0f075eee1fe20c1afb417e9765bef76"
+ integrity sha512-Eem5pH9pmWBHoGAT8Dr5fdc5rYA+4NAovdM4EktRPVAAiJhmWWfQrA0cFhAbOsQdSfIHjAud6YdkbL69+zSKjw==
+ dependencies:
+ undici-types "~5.26.4"
+
+"@types/prop-types@*":
+ version "15.7.12"
+ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6"
+ integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==
+
+"@types/react-dom@^18.2.22":
+ version "18.3.0"
+ resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0"
+ integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==
+ dependencies:
+ "@types/react" "*"
+
+"@types/react@*", "@types/react@^18.2.66":
+ version "18.3.1"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.1.tgz#fed43985caa834a2084d002e4771e15dfcbdbe8e"
+ integrity sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==
+ dependencies:
+ "@types/prop-types" "*"
+ csstype "^3.0.2"
+
+"@types/semver@^7.5.8":
+ version "7.5.8"
+ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e"
+ integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==
+
+"@types/use-sync-external-store@^0.0.3":
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43"
+ integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==
+
+"@typescript-eslint/eslint-plugin@^7.2.0":
+ version "7.8.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz#c78e309fe967cb4de05b85cdc876fb95f8e01b6f"
+ integrity sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==
+ dependencies:
+ "@eslint-community/regexpp" "^4.10.0"
+ "@typescript-eslint/scope-manager" "7.8.0"
+ "@typescript-eslint/type-utils" "7.8.0"
+ "@typescript-eslint/utils" "7.8.0"
+ "@typescript-eslint/visitor-keys" "7.8.0"
+ debug "^4.3.4"
+ graphemer "^1.4.0"
+ ignore "^5.3.1"
+ natural-compare "^1.4.0"
+ semver "^7.6.0"
+ ts-api-utils "^1.3.0"
+
+"@typescript-eslint/parser@^7.2.0":
+ version "7.8.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.8.0.tgz#1e1db30c8ab832caffee5f37e677dbcb9357ddc8"
+ integrity sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==
+ dependencies:
+ "@typescript-eslint/scope-manager" "7.8.0"
+ "@typescript-eslint/types" "7.8.0"
+ "@typescript-eslint/typescript-estree" "7.8.0"
+ "@typescript-eslint/visitor-keys" "7.8.0"
+ debug "^4.3.4"
+
+"@typescript-eslint/scope-manager@7.8.0":
+ version "7.8.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz#bb19096d11ec6b87fb6640d921df19b813e02047"
+ integrity sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==
+ dependencies:
+ "@typescript-eslint/types" "7.8.0"
+ "@typescript-eslint/visitor-keys" "7.8.0"
+
+"@typescript-eslint/type-utils@7.8.0":
+ version "7.8.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz#9de166f182a6e4d1c5da76e94880e91831e3e26f"
+ integrity sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==
+ dependencies:
+ "@typescript-eslint/typescript-estree" "7.8.0"
+ "@typescript-eslint/utils" "7.8.0"
+ debug "^4.3.4"
+ ts-api-utils "^1.3.0"
+
+"@typescript-eslint/types@7.8.0":
+ version "7.8.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.8.0.tgz#1fd2577b3ad883b769546e2d1ef379f929a7091d"
+ integrity sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==
+
+"@typescript-eslint/typescript-estree@7.8.0":
+ version "7.8.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz#b028a9226860b66e623c1ee55cc2464b95d2987c"
+ integrity sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==
+ dependencies:
+ "@typescript-eslint/types" "7.8.0"
+ "@typescript-eslint/visitor-keys" "7.8.0"
+ debug "^4.3.4"
+ globby "^11.1.0"
+ is-glob "^4.0.3"
+ minimatch "^9.0.4"
+ semver "^7.6.0"
+ ts-api-utils "^1.3.0"
+
+"@typescript-eslint/utils@7.8.0":
+ version "7.8.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.8.0.tgz#57a79f9c0c0740ead2f622e444cfaeeb9fd047cd"
+ integrity sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==
+ dependencies:
+ "@eslint-community/eslint-utils" "^4.4.0"
+ "@types/json-schema" "^7.0.15"
+ "@types/semver" "^7.5.8"
+ "@typescript-eslint/scope-manager" "7.8.0"
+ "@typescript-eslint/types" "7.8.0"
+ "@typescript-eslint/typescript-estree" "7.8.0"
+ semver "^7.6.0"
+
+"@typescript-eslint/visitor-keys@7.8.0":
+ version "7.8.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz#7285aab991da8bee411a42edbd5db760d22fdd91"
+ integrity sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==
+ dependencies:
+ "@typescript-eslint/types" "7.8.0"
+ eslint-visitor-keys "^3.4.3"
+
+"@ungap/structured-clone@^1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
+ integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
+
+"@vitejs/plugin-react-swc@^3.5.0":
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-swc/-/plugin-react-swc-3.6.0.tgz#dc9cd1363baf3780f3ad3e0a12a46a3ffe0c7526"
+ integrity sha512-XFRbsGgpGxGzEV5i5+vRiro1bwcIaZDIdBRP16qwm+jP68ue/S8FJTBEgOeojtVDYrbSua3XFp71kC8VJE6v+g==
+ dependencies:
+ "@swc/core" "^1.3.107"
+
+"@volar/language-core@1.11.1", "@volar/language-core@~1.11.1":
+ version "1.11.1"
+ resolved "https://registry.yarnpkg.com/@volar/language-core/-/language-core-1.11.1.tgz#ecdf12ea8dc35fb8549e517991abcbf449a5ad4f"
+ integrity sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==
+ dependencies:
+ "@volar/source-map" "1.11.1"
+
+"@volar/source-map@1.11.1", "@volar/source-map@~1.11.1":
+ version "1.11.1"
+ resolved "https://registry.yarnpkg.com/@volar/source-map/-/source-map-1.11.1.tgz#535b0328d9e2b7a91dff846cab4058e191f4452f"
+ integrity sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==
+ dependencies:
+ muggle-string "^0.3.1"
+
+"@volar/typescript@~1.11.1":
+ version "1.11.1"
+ resolved "https://registry.yarnpkg.com/@volar/typescript/-/typescript-1.11.1.tgz#ba86c6f326d88e249c7f5cfe4b765be3946fd627"
+ integrity sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==
+ dependencies:
+ "@volar/language-core" "1.11.1"
+ path-browserify "^1.0.1"
+
+"@vue/compiler-core@3.4.27":
+ version "3.4.27"
+ resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.4.27.tgz#e69060f4b61429fe57976aa5872cfa21389e4d91"
+ integrity sha512-E+RyqY24KnyDXsCuQrI+mlcdW3ALND6U7Gqa/+bVwbcpcR3BRRIckFoz7Qyd4TTlnugtwuI7YgjbvsLmxb+yvg==
+ dependencies:
+ "@babel/parser" "^7.24.4"
+ "@vue/shared" "3.4.27"
+ entities "^4.5.0"
+ estree-walker "^2.0.2"
+ source-map-js "^1.2.0"
+
+"@vue/compiler-dom@^3.3.0":
+ version "3.4.27"
+ resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.4.27.tgz#d51d35f40d00ce235d7afc6ad8b09dfd92b1cc1c"
+ integrity sha512-kUTvochG/oVgE1w5ViSr3KUBh9X7CWirebA3bezTbB5ZKBQZwR2Mwj9uoSKRMFcz4gSMzzLXBPD6KpCLb9nvWw==
+ dependencies:
+ "@vue/compiler-core" "3.4.27"
+ "@vue/shared" "3.4.27"
+
+"@vue/language-core@1.8.27", "@vue/language-core@^1.8.27":
+ version "1.8.27"
+ resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-1.8.27.tgz#2ca6892cb524e024a44e554e4c55d7a23e72263f"
+ integrity sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==
+ dependencies:
+ "@volar/language-core" "~1.11.1"
+ "@volar/source-map" "~1.11.1"
+ "@vue/compiler-dom" "^3.3.0"
+ "@vue/shared" "^3.3.0"
+ computeds "^0.0.1"
+ minimatch "^9.0.3"
+ muggle-string "^0.3.1"
+ path-browserify "^1.0.1"
+ vue-template-compiler "^2.7.14"
+
+"@vue/shared@3.4.27", "@vue/shared@^3.3.0":
+ version "3.4.27"
+ resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.4.27.tgz#f05e3cd107d157354bb4ae7a7b5fc9cf73c63b50"
+ integrity sha512-DL3NmY2OFlqmYYrzp39yi3LDkKxa5vZVwxWdQ3rG0ekuWscHraeIbnI8t+aZK7qhYqEqWKTUdijadunb9pnrgA==
+
+acorn-jsx@^5.3.2:
+ version "5.3.2"
+ resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
+ integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
+
+acorn@^8.9.0:
+ version "8.11.3"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a"
+ integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==
+
+ajv@^6.12.4, ajv@~6.12.6:
+ version "6.12.6"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+ integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
+ dependencies:
+ fast-deep-equal "^3.1.1"
+ fast-json-stable-stringify "^2.0.0"
+ json-schema-traverse "^0.4.1"
+ uri-js "^4.2.2"
+
+ansi-regex@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
+ integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
+
+ansi-regex@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a"
+ integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==
+
+ansi-styles@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+ integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+ dependencies:
+ color-convert "^1.9.0"
+
+ansi-styles@^4.0.0, ansi-styles@^4.1.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+ integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
+ dependencies:
+ color-convert "^2.0.1"
+
+ansi-styles@^6.1.0:
+ version "6.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
+ integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
+
+argparse@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
+ integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
+
+argparse@~1.0.9:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+ integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
+ dependencies:
+ sprintf-js "~1.0.2"
+
+array-union@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
+ integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
+
+balanced-match@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+brace-expansion@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
+ integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
+ dependencies:
+ balanced-match "^1.0.0"
+
+braces@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+ integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+ dependencies:
+ fill-range "^7.0.1"
+
+callsites@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
+ integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
+
+chalk@^2.4.2:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+ integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+ dependencies:
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
+
+chalk@^4.0.0:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
+ integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
+ dependencies:
+ ansi-styles "^4.1.0"
+ supports-color "^7.1.0"
+
+color-convert@^1.9.0:
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+ integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+ dependencies:
+ color-name "1.1.3"
+
+color-convert@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+ integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+ dependencies:
+ color-name "~1.1.4"
+
+color-name@1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+ integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
+
+color-name@~1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+ integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+commander@^10.0.0:
+ version "10.0.1"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06"
+ integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==
+
+computeds@^0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/computeds/-/computeds-0.0.1.tgz#215b08a4ba3e08a11ff6eee5d6d8d7166a97ce2e"
+ integrity sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+
+cross-spawn@^7.0.0, cross-spawn@^7.0.2:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
+ integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
+ dependencies:
+ path-key "^3.1.0"
+ shebang-command "^2.0.0"
+ which "^2.0.1"
+
+csstype@^3.0.2:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
+ integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
+
+de-indent@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
+ integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==
+
+debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
+ version "4.3.4"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
+ integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
+ dependencies:
+ ms "2.1.2"
+
+deep-is@^0.1.3:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
+ integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
+
+dir-glob@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
+ integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
+ dependencies:
+ path-type "^4.0.0"
+
+doctrine@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
+ integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
+ dependencies:
+ esutils "^2.0.2"
+
+eastasianwidth@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
+ integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
+
+emoji-regex@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+ integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+
+emoji-regex@^9.2.2:
+ version "9.2.2"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
+ integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
+
+entities@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
+ integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
+
+esbuild@^0.20.1:
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.20.2.tgz#9d6b2386561766ee6b5a55196c6d766d28c87ea1"
+ integrity sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==
+ optionalDependencies:
+ "@esbuild/aix-ppc64" "0.20.2"
+ "@esbuild/android-arm" "0.20.2"
+ "@esbuild/android-arm64" "0.20.2"
+ "@esbuild/android-x64" "0.20.2"
+ "@esbuild/darwin-arm64" "0.20.2"
+ "@esbuild/darwin-x64" "0.20.2"
+ "@esbuild/freebsd-arm64" "0.20.2"
+ "@esbuild/freebsd-x64" "0.20.2"
+ "@esbuild/linux-arm" "0.20.2"
+ "@esbuild/linux-arm64" "0.20.2"
+ "@esbuild/linux-ia32" "0.20.2"
+ "@esbuild/linux-loong64" "0.20.2"
+ "@esbuild/linux-mips64el" "0.20.2"
+ "@esbuild/linux-ppc64" "0.20.2"
+ "@esbuild/linux-riscv64" "0.20.2"
+ "@esbuild/linux-s390x" "0.20.2"
+ "@esbuild/linux-x64" "0.20.2"
+ "@esbuild/netbsd-x64" "0.20.2"
+ "@esbuild/openbsd-x64" "0.20.2"
+ "@esbuild/sunos-x64" "0.20.2"
+ "@esbuild/win32-arm64" "0.20.2"
+ "@esbuild/win32-ia32" "0.20.2"
+ "@esbuild/win32-x64" "0.20.2"
+
+escape-string-regexp@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+ integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
+
+escape-string-regexp@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
+ integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
+
+eslint-plugin-react-hooks@^4.6.0:
+ version "4.6.2"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz#c829eb06c0e6f484b3fbb85a97e57784f328c596"
+ integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==
+
+eslint-plugin-react-refresh@^0.4.6:
+ version "0.4.6"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.6.tgz#e8e8accab681861baed00c5c12da70267db0936f"
+ integrity sha512-NjGXdm7zgcKRkKMua34qVO9doI7VOxZ6ancSvBELJSSoX97jyndXcSoa8XBh69JoB31dNz3EEzlMcizZl7LaMA==
+
+eslint-scope@^7.2.2:
+ version "7.2.2"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f"
+ integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==
+ dependencies:
+ esrecurse "^4.3.0"
+ estraverse "^5.2.0"
+
+eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3:
+ version "3.4.3"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
+ integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
+
+eslint@^8.57.0:
+ version "8.57.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668"
+ integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==
+ dependencies:
+ "@eslint-community/eslint-utils" "^4.2.0"
+ "@eslint-community/regexpp" "^4.6.1"
+ "@eslint/eslintrc" "^2.1.4"
+ "@eslint/js" "8.57.0"
+ "@humanwhocodes/config-array" "^0.11.14"
+ "@humanwhocodes/module-importer" "^1.0.1"
+ "@nodelib/fs.walk" "^1.2.8"
+ "@ungap/structured-clone" "^1.2.0"
+ ajv "^6.12.4"
+ chalk "^4.0.0"
+ cross-spawn "^7.0.2"
+ debug "^4.3.2"
+ doctrine "^3.0.0"
+ escape-string-regexp "^4.0.0"
+ eslint-scope "^7.2.2"
+ eslint-visitor-keys "^3.4.3"
+ espree "^9.6.1"
+ esquery "^1.4.2"
+ esutils "^2.0.2"
+ fast-deep-equal "^3.1.3"
+ file-entry-cache "^6.0.1"
+ find-up "^5.0.0"
+ glob-parent "^6.0.2"
+ globals "^13.19.0"
+ graphemer "^1.4.0"
+ ignore "^5.2.0"
+ imurmurhash "^0.1.4"
+ is-glob "^4.0.0"
+ is-path-inside "^3.0.3"
+ js-yaml "^4.1.0"
+ json-stable-stringify-without-jsonify "^1.0.1"
+ levn "^0.4.1"
+ lodash.merge "^4.6.2"
+ minimatch "^3.1.2"
+ natural-compare "^1.4.0"
+ optionator "^0.9.3"
+ strip-ansi "^6.0.1"
+ text-table "^0.2.0"
+
+espree@^9.6.0, espree@^9.6.1:
+ version "9.6.1"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f"
+ integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==
+ dependencies:
+ acorn "^8.9.0"
+ acorn-jsx "^5.3.2"
+ eslint-visitor-keys "^3.4.1"
+
+esquery@^1.4.2:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b"
+ integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==
+ dependencies:
+ estraverse "^5.1.0"
+
+esrecurse@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
+ integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
+ dependencies:
+ estraverse "^5.2.0"
+
+estraverse@^5.1.0, estraverse@^5.2.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
+ integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
+
+estree-walker@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
+ integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
+
+esutils@^2.0.2:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
+ integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
+
+fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
+ integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
+
+fast-glob@^3.2.9:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
+ integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
+ dependencies:
+ "@nodelib/fs.stat" "^2.0.2"
+ "@nodelib/fs.walk" "^1.2.3"
+ glob-parent "^5.1.2"
+ merge2 "^1.3.0"
+ micromatch "^4.0.4"
+
+fast-json-stable-stringify@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+ integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
+
+fast-levenshtein@^2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+ integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
+
+fastq@^1.6.0:
+ version "1.17.1"
+ resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47"
+ integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==
+ dependencies:
+ reusify "^1.0.4"
+
+file-entry-cache@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
+ integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==
+ dependencies:
+ flat-cache "^3.0.4"
+
+fill-range@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+ integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+ dependencies:
+ to-regex-range "^5.0.1"
+
+find-up@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
+ integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
+ dependencies:
+ locate-path "^6.0.0"
+ path-exists "^4.0.0"
+
+flat-cache@^3.0.4:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee"
+ integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==
+ dependencies:
+ flatted "^3.2.9"
+ keyv "^4.5.3"
+ rimraf "^3.0.2"
+
+flatted@^3.2.9:
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a"
+ integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==
+
+foreground-child@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d"
+ integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==
+ dependencies:
+ cross-spawn "^7.0.0"
+ signal-exit "^4.0.1"
+
+fs-extra@~7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
+ integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==
+ dependencies:
+ graceful-fs "^4.1.2"
+ jsonfile "^4.0.0"
+ universalify "^0.1.0"
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+ integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
+
+fsevents@~2.3.2, fsevents@~2.3.3:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
+ integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
+
+function-bind@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
+ integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
+
+glob-parent@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+ integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
+ dependencies:
+ is-glob "^4.0.1"
+
+glob-parent@^6.0.2:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
+ integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
+ dependencies:
+ is-glob "^4.0.3"
+
+glob@^10.3.12:
+ version "10.3.12"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.12.tgz#3a65c363c2e9998d220338e88a5f6ac97302960b"
+ integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==
+ dependencies:
+ foreground-child "^3.1.0"
+ jackspeak "^2.3.6"
+ minimatch "^9.0.1"
+ minipass "^7.0.4"
+ path-scurry "^1.10.2"
+
+glob@^7.1.3:
+ version "7.2.3"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
+ integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.1.1"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+globals@^11.1.0:
+ version "11.12.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
+ integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
+
+globals@^13.19.0:
+ version "13.24.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171"
+ integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==
+ dependencies:
+ type-fest "^0.20.2"
+
+globby@^11.1.0:
+ version "11.1.0"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
+ integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
+ dependencies:
+ array-union "^2.1.0"
+ dir-glob "^3.0.1"
+ fast-glob "^3.2.9"
+ ignore "^5.2.0"
+ merge2 "^1.4.1"
+ slash "^3.0.0"
+
+graceful-fs@^4.1.2, graceful-fs@^4.1.6:
+ version "4.2.11"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
+ integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
+
+graphemer@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
+ integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
+
+has-flag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+ integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
+
+has-flag@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+ integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+
+hasown@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
+ integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
+ dependencies:
+ function-bind "^1.1.2"
+
+he@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
+ integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+
+ignore@^5.2.0, ignore@^5.3.1:
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef"
+ integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==
+
immer@^10.0.3:
- version "10.0.4"
- resolved "https://registry.yarnpkg.com/immer/-/immer-10.0.4.tgz#09af41477236b99449f9d705369a4daaf780362b"
- integrity sha512-cuBuGK40P/sk5IzWa9QPUaAdvPHjkk1c+xYsd9oZw+YQQEV+10G0P5uMpGctZZKnyQ+ibRO08bD25nWLmYi2pw==
+ version "10.1.1"
+ resolved "https://registry.yarnpkg.com/immer/-/immer-10.1.1.tgz#206f344ea372d8ea176891545ee53ccc062db7bc"
+ integrity sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==
+
+import-fresh@^3.2.1:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
+ integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
+ dependencies:
+ parent-module "^1.0.0"
+ resolve-from "^4.0.0"
+
+import-lazy@~4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153"
+ integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==
+
+imurmurhash@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+ integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@2:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+ integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+is-core-module@^2.1.0, is-core-module@^2.13.0:
+ version "2.13.1"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384"
+ integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==
+ dependencies:
+ hasown "^2.0.0"
+
+is-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+ integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+
+is-fullwidth-code-point@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+ integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
+is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
+ integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
+ dependencies:
+ is-extglob "^2.1.1"
+
+is-number@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+ integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
+is-path-inside@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
+ integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
+
+isexe@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+ integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
+
+jackspeak@^2.3.6:
+ version "2.3.6"
+ resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8"
+ integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==
+ dependencies:
+ "@isaacs/cliui" "^8.0.2"
+ optionalDependencies:
+ "@pkgjs/parseargs" "^0.11.0"
+
+javascript-natural-sort@0.7.1:
+ version "0.7.1"
+ resolved "https://registry.yarnpkg.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59"
+ integrity sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==
+
+jju@~1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/jju/-/jju-1.4.0.tgz#a3abe2718af241a2b2904f84a625970f389ae32a"
+ integrity sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==
+
+"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+ integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+js-yaml@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
+ integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
+ dependencies:
+ argparse "^2.0.1"
+
+jsesc@^2.5.1:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
+ integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
+
+json-buffer@3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
+ integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
+
+json-schema-traverse@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+ integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+json-stable-stringify-without-jsonify@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
+ integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
+
+jsonfile@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
+ integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==
+ optionalDependencies:
+ graceful-fs "^4.1.6"
+
+keyv@^4.5.3:
+ version "4.5.4"
+ resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
+ integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
+ dependencies:
+ json-buffer "3.0.1"
+
+kolorist@^1.8.0:
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.8.0.tgz#edddbbbc7894bc13302cdf740af6374d4a04743c"
+ integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==
+
+levn@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
+ integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
+ dependencies:
+ prelude-ls "^1.2.1"
+ type-check "~0.4.0"
+
+locate-path@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
+ integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
+ dependencies:
+ p-locate "^5.0.0"
+
+lodash.get@^4.4.2:
+ version "4.4.2"
+ resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
+ integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==
+
+lodash.isequal@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
+ integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==
+
+lodash.merge@^4.6.2:
+ version "4.6.2"
+ resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
+ integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
+
+lodash@^4.17.21, lodash@~4.17.15:
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+ integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+
+loose-envify@^1.1.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+ integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
+ dependencies:
+ js-tokens "^3.0.0 || ^4.0.0"
+
+lru-cache@^10.2.0:
+ version "10.2.2"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.2.tgz#48206bc114c1252940c41b25b41af5b545aca878"
+ integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==
+
+lru-cache@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
+ integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
+ dependencies:
+ yallist "^4.0.0"
+
+magic-string@^0.30.8:
+ version "0.30.10"
+ resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.10.tgz#123d9c41a0cb5640c892b041d4cfb3bd0aa4b39e"
+ integrity sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==
+ dependencies:
+ "@jridgewell/sourcemap-codec" "^1.4.15"
+
+merge2@^1.3.0, merge2@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
+ integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+
+micromatch@^4.0.4:
+ version "4.0.5"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
+ integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
+ dependencies:
+ braces "^3.0.2"
+ picomatch "^2.3.1"
+
+minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+ integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+ dependencies:
+ brace-expansion "^1.1.7"
+
+minimatch@^9.0.1, minimatch@^9.0.3, minimatch@^9.0.4:
+ version "9.0.4"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51"
+ integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==
+ dependencies:
+ brace-expansion "^2.0.1"
+
+minimatch@~3.0.3:
+ version "3.0.8"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.8.tgz#5e6a59bd11e2ab0de1cfb843eb2d82e546c321c1"
+ integrity sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==
+ dependencies:
+ brace-expansion "^1.1.7"
+
+"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.0.tgz#b545f84af94e567386770159302ca113469c80b8"
+ integrity sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig==
+
+ms@2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+ integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
+muggle-string@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/muggle-string/-/muggle-string-0.3.1.tgz#e524312eb1728c63dd0b2ac49e3282e6ed85963a"
+ integrity sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==
+
+nanoid@^3.3.7:
+ version "3.3.7"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
+ integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
+
+natural-compare@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+ integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
+
+once@^1.3.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
+ dependencies:
+ wrappy "1"
+
+optionator@^0.9.3:
+ version "0.9.4"
+ resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734"
+ integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==
+ dependencies:
+ deep-is "^0.1.3"
+ fast-levenshtein "^2.0.6"
+ levn "^0.4.1"
+ prelude-ls "^1.2.1"
+ type-check "^0.4.0"
+ word-wrap "^1.2.5"
+
+p-limit@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
+ integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
+ dependencies:
+ yocto-queue "^0.1.0"
+
+p-locate@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
+ integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
+ dependencies:
+ p-limit "^3.0.2"
+
+parent-module@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+ integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
+ dependencies:
+ callsites "^3.0.0"
+
+path-browserify@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd"
+ integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==
+
+path-exists@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
+ integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
+
+path-is-absolute@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+ integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
+
+path-key@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
+ integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
+
+path-parse@^1.0.6, path-parse@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+
+path-scurry@^1.10.2:
+ version "1.10.2"
+ resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.2.tgz#8f6357eb1239d5fa1da8b9f70e9c080675458ba7"
+ integrity sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==
+ dependencies:
+ lru-cache "^10.2.0"
+ minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
+
+path-type@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
+ integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
+
+picocolors@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
+ integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
+
+picomatch@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+ integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+postcss@^8.4.38:
+ version "8.4.38"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.38.tgz#b387d533baf2054288e337066d81c6bee9db9e0e"
+ integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==
+ dependencies:
+ nanoid "^3.3.7"
+ picocolors "^1.0.0"
+ source-map-js "^1.2.0"
+
+prelude-ls@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
+ integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
+
+prettier@^3.2.5:
+ version "3.2.5"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368"
+ integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==
+
+punycode@^2.1.0:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
+ integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
+
+queue-microtask@^1.2.2:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
+ integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+
+react-dom@^18.2.0:
+ version "18.3.1"
+ resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4"
+ integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==
+ dependencies:
+ loose-envify "^1.1.0"
+ scheduler "^0.23.2"
+
+react-icons@^5.2.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-5.2.1.tgz#28c2040917b2a2eda639b0f797bff1888e018e4a"
+ integrity sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==
+
+react-redux@^9.1.2:
+ version "9.1.2"
+ resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-9.1.2.tgz#deba38c64c3403e9abd0c3fbeab69ffd9d8a7e4b"
+ integrity sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==
+ dependencies:
+ "@types/use-sync-external-store" "^0.0.3"
+ use-sync-external-store "^1.0.0"
+
+react@^18.2.0:
+ version "18.3.1"
+ resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891"
+ integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==
+ dependencies:
+ loose-envify "^1.1.0"
redux-thunk@^3.1.0:
version "3.1.0"
@@ -32,7 +1830,378 @@ reselect@^5.0.1:
resolved "https://registry.yarnpkg.com/reselect/-/reselect-5.1.0.tgz#c479139ab9dd91be4d9c764a7f3868210ef8cd21"
integrity sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg==
-zod@^3.22.4:
- version "3.22.4"
- resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.4.tgz#f31c3a9386f61b1f228af56faa9255e845cf3fff"
- integrity sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==
+resolve-from@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+ integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+
+resolve@~1.19.0:
+ version "1.19.0"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c"
+ integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==
+ dependencies:
+ is-core-module "^2.1.0"
+ path-parse "^1.0.6"
+
+resolve@~1.22.1:
+ version "1.22.8"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
+ integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
+ dependencies:
+ is-core-module "^2.13.0"
+ path-parse "^1.0.7"
+ supports-preserve-symlinks-flag "^1.0.0"
+
+reusify@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+ integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
+
+rimraf@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+ integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
+ dependencies:
+ glob "^7.1.3"
+
+rollup@^4.13.0:
+ version "4.17.2"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.17.2.tgz#26d1785d0144122277fdb20ab3a24729ae68301f"
+ integrity sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==
+ dependencies:
+ "@types/estree" "1.0.5"
+ optionalDependencies:
+ "@rollup/rollup-android-arm-eabi" "4.17.2"
+ "@rollup/rollup-android-arm64" "4.17.2"
+ "@rollup/rollup-darwin-arm64" "4.17.2"
+ "@rollup/rollup-darwin-x64" "4.17.2"
+ "@rollup/rollup-linux-arm-gnueabihf" "4.17.2"
+ "@rollup/rollup-linux-arm-musleabihf" "4.17.2"
+ "@rollup/rollup-linux-arm64-gnu" "4.17.2"
+ "@rollup/rollup-linux-arm64-musl" "4.17.2"
+ "@rollup/rollup-linux-powerpc64le-gnu" "4.17.2"
+ "@rollup/rollup-linux-riscv64-gnu" "4.17.2"
+ "@rollup/rollup-linux-s390x-gnu" "4.17.2"
+ "@rollup/rollup-linux-x64-gnu" "4.17.2"
+ "@rollup/rollup-linux-x64-musl" "4.17.2"
+ "@rollup/rollup-win32-arm64-msvc" "4.17.2"
+ "@rollup/rollup-win32-ia32-msvc" "4.17.2"
+ "@rollup/rollup-win32-x64-msvc" "4.17.2"
+ fsevents "~2.3.2"
+
+run-parallel@^1.1.9:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
+ integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
+ dependencies:
+ queue-microtask "^1.2.2"
+
+scheduler@^0.23.2:
+ version "0.23.2"
+ resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3"
+ integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==
+ dependencies:
+ loose-envify "^1.1.0"
+
+semver@^7.5.4, semver@^7.6.0:
+ version "7.6.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.1.tgz#60bfe090bf907a25aa8119a72b9f90ef7ca281b2"
+ integrity sha512-f/vbBsu+fOiYt+lmwZV0rVwJScl46HppnOA1ZvIuBWKOTlllpyJ3bfVax76/OrhCH38dyxoDIA8K7uB963IYgA==
+
+semver@~7.5.4:
+ version "7.5.4"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
+ integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
+ dependencies:
+ lru-cache "^6.0.0"
+
+shebang-command@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+ integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
+ dependencies:
+ shebang-regex "^3.0.0"
+
+shebang-regex@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+ integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
+
+signal-exit@^4.0.1:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
+ integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
+
+slash@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
+ integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
+
+source-map-js@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"
+ integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==
+
+source-map@^0.5.0:
+ version "0.5.7"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+ integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
+
+source-map@~0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+ integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+sprintf-js@~1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+ integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
+
+string-argv@~0.3.1:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6"
+ integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==
+
+"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.1"
+
+string-width@^5.0.1, string-width@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
+ integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==
+ dependencies:
+ eastasianwidth "^0.2.0"
+ emoji-regex "^9.2.2"
+ strip-ansi "^7.0.1"
+
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+ integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+ dependencies:
+ ansi-regex "^5.0.1"
+
+strip-ansi@^7.0.1:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
+ integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==
+ dependencies:
+ ansi-regex "^6.0.1"
+
+strip-json-comments@^3.1.1, strip-json-comments@~3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
+ integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
+
+supports-color@^5.3.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+ integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+ dependencies:
+ has-flag "^3.0.0"
+
+supports-color@^7.1.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+ integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
+ dependencies:
+ has-flag "^4.0.0"
+
+supports-color@~8.1.1:
+ version "8.1.1"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
+ integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
+ dependencies:
+ has-flag "^4.0.0"
+
+supports-preserve-symlinks-flag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
+ integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+
+text-table@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
+ integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
+
+to-fast-properties@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
+ integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
+
+to-regex-range@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+ integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+ dependencies:
+ is-number "^7.0.0"
+
+ts-api-utils@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1"
+ integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==
+
+type-check@^0.4.0, type-check@~0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
+ integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
+ dependencies:
+ prelude-ls "^1.2.1"
+
+type-fest@^0.20.2:
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
+ integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
+
+typescript@5.4.2:
+ version "5.4.2"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.2.tgz#0ae9cebcfae970718474fe0da2c090cad6577372"
+ integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==
+
+typescript@^5.2.2:
+ version "5.4.5"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611"
+ integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==
+
+undici-types@~5.26.4:
+ version "5.26.5"
+ resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
+ integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
+
+universalify@^0.1.0:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
+ integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
+
+uri-js@^4.2.2:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
+ integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
+ dependencies:
+ punycode "^2.1.0"
+
+use-sync-external-store@^1.0.0:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9"
+ integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==
+
+validator@^13.7.0:
+ version "13.11.0"
+ resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b"
+ integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==
+
+vite-plugin-dts@^3.9.1:
+ version "3.9.1"
+ resolved "https://registry.yarnpkg.com/vite-plugin-dts/-/vite-plugin-dts-3.9.1.tgz#625ad388ec3956708ccec7960550a7b0a8e8909e"
+ integrity sha512-rVp2KM9Ue22NGWB8dNtWEr+KekN3rIgz1tWD050QnRGlriUCmaDwa7qA5zDEjbXg5lAXhYMSBJtx3q3hQIJZSg==
+ dependencies:
+ "@microsoft/api-extractor" "7.43.0"
+ "@rollup/pluginutils" "^5.1.0"
+ "@vue/language-core" "^1.8.27"
+ debug "^4.3.4"
+ kolorist "^1.8.0"
+ magic-string "^0.30.8"
+ vue-tsc "^1.8.27"
+
+vite-plugin-lib-inject-css@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/vite-plugin-lib-inject-css/-/vite-plugin-lib-inject-css-2.0.1.tgz#3243c1b87feb106f942a1bb205ca8cd8a424e72b"
+ integrity sha512-86VU8m4t3TNPk9xfdnNDqn1OHkgrPHpP7B5wkVys4tWSLwMMIucCgJdc5wenGntLNMWKChJV0Ut3qGH6iGojMg==
+ dependencies:
+ magic-string "^0.30.8"
+ picocolors "^1.0.0"
+
+vite@^5.2.0:
+ version "5.2.11"
+ resolved "https://registry.yarnpkg.com/vite/-/vite-5.2.11.tgz#726ec05555431735853417c3c0bfb36003ca0cbd"
+ integrity sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==
+ dependencies:
+ esbuild "^0.20.1"
+ postcss "^8.4.38"
+ rollup "^4.13.0"
+ optionalDependencies:
+ fsevents "~2.3.3"
+
+vue-template-compiler@^2.7.14:
+ version "2.7.16"
+ resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz#c81b2d47753264c77ac03b9966a46637482bb03b"
+ integrity sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==
+ dependencies:
+ de-indent "^1.0.2"
+ he "^1.2.0"
+
+vue-tsc@^1.8.27:
+ version "1.8.27"
+ resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-1.8.27.tgz#feb2bb1eef9be28017bb9e95e2bbd1ebdd48481c"
+ integrity sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==
+ dependencies:
+ "@volar/typescript" "~1.11.1"
+ "@vue/language-core" "1.8.27"
+ semver "^7.5.4"
+
+which@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+ integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
+ dependencies:
+ isexe "^2.0.0"
+
+word-wrap@^1.2.5:
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
+ integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
+
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
+wrap-ansi@^8.1.0:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
+ integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==
+ dependencies:
+ ansi-styles "^6.1.0"
+ string-width "^5.0.1"
+ strip-ansi "^7.0.1"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
+
+yallist@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
+ integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
+
+yocto-queue@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
+ integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
+
+z-schema@~5.0.2:
+ version "5.0.6"
+ resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-5.0.6.tgz#46d6a687b15e4a4369e18d6cb1c7b8618fc256c5"
+ integrity sha512-+XR1GhnWklYdfr8YaZv/iu+vY+ux7V5DS5zH1DQf6bO5ufrt/5cgNhVO5qyhsjFXvsqQb/f08DWE9b6uPscyAg==
+ dependencies:
+ lodash.get "^4.4.2"
+ lodash.isequal "^4.5.0"
+ validator "^13.7.0"
+ optionalDependencies:
+ commander "^10.0.0"
+
+zod@^3.23.6:
+ version "3.23.6"
+ resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.6.tgz#c08a977e2255dab1fdba933651584a05fcbf19e1"
+ integrity sha512-RTHJlZhsRbuA8Hmp/iNL7jnfc4nZishjsanDAfEY1QpDQZCahUp3xDzl+zfweE9BklxMUcgBgS1b7Lvie/ZVwA==
diff --git a/frontend/mobile/.gitignore b/frontend/mobile/.gitignore
index 4ed2821fa..0b37b6eb4 100644
--- a/frontend/mobile/.gitignore
+++ b/frontend/mobile/.gitignore
@@ -3,9 +3,6 @@
# dependencies
node_modules/
-# testing
-coverage/
-
# Expo
.expo/
dist/
diff --git a/frontend/mobile/app.d.ts b/frontend/mobile/app.d.ts
deleted file mode 100644
index a13e3136b..000000000
--- a/frontend/mobile/app.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-///
diff --git a/frontend/mobile/app/(app)/(tabs)/_layout.tsx b/frontend/mobile/app/(app)/(tabs)/_layout.tsx
index 8aa17c7b3..dff3314e5 100644
--- a/frontend/mobile/app/(app)/(tabs)/_layout.tsx
+++ b/frontend/mobile/app/(app)/(tabs)/_layout.tsx
@@ -1,94 +1,30 @@
-import React, { useEffect } from 'react';
-import { Text, View } from 'react-native';
+import React from 'react';
import { Tabs } from 'expo-router';
-import HomeSelectedIcon from '@/assets/images/svg/home-selected.svg';
-import HomeIcon from '@/assets/images/svg/home.svg';
-import NotificationIcon from '@/assets/images/svg/notification.svg';
-import ProfileSelectedIcon from '@/assets/images/svg/profile-selected.svg';
-import ProfileIcon from '@/assets/images/svg/profile.svg';
-import SearchSelectedIcon from '@/assets/images/svg/search-selected.svg';
-import SearchIcon from '@/assets/images/svg/search.svg';
-import { useAuthStore } from '@/hooks/use-auth';
-
const Layout = () => {
- const { isLoggedIn, fetchUser, user } = useAuthStore();
-
- useEffect(() => {
- if (isLoggedIn) fetchUser();
- }, [isLoggedIn, fetchUser]);
-
return (
(
-
- ),
- headerLeft: () => (
-
-
- Hi, {user?.first_name}
-
-
- ),
- headerRight: () => (
-
-
-
- ),
- headerShown: true,
- tabBarIcon: ({ focused }) =>
- focused ? (
-
-
-
- ) : (
-
-
-
- )
+ title: 'home',
+ headerShown: false
}}
- redirect={!isLoggedIn}
/>
- focused ? (
-
-
-
- ) : (
-
-
-
- )
+ headerShown: false
}}
- redirect={!isLoggedIn}
/>
- focused ? (
-
-
-
- ) : (
-
-
-
- )
+ headerShown: false
}}
- redirect={!isLoggedIn}
/>
);
diff --git a/frontend/mobile/app/(app)/(tabs)/discover.tsx b/frontend/mobile/app/(app)/(tabs)/discover.tsx
index ee56ebb0a..46cd70909 100644
--- a/frontend/mobile/app/(app)/(tabs)/discover.tsx
+++ b/frontend/mobile/app/(app)/(tabs)/discover.tsx
@@ -1,143 +1,28 @@
-import React from 'react';
-import {
- SafeAreaView,
- ScrollView,
- Text,
- TouchableOpacity,
- View
-} from 'react-native';
-
-import { router } from 'expo-router';
-
-import { useClubsQuery, useEventsQuery } from '@sac/lib';
-
-import { SearchBar } from '@/app/(app)/search/_components/search-bar';
-import { TopSearch } from '@/app/(app)/search/_components/top-search';
-
-import { ClubHomePageCard } from './_components/club-homepage-card';
-import { EventHomePageCardHorizontal } from './_components/event-homepage-card';
-
-const Discover = () => {
- const {
- data: events,
- isLoading: eIsLoading,
- error: eError
- } = useEventsQuery({});
-
- const {
- data: clubs,
- isLoading: cIsLoading,
- error: cError
- } = useClubsQuery({});
-
- if (eIsLoading || cIsLoading) {
- return Loading... ;
- }
-
- if (eError || cError) {
- return Error... ;
- }
+import { StyleSheet, Text, View } from 'react-native';
+const DiscoverPage = () => {
return (
-
-
- {
- router.push('/(app)/search/recents');
- return undefined;
- }}
- />
-
-
- Top Searches
-
- {/* FIXME: this and discover clubs have the same layout, make like a 2d grid scroll view elem */}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Discover Clubs
-
-
-
- View All
-
-
-
-
-
-
- {clubs?.map((club) => {
- return ;
- })}
-
-
-
-
-
- Discover Events
-
-
-
- View All
-
-
-
-
- {events?.map((event) => {
- return (
-
- );
- })}
-
-
-
-
+
+ Discover
+
);
};
-export default Discover;
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ title: {
+ fontSize: 20,
+ fontWeight: 'bold'
+ },
+ separator: {
+ marginVertical: 30,
+ height: 1,
+ width: '80%'
+ }
+});
+
+export default DiscoverPage;
diff --git a/frontend/mobile/app/(app)/(tabs)/index.tsx b/frontend/mobile/app/(app)/(tabs)/index.tsx
index ea130844c..c1e40d376 100644
--- a/frontend/mobile/app/(app)/(tabs)/index.tsx
+++ b/frontend/mobile/app/(app)/(tabs)/index.tsx
@@ -1,67 +1,28 @@
-import React from 'react';
-import { SectionList, Text, View } from 'react-native';
-
-import { StatusBar } from 'expo-status-bar';
-
-import { useUserFollowingQuery } from '@sac/lib';
-
-import { useAuthStore } from '@/hooks/use-auth';
-
-import { HappeningToday } from './_components/happening-today';
-import { RecommendedClubs } from './_components/recommended-clubs';
-import { UpcomingEvents } from './_components/upcoming-events';
+import { StyleSheet, Text, View } from 'react-native';
const HomePage = () => {
- const { user } = useAuthStore();
- const {
- data: clubs,
- isLoading: cIsLoading,
- error: cError
- } = useUserFollowingQuery(user?.id!);
return (
- <>
-
-
- {cIsLoading && Loading... }
- {cError && Error... }
- {clubs && clubs.length === 0 && (
- Follow some clubs to see them here!
- )}
- {clubs && clubs.length > 0 && (
- Following Clubs: {clubs.length}
- )}
- {clubs &&
- clubs.map((club) => {club.name} )}
-
-
- ]
- },
- {
- title: 'Upcoming Events',
- data: [ ]
- },
- {
- title: 'Recommended Clubs',
- data: [ ]
- }
- ]}
- keyExtractor={(_, index) => index.toString()}
- renderItem={({ item }) => {item} }
- renderSectionHeader={({ section: { title } }) => (
-
- {title}
-
- )}
- stickyHeaderHiddenOnScroll={true}
- stickySectionHeadersEnabled={false}
- />
-
- >
+
+ Home
+
);
};
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ title: {
+ fontSize: 20,
+ fontWeight: 'bold'
+ },
+ separator: {
+ marginVertical: 30,
+ height: 1,
+ width: '80%'
+ }
+});
+
export default HomePage;
diff --git a/frontend/mobile/app/(app)/(tabs)/profile.tsx b/frontend/mobile/app/(app)/(tabs)/profile.tsx
index 98d5bd882..7d6ca1183 100644
--- a/frontend/mobile/app/(app)/(tabs)/profile.tsx
+++ b/frontend/mobile/app/(app)/(tabs)/profile.tsx
@@ -1,24 +1,28 @@
-import React from 'react';
-import { SafeAreaView, Text, View } from 'react-native';
-
-import { Button } from '@/components/button';
-import { useAuthStore } from '@/hooks/use-auth';
-
-const Profile = () => {
- const { onLogout, user } = useAuthStore();
-
- const handleSignOut = async () => {
- onLogout();
- };
+import { StyleSheet, Text, View } from 'react-native';
+const ProfilePage = () => {
return (
-
-
- Welcome {user?.first_name}
- Sign Out
-
-
+
+ Profile
+
);
};
-export default Profile;
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ title: {
+ fontSize: 20,
+ fontWeight: 'bold'
+ },
+ separator: {
+ marginVertical: 30,
+ height: 1,
+ width: '80%'
+ }
+});
+
+export default ProfilePage;
diff --git a/frontend/mobile/app/(app)/_layout.tsx b/frontend/mobile/app/(app)/_layout.tsx
index f283ca7bd..b8aa8a74e 100644
--- a/frontend/mobile/app/(app)/_layout.tsx
+++ b/frontend/mobile/app/(app)/_layout.tsx
@@ -1,62 +1,11 @@
import React from 'react';
-import { View } from 'react-native';
import { Stack } from 'expo-router';
-import { Arrow } from '@/components/arrow';
-
-import { ClubKebab } from './_components/club-kebab';
-import { EventKabab } from './_components/event-kebab';
-
const Layout = () => {
return (
- ,
- headerRight: () =>
- }}
- />
- ,
- headerRight: () =>
- }}
- />
- (
-
- ),
- headerLeft: () =>
- }}
- />
-
);
};
diff --git a/frontend/mobile/app/(auth)/_layout.tsx b/frontend/mobile/app/(auth)/_layout.tsx
index 670d9c7ae..0e369d3c7 100644
--- a/frontend/mobile/app/(auth)/_layout.tsx
+++ b/frontend/mobile/app/(auth)/_layout.tsx
@@ -1,106 +1,11 @@
import React from 'react';
-import { View } from 'react-native';
-import { Stack, router } from 'expo-router';
-
-import { Arrow } from '@/components/arrow';
-import { Button } from '@/components/button';
-import { Wordmark } from '@/components/wordmark';
-import { useAuthStore } from '@/hooks/use-auth';
+import { Stack } from 'expo-router';
const Layout = () => {
- const { onLogout } = useAuthStore();
return (
-
- ,
- headerBackground: () =>
- }}
- />
- ,
- headerBackground: () => (
-
- ),
- animationTypeForReplace: 'push',
- animation: 'slide_from_right'
- }}
- />
- ,
- headerRight: () => (
- router.replace('/login')}
- >
- Login
-
- ),
- headerBackground: () => ,
- animationTypeForReplace: 'pop',
- animation: 'slide_from_left'
- }}
- />
- {
- return onLogout()} />;
- },
- headerBackground: () =>
- }}
- />
- ,
- headerBackground: () => ,
- headerRight: () => (
- router.replace('/(app)/(tabs)/')}
- />
- )
- }}
- />
- ,
- headerBackground: () => ,
- headerRight: () => (
- router.replace('/(app)/(tabs)/')}
- />
- )
- }}
- />
+
+
);
};
diff --git a/frontend/mobile/app/(auth)/index.tsx b/frontend/mobile/app/(auth)/index.tsx
new file mode 100644
index 000000000..d1e4b89e7
--- /dev/null
+++ b/frontend/mobile/app/(auth)/index.tsx
@@ -0,0 +1,12 @@
+import React from 'react';
+import { Text, View } from 'react-native';
+
+const Welcome = () => {
+ return (
+
+ Welcome
+
+ );
+};
+
+export default Welcome;
diff --git a/frontend/mobile/app/_layout.tsx b/frontend/mobile/app/_layout.tsx
index 609f7647d..2d1c8c6e0 100644
--- a/frontend/mobile/app/_layout.tsx
+++ b/frontend/mobile/app/_layout.tsx
@@ -1,78 +1,26 @@
import { useEffect } from 'react';
-import { View } from 'react-native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
-import Spinner from 'react-native-loading-spinner-overlay';
+import 'react-native-reanimated';
import { Provider } from 'react-redux';
import { useFonts } from 'expo-font';
-import { Stack, useRouter, useSegments } from 'expo-router';
+import { Stack } from 'expo-router';
import * as SplashScreen from 'expo-splash-screen';
import { StatusBar } from 'expo-status-bar';
import FontAwesome from '@expo/vector-icons/FontAwesome';
-import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
-import { useAuthStore } from '@/hooks/use-auth';
import { store } from '@/store/store';
-export {
- // Catch any errors thrown by the Layout component.
- ErrorBoundary
-} from 'expo-router';
+export { ErrorBoundary } from 'expo-router';
-// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();
-export const queryClient = new QueryClient({
- defaultOptions: {
- queries: {
- refetchOnWindowFocus: false,
- retry: false,
- staleTime: 1000 * 60 * 5
- }
- }
-});
-
const InitalLayout = () => {
- const { isLoggedIn, fetchCache, isVerified, user } = useAuthStore();
- const router = useRouter();
- const segments = useSegments();
-
useEffect(() => {
- const handleNavigation = () => {
- if (isLoggedIn === null) return fetchCache();
-
- const inApp = segments[0] === '(app)';
-
- console.log({ isLoggedIn, isVerified, inApp });
-
- if (isLoggedIn && isVerified === false) {
- router.push('/(auth)/verification');
- } else if (isLoggedIn && isVerified) {
- router.push('/(app)/(tabs)/');
- } else if (!isLoggedIn) {
- router.push('/(auth)/welcome');
- }
- };
-
- console.log({ isLoggedIn, isVerified, user });
-
+ const handleNavigation = () => {};
handleNavigation();
-
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [isLoggedIn, isVerified]);
-
- if (isLoggedIn === null)
- return (
-
-
-
- );
+ }, []);
return (
<>
@@ -104,10 +52,8 @@ const RootLayout = () => {
return (
-
-
-
-
+
+
);
diff --git a/frontend/mobile/assets/images/bell.png b/frontend/mobile/assets/images/bell.png
deleted file mode 100644
index d94644403..000000000
Binary files a/frontend/mobile/assets/images/bell.png and /dev/null differ
diff --git a/frontend/mobile/assets/images/box.png b/frontend/mobile/assets/images/box.png
deleted file mode 100644
index e60e632e3..000000000
Binary files a/frontend/mobile/assets/images/box.png and /dev/null differ
diff --git a/frontend/mobile/assets/images/campus.png b/frontend/mobile/assets/images/campus.png
deleted file mode 100644
index cf96cf698..000000000
Binary files a/frontend/mobile/assets/images/campus.png and /dev/null differ
diff --git a/frontend/mobile/assets/images/girl-1.jpeg b/frontend/mobile/assets/images/girl-1.jpeg
deleted file mode 100644
index 761c26539..000000000
Binary files a/frontend/mobile/assets/images/girl-1.jpeg and /dev/null differ
diff --git a/frontend/mobile/assets/images/guy-1.jpeg b/frontend/mobile/assets/images/guy-1.jpeg
deleted file mode 100644
index a7d034358..000000000
Binary files a/frontend/mobile/assets/images/guy-1.jpeg and /dev/null differ
diff --git a/frontend/mobile/assets/images/placeholder_club_logo.png b/frontend/mobile/assets/images/placeholder_club_logo.png
deleted file mode 100644
index 65c26b8ba..000000000
Binary files a/frontend/mobile/assets/images/placeholder_club_logo.png and /dev/null differ
diff --git a/frontend/mobile/assets/images/placeholder_location.png b/frontend/mobile/assets/images/placeholder_location.png
deleted file mode 100644
index 24fb78e20..000000000
Binary files a/frontend/mobile/assets/images/placeholder_location.png and /dev/null differ
diff --git a/frontend/mobile/assets/images/sandbox-header.png b/frontend/mobile/assets/images/sandbox-header.png
deleted file mode 100644
index 9b2bc3867..000000000
Binary files a/frontend/mobile/assets/images/sandbox-header.png and /dev/null differ
diff --git a/frontend/mobile/assets/images/showcase.png b/frontend/mobile/assets/images/showcase.png
deleted file mode 100644
index 5ee136c25..000000000
Binary files a/frontend/mobile/assets/images/showcase.png and /dev/null differ
diff --git a/frontend/mobile/assets/images/svg/blue-pin.svg b/frontend/mobile/assets/images/svg/blue-pin.svg
deleted file mode 100644
index e9ccab689..000000000
--- a/frontend/mobile/assets/images/svg/blue-pin.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/calendar.svg b/frontend/mobile/assets/images/svg/calendar.svg
deleted file mode 100644
index 8748b5b78..000000000
--- a/frontend/mobile/assets/images/svg/calendar.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/cancel.svg b/frontend/mobile/assets/images/svg/cancel.svg
deleted file mode 100644
index 3430caf0c..000000000
--- a/frontend/mobile/assets/images/svg/cancel.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/circle-clock.svg b/frontend/mobile/assets/images/svg/circle-clock.svg
deleted file mode 100644
index 832d32910..000000000
--- a/frontend/mobile/assets/images/svg/circle-clock.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/default-header.svg b/frontend/mobile/assets/images/svg/default-header.svg
deleted file mode 100644
index 6894fde1b..000000000
--- a/frontend/mobile/assets/images/svg/default-header.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/document.svg b/frontend/mobile/assets/images/svg/document.svg
deleted file mode 100644
index 533bfe4b8..000000000
--- a/frontend/mobile/assets/images/svg/document.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/frontend/mobile/assets/images/svg/email-confirm.svg b/frontend/mobile/assets/images/svg/email-confirm.svg
deleted file mode 100644
index 3953ab5ed..000000000
--- a/frontend/mobile/assets/images/svg/email-confirm.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/frontend/mobile/assets/images/svg/email.svg b/frontend/mobile/assets/images/svg/email.svg
deleted file mode 100644
index a99bb0d8c..000000000
--- a/frontend/mobile/assets/images/svg/email.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/event-demo-day.svg b/frontend/mobile/assets/images/svg/event-demo-day.svg
deleted file mode 100644
index 081121dcb..000000000
--- a/frontend/mobile/assets/images/svg/event-demo-day.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/event-drop-party.svg b/frontend/mobile/assets/images/svg/event-drop-party.svg
deleted file mode 100644
index 3876ebd09..000000000
--- a/frontend/mobile/assets/images/svg/event-drop-party.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/event-showcase.svg b/frontend/mobile/assets/images/svg/event-showcase.svg
deleted file mode 100644
index 8ab566d58..000000000
--- a/frontend/mobile/assets/images/svg/event-showcase.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/expand.svg b/frontend/mobile/assets/images/svg/expand.svg
deleted file mode 100644
index ea8e51b43..000000000
--- a/frontend/mobile/assets/images/svg/expand.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/home-selected.svg b/frontend/mobile/assets/images/svg/home-selected.svg
deleted file mode 100644
index 44721e51d..000000000
--- a/frontend/mobile/assets/images/svg/home-selected.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/frontend/mobile/assets/images/svg/home.svg b/frontend/mobile/assets/images/svg/home.svg
deleted file mode 100644
index cf07f3ef0..000000000
--- a/frontend/mobile/assets/images/svg/home.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/instagram.svg b/frontend/mobile/assets/images/svg/instagram.svg
deleted file mode 100644
index 5e13e2ef1..000000000
--- a/frontend/mobile/assets/images/svg/instagram.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/leftarrow.svg b/frontend/mobile/assets/images/svg/leftarrow.svg
deleted file mode 100644
index e0fc241ee..000000000
--- a/frontend/mobile/assets/images/svg/leftarrow.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/like.svg b/frontend/mobile/assets/images/svg/like.svg
deleted file mode 100644
index 3d86298dd..000000000
--- a/frontend/mobile/assets/images/svg/like.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/location.svg b/frontend/mobile/assets/images/svg/location.svg
deleted file mode 100644
index 9a5f9fafd..000000000
--- a/frontend/mobile/assets/images/svg/location.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/members.svg b/frontend/mobile/assets/images/svg/members.svg
deleted file mode 100644
index c51398c05..000000000
--- a/frontend/mobile/assets/images/svg/members.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/mini-location-pin.svg b/frontend/mobile/assets/images/svg/mini-location-pin.svg
deleted file mode 100644
index 5063dbe24..000000000
--- a/frontend/mobile/assets/images/svg/mini-location-pin.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/notification.svg b/frontend/mobile/assets/images/svg/notification.svg
deleted file mode 100644
index 32d071ac3..000000000
--- a/frontend/mobile/assets/images/svg/notification.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/peace-hand.svg b/frontend/mobile/assets/images/svg/peace-hand.svg
deleted file mode 100644
index f445ff242..000000000
--- a/frontend/mobile/assets/images/svg/peace-hand.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/person.svg b/frontend/mobile/assets/images/svg/person.svg
deleted file mode 100644
index 10d78584e..000000000
--- a/frontend/mobile/assets/images/svg/person.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/pin.svg b/frontend/mobile/assets/images/svg/pin.svg
deleted file mode 100644
index be2ec400d..000000000
--- a/frontend/mobile/assets/images/svg/pin.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/frontend/mobile/assets/images/svg/placeholder_location.svg b/frontend/mobile/assets/images/svg/placeholder_location.svg
deleted file mode 100644
index c7ace3717..000000000
--- a/frontend/mobile/assets/images/svg/placeholder_location.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/profile-selected.svg b/frontend/mobile/assets/images/svg/profile-selected.svg
deleted file mode 100644
index 78a5a2237..000000000
--- a/frontend/mobile/assets/images/svg/profile-selected.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/profile.svg b/frontend/mobile/assets/images/svg/profile.svg
deleted file mode 100644
index 8f607b254..000000000
--- a/frontend/mobile/assets/images/svg/profile.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/frontend/mobile/assets/images/svg/sandbox-header.svg b/frontend/mobile/assets/images/svg/sandbox-header.svg
deleted file mode 100644
index 67aa1d239..000000000
--- a/frontend/mobile/assets/images/svg/sandbox-header.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-