UPDATE: Add super admin
This commit is contained in:
@@ -3,12 +3,14 @@ package database
|
||||
import (
|
||||
"context"
|
||||
"history-api/pkg/config"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
func NewPostgresqlDB() (*pgxpool.Pool, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
connectionURI, err := config.GetConfig("PGX_CONNECTION_URI")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -19,14 +21,21 @@ func NewPostgresqlDB() (*pgxpool.Pool, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pool, err := pgxpool.NewWithConfig(ctx, poolConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var pool *pgxpool.Pool
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
pool, err = pgxpool.NewWithConfig(ctx, poolConfig)
|
||||
if err != nil {
|
||||
time.Sleep(2 * time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
if err = pool.Ping(ctx); err == nil {
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
|
||||
if err := pool.Ping(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pool, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
75
pkg/database/seed.go
Normal file
75
pkg/database/seed.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"history-api/internal/gen/sqlc"
|
||||
"history-api/pkg/config"
|
||||
"history-api/pkg/constants"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func SeedSuperAdmin(pool *pgxpool.Pool) error {
|
||||
ctx := context.Background()
|
||||
|
||||
displayName, err := config.GetConfig("ADMIN_DISPLAY_NAME")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
email, err := config.GetConfig("ADMIN_EMAIL")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
password, err := config.GetConfig("ADMIN_PASSWORD")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
q := sqlc.New(pool)
|
||||
|
||||
_, err = q.GetUserByEmail(ctx, email)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !errors.Is(err, sql.ErrNoRows) {
|
||||
return err
|
||||
}
|
||||
|
||||
hashed, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
user, err := q.UpsertUser(ctx, sqlc.UpsertUserParams{
|
||||
Email: email,
|
||||
PasswordHash: pgtype.Text{
|
||||
String: string(hashed),
|
||||
Valid: len(hashed) != 0,
|
||||
},
|
||||
AuthProvider: constants.LocalProvider.String(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = q.CreateUserProfile(ctx, sqlc.CreateUserProfileParams{
|
||||
UserID: user.ID,
|
||||
DisplayName: pgtype.Text{
|
||||
String: displayName,
|
||||
Valid: displayName != "",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
139
pkg/storage/rustfs.go
Normal file
139
pkg/storage/rustfs.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/credentials"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
ffconfig "history-api/pkg/config"
|
||||
)
|
||||
|
||||
type UploadOptions struct {
|
||||
ContentType string
|
||||
ContentDisposition string
|
||||
Metadata map[string]string
|
||||
}
|
||||
|
||||
type Storage interface {
|
||||
Upload(ctx context.Context, key string, body io.Reader, size int64, opts UploadOptions) error
|
||||
PresignUpload(ctx context.Context, key string, expire time.Duration, opts UploadOptions) (string, error)
|
||||
GetURL(ctx context.Context, key string, expire time.Duration) (string, error)
|
||||
Delete(ctx context.Context, key string) error
|
||||
}
|
||||
|
||||
type s3Storage struct {
|
||||
client *s3.Client
|
||||
ps *s3.PresignClient
|
||||
bucket string
|
||||
endPoint string
|
||||
}
|
||||
|
||||
func NewS3Storage() (Storage, error) {
|
||||
accessKey, err := ffconfig.GetConfig("STORAGE_ACCESS_KEY")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
secretAccessKey, err := ffconfig.GetConfig("STORAGE_SECRET_KEY")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bucketName, err := ffconfig.GetConfig("STORAGE_BUCKET_NAME")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
endpoint, err := ffconfig.GetConfig("STORAGE_ENDPOINT")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg, err := config.LoadDefaultConfig(context.TODO(),
|
||||
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(accessKey, secretAccessKey, "")),
|
||||
config.WithRegion("auto"),
|
||||
)
|
||||
if err != nil {
|
||||
log.Error().Msgf("unable to load AWS SDK config, %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := s3.NewFromConfig(cfg, func(o *s3.Options) {
|
||||
o.BaseEndpoint = aws.String(endpoint)
|
||||
})
|
||||
|
||||
return &s3Storage{
|
||||
client: client,
|
||||
ps: s3.NewPresignClient(client),
|
||||
bucket: bucketName,
|
||||
endPoint: endpoint,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *s3Storage) Upload(ctx context.Context, key string, body io.Reader, size int64, opts UploadOptions) error {
|
||||
input := &s3.PutObjectInput{
|
||||
Bucket: &s.bucket,
|
||||
Key: &key,
|
||||
Body: body,
|
||||
}
|
||||
|
||||
if opts.ContentType != "" {
|
||||
input.ContentType = aws.String(opts.ContentType)
|
||||
}
|
||||
if opts.ContentDisposition != "" {
|
||||
input.ContentDisposition = aws.String(opts.ContentDisposition)
|
||||
}
|
||||
if len(opts.Metadata) > 0 {
|
||||
input.Metadata = opts.Metadata
|
||||
}
|
||||
|
||||
_, err := s.client.PutObject(ctx, input)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *s3Storage) PresignUpload(ctx context.Context, key string, expire time.Duration, opts UploadOptions) (string, error) {
|
||||
input := &s3.PutObjectInput{
|
||||
Bucket: &s.bucket,
|
||||
Key: &key,
|
||||
}
|
||||
|
||||
if opts.ContentType != "" {
|
||||
input.ContentType = aws.String(opts.ContentType)
|
||||
}
|
||||
if opts.ContentDisposition != "" {
|
||||
input.ContentDisposition = aws.String(opts.ContentDisposition)
|
||||
}
|
||||
if len(opts.Metadata) > 0 {
|
||||
input.Metadata = opts.Metadata
|
||||
}
|
||||
|
||||
req, err := s.ps.PresignPutObject(ctx, input, s3.WithPresignExpires(expire))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return req.URL, nil
|
||||
}
|
||||
func (s *s3Storage) GetURL(ctx context.Context, key string, expire time.Duration) (string, error) {
|
||||
req, err := s.ps.PresignGetObject(ctx, &s3.GetObjectInput{
|
||||
Bucket: &s.bucket,
|
||||
Key: &key,
|
||||
}, s3.WithPresignExpires(expire))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return req.URL, nil
|
||||
}
|
||||
|
||||
func (s *s3Storage) Delete(ctx context.Context, key string) error {
|
||||
_, err := s.client.DeleteObject(ctx, &s3.DeleteObjectInput{
|
||||
Bucket: &s.bucket,
|
||||
Key: &key,
|
||||
})
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user