chore: update golangci-lint config

This commit is contained in:
steven 2023-09-22 17:55:26 +08:00 committed by Steven
parent a58ebd27ca
commit 07e0bb2d4c
42 changed files with 195 additions and 137 deletions

View File

@ -1,5 +1,6 @@
linters: linters:
enable: enable:
- errcheck
- goimports - goimports
- revive - revive
- govet - govet
@ -10,17 +11,30 @@ linters:
- rowserrcheck - rowserrcheck
- nilerr - nilerr
- godot - godot
- forbidigo
- mirror
- bodyclose
issues: issues:
include:
# https://golangci-lint.run/usage/configuration/#command-line-options
exclude: exclude:
- Rollback - Rollback
- logger.Sync
- pgInstance.Stop
- fmt.Printf - fmt.Printf
- fmt.Print - Enter(.*)_(.*)
- Exit(.*)_(.*)
linters-settings: linters-settings:
goimports:
# Put imports beginning with prefix after 3rd-party packages.
local-prefixes: github.com/boojack/slash
revive: revive:
# Default to run all linters so that new rules in the future could automatically be added to the static check.
enable-all-rules: true enable-all-rules: true
rules: rules:
# The following rules are too strict and make coding harder. We do not enable them for now.
- name: file-header - name: file-header
disabled: true disabled: true
- name: line-length-limit - name: line-length-limit
@ -59,9 +73,14 @@ linters-settings:
- ifElseChain - ifElseChain
govet: govet:
settings: settings:
printf: printf: # The name of the analyzer, run `go tool vet help` to see the list of all analyzers
funcs: funcs: # Run `go tool vet help printf` to see the full configuration of `printf`.
- common.Errorf - common.Errorf
enable-all: true
disable:
- fieldalignment
- shadow
forbidigo: forbidigo:
forbid: forbid:
- 'fmt\.Errorf(# Please use errors\.Wrap\|Wrapf\|Errorf instead)?' - 'fmt\.Errorf(# Please use errors\.Wrap\|Wrapf\|Errorf instead)?'
- 'ioutil\.ReadDir(# Please use os\.ReadDir)?'

View File

@ -6,10 +6,11 @@ import (
"net/http" "net/http"
"strconv" "strconv"
"github.com/boojack/slash/store"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/mssola/useragent" "github.com/mssola/useragent"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
"github.com/boojack/slash/store"
) )
type ReferenceInfo struct { type ReferenceInfo struct {

View File

@ -7,12 +7,13 @@ import (
"net/http" "net/http"
"time" "time"
"github.com/boojack/slash/api/auth"
storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
"github.com/boojack/slash/api/auth"
storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store"
) )
type SignInRequest struct { type SignInRequest struct {

View File

@ -5,13 +5,14 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/golang-jwt/jwt/v4"
"github.com/labstack/echo/v4"
"github.com/pkg/errors"
"github.com/boojack/slash/api/auth" "github.com/boojack/slash/api/auth"
"github.com/boojack/slash/internal/util" "github.com/boojack/slash/internal/util"
storepb "github.com/boojack/slash/proto/gen/store" storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store" "github.com/boojack/slash/store"
"github.com/golang-jwt/jwt/v4"
"github.com/labstack/echo/v4"
"github.com/pkg/errors"
) )
const ( const (

View File

@ -8,10 +8,11 @@ import (
"net/url" "net/url"
"strings" "strings"
storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/pkg/errors" "github.com/pkg/errors"
storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store"
) )
func (s *APIV1Service) registerRedirectorRoutes(g *echo.Group) { func (s *APIV1Service) registerRedirectorRoutes(g *echo.Group) {

View File

@ -7,11 +7,12 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/labstack/echo/v4"
"github.com/pkg/errors"
"github.com/boojack/slash/internal/util" "github.com/boojack/slash/internal/util"
storepb "github.com/boojack/slash/proto/gen/store" storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store" "github.com/boojack/slash/store"
"github.com/labstack/echo/v4"
"github.com/pkg/errors"
) )
// Visibility is the type of a shortcut visibility. // Visibility is the type of a shortcut visibility.

View File

@ -6,10 +6,12 @@ import (
"net/http" "net/http"
"net/mail" "net/mail"
"github.com/labstack/echo/v4"
"github.com/pkg/errors"
"golang.org/x/crypto/bcrypt"
"github.com/boojack/slash/internal/util" "github.com/boojack/slash/internal/util"
"github.com/boojack/slash/store" "github.com/boojack/slash/store"
"github.com/labstack/echo/v4"
"golang.org/x/crypto/bcrypt"
) )
const ( const (
@ -60,13 +62,13 @@ type CreateUserRequest struct {
func (create CreateUserRequest) Validate() error { func (create CreateUserRequest) Validate() error {
if create.Email != "" && !validateEmail(create.Email) { if create.Email != "" && !validateEmail(create.Email) {
return fmt.Errorf("invalid email format") return errors.New("invalid email format")
} }
if create.Nickname != "" && len(create.Nickname) < 3 { if create.Nickname != "" && len(create.Nickname) < 3 {
return fmt.Errorf("nickname is too short, minimum length is 3") return errors.New("nickname is too short, minimum length is 3")
} }
if len(create.Password) < 3 { if len(create.Password) < 3 {
return fmt.Errorf("password is too short, minimum length is 3") return errors.New("password is too short, minimum length is 3")
} }
return nil return nil

View File

@ -2,7 +2,8 @@ package v1
import ( import (
"encoding/json" "encoding/json"
"fmt"
"github.com/pkg/errors"
) )
type UserSettingKey string type UserSettingKey string
@ -39,7 +40,7 @@ func (upsert UserSettingUpsert) Validate() error {
localeValue := "en" localeValue := "en"
err := json.Unmarshal([]byte(upsert.Value), &localeValue) err := json.Unmarshal([]byte(upsert.Value), &localeValue)
if err != nil { if err != nil {
return fmt.Errorf("failed to unmarshal user setting locale value") return errors.New("failed to unmarshal user setting locale value")
} }
invalid := true invalid := true
@ -50,10 +51,10 @@ func (upsert UserSettingUpsert) Validate() error {
} }
} }
if invalid { if invalid {
return fmt.Errorf("invalid user setting locale value") return errors.New("invalid user setting locale value")
} }
} else { } else {
return fmt.Errorf("invalid user setting key") return errors.New("invalid user setting key")
} }
return nil return nil

View File

@ -1,10 +1,11 @@
package v1 package v1
import ( import (
"github.com/labstack/echo/v4"
"github.com/boojack/slash/server/profile" "github.com/boojack/slash/server/profile"
"github.com/boojack/slash/server/service/license" "github.com/boojack/slash/server/service/license"
"github.com/boojack/slash/store" "github.com/boojack/slash/store"
"github.com/labstack/echo/v4"
) )
type APIV1Service struct { type APIV1Service struct {

View File

@ -4,10 +4,11 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"github.com/labstack/echo/v4"
storepb "github.com/boojack/slash/proto/gen/store" storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/server/profile" "github.com/boojack/slash/server/profile"
"github.com/boojack/slash/store" "github.com/boojack/slash/store"
"github.com/labstack/echo/v4"
) )
type WorkspaceProfile struct { type WorkspaceProfile struct {

View File

@ -5,16 +5,17 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/boojack/slash/api/auth"
"github.com/boojack/slash/internal/util"
storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store"
"github.com/golang-jwt/jwt/v4" "github.com/golang-jwt/jwt/v4"
"github.com/pkg/errors" "github.com/pkg/errors"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"github.com/boojack/slash/api/auth"
"github.com/boojack/slash/internal/util"
storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store"
) )
// ContextKey is the key type of context value. // ContextKey is the key type of context value.

View File

@ -3,13 +3,14 @@ package v2
import ( import (
"context" "context"
apiv2pb "github.com/boojack/slash/proto/gen/api/v2"
storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store"
"github.com/pkg/errors" "github.com/pkg/errors"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/encoding/protojson"
apiv2pb "github.com/boojack/slash/proto/gen/api/v2"
storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store"
) )
type ShortcutService struct { type ShortcutService struct {

View File

@ -3,12 +3,13 @@ package v2
import ( import (
"context" "context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
apiv2pb "github.com/boojack/slash/proto/gen/api/v2" apiv2pb "github.com/boojack/slash/proto/gen/api/v2"
"github.com/boojack/slash/server/profile" "github.com/boojack/slash/server/profile"
"github.com/boojack/slash/server/service/license" "github.com/boojack/slash/server/service/license"
"github.com/boojack/slash/store" "github.com/boojack/slash/store"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
) )
type SubscriptionService struct { type SubscriptionService struct {

View File

@ -4,10 +4,6 @@ import (
"context" "context"
"time" "time"
"github.com/boojack/slash/api/auth"
apiv2pb "github.com/boojack/slash/proto/gen/api/v2"
storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store"
"github.com/golang-jwt/jwt/v4" "github.com/golang-jwt/jwt/v4"
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
@ -15,6 +11,11 @@ import (
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/boojack/slash/api/auth"
apiv2pb "github.com/boojack/slash/proto/gen/api/v2"
storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store"
) )
type UserService struct { type UserService struct {

View File

@ -3,12 +3,13 @@ package v2
import ( import (
"context" "context"
apiv2pb "github.com/boojack/slash/proto/gen/api/v2"
storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store"
"github.com/pkg/errors" "github.com/pkg/errors"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
apiv2pb "github.com/boojack/slash/proto/gen/api/v2"
storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store"
) )
type UserSettingService struct { type UserSettingService struct {

View File

@ -4,16 +4,17 @@ import (
"context" "context"
"fmt" "fmt"
apiv2pb "github.com/boojack/slash/proto/gen/api/v2"
"github.com/boojack/slash/server/profile"
"github.com/boojack/slash/server/service/license"
"github.com/boojack/slash/store"
grpcRuntime "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" grpcRuntime "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/improbable-eng/grpc-web/go/grpcweb" "github.com/improbable-eng/grpc-web/go/grpcweb"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/reflection" "google.golang.org/grpc/reflection"
apiv2pb "github.com/boojack/slash/proto/gen/api/v2"
"github.com/boojack/slash/server/profile"
"github.com/boojack/slash/server/service/license"
"github.com/boojack/slash/store"
) )
type APIV2Service struct { type APIV2Service struct {

View File

@ -3,13 +3,14 @@ package v2
import ( import (
"context" "context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
apiv2pb "github.com/boojack/slash/proto/gen/api/v2" apiv2pb "github.com/boojack/slash/proto/gen/api/v2"
storepb "github.com/boojack/slash/proto/gen/store" storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/server/profile" "github.com/boojack/slash/server/profile"
"github.com/boojack/slash/server/service/license" "github.com/boojack/slash/server/service/license"
"github.com/boojack/slash/store" "github.com/boojack/slash/store"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
) )
type WorkspaceService struct { type WorkspaceService struct {

View File

@ -8,15 +8,16 @@ import (
"os/signal" "os/signal"
"syscall" "syscall"
"github.com/boojack/slash/internal/log"
"github.com/boojack/slash/server"
_profile "github.com/boojack/slash/server/profile"
"github.com/boojack/slash/store"
"github.com/boojack/slash/store/db"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
"go.uber.org/zap" "go.uber.org/zap"
_ "modernc.org/sqlite" _ "modernc.org/sqlite"
"github.com/boojack/slash/internal/log"
"github.com/boojack/slash/server"
"github.com/boojack/slash/server/profile"
"github.com/boojack/slash/store"
"github.com/boojack/slash/store/db"
) )
const ( const (
@ -24,25 +25,25 @@ const (
) )
var ( var (
profile *_profile.Profile serverProfile *profile.Profile
mode string mode string
port int port int
data string data string
rootCmd = &cobra.Command{ rootCmd = &cobra.Command{
Use: "slash", Use: "slash",
Short: `An open source, self-hosted bookmarks and link sharing platform.`, Short: `An open source, self-hosted bookmarks and link sharing platform.`,
Run: func(_cmd *cobra.Command, _args []string) { Run: func(_cmd *cobra.Command, _args []string) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
db := db.NewDB(profile) db := db.NewDB(serverProfile)
if err := db.Open(ctx); err != nil { if err := db.Open(ctx); err != nil {
cancel() cancel()
log.Error("failed to open database", zap.Error(err)) log.Error("failed to open database", zap.Error(err))
return return
} }
storeInstance := store.New(db.DBInstance, profile) storeInstance := store.New(db.DBInstance, serverProfile)
s, err := server.NewServer(ctx, profile, storeInstance) s, err := server.NewServer(ctx, serverProfile, storeInstance)
if err != nil { if err != nil {
cancel() cancel()
log.Error("failed to create server", zap.Error(err)) log.Error("failed to create server", zap.Error(err))
@ -109,7 +110,7 @@ func init() {
func initConfig() { func initConfig() {
viper.AutomaticEnv() viper.AutomaticEnv()
var err error var err error
profile, err = _profile.GetProfile() serverProfile, err = profile.GetProfile()
if err != nil { if err != nil {
log.Error("failed to get profile", zap.Error(err)) log.Error("failed to get profile", zap.Error(err))
return return
@ -117,20 +118,20 @@ func initConfig() {
println("---") println("---")
println("Server profile") println("Server profile")
println("dsn:", profile.DSN) println("dsn:", serverProfile.DSN)
println("port:", profile.Port) println("port:", serverProfile.Port)
println("mode:", profile.Mode) println("mode:", serverProfile.Mode)
println("version:", profile.Version) println("version:", serverProfile.Version)
println("---") println("---")
} }
func printGreetings() { func printGreetings() {
fmt.Println(greetingBanner) println(greetingBanner)
fmt.Printf("Version %s has been started on port %d\n", profile.Version, profile.Port) fmt.Printf("Version %s has been started on port %d\n", serverProfile.Version, serverProfile.Port)
fmt.Println("---") println("---")
fmt.Println("See more in:") println("See more in:")
fmt.Printf("👉GitHub: %s\n", "https://github.com/boojack/slash") fmt.Printf("👉GitHub: %s\n", "https://github.com/boojack/slash")
fmt.Println("---") println("---")
} }
func main() { func main() {

View File

@ -28,7 +28,7 @@ const SignIn: React.FC = () => {
} }
if (mode === "demo") { if (mode === "demo") {
setEmail("steven@usememos.com"); setEmail("steven@yourselfhosted.com");
setPassword("secret"); setPassword("secret");
} }
}, []); }, []);

View File

@ -1,3 +1,5 @@
package cron
// Package cron implements a crontab-like service to execute and schedule // Package cron implements a crontab-like service to execute and schedule
// repeative tasks/jobs. // repeative tasks/jobs.
// //
@ -6,13 +8,12 @@
// c := cron.New() // c := cron.New()
// c.MustAdd("dailyReport", "0 0 * * *", func() { ... }) // c.MustAdd("dailyReport", "0 0 * * *", func() { ... })
// c.Start() // c.Start()
package cron
import ( import (
"errors"
"fmt"
"sync" "sync"
"time" "time"
"github.com/pkg/errors"
) )
type job struct { type job struct {
@ -90,7 +91,7 @@ func (c *Cron) Add(jobID string, cronExpr string, run func()) error {
schedule, err := NewSchedule(cronExpr) schedule, err := NewSchedule(cronExpr)
if err != nil { if err != nil {
return fmt.Errorf("failed to add new cron job: %w", err) return errors.Wrap(err, "failed to add new cron job")
} }
c.jobs[jobID] = &job{ c.jobs[jobID] = &job{

View File

@ -1,11 +1,11 @@
package cron package cron
import ( import (
"errors"
"fmt"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/pkg/errors"
) )
// Moment represents a parsed single time moment. // Moment represents a parsed single time moment.
@ -132,7 +132,7 @@ func parseCronSegment(segment string, min int, max int) (map[int]struct{}, error
return nil, err return nil, err
} }
if parsedStep < 1 || parsedStep > max { if parsedStep < 1 || parsedStep > max {
return nil, fmt.Errorf("invalid segment step boundary - the step must be between 1 and the %d", max) return nil, errors.New("invalid segment step boundary")
} }
step = parsedStep step = parsedStep
default: default:
@ -167,7 +167,7 @@ func parseCronSegment(segment string, min int, max int) (map[int]struct{}, error
return nil, err return nil, err
} }
if parsedMin < min || parsedMin > max { if parsedMin < min || parsedMin > max {
return nil, fmt.Errorf("invalid segment range minimum - must be between %d and %d", min, max) return nil, errors.New("invalid segment range minimum")
} }
rangeMin = parsedMin rangeMin = parsedMin
@ -176,7 +176,7 @@ func parseCronSegment(segment string, min int, max int) (map[int]struct{}, error
return nil, err return nil, err
} }
if parsedMax < parsedMin || parsedMax > max { if parsedMax < parsedMin || parsedMax > max {
return nil, fmt.Errorf("invalid segment range maximum - must be between %d and %d", rangeMin, max) return nil, errors.New("invalid segment range maximum")
} }
rangeMax = parsedMax rangeMax = parsedMax
default: default:

View File

@ -5,9 +5,10 @@ import (
"io/fs" "io/fs"
"net/http" "net/http"
"github.com/boojack/slash/internal/util"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware" "github.com/labstack/echo/v4/middleware"
"github.com/boojack/slash/internal/util"
) )
//go:embed dist //go:embed dist

View File

@ -7,8 +7,10 @@ import (
"runtime" "runtime"
"strings" "strings"
"github.com/boojack/slash/server/version" "github.com/pkg/errors"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/boojack/slash/server/version"
) )
// Profile is the configuration to start main server. // Profile is the configuration to start main server.
@ -44,7 +46,7 @@ func checkDSN(dataDir string) (string, error) {
dataDir = strings.TrimRight(dataDir, "\\/") dataDir = strings.TrimRight(dataDir, "\\/")
if _, err := os.Stat(dataDir); err != nil { if _, err := os.Stat(dataDir); err != nil {
return "", fmt.Errorf("unable to access data folder %s, err %w", dataDir, err) return "", errors.Wrapf(err, "unable to access data folder %s", dataDir)
} }
return dataDir, nil return dataDir, nil

View File

@ -6,11 +6,12 @@ import (
"net/http" "net/http"
"os" "os"
"github.com/h2non/filetype"
"github.com/labstack/echo/v4"
storepb "github.com/boojack/slash/proto/gen/store" storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/server/profile" "github.com/boojack/slash/server/profile"
"github.com/boojack/slash/store" "github.com/boojack/slash/store"
"github.com/h2non/filetype"
"github.com/labstack/echo/v4"
) )
type ResourceService struct { type ResourceService struct {

View File

@ -8,15 +8,17 @@ import (
"strings" "strings"
"time" "time"
"github.com/google/uuid"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"github.com/pkg/errors"
apiv1 "github.com/boojack/slash/api/v1" apiv1 "github.com/boojack/slash/api/v1"
apiv2 "github.com/boojack/slash/api/v2" apiv2 "github.com/boojack/slash/api/v2"
storepb "github.com/boojack/slash/proto/gen/store" storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/server/profile" "github.com/boojack/slash/server/profile"
"github.com/boojack/slash/server/service/license" "github.com/boojack/slash/server/service/license"
"github.com/boojack/slash/store" "github.com/boojack/slash/store"
"github.com/google/uuid"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
) )
type Server struct { type Server struct {
@ -102,7 +104,7 @@ func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store
s.apiV2Service = apiv2.NewAPIV2Service(secret, profile, store, licenseService, s.Profile.Port+1) s.apiV2Service = apiv2.NewAPIV2Service(secret, profile, store, licenseService, s.Profile.Port+1)
// Register gRPC gateway as api v2. // Register gRPC gateway as api v2.
if err := s.apiV2Service.RegisterGateway(ctx, e); err != nil { if err := s.apiV2Service.RegisterGateway(ctx, e); err != nil {
return nil, fmt.Errorf("failed to register gRPC gateway: %w", err) return nil, errors.Wrap(err, "failed to register gRPC gateway")
} }
// Register resource service. // Register resource service.

View File

@ -4,12 +4,13 @@ import (
"context" "context"
"time" "time"
"github.com/pkg/errors"
"google.golang.org/protobuf/types/known/timestamppb"
apiv2pb "github.com/boojack/slash/proto/gen/api/v2" apiv2pb "github.com/boojack/slash/proto/gen/api/v2"
storepb "github.com/boojack/slash/proto/gen/store" storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/server/profile" "github.com/boojack/slash/server/profile"
"github.com/boojack/slash/store" "github.com/boojack/slash/store"
"github.com/pkg/errors"
"google.golang.org/protobuf/types/known/timestamppb"
) )
type LicenseService struct { type LicenseService struct {

View File

@ -4,7 +4,6 @@ import (
"context" "context"
"database/sql" "database/sql"
"embed" "embed"
"errors"
"fmt" "fmt"
"io/fs" "io/fs"
"os" "os"
@ -12,6 +11,8 @@ import (
"sort" "sort"
"time" "time"
"github.com/pkg/errors"
"github.com/boojack/slash/server/profile" "github.com/boojack/slash/server/profile"
"github.com/boojack/slash/server/version" "github.com/boojack/slash/server/version"
) )
@ -39,7 +40,7 @@ func NewDB(profile *profile.Profile) *DB {
func (db *DB) Open(ctx context.Context) (err error) { func (db *DB) Open(ctx context.Context) (err error) {
// Ensure a DSN is set before attempting to open the database. // Ensure a DSN is set before attempting to open the database.
if db.profile.DSN == "" { if db.profile.DSN == "" {
return fmt.Errorf("dsn required") return errors.New("dsn required")
} }
// Connect to the database with some sane settings: // Connect to the database with some sane settings:
@ -58,7 +59,7 @@ func (db *DB) Open(ctx context.Context) (err error) {
// - https://www.sqlite.org/pragma.html // - https://www.sqlite.org/pragma.html
sqliteDB, err := sql.Open("sqlite", db.profile.DSN+"?_pragma=foreign_keys(0)&_pragma=busy_timeout(10000)&_pragma=journal_mode(WAL)") sqliteDB, err := sql.Open("sqlite", db.profile.DSN+"?_pragma=foreign_keys(0)&_pragma=busy_timeout(10000)&_pragma=journal_mode(WAL)")
if err != nil { if err != nil {
return fmt.Errorf("failed to open db with dsn: %s, err: %w", db.profile.DSN, err) return errors.Wrapf(err, "failed to open db with dsn: %s", db.profile.DSN)
} }
db.DBInstance = sqliteDB db.DBInstance = sqliteDB
@ -68,24 +69,24 @@ func (db *DB) Open(ctx context.Context) (err error) {
// If db file not exists, we should create a new one with latest schema. // If db file not exists, we should create a new one with latest schema.
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
if err := db.applyLatestSchema(ctx); err != nil { if err := db.applyLatestSchema(ctx); err != nil {
return fmt.Errorf("failed to apply latest schema, err: %w", err) return errors.Wrap(err, "failed to apply latest schema")
} }
} else { } else {
return fmt.Errorf("failed to get db file stat, err: %w", err) return errors.Wrap(err, "failed to get db file stat")
} }
} else { } else {
// If db file exists, we should check if we need to migrate the database. // If db file exists, we should check if we need to migrate the database.
currentVersion := version.GetCurrentVersion(db.profile.Mode) currentVersion := version.GetCurrentVersion(db.profile.Mode)
migrationHistoryList, err := db.FindMigrationHistoryList(ctx, &MigrationHistoryFind{}) migrationHistoryList, err := db.FindMigrationHistoryList(ctx, &MigrationHistoryFind{})
if err != nil { if err != nil {
return fmt.Errorf("failed to find migration history, err: %w", err) return errors.Wrap(err, "failed to find migration history")
} }
if len(migrationHistoryList) == 0 { if len(migrationHistoryList) == 0 {
_, err := db.UpsertMigrationHistory(ctx, &MigrationHistoryUpsert{ _, err := db.UpsertMigrationHistory(ctx, &MigrationHistoryUpsert{
Version: currentVersion, Version: currentVersion,
}) })
if err != nil { if err != nil {
return fmt.Errorf("failed to upsert migration history, err: %w", err) return errors.Wrap(err, "failed to upsert migration history")
} }
return nil return nil
} }
@ -103,11 +104,11 @@ func (db *DB) Open(ctx context.Context) (err error) {
// backup the raw database file before migration // backup the raw database file before migration
rawBytes, err := os.ReadFile(db.profile.DSN) rawBytes, err := os.ReadFile(db.profile.DSN)
if err != nil { if err != nil {
return fmt.Errorf("failed to read raw database file, err: %w", err) return errors.Wrap(err, "failed to read raw database file")
} }
backupDBFilePath := fmt.Sprintf("%s/slash_%s_%d_backup.db", db.profile.Data, db.profile.Version, time.Now().Unix()) backupDBFilePath := fmt.Sprintf("%s/slash_%s_%d_backup.db", db.profile.Data, db.profile.Version, time.Now().Unix())
if err := os.WriteFile(backupDBFilePath, rawBytes, 0644); err != nil { if err := os.WriteFile(backupDBFilePath, rawBytes, 0644); err != nil {
return fmt.Errorf("failed to write raw database file, err: %w", err) return errors.Wrap(err, "failed to write raw database file")
} }
println("succeed to copy a backup database file") println("succeed to copy a backup database file")
@ -117,7 +118,7 @@ func (db *DB) Open(ctx context.Context) (err error) {
if version.IsVersionGreaterThan(normalizedVersion, latestMigrationHistoryVersion) && version.IsVersionGreaterOrEqualThan(currentVersion, normalizedVersion) { if version.IsVersionGreaterThan(normalizedVersion, latestMigrationHistoryVersion) && version.IsVersionGreaterOrEqualThan(currentVersion, normalizedVersion) {
println("applying migration for", normalizedVersion) println("applying migration for", normalizedVersion)
if err := db.applyMigrationForMinorVersion(ctx, minorVersion); err != nil { if err := db.applyMigrationForMinorVersion(ctx, minorVersion); err != nil {
return fmt.Errorf("failed to apply minor version migration: %w", err) return errors.Wrap(err, "failed to apply minor version migration")
} }
} }
} }
@ -133,12 +134,12 @@ func (db *DB) Open(ctx context.Context) (err error) {
// In non-prod mode, we should always migrate the database. // In non-prod mode, we should always migrate the database.
if _, err := os.Stat(db.profile.DSN); errors.Is(err, os.ErrNotExist) { if _, err := os.Stat(db.profile.DSN); errors.Is(err, os.ErrNotExist) {
if err := db.applyLatestSchema(ctx); err != nil { if err := db.applyLatestSchema(ctx); err != nil {
return fmt.Errorf("failed to apply latest schema: %w", err) return errors.Wrap(err, "failed to apply latest schema")
} }
// In demo mode, we should seed the database. // In demo mode, we should seed the database.
if db.profile.Mode == "demo" { if db.profile.Mode == "demo" {
if err := db.seed(ctx); err != nil { if err := db.seed(ctx); err != nil {
return fmt.Errorf("failed to seed: %w", err) return errors.Wrap(err, "failed to seed")
} }
} }
} }
@ -159,11 +160,11 @@ func (db *DB) applyLatestSchema(ctx context.Context) error {
latestSchemaPath := fmt.Sprintf("%s/%s/%s", "migration", schemaMode, latestSchemaFileName) latestSchemaPath := fmt.Sprintf("%s/%s/%s", "migration", schemaMode, latestSchemaFileName)
buf, err := migrationFS.ReadFile(latestSchemaPath) buf, err := migrationFS.ReadFile(latestSchemaPath)
if err != nil { if err != nil {
return fmt.Errorf("failed to read latest schema %q, error %w", latestSchemaPath, err) return errors.Wrapf(err, "failed to read latest schema %q", latestSchemaPath)
} }
stmt := string(buf) stmt := string(buf)
if err := db.execute(ctx, stmt); err != nil { if err := db.execute(ctx, stmt); err != nil {
return fmt.Errorf("migrate error: statement:%s err=%w", stmt, err) return errors.Wrapf(err, "migrate error: statement %s", stmt)
} }
return nil return nil
} }
@ -171,7 +172,7 @@ func (db *DB) applyLatestSchema(ctx context.Context) error {
func (db *DB) applyMigrationForMinorVersion(ctx context.Context, minorVersion string) error { func (db *DB) applyMigrationForMinorVersion(ctx context.Context, minorVersion string) error {
filenames, err := fs.Glob(migrationFS, fmt.Sprintf("%s/%s/*.sql", "migration/prod", minorVersion)) filenames, err := fs.Glob(migrationFS, fmt.Sprintf("%s/%s/*.sql", "migration/prod", minorVersion))
if err != nil { if err != nil {
return fmt.Errorf("failed to read ddl files, err: %w", err) return errors.Wrap(err, "failed to read ddl files")
} }
sort.Strings(filenames) sort.Strings(filenames)
@ -181,12 +182,12 @@ func (db *DB) applyMigrationForMinorVersion(ctx context.Context, minorVersion st
for _, filename := range filenames { for _, filename := range filenames {
buf, err := migrationFS.ReadFile(filename) buf, err := migrationFS.ReadFile(filename)
if err != nil { if err != nil {
return fmt.Errorf("failed to read minor version migration file, filename=%s err=%w", filename, err) return errors.Wrapf(err, "failed to read minor version migration file, filename %s", filename)
} }
stmt := string(buf) stmt := string(buf)
migrationStmt += stmt migrationStmt += stmt
if err := db.execute(ctx, stmt); err != nil { if err := db.execute(ctx, stmt); err != nil {
return fmt.Errorf("migrate error: statement:%s err=%w", stmt, err) return errors.Wrapf(err, "migrate error: statement %s", stmt)
} }
} }
@ -195,7 +196,7 @@ func (db *DB) applyMigrationForMinorVersion(ctx context.Context, minorVersion st
if _, err = db.UpsertMigrationHistory(ctx, &MigrationHistoryUpsert{ if _, err = db.UpsertMigrationHistory(ctx, &MigrationHistoryUpsert{
Version: version, Version: version,
}); err != nil { }); err != nil {
return fmt.Errorf("failed to upsert migration history with version: %s, err: %w", version, err) return errors.Wrapf(err, "failed to upsert migration history with version %s", version)
} }
return nil return nil
@ -204,7 +205,7 @@ func (db *DB) applyMigrationForMinorVersion(ctx context.Context, minorVersion st
func (db *DB) seed(ctx context.Context) error { func (db *DB) seed(ctx context.Context) error {
filenames, err := fs.Glob(seedFS, fmt.Sprintf("%s/*.sql", "seed")) filenames, err := fs.Glob(seedFS, fmt.Sprintf("%s/*.sql", "seed"))
if err != nil { if err != nil {
return fmt.Errorf("failed to read seed files, err: %w", err) return errors.Wrap(err, "failed to read seed files")
} }
sort.Strings(filenames) sort.Strings(filenames)
@ -213,11 +214,11 @@ func (db *DB) seed(ctx context.Context) error {
for _, filename := range filenames { for _, filename := range filenames {
buf, err := seedFS.ReadFile(filename) buf, err := seedFS.ReadFile(filename)
if err != nil { if err != nil {
return fmt.Errorf("failed to read seed file, filename=%s err=%w", filename, err) return errors.Wrapf(err, "failed to read seed file, filename %s", filename)
} }
stmt := string(buf) stmt := string(buf)
if err := db.execute(ctx, stmt); err != nil { if err := db.execute(ctx, stmt); err != nil {
return fmt.Errorf("seed error: statement:%s err=%w", stmt, err) return errors.Wrapf(err, "seed error: statement %s", stmt)
} }
} }
return nil return nil
@ -226,7 +227,7 @@ func (db *DB) seed(ctx context.Context) error {
// execute runs a single SQL statement within a transaction. // execute runs a single SQL statement within a transaction.
func (db *DB) execute(ctx context.Context, stmt string) error { func (db *DB) execute(ctx context.Context, stmt string) error {
if _, err := db.DBInstance.ExecContext(ctx, stmt); err != nil { if _, err := db.DBInstance.ExecContext(ctx, stmt); err != nil {
return fmt.Errorf("failed to execute statement, err: %w", err) return errors.Wrap(err, "failed to execute statement")
} }
return nil return nil

View File

@ -27,7 +27,7 @@ VALUES
( (
102, 102,
'USER', 'USER',
'steven@usememos.com', 'steven@yourselfhosted.com',
'Steven', 'Steven',
-- raw password: secret -- raw password: secret
'$2a$14$ajq8Q7fbtFRQvXpdCq7Jcuy.Rx1h/L4J60Otx.gyNLbAYctGMJ9tK' '$2a$14$ajq8Q7fbtFRQvXpdCq7Jcuy.Rx1h/L4J60Otx.gyNLbAYctGMJ9tK'

View File

@ -4,11 +4,13 @@ import (
"context" "context"
"database/sql" "database/sql"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"strings" "strings"
storepb "github.com/boojack/slash/proto/gen/store"
"google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/encoding/protojson"
storepb "github.com/boojack/slash/proto/gen/store"
) )
// Visibility is the type of a visibility. // Visibility is the type of a visibility.
@ -134,7 +136,7 @@ func (s *Store) UpdateShortcut(ctx context.Context, update *UpdateShortcut) (*st
set, args = append(set, "og_metadata = ?"), append(args, string(openGraphMetadataBytes)) set, args = append(set, "og_metadata = ?"), append(args, string(openGraphMetadataBytes))
} }
if len(set) == 0 { if len(set) == 0 {
return nil, fmt.Errorf("no update specified") return nil, errors.New("no update specified")
} }
args = append(args, update.ID) args = append(args, update.ID)

View File

@ -2,7 +2,7 @@ package store
import ( import (
"context" "context"
"fmt" "errors"
"strings" "strings"
) )
@ -102,7 +102,7 @@ func (s *Store) UpdateUser(ctx context.Context, update *UpdateUser) (*User, erro
} }
if len(set) == 0 { if len(set) == 0 {
return nil, fmt.Errorf("no fields to update") return nil, errors.New("no fields to update")
} }
stmt := ` stmt := `

View File

@ -6,8 +6,9 @@ import (
"errors" "errors"
"strings" "strings"
storepb "github.com/boojack/slash/proto/gen/store"
"google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/encoding/protojson"
storepb "github.com/boojack/slash/proto/gen/store"
) )
type FindUserSetting struct { type FindUserSetting struct {

View File

@ -6,8 +6,9 @@ import (
"strconv" "strconv"
"strings" "strings"
storepb "github.com/boojack/slash/proto/gen/store"
"google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/encoding/protojson"
storepb "github.com/boojack/slash/proto/gen/store"
) )
type FindWorkspaceSetting struct { type FindWorkspaceSetting struct {

View File

@ -6,9 +6,10 @@ import (
"encoding/json" "encoding/json"
"testing" "testing"
apiv1 "github.com/boojack/slash/api/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
apiv1 "github.com/boojack/slash/api/v1"
) )
func TestAuthServer(t *testing.T) { func TestAuthServer(t *testing.T) {

View File

@ -10,16 +10,16 @@ import (
"testing" "testing"
"time" "time"
"github.com/pkg/errors"
// sqlite driver.
_ "modernc.org/sqlite"
"github.com/boojack/slash/api/auth" "github.com/boojack/slash/api/auth"
"github.com/boojack/slash/server" "github.com/boojack/slash/server"
"github.com/boojack/slash/server/profile" "github.com/boojack/slash/server/profile"
"github.com/boojack/slash/store" "github.com/boojack/slash/store"
"github.com/boojack/slash/store/db" "github.com/boojack/slash/store/db"
"github.com/boojack/slash/test" "github.com/boojack/slash/test"
"github.com/pkg/errors"
// sqlite driver.
_ "modernc.org/sqlite"
) )
type TestingServer struct { type TestingServer struct {

View File

@ -7,9 +7,10 @@ import (
"fmt" "fmt"
"testing" "testing"
apiv1 "github.com/boojack/slash/api/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
apiv1 "github.com/boojack/slash/api/v1"
) )
func TestShortcutServer(t *testing.T) { func TestShortcutServer(t *testing.T) {

View File

@ -7,9 +7,10 @@ import (
"fmt" "fmt"
"testing" "testing"
apiv1 "github.com/boojack/slash/api/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
apiv1 "github.com/boojack/slash/api/v1"
) )
func TestUserServer(t *testing.T) { func TestUserServer(t *testing.T) {
@ -31,7 +32,7 @@ func TestUserServer(t *testing.T) {
user, err = s.getUserByID(user.ID) user, err = s.getUserByID(user.ID)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, signup.Email, user.Email) require.Equal(t, signup.Email, user.Email)
newEmail := "test@usermemos.com" newEmail := "test@yourselfhosted.com"
userPatch := &apiv1.PatchUserRequest{ userPatch := &apiv1.PatchUserRequest{
Email: &newEmail, Email: &newEmail,
} }

View File

@ -4,8 +4,9 @@ import (
"context" "context"
"testing" "testing"
"github.com/boojack/slash/store"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/boojack/slash/store"
) )
func TestActivityStore(t *testing.T) { func TestActivityStore(t *testing.T) {

View File

@ -4,9 +4,10 @@ import (
"context" "context"
"testing" "testing"
"github.com/stretchr/testify/require"
storepb "github.com/boojack/slash/proto/gen/store" storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store" "github.com/boojack/slash/store"
"github.com/stretchr/testify/require"
) )
func TestShortcutStore(t *testing.T) { func TestShortcutStore(t *testing.T) {

View File

@ -5,12 +5,12 @@ import (
"fmt" "fmt"
"testing" "testing"
// sqlite driver.
_ "modernc.org/sqlite"
"github.com/boojack/slash/store" "github.com/boojack/slash/store"
"github.com/boojack/slash/store/db" "github.com/boojack/slash/store/db"
test "github.com/boojack/slash/test" test "github.com/boojack/slash/test"
// sqlite driver.
_ "modernc.org/sqlite"
) )
func NewTestingStore(ctx context.Context, t *testing.T) *store.Store { func NewTestingStore(ctx context.Context, t *testing.T) *store.Store {

View File

@ -4,9 +4,10 @@ import (
"context" "context"
"testing" "testing"
"github.com/stretchr/testify/require"
storepb "github.com/boojack/slash/proto/gen/store" storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store" "github.com/boojack/slash/store"
"github.com/stretchr/testify/require"
) )
func TestUserSettingStore(t *testing.T) { func TestUserSettingStore(t *testing.T) {

View File

@ -4,10 +4,11 @@ import (
"context" "context"
"testing" "testing"
storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store"
) )
func TestUserStore(t *testing.T) { func TestUserStore(t *testing.T) {

View File

@ -4,10 +4,11 @@ import (
"context" "context"
"testing" "testing"
storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
storepb "github.com/boojack/slash/proto/gen/store"
"github.com/boojack/slash/store"
) )
func TestWorkspaceSettingStore(t *testing.T) { func TestWorkspaceSettingStore(t *testing.T) {