215 lines
7.3 KiB
Go
215 lines
7.3 KiB
Go
//go:build mysql
|
|
// +build mysql
|
|
|
|
package mysql
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/jmoiron/sqlx"
|
|
t "github.com/tinode/chat/server/store/types"
|
|
)
|
|
|
|
func (a *adapter) PublicUploadCreate(upload *t.PublicUpload) (*t.PublicUpload, error) {
|
|
db := a.controlDB()
|
|
if db == nil {
|
|
return nil, t.ErrInternal
|
|
}
|
|
now := t.TimeNow()
|
|
if upload.CreatedAt.IsZero() {
|
|
upload.CreatedAt = now
|
|
}
|
|
if upload.UploadedAt.IsZero() {
|
|
upload.UploadedAt = now
|
|
}
|
|
ctx, cancel := a.getContext()
|
|
if cancel != nil {
|
|
defer cancel()
|
|
}
|
|
_, err := db.ExecContext(ctx, `INSERT INTO im_public_uploads
|
|
(file_id,purpose,mime_type,size,etag,location,expires_at,created_at,uploaded_at)
|
|
VALUES(?,?,?,?,?,?,?,?,?)`,
|
|
upload.FileID, upload.Purpose, upload.MimeType, upload.Size, upload.ETag, upload.Location,
|
|
nullableTenantEntryTime(upload.ExpiresAt), upload.CreatedAt, upload.UploadedAt)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return upload, nil
|
|
}
|
|
|
|
func (a *adapter) TenantApplicationCreate(application *t.TenantApplication) (*t.TenantApplication, error) {
|
|
db := a.controlDB()
|
|
if db == nil {
|
|
return nil, t.ErrInternal
|
|
}
|
|
now := t.TimeNow()
|
|
if application.Status == "" {
|
|
application.Status = t.TenantApplicationStatusReceived
|
|
}
|
|
if application.EstimatedReviewHour <= 0 {
|
|
application.EstimatedReviewHour = 24
|
|
}
|
|
if application.SubmittedAt.IsZero() {
|
|
application.SubmittedAt = now
|
|
}
|
|
application.CreatedAt = now
|
|
application.UpdatedAt = now
|
|
clientContext, _ := json.Marshal(application.ClientContext)
|
|
ctx, cancel := a.getContext()
|
|
if cancel != nil {
|
|
defer cancel()
|
|
}
|
|
var existingID string
|
|
err := db.QueryRowContext(ctx, `SELECT application_id FROM im_tenant_applications
|
|
WHERE credit_code=? AND status IN ('received','pending','reviewing') ORDER BY id DESC LIMIT 1`,
|
|
strings.ToUpper(strings.TrimSpace(application.CreditCode))).Scan(&existingID)
|
|
if err == nil && existingID != "" {
|
|
return nil, t.ErrDuplicate
|
|
}
|
|
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
|
return nil, err
|
|
}
|
|
_, err = db.ExecContext(ctx, `INSERT INTO im_tenant_applications
|
|
(application_id,credit_code,enterprise_email,license_file_id,tenant_code_hint,client_context,idempotency_key,status,estimated_review_hour,submitted_at,created_at,updated_at)
|
|
VALUES(?,?,?,?,?,?,?,?,?,?,?,?)`,
|
|
application.ApplicationID, application.CreditCode, application.EnterpriseEmail, application.LicenseFileID,
|
|
application.TenantCodeHint, string(clientContext), application.IdempotencyKey, application.Status,
|
|
application.EstimatedReviewHour, application.SubmittedAt, now, now)
|
|
if err != nil {
|
|
return a.tenantApplicationByIdempotency(application.IdempotencyKey)
|
|
}
|
|
return a.tenantApplicationByIdempotency(application.IdempotencyKey)
|
|
}
|
|
|
|
func (a *adapter) TenantEntryFeedbackCreate(feedback *t.TenantEntryFeedback) (*t.TenantEntryFeedback, error) {
|
|
db := a.controlDB()
|
|
if db == nil {
|
|
return nil, t.ErrInternal
|
|
}
|
|
now := t.TimeNow()
|
|
if feedback.Status == "" {
|
|
feedback.Status = t.TenantEntryFeedbackReceived
|
|
}
|
|
if feedback.SubmittedAt.IsZero() {
|
|
feedback.SubmittedAt = now
|
|
}
|
|
feedback.CreatedAt = now
|
|
feedback.UpdatedAt = now
|
|
screenshots, _ := json.Marshal(feedback.ScreenshotFileIDs)
|
|
clientContext, _ := json.Marshal(feedback.ClientContext)
|
|
ctx, cancel := a.getContext()
|
|
if cancel != nil {
|
|
defer cancel()
|
|
}
|
|
_, err := db.ExecContext(ctx, `INSERT INTO im_tenant_entry_feedbacks
|
|
(feedback_id,description,contact,tenant_code_hint,screenshot_file_ids,client_context,idempotency_key,status,submitted_at,created_at,updated_at)
|
|
VALUES(?,?,?,?,?,?,?,?,?,?,?)`,
|
|
feedback.FeedbackID, feedback.Description, feedback.Contact, feedback.TenantCodeHint,
|
|
string(screenshots), string(clientContext), feedback.IdempotencyKey, feedback.Status,
|
|
feedback.SubmittedAt, now, now)
|
|
if err != nil {
|
|
return a.tenantEntryFeedbackByIdempotency(feedback.IdempotencyKey)
|
|
}
|
|
return a.tenantEntryFeedbackByIdempotency(feedback.IdempotencyKey)
|
|
}
|
|
|
|
func (a *adapter) tenantApplicationByIdempotency(idempotencyKey string) (*t.TenantApplication, error) {
|
|
db := a.controlDB()
|
|
ctx, cancel := a.getContext()
|
|
if cancel != nil {
|
|
defer cancel()
|
|
}
|
|
row := struct {
|
|
ApplicationID string `db:"application_id"`
|
|
CreditCode string `db:"credit_code"`
|
|
EnterpriseEmail string `db:"enterprise_email"`
|
|
LicenseFileID string `db:"license_file_id"`
|
|
TenantCodeHint string `db:"tenant_code_hint"`
|
|
ClientContext []byte `db:"client_context"`
|
|
IdempotencyKey string `db:"idempotency_key"`
|
|
Status string `db:"status"`
|
|
EstimatedReviewHour int `db:"estimated_review_hour"`
|
|
SubmittedAt time.Time `db:"submitted_at"`
|
|
CreatedAt time.Time `db:"created_at"`
|
|
UpdatedAt time.Time `db:"updated_at"`
|
|
}{}
|
|
if err := db.GetContext(ctx, &row, `SELECT application_id,credit_code,enterprise_email,license_file_id,
|
|
tenant_code_hint,client_context,idempotency_key,status,estimated_review_hour,submitted_at,created_at,updated_at
|
|
FROM im_tenant_applications WHERE idempotency_key=?`, idempotencyKey); err != nil {
|
|
return nil, err
|
|
}
|
|
app := &t.TenantApplication{
|
|
ApplicationID: row.ApplicationID,
|
|
CreditCode: row.CreditCode,
|
|
EnterpriseEmail: row.EnterpriseEmail,
|
|
LicenseFileID: row.LicenseFileID,
|
|
TenantCodeHint: row.TenantCodeHint,
|
|
IdempotencyKey: row.IdempotencyKey,
|
|
Status: row.Status,
|
|
EstimatedReviewHour: row.EstimatedReviewHour,
|
|
SubmittedAt: row.SubmittedAt,
|
|
CreatedAt: row.CreatedAt,
|
|
UpdatedAt: row.UpdatedAt,
|
|
}
|
|
_ = json.Unmarshal(row.ClientContext, &app.ClientContext)
|
|
return app, nil
|
|
}
|
|
|
|
func (a *adapter) tenantEntryFeedbackByIdempotency(idempotencyKey string) (*t.TenantEntryFeedback, error) {
|
|
db := a.controlDB()
|
|
ctx, cancel := a.getContext()
|
|
if cancel != nil {
|
|
defer cancel()
|
|
}
|
|
row := struct {
|
|
FeedbackID string `db:"feedback_id"`
|
|
Description string `db:"description"`
|
|
Contact string `db:"contact"`
|
|
TenantCodeHint string `db:"tenant_code_hint"`
|
|
ScreenshotFileIDs []byte `db:"screenshot_file_ids"`
|
|
ClientContext []byte `db:"client_context"`
|
|
IdempotencyKey string `db:"idempotency_key"`
|
|
Status string `db:"status"`
|
|
SubmittedAt time.Time `db:"submitted_at"`
|
|
CreatedAt time.Time `db:"created_at"`
|
|
UpdatedAt time.Time `db:"updated_at"`
|
|
}{}
|
|
if err := db.GetContext(ctx, &row, `SELECT feedback_id,description,contact,tenant_code_hint,
|
|
screenshot_file_ids,client_context,idempotency_key,status,submitted_at,created_at,updated_at
|
|
FROM im_tenant_entry_feedbacks WHERE idempotency_key=?`, idempotencyKey); err != nil {
|
|
return nil, err
|
|
}
|
|
feedback := &t.TenantEntryFeedback{
|
|
FeedbackID: row.FeedbackID,
|
|
Description: row.Description,
|
|
Contact: row.Contact,
|
|
TenantCodeHint: row.TenantCodeHint,
|
|
IdempotencyKey: row.IdempotencyKey,
|
|
Status: row.Status,
|
|
SubmittedAt: row.SubmittedAt,
|
|
CreatedAt: row.CreatedAt,
|
|
UpdatedAt: row.UpdatedAt,
|
|
}
|
|
_ = json.Unmarshal(row.ScreenshotFileIDs, &feedback.ScreenshotFileIDs)
|
|
_ = json.Unmarshal(row.ClientContext, &feedback.ClientContext)
|
|
return feedback, nil
|
|
}
|
|
|
|
func (a *adapter) controlDB() *sqlx.DB {
|
|
if a.registryDB != nil {
|
|
return a.registryDB
|
|
}
|
|
return a.db
|
|
}
|
|
|
|
func nullableTenantEntryTime(value time.Time) any {
|
|
if value.IsZero() {
|
|
return nil
|
|
}
|
|
return value
|
|
}
|