14 Commits
Author SHA1 Message Date
aditya.siregar 30091f3362 Update Env 2025-03-03 19:55:44 +07:00
aditya.siregar ed8c523b26 update docker 2025-03-03 19:39:11 +07:00
aditya.siregar e9b9a367a9 add docker file 2025-03-03 19:29:59 +07:00
aditya.siregar c9f1e33c24 Add Infra 2025-03-03 18:59:25 +07:00
ericprd c02d8cda69 fix: return error when there is no subscribe plan found 2025-03-02 10:07:42 +08:00
ericprd 55460653e3 fix: should be find one instead of find all 2025-03-02 09:48:40 +08:00
ericprd 915f12eaf7 feat: news router 2025-03-02 04:36:17 +08:00
ericprd f4ae93bc48 fix: condition query 2025-03-02 02:33:03 +08:00
ericprd eb1584f8c4 fix: unique entity 2025-03-01 21:27:28 +08:00
ericprd bdf6dd131e feat: category routes 2025-03-01 21:20:51 +08:00
ericprd acd80480dd feat: tag routes 2025-03-01 20:00:54 +08:00
ericprd 613379c8a5 fix: simplified gorm query 2025-03-01 19:00:12 +08:00
Ardeman c29df8a3d6 feat: add VSCode extensions recommendations 2025-02-28 22:12:35 +08:00
ericprd 2bef24fbb6 docs: fix tags 2025-02-28 22:03:47 +08:00
1851 changed files with 694517 additions and 211 deletions
+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+119
View File
@@ -0,0 +1,119 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="ALL" />
</component>
<component name="ChangeListManager">
<list default="true" id="e5a7c631-b0eb-4bcf-9341-cd30afbc8d51" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/.idea/legalgo-BE-go.iml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/config/auth.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/config/configs.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/config/db.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/config/http.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/config/jwt.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/config/module.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/config/oss.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/config/server.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/development.yaml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/internal/accessor/oss/oss.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/internal/accessor/oss/upload.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/internal/api/http/oss/module.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/internal/api/http/oss/upload.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/internal/domain/oss/oss.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/internal/services/oss/impl.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/internal/services/oss/init.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/k8s/staging/deployment.yaml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/k8s/staging/ingress.yaml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/k8s/staging/namespace.yaml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/k8s/staging/service.yaml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/cmd/gorm/main.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/gorm/main.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/cmd/legalgo/main.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/legalgo/main.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/database/new_db.go" beforeDir="false" afterPath="$PROJECT_DIR$/database/new_db.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/go.mod" beforeDir="false" afterPath="$PROJECT_DIR$/go.mod" afterDir="false" />
<change beforePath="$PROJECT_DIR$/go.sum" beforeDir="false" afterPath="$PROJECT_DIR$/go.sum" afterDir="false" />
<change beforePath="$PROJECT_DIR$/internal/accessor/module.go" beforeDir="false" afterPath="$PROJECT_DIR$/internal/accessor/module.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/internal/api/http/router.go" beforeDir="false" afterPath="$PROJECT_DIR$/internal/api/http/router.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/internal/services/module.go" beforeDir="false" afterPath="$PROJECT_DIR$/internal/services/module.go" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Go File" />
</list>
</option>
</component>
<component name="GOROOT" url="file:///opt/homebrew/Cellar/go/1.24.0/libexec" />
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="MarkdownSettingsMigration">
<option name="stateVersion" value="1" />
</component>
<component name="ProjectId" id="2tlQuDgnVjD2XCHsYVtzhu4hYTb" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
"DefaultGoTemplateProperty": "Go File",
"RunOnceActivity.OpenProjectViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.go.formatter.settings.were.checked": "true",
"RunOnceActivity.go.migrated.go.modules.settings": "true",
"RunOnceActivity.go.modules.go.list.on.any.changes.was.set": "true",
"RunOnceActivity.go.vendoring.notification.had.been.shown": "true",
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
"WebServerToolWindowFactoryState": "false",
"configurable..is.expanded": "false",
"configurable.GoLibrariesConfigurable.is.expanded": "true",
"go.import.settings.migrated": "true",
"go.sdk.automatically.set": "true",
"last_opened_file_path": "/Users/aditya.siregar/Personal/Altru/legalgo-news/legalgo-BE-go",
"node.js.detected.package.eslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"settings.editor.selected.configurable": "go.sdk"
}
}]]></component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$" />
<recent name="$PROJECT_DIR$/internal/api/http/oss" />
<recent name="$PROJECT_DIR$/internal/services" />
<recent name="$PROJECT_DIR$/internal/accessor" />
<recent name="$PROJECT_DIR$/config" />
</key>
<key name="MoveFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/internal/api/http/oss" />
</key>
</component>
<component name="RunManager">
<configuration name="go build legalgo-BE-go/cmd/legalgo" type="GoApplicationRunConfiguration" factoryName="Go Application" temporary="true" nameIsGenerated="true">
<module name="legalgo-BE-go" />
<working_directory value="$PROJECT_DIR$" />
<kind value="PACKAGE" />
<package value="legalgo-BE-go/cmd/legalgo" />
<directory value="$PROJECT_DIR$" />
<filePath value="$PROJECT_DIR$/cmd/legalgo/main.go" />
<method v="2" />
</configuration>
<recent_temporary>
<list>
<item itemvalue="Go Build.go build legalgo-BE-go/cmd/legalgo" />
</list>
</recent_temporary>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="VgoProject">
<settings-migrated>true</settings-migrated>
</component>
</project>
+5
View File
@@ -0,0 +1,5 @@
{
"recommendations": [
"arjun.swagger-viewer"
]
}
+22
View File
@@ -0,0 +1,22 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceFolder}/cmd/legalgo/",
"dlvLoadConfig":{
"followPointers": true,
"maxVariableRecurse": 1,
"maxStringLen": 512, // 字符串最大长度
"maxArrayValues": 64,
"maxStructFields": -1
},
"dlvFlags": ["--check-go-version=false"],
"env": {
"TZ": ""
}
}]
}
+22
View File
@@ -0,0 +1,22 @@
FROM golang:1.24 AS build
WORKDIR /src
COPY . .
# RUN CGO_ENABLED=0 GOOS=linux go build -o /app cmd/klinik-core-service
RUN CGO_ENABLED=0 GOOS=linux go build -o /app cmd/legalgo/main.go
RUN ls -la /
FROM gcr.io/distroless/static
WORKDIR /
COPY --from=build /usr/share/zoneinfo /usr/share/zoneinfo
COPY --from=build /app /app
# RUN ls -la /
ENV TZ=Asia/Jakarta
ENTRYPOINT ["/app"]
+4 -1
View File
@@ -24,11 +24,14 @@ func main() {
}
config.InitEnv()
db, err := database.NewDB()
cfg := config.LoadConfig()
db, err := database.NewDB(cfg)
if err != nil {
log.Fatalf("failed to connect to database: %v", err)
}
// db.DropTables()
if err := db.Migrate(); err != nil {
log.Fatal("Migration failed: ", err)
}
+2 -1
View File
@@ -49,10 +49,11 @@ func run(lc fx.Lifecycle, db *database.DB, apiRouter chi.Router) {
func main() {
app := fx.New(
config.Module,
database.Module,
repository.Module,
internalhttp.Module,
services.Module,
internalhttp.Module,
fx.Invoke(run),
)
+17
View File
@@ -0,0 +1,17 @@
package config
import "time"
type AuthConfig struct {
jwtTokenExpiresTTL int
jwtTokenSecret string
}
func (c *AuthConfig) AccessTokenSecret() string {
return c.jwtTokenSecret
}
func (c *AuthConfig) AccessTokenExpiresDate() time.Time {
duration := time.Duration(c.jwtTokenExpiresTTL)
return time.Now().UTC().Add(time.Minute * duration)
}
+68
View File
@@ -0,0 +1,68 @@
package config
import (
"fmt"
"os"
"sync"
"github.com/spf13/viper"
_ "gopkg.in/yaml.v3"
)
const (
YAML_PATH = "env/%s"
ENV_MODE = "ENV_MODE"
DEFAULT_ENV_MODE = "development"
)
var (
validEnvMode = map[string]struct{}{
"local": {},
"development": {},
"production": {},
}
)
type Config struct {
Server Server `mapstructure:"server"`
Database Database `mapstructure:"postgresql"`
Jwt Jwt `mapstructure:"jwt"`
OSSConfig OSSConfig `mapstructure:"oss"`
}
var (
config *Config
configOnce sync.Once
)
func LoadConfig() *Config {
envMode := os.Getenv(ENV_MODE)
if _, ok := validEnvMode[envMode]; !ok {
envMode = DEFAULT_ENV_MODE // default env mode
}
cfgFilePath := fmt.Sprintf(YAML_PATH, envMode)
configOnce.Do(func() {
v := viper.New()
v.SetConfigType("yaml")
v.AddConfigPath(".")
v.SetConfigName(cfgFilePath)
if err := v.ReadInConfig(); err != nil {
panic(fmt.Errorf("failed to read config file: %s", err))
}
config = &Config{}
if err := v.Unmarshal(config); err != nil {
panic(fmt.Errorf("failed to unmarshal config: %s", err))
}
})
return config
}
func (c *Config) Auth() *AuthConfig {
return &AuthConfig{
jwtTokenSecret: c.Jwt.Token.Secret,
jwtTokenExpiresTTL: c.Jwt.Token.ExpiresTTL,
}
}
+28
View File
@@ -0,0 +1,28 @@
package config
import (
"fmt"
"time"
)
type Database struct {
Host string `mapstructure:"host"`
Port string `mapstructure:"port"`
DB string `mapstructure:"db"`
Driver string `mapstructure:"driver"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
SslMode string `mapstructure:"ssl-mode"`
Debug bool `mapstructure:"debug"`
MaxIdleConnectionsInSecond int `mapstructure:"max-idle-connections-in-second"`
MaxOpenConnectionsInSecond int `mapstructure:"max-open-connections-in-second"`
ConnectionMaxLifetimeInSecond int64 `mapstructure:"connection-max-life-time-in-second"`
}
func (c Database) DSN() string {
return fmt.Sprintf("host=%s port=%s dbname=%s user=%s password=%s sslmode=%s", c.Host, c.Port, c.DB, c.Username, c.Password, c.SslMode)
}
func (c Database) ConnectionMaxLifetime() time.Duration {
return time.Duration(c.ConnectionMaxLifetimeInSecond) * time.Second
}
+17
View File
@@ -0,0 +1,17 @@
package config
import "fmt"
type httpConfig struct {
host string
port int
detailedError bool
}
func (c *httpConfig) Address() string {
return fmt.Sprintf("%s:%d", c.host, c.port)
}
func (c *httpConfig) DetailedError() bool {
return c.detailedError
}
+10
View File
@@ -0,0 +1,10 @@
package config
type Jwt struct {
Token Token `mapstructure:"token"`
}
type Token struct {
ExpiresTTL int `mapstructure:"expires-ttl"`
Secret string `mapstructure:"secret"`
}
+11
View File
@@ -0,0 +1,11 @@
package config
import (
"go.uber.org/fx"
)
var Module = fx.Module("config",
fx.Provide(
LoadConfig,
),
)
+44
View File
@@ -0,0 +1,44 @@
package config
type OSSConfig struct {
AccessKeyID string `mapstructure:"access_key_id"`
AccessKeySecret string `mapstructure:"access_key_secret"`
Endpoint string `mapstructure:"endpoint"`
BucketName string `mapstructure:"bucket_name"`
PhotoFolder string `mapstructure:"photo_folder"`
LogLevel string `mapstructure:"log_level"`
HostURL string `mapstructure:"host_url"`
PublicURL string `mapstructure:"public_url"`
}
func (c OSSConfig) GetAccessKeyID() string {
return c.AccessKeyID
}
func (c OSSConfig) GetAccessKeySecret() string {
return c.AccessKeySecret
}
func (c OSSConfig) GetEndpoint() string {
return c.Endpoint
}
func (c OSSConfig) GetBucketName() string {
return c.BucketName
}
func (c OSSConfig) GetLogLevel() string {
return c.LogLevel
}
func (c OSSConfig) GetHostURL() string {
return c.HostURL
}
func (c OSSConfig) GetPublicURL() string {
return c.PublicURL
}
func (c OSSConfig) GetPhotoFolder() string {
return c.PhotoFolder
}
+7
View File
@@ -0,0 +1,7 @@
package config
type Server struct {
Port string `mapstructure:"port"`
BaseUrl string `mapstructure:"common-url"`
LocalUrl string `mapstructure:"local-url"`
}
+21
View File
@@ -0,0 +1,21 @@
package database
import (
"time"
)
type Category struct {
ID string `gorm:"primaryKey" json:"id"`
Code string `gorm:"not null;unique" json:"code"`
Name string `gorm:"not null" json:"name"`
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
}
type CategoryModel struct {
ID string `gorm:"primaryKey" json:"id"`
Name string `gorm:"not null;unique" json:"name"`
Code string `gorm:"not null" json:"code"`
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
}
+24 -6
View File
@@ -13,14 +13,14 @@ type DB struct {
*gorm.DB
}
func NewDB() (*DB, error) {
func NewDB(cfg *config.Config) (*DB, error) {
dsn := fmt.Sprintf(
"host=%s user=%s password=%s dbname=%s port=%v sslmode=disable",
config.DB_HOST,
config.DB_USER,
config.DB_PASSWORD,
config.DB_NAME,
config.DB_PORT,
cfg.Database.Host,
cfg.Database.Username,
cfg.Database.Password,
cfg.Database.DB,
cfg.Database.Port,
)
if dsn == "" {
@@ -36,6 +36,18 @@ func NewDB() (*DB, error) {
return &DB{db}, nil
}
func (db *DB) DropTables() error {
// Auto Migrate the User model
return db.Migrator().DropTable(
// &Staff{},
// &SubscribePlan{},
// &Subscribe{},
// &User{},
&Tag{},
&Category{},
&News{},
)
}
func (db *DB) Migrate() error {
// Auto Migrate the User model
return db.AutoMigrate(
@@ -43,5 +55,11 @@ func (db *DB) Migrate() error {
&SubscribePlan{},
&Subscribe{},
&User{},
// &Tag{},
// &Category{},
// &News{},
&NewsModel{},
&TagModel{},
&CategoryModel{},
)
}
+27 -9
View File
@@ -5,13 +5,31 @@ import (
)
type News struct {
ID string `gorm:"primaryKey" json:"id"`
AuthorID string `gorm:"not null" json:"author_id"`
Title string `gorm:"default:null" json:"title"`
Content string `gorm:"default:null" json:"content"`
IsPremium bool `gorm:"default:false" json:"is_premium"`
Slug string `gorm:"default:null" json:"slug"`
FeaturedImage string `gorm:"default:null" json:"featured_image"`
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
ID string `gorm:"primaryKey" json:"id"`
Title string `gorm:"default:null" json:"title"`
Tags []Tag `gorm:"many2many:news_tags" json:"tags"`
Categories []Category `gorm:"many2many:news_categories" json:"categories"`
Content string `gorm:"default:null" json:"content"`
LiveAt time.Time `gorm:"not null" json:"live_at"`
AuthorID string `gorm:"not null" json:"author_id"`
IsPremium bool `gorm:"default:false" json:"is_premium"`
Slug string `gorm:"default:null" json:"slug"`
FeaturedImage string `gorm:"default:null" json:"featured_image"`
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
}
type NewsModel struct {
ID string `gorm:"primaryKey" json:"id"`
Title string `json:"title"`
Content string `json:"content"`
Categories []CategoryModel `gorm:"many2many:news_categories" json:"categories"`
Tags []TagModel `gorm:"many2many:news_tags" json:"tags"`
IsPremium bool `gorm:"default:false" json:"is_premium"`
Slug string `gorm:"default:null" json:"slug"`
FeaturedImage string `gorm:"default:null" json:"featured_image"`
AuthorID string `gorm:"not null" json:"author_id"`
LiveAt time.Time `gorm:"not null" json:"live_at"`
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
}
+2 -2
View File
@@ -6,8 +6,8 @@ import (
type Staff struct {
ID string `gorm:"primaryKey" json:"id"`
Username string `gorm:"default:null" json:"username"`
Email string `gorm:"unique,not null" json:"email"`
Username string `gorm:"default:null;unique" json:"username"`
Email string `gorm:"unique;not null" json:"email"`
Password string `gorm:"not null" json:"password"`
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
+1 -1
View File
@@ -19,7 +19,7 @@ type Subscribe struct {
type SubscribePlan struct {
ID string `gorm:"primaryKey" json:"id"`
Code string `gorm:"not null" json:"code"`
Code string `gorm:"not null;unique" json:"code"`
Name string `gorm:"not null" json:"name"`
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"`
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"`
+21
View File
@@ -0,0 +1,21 @@
package database
import (
"time"
)
type Tag struct {
ID string `gorm:"primaryKey" json:"id"`
Code string `gorm:"not null;unique" json:"code"`
Name string `gorm:"not null" json:"name"`
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
}
type TagModel struct {
ID string `gorm:"primaryKey" json:"id"`
Name string `gorm:"not null;unique" json:"name"`
Code string `gorm:"not null" json:"code"`
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
}
-13
View File
@@ -1,13 +0,0 @@
package database
import (
"time"
)
type Tags struct {
ID string `gorm:"primaryKey;not null" json:"id"`
Code string `gorm:"not null" json:"code"`
Name string `gorm:"not null" json:"name"`
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
}
+3 -3
View File
@@ -5,11 +5,11 @@ import (
)
type User struct {
ID string `gorm:"primaryKey" json:"id"`
ID string `gorm:"primaryKey;not null" json:"id"`
SubscribeID string `gorm:"not null" json:"subscribe_id"`
Email string `gorm:"unique,not null" json:"email"`
Email string `gorm:"unique;not null" json:"email"`
Password string `gorm:"not null" json:"password"`
Phone string `gorm:"default:null" json:"phone"`
Phone string `gorm:"default:not null;unique" json:"phone"`
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
+31
View File
@@ -0,0 +1,31 @@
server:
base-url: https://api.legalgo.id/core
local-url: http://localhost:3300
port: 3300
jwt:
token:
expires-ttl: 1440
secret: "5Lm25V3Qd7aut8dr4QUxm5PZUrSFs"
postgresql:
host: 62.72.45.250
port: 20826
driver: postgres
db: legalgonews-dev
username: legalgo_admin
password: 'K4K!2Kg7c@KW6H&4A2aBy2dFCRY3Sh'
ssl-mode: disable
max-idle-connections-in-second: 600
max-open-connections-in-second: 600
connection-max-life-time-in-second: 600
debug: false
oss:
access_key_id: cf9a475e18bc7626cbdbf09709d82a64
access_key_secret: 91f3321294d3e23035427a0ecb893ada
endpoint: sin1.contabostorage.com
bucket_name: legalgonews-dev
log_level: Error
host_url: https://sin1.contabostorage.com
public_url: https://sin1.contabostorage.com/fda98c2228f246f29a7e466b86b3b9e7
+21 -4
View File
@@ -1,31 +1,48 @@
module legalgo-BE-go
go 1.24.0
go 1.24
require (
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/joho/godotenv v1.5.1
github.com/spf13/viper v1.19.0
go.uber.org/fx v1.23.0
golang.org/x/crypto v0.34.0
gorm.io/driver/postgres v1.5.11
gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/postgres v1.4.7
)
require (
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.7.2 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jackc/pgx/v5 v5.2.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/text v0.22.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
)
require (
github.com/aws/aws-sdk-go v1.50.0
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/go-chi/chi/v5 v5.2.1
+116 -9
View File
@@ -1,14 +1,22 @@
github.com/aws/aws-sdk-go v1.50.0 h1:HBtrLeO+QyDKnc3t1+5DR1RxodOHCGr8ZcrHudpv7jI=
github.com/aws/aws-sdk-go v1.50.0/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.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
@@ -25,35 +33,89 @@ github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0
github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
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/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI=
github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jackc/pgx/v5 v5.2.0 h1:NdPpngX0Y6z6XDFKqmFQaE+bCtkqzvQIOt1wvBlAqs8=
github.com/jackc/pgx/v5 v5.2.0/go.mod h1:Ptn7zmohNsWEsdxRawMzk3gaKma2obW+NWTnKa0S4nk=
github.com/jackc/puddle/v2 v2.1.2/go.mod h1:2lpufsF5mRHO6SuZkm0fNYxM6SWHfvyFj62KwNzgels=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
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.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
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/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/v9 v9.7.1 h1:4LhKRCIduqXqtvCUlaq9c8bdHOkICjDMrr1+Zb3osAc=
github.com/redis/go-redis/v9 v9.7.1/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/dig v1.18.0 h1:imUL1UiY0Mg4bqbFfsRQO5G4CGRBec/ZujWTvSVp3pw=
go.uber.org/dig v1.18.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE=
go.uber.org/fx v1.23.0 h1:lIr/gYWQGfTwGcSXWXu4vP5Ws6iqnNEIY+F/aFzCKTg=
@@ -64,22 +126,67 @@ go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
golang.org/x/crypto v0.34.0 h1:+/C6tk6rf/+t5DhUketUbD1aNGqiSX3j15Z6xuIDlBA=
golang.org/x/crypto v0.34.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
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.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314=
gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
gorm.io/driver/postgres v1.4.7 h1:J06jXZCNq7Pdf7LIPn8tZn9LsWjd81BRSKveKNr0ZfA=
gorm.io/driver/postgres v1.4.7/go.mod h1:UJChCNLFKeBqQRE+HrkFUbKbq9idPXmTOk2u4Wok8S4=
gorm.io/gorm v1.24.2/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
+21
View File
@@ -0,0 +1,21 @@
package categoryrepository
import (
categorydomain "legalgo-BE-go/internal/domain/category"
"github.com/google/uuid"
)
func (a *accessor) Create(spec categorydomain.CategoryReq) error {
data := categorydomain.Category{
ID: uuid.NewString(),
Name: spec.Name,
Code: spec.Code,
}
if err := a.DB.Create(&data).Error; err != nil {
return err
}
return nil
}
@@ -0,0 +1,22 @@
package categoryrepository
import (
"legalgo-BE-go/database"
categorydomain "legalgo-BE-go/internal/domain/category"
"github.com/google/uuid"
)
func (a *accessor) CreateModel(spec categorydomain.CategoryReq) error {
data := database.CategoryModel{
ID: uuid.NewString(),
Name: spec.Name,
Code: spec.Code,
}
if err := a.DB.Create(&data).Error; err != nil {
return err
}
return nil
}
+13
View File
@@ -0,0 +1,13 @@
package categoryrepository
import categorydomain "legalgo-BE-go/internal/domain/category"
func (a *accessor) GetAll() ([]categorydomain.Category, error) {
var categories []categorydomain.Category
if err := a.DB.Find(&categories).Error; err != nil {
return nil, err
}
return categories, nil
}
@@ -0,0 +1,15 @@
package categoryrepository
import (
"legalgo-BE-go/database"
)
func (a *accessor) GetAllModel() ([]database.CategoryModel, error) {
var categories []database.CategoryModel
if err := a.DB.Find(&categories).Error; err != nil {
return nil, err
}
return categories, nil
}
+15
View File
@@ -0,0 +1,15 @@
package categoryrepository
import (
categorydomain "legalgo-BE-go/internal/domain/category"
)
func (a *accessor) GetByIDs(ids []string) ([]categorydomain.Category, error) {
var categories []categorydomain.Category
if err := a.DB.Find(&categories, "id IN ?", ids).Error; err != nil {
return nil, err
}
return categories, nil
}
@@ -0,0 +1,15 @@
package categoryrepository
import (
"legalgo-BE-go/database"
)
func (a *accessor) GetBulks(ids []string) ([]database.CategoryModel, error) {
var categories []database.CategoryModel
if err := a.DB.Find(&categories, "id IN ?", ids).Error; err != nil {
return nil, err
}
return categories, nil
}
+27
View File
@@ -0,0 +1,27 @@
package categoryrepository
import (
"legalgo-BE-go/database"
categorydomain "legalgo-BE-go/internal/domain/category"
)
type accessor struct {
DB *database.DB
}
type Category interface {
Create(categorydomain.CategoryReq) error
CreateModel(categorydomain.CategoryReq) error
GetAll() ([]categorydomain.Category, error)
GetAllModel() ([]database.CategoryModel, error)
GetByIDs([]string) ([]categorydomain.Category, error)
GetBulks([]string) ([]database.CategoryModel, error)
}
func New(
db *database.DB,
) Category {
return &accessor{db}
}
+8
View File
@@ -1,10 +1,14 @@
package repository
import (
categoryrepository "legalgo-BE-go/internal/accessor/category"
newsrepository "legalgo-BE-go/internal/accessor/news"
"legalgo-BE-go/internal/accessor/oss"
redisaccessor "legalgo-BE-go/internal/accessor/redis"
staffrepository "legalgo-BE-go/internal/accessor/staff"
subscriberepository "legalgo-BE-go/internal/accessor/subscribe"
subscribeplanrepository "legalgo-BE-go/internal/accessor/subscribeplan"
tagrepository "legalgo-BE-go/internal/accessor/tag"
userrepository "legalgo-BE-go/internal/accessor/user_repository"
"go.uber.org/fx"
@@ -16,4 +20,8 @@ var Module = fx.Module("repository", fx.Provide(
redisaccessor.New,
subscribeplanrepository.New,
subscriberepository.New,
tagrepository.New,
categoryrepository.New,
newsrepository.New,
oss.New,
))
+13
View File
@@ -0,0 +1,13 @@
package newsrepository
import (
"fmt"
newsdomain "legalgo-BE-go/internal/domain/news"
)
func (a *accessor) Create(spec *newsdomain.News) error {
if err := a.db.Create(&spec).Error; err != nil {
return fmt.Errorf("failed to create news: %w", err)
}
return nil
}
+13
View File
@@ -0,0 +1,13 @@
package newsrepository
import (
"fmt"
"legalgo-BE-go/database"
)
func (a *accessor) CreateModel(spec database.NewsModel) error {
if err := a.db.Create(&spec).Error; err != nil {
return fmt.Errorf("failed to create news: %w", err)
}
return nil
}
+13
View File
@@ -0,0 +1,13 @@
package newsrepository
import newsdomain "legalgo-BE-go/internal/domain/news"
func (a *accessor) GetAll() ([]newsdomain.News, error) {
var news []newsdomain.News
if err := a.db.Preload("Tags").Preload("Categories").Find(&news).Error; err != nil {
return nil, err
}
return news, nil
}
+13
View File
@@ -0,0 +1,13 @@
package newsrepository
import "legalgo-BE-go/database"
func (a *accessor) GetAllModel() ([]database.NewsModel, error) {
var news []database.NewsModel
if err := a.db.Preload("Tags").Preload("Categories").Find(&news).Error; err != nil {
return nil, err
}
return news, nil
}
+21
View File
@@ -0,0 +1,21 @@
package newsrepository
import (
"legalgo-BE-go/database"
newsdomain "legalgo-BE-go/internal/domain/news"
)
type accessor struct {
db *database.DB
}
type News interface {
GetAll() ([]newsdomain.News, error)
GetAllModel() ([]database.NewsModel, error)
Create(*newsdomain.News) error
CreateModel(database.NewsModel) error
}
func New(db *database.DB) News {
return &accessor{db}
}
+70
View File
@@ -0,0 +1,70 @@
package oss
import (
"bytes"
"context"
"fmt"
"legalgo-BE-go/config"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
type OSSConfig interface {
GetAccessKeyID() string
GetAccessKeySecret() string
GetEndpoint() string
GetBucketName() string
GetHostURL() string
GetPublicURL() string
}
const _awsRegion = "us-east-1"
const _s3ACL = "public-read"
type OssRepositoryImpl struct {
s3 *s3.S3
cfg OSSConfig
}
func New(cfg *config.Config) OSSRepository {
ossCfg := cfg.OSSConfig
sess, err := session.NewSession(&aws.Config{
S3ForcePathStyle: aws.Bool(true),
Endpoint: aws.String(ossCfg.GetEndpoint()),
Region: aws.String(_awsRegion),
Credentials: credentials.NewStaticCredentials(ossCfg.GetAccessKeyID(), ossCfg.GetAccessKeySecret(), ""),
})
if err != nil {
fmt.Println("Failed to create AWS session:", err)
return nil
}
return &OssRepositoryImpl{
s3: s3.New(sess),
cfg: ossCfg,
}
}
func (r *OssRepositoryImpl) UploadFile(ctx context.Context, fileName string, fileContent []byte) (fileUrl string, err error) {
reader := bytes.NewReader(fileContent)
_, err = r.s3.PutObject(&s3.PutObjectInput{
Bucket: aws.String(r.cfg.GetBucketName()),
Key: aws.String(fileName),
Body: reader,
ACL: aws.String(_s3ACL),
})
return r.GetPublicURL(fileName), err
}
func (r *OssRepositoryImpl) GetPublicURL(fileName string) string {
if fileName == "" {
return ""
}
return fmt.Sprintf("%s:%s%s", r.cfg.GetPublicURL(), r.cfg.GetBucketName(), fileName)
}
+10
View File
@@ -0,0 +1,10 @@
package oss
import (
"context"
)
type OSSRepository interface {
UploadFile(ctx context.Context, fileName string, fileContent []byte) (fileUrl string, err error)
GetPublicURL(fileName string) string
}
+1 -1
View File
@@ -15,7 +15,7 @@ func (sr *StaffRepository) GetStaffByEmail(email string) (*authdomain.Staff, err
return nil, errors.New("email is required")
}
if err := sr.DB.Where("email = ?", email).First(&staff).Error; err != nil {
if err := sr.DB.First(&staff, "email = ?", email).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("staff not found")
}
+1 -1
View File
@@ -14,7 +14,7 @@ func (sr *StaffRepository) GetStaffByID(ID string) (*authdomain.Staff, error) {
return nil, errors.New("id is required")
}
if err := sr.DB.Where("id = ? ", ID).First(&staff).Error; err != nil {
if err := sr.DB.First(&staff, "id = ? ", ID).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("staff not found")
}
@@ -0,0 +1,21 @@
package subscribeplanrepository
import (
"errors"
subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan"
"gorm.io/gorm"
)
func (s *SubsPlan) GetByID(id string) (subscribeplandomain.SubscribePlan, error) {
var subscribePlan subscribeplandomain.SubscribePlan
if err := s.DB.First(&subscribePlan, "id = ? ", id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return subscribePlan, errors.New("subscribe plan not found")
}
return subscribePlan, err
}
return subscribePlan, nil
}
@@ -9,7 +9,7 @@ import (
func (s *SubsPlan) GetDefault() (subscribeplandomain.SubscribePlan, error) {
var subscribePlan subscribeplandomain.SubscribePlan
if err := s.DB.Where("code = ?", "basic").First(&subscribePlan).Error; err != nil {
if err := s.DB.First(&subscribePlan, "code = ?", "basic").Error; err != nil {
s.DB.Create(&subscribeplandomain.SubscribePlan{
ID: uuid.NewString(),
Code: "basic",
+1
View File
@@ -12,6 +12,7 @@ type SubsPlan struct {
type SubsPlanIntf interface {
Create(subscribeplandomain.SubscribePlanReq) error
GetAll() ([]subscribeplandomain.SubscribePlan, error)
GetByID(string) (subscribeplandomain.SubscribePlan, error)
GetDefault() (subscribeplandomain.SubscribePlan, error)
}
+21
View File
@@ -0,0 +1,21 @@
package tagrepository
import (
tagdomain "legalgo-BE-go/internal/domain/tag"
"github.com/google/uuid"
)
func (acc *accessor) Create(spec tagdomain.TagReq) error {
data := &tagdomain.Tag{
ID: uuid.NewString(),
Code: spec.Code,
Name: spec.Name,
}
if err := acc.DB.Create(&data).Error; err != nil {
return err
}
return nil
}
+22
View File
@@ -0,0 +1,22 @@
package tagrepository
import (
"legalgo-BE-go/database"
tagdomain "legalgo-BE-go/internal/domain/tag"
"github.com/google/uuid"
)
func (acc *accessor) CreateModel(spec tagdomain.TagReq) error {
data := &database.TagModel{
ID: uuid.NewString(),
Code: spec.Code,
Name: spec.Name,
}
if err := acc.DB.Create(&data).Error; err != nil {
return err
}
return nil
}
+15
View File
@@ -0,0 +1,15 @@
package tagrepository
import (
tagdomain "legalgo-BE-go/internal/domain/tag"
)
func (acc *accessor) GetAll() ([]tagdomain.Tag, error) {
var tags []tagdomain.Tag
if err := acc.DB.Find(&tags).Error; err != nil {
return nil, err
}
return tags, nil
}
+13
View File
@@ -0,0 +1,13 @@
package tagrepository
import "legalgo-BE-go/database"
func (acc *accessor) GetAllModel() ([]database.TagModel, error) {
var tags []database.TagModel
if err := acc.DB.Find(&tags).Error; err != nil {
return nil, err
}
return tags, nil
}
+13
View File
@@ -0,0 +1,13 @@
package tagrepository
import tagdomain "legalgo-BE-go/internal/domain/tag"
func (a *accessor) GetByIDs(ids []string) ([]tagdomain.Tag, error) {
var tags []tagdomain.Tag
if err := a.DB.Find(&tags, "id IN ?", ids).Error; err != nil {
return nil, err
}
return tags, nil
}
+13
View File
@@ -0,0 +1,13 @@
package tagrepository
import "legalgo-BE-go/database"
func (a *accessor) GetBulks(ids []string) ([]database.TagModel, error) {
var tags []database.TagModel
if err := a.DB.Find(&tags, "id IN ?", ids).Error; err != nil {
return nil, err
}
return tags, nil
}
+25
View File
@@ -0,0 +1,25 @@
package tagrepository
import (
"legalgo-BE-go/database"
tagdomain "legalgo-BE-go/internal/domain/tag"
)
type accessor struct {
DB *database.DB
}
type TagAccessor interface {
Create(tagdomain.TagReq) error
CreateModel(tagdomain.TagReq) error
GetAll() ([]tagdomain.Tag, error)
GetAllModel() ([]database.TagModel, error)
GetByIDs([]string) ([]tagdomain.Tag, error)
GetBulks(ids []string) ([]database.TagModel, error)
}
func New(
db *database.DB,
) TagAccessor {
return &accessor{db}
}
@@ -15,7 +15,7 @@ func (ur *UserRepository) GetUserByEmail(email string) (*authdomain.User, error)
return nil, errors.New("email is empty")
}
if err := ur.DB.Where("email = ?", email).First(&user).Error; err != nil {
if err := ur.DB.First(&user, "email = ?", email).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("user not found")
}
@@ -15,6 +15,7 @@ func (ur *UserRepository) GetUserProfile(email string) (*authdomain.UserProfile,
}
if err := ur.DB.Table("users u").
Where("email = ?", email).
Select("u.email, u.id, s.status as subscribe_status, sp.code as subscribe_plan_code, sp.name as subscribe_plan_name").
Joins("join subscribes s on s.id = u.subscribe_id").
Joins("join subscribe_plans sp on s.subscribe_plan_id = sp.id").
+2 -82
View File
@@ -1,12 +1,10 @@
package authhttp
import (
"errors"
authsvc "legalgo-BE-go/internal/services/auth"
"legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils"
"net/http"
"strings"
"github.com/go-chi/chi/v5"
)
@@ -17,46 +15,7 @@ func GetStaffProfile(
) {
router.Get("/staff/profile", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
response.ResponseWithErrorCode(
ctx,
w,
errors.New("provided auth is empty"),
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"required params is not provided",
)
return
}
if !strings.HasPrefix(authHeader, "Bearer") {
response.ResponseWithErrorCode(
ctx,
w,
errors.New("invalid authorization token"),
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"invalid required token",
)
return
}
token := strings.Split(authHeader, " ")
if len(token) < 2 {
response.ResponseWithErrorCode(
ctx,
w,
errors.New("invalid authorization"),
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"invalid required token",
)
return
}
destructedToken, err := utils.DestructToken(token[1])
destructedToken, err := utils.GetTokenDetail(r)
if err != nil {
response.ResponseWithErrorCode(
ctx,
@@ -92,46 +51,7 @@ func GetUserProfile(
) {
router.Get("/user/profile", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
response.ResponseWithErrorCode(
ctx,
w,
errors.New("provided auth is empty"),
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"required params is not provided",
)
return
}
if !strings.HasPrefix(authHeader, "Bearer") {
response.ResponseWithErrorCode(
ctx,
w,
errors.New("invalid authorization token"),
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"invalid required token",
)
return
}
token := strings.Split(authHeader, " ")
if len(token) < 2 {
response.ResponseWithErrorCode(
ctx,
w,
errors.New("invalid authorization"),
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"invalid required token",
)
return
}
destructedToken, err := utils.DestructToken(token[1])
destructedToken, err := utils.GetTokenDetail(r)
if err != nil {
response.ResponseWithErrorCode(
ctx,
+67
View File
@@ -0,0 +1,67 @@
package categoryhttp
import (
categorydomain "legalgo-BE-go/internal/domain/category"
categorysvc "legalgo-BE-go/internal/services/category"
"legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-playground/validator/v10"
)
func Create(
router chi.Router,
validate *validator.Validate,
categorySvc categorysvc.Category,
) {
router.Post("/category/create", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var spec categorydomain.CategoryReq
if err := utils.UnmarshalBody(r, &spec); err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
if err := validate.Struct(spec); err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.(validator.ValidationErrors).Error(),
)
return
}
if err := categorySvc.Create(spec); err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrCreateEntity.Code,
response.ErrCreateEntity.HttpCode,
err.Error(),
)
return
}
response.RespondJsonSuccess(ctx, w, struct {
Message string
}{
Message: "category created successfully",
})
})
}
+33
View File
@@ -0,0 +1,33 @@
package categoryhttp
import (
categorysvc "legalgo-BE-go/internal/services/category"
"legalgo-BE-go/internal/utilities/response"
"net/http"
"github.com/go-chi/chi/v5"
)
func GetAll(
router chi.Router,
categorySvc categorysvc.Category,
) {
router.Get("/category", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
subsPlan, err := categorySvc.GetAllModel()
// subsPlan, err := categorySvc.GetAll()
if err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
response.RespondJsonSuccess(ctx, w, subsPlan)
})
}
+8
View File
@@ -0,0 +1,8 @@
package categoryhttp
import "go.uber.org/fx"
var Module = fx.Module("categories", fx.Invoke(
Create,
GetAll,
))
+93
View File
@@ -0,0 +1,93 @@
package newshttp
import (
staffrepository "legalgo-BE-go/internal/accessor/staff"
newsdomain "legalgo-BE-go/internal/domain/news"
newssvc "legalgo-BE-go/internal/services/news"
"legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-playground/validator/v10"
)
func Create(
validate *validator.Validate,
newsSvc newssvc.News,
staffRepo staffrepository.StaffIntf,
router chi.Router,
) {
router.Post("/news/create", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var spec newsdomain.NewsReq
if err := utils.UnmarshalBody(r, &spec); err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
if err := validate.Struct(spec); err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.(validator.ValidationErrors).Error(),
)
return
}
destructedToken, err := utils.GetTokenDetail(r)
if err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
staffProfile, err := staffRepo.GetStaffByEmail(destructedToken.Email)
if err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
if err := newsSvc.CreateModel(spec, staffProfile.ID); err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
response.RespondJsonSuccess(ctx, w, struct {
Message string
}{
Message: "news created successfully.",
})
})
}
+32
View File
@@ -0,0 +1,32 @@
package newshttp
import (
newssvc "legalgo-BE-go/internal/services/news"
"legalgo-BE-go/internal/utilities/response"
"net/http"
"github.com/go-chi/chi/v5"
)
func GetAll(
router chi.Router,
newsSvc newssvc.News,
) {
router.Get("/news", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
news, err := newsSvc.GetAllModel()
if err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
response.RespondJsonSuccess(ctx, w, news)
})
}
+8
View File
@@ -0,0 +1,8 @@
package newshttp
import "go.uber.org/fx"
var Module = fx.Module("news", fx.Invoke(
GetAll,
Create,
))
+11
View File
@@ -0,0 +1,11 @@
package osshttp
import (
"go.uber.org/fx"
)
var Module = fx.Module("upload",
fx.Invoke(
RegisterUploadFile,
),
)
+92
View File
@@ -0,0 +1,92 @@
package osshttp
import (
"fmt"
oss2 "legalgo-BE-go/internal/domain/oss"
"legalgo-BE-go/internal/services/oss"
"legalgo-BE-go/internal/utilities/response"
"net/http"
"github.com/go-chi/chi/v5"
)
const _oneMB = 1 << 20
const _maxUploadSize = 2 * _oneMB
const _folderName = "/file"
func RegisterUploadFile(ossService oss.OSSService, router chi.Router) {
router.Post("/file", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
// Limit the size of the request body to prevent very large uploads.
r.Body = http.MaxBytesReader(w, r.Body, int64(_maxUploadSize))
if err := r.ParseMultipartForm(int64(_maxUploadSize)); err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"Failed to parse multipart form",
)
return
}
// Retrieve the file from the form.
file, header, err := r.FormFile("file")
if err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"Failed to retrieve file",
)
return
}
defer file.Close()
// Check if file size exceeds the maximum limit.
if header.Size > int64(_maxUploadSize) {
response.ResponseWithErrorCode(
ctx,
w,
fmt.Errorf("file too big"),
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
fmt.Sprintf("The file is too big. The maximum size is %d MB", _maxUploadSize/_oneMB),
)
return
}
// Prepare the request for the OSS service.
uploadReq := &oss2.UploadFileRequest{
FileHeader: header,
FolderName: _folderName,
}
// Call the OSS service to handle the file upload.
result, err := ossService.UploadFile(ctx, uploadReq)
if err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
// Return a successful JSON response.
response.RespondJsonSuccess(ctx, w, struct {
Message string `json:"message"`
Data interface{} `json:"data"`
}{
Message: "File uploaded successfully.",
Data: result,
})
})
}
+8
View File
@@ -2,7 +2,11 @@ package internalhttp
import (
authhttp "legalgo-BE-go/internal/api/http/auth"
categoryhttp "legalgo-BE-go/internal/api/http/category"
newshttp "legalgo-BE-go/internal/api/http/news"
osshttp "legalgo-BE-go/internal/api/http/oss"
subscribeplanhttp "legalgo-BE-go/internal/api/http/subscribe_plan"
taghttp "legalgo-BE-go/internal/api/http/tag"
"github.com/go-chi/chi/v5"
"github.com/go-chi/cors"
@@ -19,6 +23,10 @@ var Module = fx.Module("router",
),
authhttp.Module,
subscribeplanhttp.Module,
taghttp.Module,
categoryhttp.Module,
newshttp.Module,
osshttp.Module,
)
func initRouter() chi.Router {
+67
View File
@@ -0,0 +1,67 @@
package taghttp
import (
"net/http"
tagdomain "legalgo-BE-go/internal/domain/tag"
tagsvc "legalgo-BE-go/internal/services/tag"
"legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils"
"github.com/go-chi/chi/v5"
"github.com/go-playground/validator/v10"
)
func Create(
router chi.Router,
validate *validator.Validate,
tagSvc tagsvc.TagIntf,
) {
router.Post("/tag/create", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var spec tagdomain.TagReq
if err := utils.UnmarshalBody(r, &spec); err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"failed to unmarshal request",
)
return
}
if err := validate.Struct(spec); err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.(validator.ValidationErrors).Error(),
)
return
}
if err := tagSvc.Create(spec); err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrCreateEntity.Code,
response.ErrCreateEntity.HttpCode,
err.Error(),
)
return
}
response.RespondJsonSuccess(ctx, w, struct {
Message string
}{
Message: "tag created successfully.",
})
})
}
+33
View File
@@ -0,0 +1,33 @@
package taghttp
import (
tagsvc "legalgo-BE-go/internal/services/tag"
"legalgo-BE-go/internal/utilities/response"
"net/http"
"github.com/go-chi/chi/v5"
)
func GetAll(
router chi.Router,
tagSvc tagsvc.TagIntf,
) {
router.Get("/tag", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
tags, err := tagSvc.GetAllModel()
// tags, err := tagSvc.GetAll()
if err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
response.RespondJsonSuccess(ctx, w, tags)
})
}
+8
View File
@@ -0,0 +1,8 @@
package taghttp
import "go.uber.org/fx"
var Module = fx.Module("tag", fx.Invoke(
Create,
GetAll,
))
+1 -1
View File
@@ -3,7 +3,7 @@ package authdomain
type RegisterUserReq struct {
Email string `json:"email" validate:"required"`
Password string `json:"password" validate:"required"`
Phone string `json:"phone"`
Phone string `json:"phone" validate:"required"`
SubscribePlanID string `json:"subscribe_plan_id"`
}
+12
View File
@@ -0,0 +1,12 @@
package categorydomain
type Category struct {
ID string `json:"id" gorm:"primaryKey"`
Name string `json:"name"`
Code string `json:"code"`
}
type CategoryReq struct {
Name string `json:"name" validate:"required"`
Code string `json:"code" validate:"required"`
}
-12
View File
@@ -1,12 +0,0 @@
package newsdomain
type News struct {
Title string `json:"title"`
Content string `json:"content"`
FeaturedImage string `json:"featured_image"`
Tags []string `json:"tags"`
Categories []string `json:"categories"`
IsPremium bool `json:"is_premium"`
Slug string `json:"slug"`
Author string `json:"author"`
}
+32
View File
@@ -0,0 +1,32 @@
package newsdomain
import (
categorydomain "legalgo-BE-go/internal/domain/category"
tagdomain "legalgo-BE-go/internal/domain/tag"
"time"
)
type NewsReq struct {
Title string `json:"title" validate:"required"`
Content string `json:"content"`
FeaturedImage string `json:"featured_image"`
Tags []string `json:"tags"`
Categories []string `json:"categories"`
IsPremium bool `json:"is_premium"`
LiveAt string `json:"live_at" validate:"required"`
}
type News struct {
ID string `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
FeaturedImage string `json:"featured_image"`
Tags []tagdomain.Tag `json:"tags"`
Categories []categorydomain.Category `json:"categories"`
IsPremium bool `json:"is_premium"`
Slug string `json:"slug"`
AuthorID string `json:"author_id"`
LiveAt time.Time `json:"live_at"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
+24
View File
@@ -0,0 +1,24 @@
package oss
import "mime/multipart"
type UploadFileRequest struct {
FileHeader *multipart.FileHeader
FolderName string
FileSize int64 `validate:"max=10000000"` // 10Mb = 10000000 byte
Ext string `validate:"oneof=.png .jpeg .jpg .pdf .xlsx .csv"`
}
type DownloadFileRequest struct {
FileName string `query:"file_name" validate:"required"`
FolderName string `query:"folder_name" validate:"required"`
}
type UploadFileResponse struct {
FilePath string `json:"file_path"`
FileUrl string `json:"file_url"`
}
type DownloadFileResponse struct {
FileUrl string `json:"file_url"`
}
+12
View File
@@ -0,0 +1,12 @@
package tagdomain
type TagReq struct {
Code string `json:"code" validate:"required"`
Name string `json:"name" validate:"required"`
}
type Tag struct {
ID string `json:"id" gorm:"primaryKey"`
Code string `json:"code"`
Name string `json:"name"`
}
+6 -1
View File
@@ -25,9 +25,14 @@ func (a *AuthSvc) RegisterUser(spec authdomain.RegisterUserReq) (string, error)
spec.SubscribePlanID = subsPlan.ID
}
_, err = a.subsPlanRepo.GetByID(spec.SubscribePlanID)
if err != nil {
return "", errors.New(err.Error())
}
subsId, err := a.subsRepo.Create(spec.SubscribePlanID)
if err != nil {
return "", nil
return "", err
}
hashedPwd, err := HashPassword(spec.Password)
+8
View File
@@ -0,0 +1,8 @@
package categorysvc
import categorydomain "legalgo-BE-go/internal/domain/category"
func (i *impl) Create(spec categorydomain.CategoryReq) error {
return i.categoryRepo.CreateModel(spec)
// return i.categoryRepo.Create(spec)
}
+7
View File
@@ -0,0 +1,7 @@
package categorysvc
import categorydomain "legalgo-BE-go/internal/domain/category"
func (i *impl) GetAll() ([]categorydomain.Category, error) {
return i.categoryRepo.GetAll()
}
@@ -0,0 +1,9 @@
package categorysvc
import (
"legalgo-BE-go/database"
)
func (i *impl) GetAllModel() ([]database.CategoryModel, error) {
return i.categoryRepo.GetAllModel()
}
+25
View File
@@ -0,0 +1,25 @@
package categorysvc
import (
"legalgo-BE-go/database"
categoryrepository "legalgo-BE-go/internal/accessor/category"
categorydomain "legalgo-BE-go/internal/domain/category"
)
type impl struct {
categoryRepo categoryrepository.Category
}
type Category interface {
Create(categorydomain.CategoryReq) error
GetAll() ([]categorydomain.Category, error)
GetAllModel() ([]database.CategoryModel, error)
}
func New(
categoryRepo categoryrepository.Category,
) Category {
return &impl{
categoryRepo: categoryRepo,
}
}
+8
View File
@@ -2,8 +2,12 @@ package services
import (
serviceauth "legalgo-BE-go/internal/services/auth"
categorysvc "legalgo-BE-go/internal/services/category"
newssvc "legalgo-BE-go/internal/services/news"
"legalgo-BE-go/internal/services/oss"
subscribesvc "legalgo-BE-go/internal/services/subscribe"
subscribeplansvc "legalgo-BE-go/internal/services/subscribe_plan"
tagsvc "legalgo-BE-go/internal/services/tag"
"go.uber.org/fx"
)
@@ -13,5 +17,9 @@ var Module = fx.Module("services",
serviceauth.New,
subscribeplansvc.New,
subscribesvc.New,
tagsvc.New,
categorysvc.New,
newssvc.New,
oss.NewOSSService,
),
)
+47
View File
@@ -0,0 +1,47 @@
package newssvc
import (
newsdomain "legalgo-BE-go/internal/domain/news"
"strings"
"time"
"github.com/google/uuid"
)
func (i *impl) Create(spec newsdomain.NewsReq, staffId string) error {
slug := strings.ToLower(strings.ReplaceAll(spec.Title, " ", "-"))
tags, err := i.tagRepo.GetByIDs(spec.Tags)
if err != nil {
return err
}
categories, err := i.categoryRepo.GetByIDs(spec.Categories)
if err != nil {
return err
}
parsedTime, err := time.Parse(time.RFC3339, spec.LiveAt)
if err != nil {
return err
}
newSpec := &newsdomain.News{
ID: uuid.NewString(),
Title: spec.Title,
Content: spec.Content,
FeaturedImage: spec.FeaturedImage,
IsPremium: spec.IsPremium,
Slug: slug,
LiveAt: parsedTime,
AuthorID: staffId,
Tags: tags,
Categories: categories,
}
if err := i.newsRepo.Create(newSpec); err != nil {
return err
}
return nil
}
+48
View File
@@ -0,0 +1,48 @@
package newssvc
import (
"legalgo-BE-go/database"
newsdomain "legalgo-BE-go/internal/domain/news"
"strings"
"time"
"github.com/google/uuid"
)
func (i *impl) CreateModel(spec newsdomain.NewsReq, staffId string) error {
slug := strings.ToLower(strings.ReplaceAll(spec.Title, " ", "-"))
tags, err := i.tagRepo.GetBulks(spec.Tags)
if err != nil {
return err
}
categories, err := i.categoryRepo.GetBulks(spec.Categories)
if err != nil {
return err
}
parsedTime, err := time.Parse(time.RFC3339, spec.LiveAt)
if err != nil {
return err
}
newSpec := database.NewsModel{
ID: uuid.NewString(),
Title: spec.Title,
Content: spec.Content,
FeaturedImage: spec.FeaturedImage,
IsPremium: spec.IsPremium,
Slug: slug,
LiveAt: parsedTime,
AuthorID: staffId,
Tags: tags,
Categories: categories,
}
if err := i.newsRepo.CreateModel(newSpec); err != nil {
return err
}
return nil
}
+7
View File
@@ -0,0 +1,7 @@
package newssvc
import newsdomain "legalgo-BE-go/internal/domain/news"
func (i *impl) GetAll() ([]newsdomain.News, error) {
return i.newsRepo.GetAll()
}
+9
View File
@@ -0,0 +1,9 @@
package newssvc
import (
"legalgo-BE-go/database"
)
func (i *impl) GetAllModel() ([]database.NewsModel, error) {
return i.newsRepo.GetAllModel()
}
+34
View File
@@ -0,0 +1,34 @@
package newssvc
import (
"legalgo-BE-go/database"
categoryrepository "legalgo-BE-go/internal/accessor/category"
newsrepository "legalgo-BE-go/internal/accessor/news"
tagrepository "legalgo-BE-go/internal/accessor/tag"
newsdomain "legalgo-BE-go/internal/domain/news"
)
type impl struct {
newsRepo newsrepository.News
tagRepo tagrepository.TagAccessor
categoryRepo categoryrepository.Category
}
type News interface {
GetAll() ([]newsdomain.News, error)
GetAllModel() ([]database.NewsModel, error)
Create(newsdomain.NewsReq, string) error
CreateModel(newsdomain.NewsReq, string) error
}
func New(
newsRepo newsrepository.News,
tagRepo tagrepository.TagAccessor,
categoryRepo categoryrepository.Category,
) News {
return &impl{
newsRepo,
tagRepo,
categoryRepo,
}
}
+62
View File
@@ -0,0 +1,62 @@
package oss
import (
"context"
"fmt"
"github.com/google/uuid"
oss2 "legalgo-BE-go/internal/accessor/oss"
"legalgo-BE-go/internal/domain/oss"
"path"
"strconv"
"time"
"github.com/go-playground/validator/v10"
)
type OssService struct {
ossRepo oss2.OSSRepository
}
func NewOSSService(ossRepo oss2.OSSRepository) OSSService {
return &OssService{
ossRepo: ossRepo,
}
}
func (s *OssService) UploadFile(ctx context.Context, req *oss.UploadFileRequest) (*oss.UploadFileResponse, error) {
file := req.FileHeader
req.FileSize = file.Size
req.Ext = path.Ext(file.Filename)
validate := validator.New()
if err := validate.Struct(req); err != nil {
return nil, err
}
// Open the file and read its content
srcFile, err := file.Open()
if err != nil {
return nil, err
}
defer srcFile.Close()
fileContent := make([]byte, file.Size)
_, err = srcFile.Read(fileContent)
if err != nil {
return nil, err
}
filePath := fmt.Sprintf("%v/%v%v", req.FolderName, s.GenerateFileName(), req.Ext)
fileUrl, err := s.ossRepo.UploadFile(ctx, filePath, fileContent)
if err != nil {
return nil, err
}
return &oss.UploadFileResponse{
FilePath: filePath,
FileUrl: fileUrl,
}, nil
}
func (s *OssService) GenerateFileName() string {
return fmt.Sprintf("%v-%v", uuid.New(), strconv.Itoa(int(time.Now().Unix())))
}
+10
View File
@@ -0,0 +1,10 @@
package oss
import (
"context"
"legalgo-BE-go/internal/domain/oss"
)
type OSSService interface {
UploadFile(ctx context.Context, req *oss.UploadFileRequest) (*oss.UploadFileResponse, error)
}
@@ -5,10 +5,5 @@ import (
)
func (s *SubsPlanSvc) GetAllPlan() ([]subscribeplandomain.SubscribePlan, error) {
subsPlan, err := s.subsAccs.GetAll()
if err != nil {
return nil, err
}
return subsPlan, nil
return s.subsAccs.GetAll()
}
+8
View File
@@ -0,0 +1,8 @@
package tagsvc
import tagdomain "legalgo-BE-go/internal/domain/tag"
func (i *impl) Create(spec tagdomain.TagReq) error {
// return i.tagRepo.Create(spec)
return i.tagRepo.CreateModel(spec)
}
+7
View File
@@ -0,0 +1,7 @@
package tagsvc
import tagdomain "legalgo-BE-go/internal/domain/tag"
func (i *impl) GetAll() ([]tagdomain.Tag, error) {
return i.tagRepo.GetAll()
}
+9
View File
@@ -0,0 +1,9 @@
package tagsvc
import (
"legalgo-BE-go/database"
)
func (i *impl) GetAllModel() ([]database.TagModel, error) {
return i.tagRepo.GetAllModel()
}
+23
View File
@@ -0,0 +1,23 @@
package tagsvc
import (
"legalgo-BE-go/database"
tagrepository "legalgo-BE-go/internal/accessor/tag"
tagdomain "legalgo-BE-go/internal/domain/tag"
)
type impl struct {
tagRepo tagrepository.TagAccessor
}
type TagIntf interface {
Create(tagdomain.TagReq) error
GetAll() ([]tagdomain.Tag, error)
GetAllModel() ([]database.TagModel, error)
}
func New(
tagRepo tagrepository.TagAccessor,
) TagIntf {
return &impl{tagRepo}
}
@@ -0,0 +1,34 @@
package utils
import (
"errors"
authdomain "legalgo-BE-go/internal/domain/auth"
"net/http"
"strings"
)
func GetTokenDetail(r *http.Request) (authdomain.AuthToken, error) {
authHeader := r.Header.Get("Authorization")
var data authdomain.AuthToken
if authHeader == "" {
return data, errors.New("unauthorized")
}
if !strings.HasPrefix(authHeader, "Bearer") {
return data, errors.New("invalid token")
}
token := strings.Split(authHeader, " ")
if len(token) < 2 {
return data, errors.New("invalid token")
}
data, err := DestructToken(token[1])
if err != nil {
return data, err
}
return data, nil
}
+32
View File
@@ -0,0 +1,32 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: legalgonews-backend
namespace: altru-staging
spec:
selector:
matchLabels:
app: legalgonews-backend
replicas: 1
template:
metadata:
labels:
app: legalgonews-backend
spec:
serviceAccountName: custom-serviceaccount
containers:
- name: legalgonews-backend
image: registry.gitlab.com/altru.id/legalgo/legalgonews-backend:<VERSION>
ports:
- containerPort: 3000
volumeMounts:
- mountPath: "/env"
name: legalgonews-backend-secret
readOnly: true
volumes:
- name: legalgonews-backend-secret
secret:
secretName: legalgonews-backend-secret
imagePullSecrets:
- name: regcred
+25
View File
@@ -0,0 +1,25 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: legalgonews-backend
namespace: altru-staging
annotations:
kubernetes.io/ingress.class: "nginx" # Add this line
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/ingress-class: "nginx" # Add this line
spec:
rules:
- host: "legalgonews-be.app-dev.altru.id"
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: legalgonews-backend
port:
number: 3000
tls:
- hosts:
- "legalgonews-be.app-dev.altru.id"
secretName: legalgonews-be-app-dev-biz-id-tls
+4
View File
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: altru-staging
+15
View File
@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: legalgonews-backend
namespace: altru-staging
labels:
run: legalgonews-backend
spec:
ports:
- port: 3000
protocol: TCP
targetPort: 3000
selector:
app: legalgonews-backend
type: ClusterIP
+6 -3
View File
@@ -17,9 +17,12 @@ build-migrate:
@echo "Building the Migrate..."
go build -o $(OUTPUT_MIGRATE_DIR) $(BINARY_MIGRATE_NAME)
migrate: build-migrate
@echo "Building and running Migrate..."
$(OUTPUT_MIGRATE_DIR)
# migrate: build-migrate
# @echo "Building and running Migrate..."
# $(OUTPUT_MIGRATE_DIR)
migrate:
go run $(BINARY_MIGRATE_NAME)
clean:
@echo "Cleaning the build..."
+415 -53
View File
@@ -1,10 +1,47 @@
openapi: 3.1.0
openapi: 3.0.0
info:
title: Staff and User API
version: 1.0.0
description: API for handling staff and user login, registration, and subscription plan creation.
paths:
/staff/profile:
get:
summary: "get staff profile"
tags:
- Staff
responses:
"200":
description: Success get profile
content:
application/json:
schema:
type: object
properties:
data:
type: object
properties:
id:
type: string
email:
type: string
username:
type: string
"400":
description: Bad request
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
/staff/login:
post:
summary: Login for staff
@@ -120,62 +157,11 @@ paths:
message:
type: string
/staff/profile:
get:
summary: "get staff profile"
tags:
- staff
parameters:
- name: "id"
in: query
description: "staff id"
required: true
schema:
type: string
responses:
"200":
description: Success get profile
content:
application/json:
schema:
type: object
properties:
data:
type: object
properties:
id:
type: string
email:
type: string
username:
type: string
"400":
description: Bad request
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
/user/profile:
get:
summary: "get staff profile"
tags:
- user
parameters:
- name: "id"
in: query
description: "user id"
required: true
schema:
type: string
- User
responses:
"200":
description: Success get profile
@@ -429,3 +415,379 @@ paths:
type: string
message:
type: string
/tag:
get:
summary: Get all tags
tags:
- Tags
responses:
"200":
description: Successfully retrieved all tags
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
type: object
properties:
id:
type: string
code:
type: string
name:
type: string
"400":
description: Bad request
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
/tag/create:
post:
summary: Create a new tag
tags:
- Tags
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
code:
type: string
required:
- code
- name
responses:
"201":
description: Tag created
content:
application/json:
schema:
type: object
properties:
data:
type: object
properties:
message:
type: string
example: "tag created successfully."
"400":
description: Bad request
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
"409":
description: Conflict (tag code already exists)
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
/category:
get:
summary: Get all categories
tags:
- Category
responses:
"200":
description: Successfully retrieved all categories
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
type: object
properties:
id:
type: string
code:
type: string
name:
type: string
"400":
description: Bad request
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
/category/create:
post:
summary: Create a new category
tags:
- Category
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
code:
type: string
required:
- code
- name
responses:
"201":
description: Category created
content:
application/json:
schema:
type: object
properties:
data:
type: object
properties:
message:
type: string
example: "category created successfully."
"400":
description: Bad request
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
"409":
description: Conflict (category code already exists)
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
/news/create:
post:
summary: Create a new news article
tags:
- News
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
title:
type: string
content:
type: string
featured_image:
type: string
format: uri
tags:
type: array
items:
type: string
categories:
type: array
items:
type: string
is_premium:
type: boolean
live_at:
type: string
format: date-time
required:
- title
- content
- featured_image
- tags
- categories
- is_premium
- live_at
responses:
"201":
description: News article created
content:
application/json:
schema:
type: object
properties:
data:
type: object
properties:
message:
type: string
example: "news created successfully."
"400":
description: Bad request
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
"409":
description: Conflict (e.g., duplicate title or invalid tag/category)
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
/news:
get:
summary: Get all news articles
tags:
- News
responses:
"200":
description: Successfully retrieved all news articles
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
type: object
properties:
id:
type: string
title:
type: string
content:
type: string
categories:
type: array
items:
type: object
properties:
id:
type: string
name:
type: string
code:
type: string
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
tags:
type: array
items:
type: object
properties:
id:
type: string
name:
type: string
code:
type: string
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
is_premium:
type: boolean
slug:
type: string
featured_image:
type: string
format: uri
author_id:
type: string
live_at:
type: string
format: date-time
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
"400":
description: Bad request
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Some files were not shown because too many files have changed in this diff Show More