diff --git a/bin/slash/main.go b/bin/slash/main.go index 98ee3f5..13e0d31 100644 --- a/bin/slash/main.go +++ b/bin/slash/main.go @@ -15,6 +15,7 @@ import ( "github.com/yourselfhosted/slash/server" "github.com/yourselfhosted/slash/server/metric" "github.com/yourselfhosted/slash/server/profile" + "github.com/yourselfhosted/slash/server/version" "github.com/yourselfhosted/slash/store" "github.com/yourselfhosted/slash/store/db" ) @@ -24,36 +25,47 @@ const ( ) var ( - serverProfile *profile.Profile - mode string - port int - data string - driver string - dsn string - enableMetric bool - rootCmd = &cobra.Command{ Use: "slash", Short: `An open source, self-hosted links shortener and sharing platform.`, Run: func(_ *cobra.Command, _ []string) { + serverProfile := &profile.Profile{ + Mode: viper.GetString("mode"), + Port: viper.GetInt("port"), + Data: viper.GetString("data"), + DSN: viper.GetString("dsn"), + Driver: viper.GetString("driver"), + Public: viper.GetBool("public"), + InstanceURL: viper.GetString("instance-url"), + Version: version.GetCurrentVersion(viper.GetString("mode")), + } + if err := serverProfile.Validate(); err != nil { + panic(err) + } + ctx, cancel := context.WithCancel(context.Background()) dbDriver, err := db.NewDBDriver(serverProfile) if err != nil { cancel() - slog.Error("failed to create db driver", err) + slog.Error("failed to create db driver", "error", err) return } if err := dbDriver.Migrate(ctx); err != nil { cancel() - slog.Error("failed to migrate db", err) + slog.Error("failed to migrate db", "error", err) return } storeInstance := store.New(dbDriver, serverProfile) + if err := storeInstance.MigrateWorkspaceSettings(ctx); err != nil { + cancel() + slog.Error("failed to migrate workspace settings", "error", err) + return + } s, err := server.NewServer(ctx, serverProfile, storeInstance) if err != nil { cancel() - slog.Error("failed to create server", err) + slog.Error("failed to create server", "error", err) return } @@ -74,11 +86,11 @@ var ( cancel() }() - printGreetings() + printGreetings(serverProfile) if err := s.Start(ctx); err != nil { if err != http.ErrServerClosed { - slog.Error("failed to start server", err) + slog.Error("failed to start server", "error", err) cancel() } } @@ -89,71 +101,60 @@ var ( } ) -func Execute() error { - return rootCmd.Execute() -} - func init() { - cobra.OnInitialize(initConfig) - - rootCmd.PersistentFlags().StringVarP(&mode, "mode", "m", "demo", `mode of server, can be "prod" or "dev" or "demo"`) - rootCmd.PersistentFlags().IntVarP(&port, "port", "p", 8082, "port of server") - rootCmd.PersistentFlags().StringVarP(&data, "data", "d", "", "data directory") - rootCmd.PersistentFlags().StringVarP(&driver, "driver", "", "", "database driver") - rootCmd.PersistentFlags().StringVarP(&dsn, "dsn", "", "", "database source name(aka. DSN)") - rootCmd.PersistentFlags().BoolVarP(&enableMetric, "metric", "", true, "allow metric collection") - - err := viper.BindPFlag("mode", rootCmd.PersistentFlags().Lookup("mode")) - if err != nil { - panic(err) - } - err = viper.BindPFlag("port", rootCmd.PersistentFlags().Lookup("port")) - if err != nil { - panic(err) - } - err = viper.BindPFlag("data", rootCmd.PersistentFlags().Lookup("data")) - if err != nil { - panic(err) - } - err = viper.BindPFlag("driver", rootCmd.PersistentFlags().Lookup("driver")) - if err != nil { - panic(err) - } - err = viper.BindPFlag("dsn", rootCmd.PersistentFlags().Lookup("dsn")) - if err != nil { - panic(err) - } - err = viper.BindPFlag("metric", rootCmd.PersistentFlags().Lookup("metric")) - if err != nil { - panic(err) - } - viper.SetDefault("mode", "demo") - viper.SetDefault("port", 8082) viper.SetDefault("driver", "sqlite") - viper.SetDefault("metric", true) + viper.SetDefault("port", 8082) + viper.SetDefault("public", true) + + rootCmd.PersistentFlags().String("mode", "demo", `mode of server, can be "prod" or "dev" or "demo"`) + rootCmd.PersistentFlags().String("addr", "", "address of server") + rootCmd.PersistentFlags().Int("port", 8082, "port of server") + rootCmd.PersistentFlags().String("data", "", "data directory") + rootCmd.PersistentFlags().String("driver", "sqlite", "database driver") + rootCmd.PersistentFlags().String("dsn", "", "database source name(aka. DSN)") + rootCmd.PersistentFlags().Bool("public", true, "") + rootCmd.PersistentFlags().String("instance-url", "", "URL of the instance") + + if err := viper.BindPFlag("mode", rootCmd.PersistentFlags().Lookup("mode")); err != nil { + panic(err) + } + if err := viper.BindPFlag("port", rootCmd.PersistentFlags().Lookup("port")); err != nil { + panic(err) + } + if err := viper.BindPFlag("data", rootCmd.PersistentFlags().Lookup("data")); err != nil { + panic(err) + } + if err := viper.BindPFlag("driver", rootCmd.PersistentFlags().Lookup("driver")); err != nil { + panic(err) + } + if err := viper.BindPFlag("dsn", rootCmd.PersistentFlags().Lookup("dsn")); err != nil { + panic(err) + } + if err := viper.BindPFlag("public", rootCmd.PersistentFlags().Lookup("public")); err != nil { + panic(err) + } + if err := viper.BindPFlag("instance-url", rootCmd.PersistentFlags().Lookup("instance-url")); err != nil { + panic(err) + } + viper.SetEnvPrefix("slash") + viper.AutomaticEnv() + if err := viper.BindEnv("instance-url", "SLASH_INSTANCE_URL"); err != nil { + panic(err) + } } -func initConfig() { - viper.AutomaticEnv() - var err error - serverProfile, err = profile.GetProfile() - if err != nil { - slog.Error("failed to get profile", err) - return - } - +func printGreetings(serverProfile *profile.Profile) { println("---") println("Server profile") println("dsn:", serverProfile.DSN) println("port:", serverProfile.Port) println("mode:", serverProfile.Mode) println("version:", serverProfile.Version) + println("public:", serverProfile.Public) + println("instance-url:", serverProfile.InstanceURL) println("---") -} - -func printGreetings() { println(greetingBanner) fmt.Printf("Version %s has been started on port %d\n", serverProfile.Version, serverProfile.Port) println("---") @@ -163,8 +164,7 @@ func printGreetings() { } func main() { - err := Execute() - if err != nil { + if err := rootCmd.Execute(); err != nil { panic(err) } } diff --git a/frontend/web/src/components/LinkFavicon.tsx b/frontend/web/src/components/LinkFavicon.tsx index 1eeb650..22851a8 100644 --- a/frontend/web/src/components/LinkFavicon.tsx +++ b/frontend/web/src/components/LinkFavicon.tsx @@ -1,5 +1,4 @@ import { useState } from "react"; -import { useWorkspaceStore } from "@/stores"; import Icon from "./Icon"; interface Props { @@ -18,8 +17,7 @@ const getFaviconUrlWithProvider = (url: string, provider: string) => { const LinkFavicon = (props: Props) => { const { url } = props; - const workspaceStore = useWorkspaceStore(); - const faviconProvider = workspaceStore.profile.faviconProvider || "https://www.google.com/s2/favicons"; + const faviconProvider = "https://www.google.com/s2/favicons"; const [faviconUrl, setFaviconUrl] = useState(getFaviconUrlWithProvider(url, faviconProvider)); const handleImgError = () => { diff --git a/frontend/web/src/components/setting/WorkspaceSection.tsx b/frontend/web/src/components/setting/WorkspaceSection.tsx index 62ac505..86a9a4c 100644 --- a/frontend/web/src/components/setting/WorkspaceSection.tsx +++ b/frontend/web/src/components/setting/WorkspaceSection.tsx @@ -1,4 +1,4 @@ -import { Button, Input, Link, Option, Select, Switch, Textarea } from "@mui/joy"; +import { Button, Option, Select, Textarea } from "@mui/joy"; import { isEqual } from "lodash-es"; import { useRef, useState } from "react"; import toast from "react-hot-toast"; @@ -7,7 +7,6 @@ import { workspaceServiceClient } from "@/grpcweb"; import { useWorkspaceStore } from "@/stores"; import { Visibility } from "@/types/proto/api/v1/common"; import { WorkspaceSetting } from "@/types/proto/api/v1/workspace_service"; -import BetaBadge from "../BetaBadge"; const getDefaultVisibility = (visibility?: Visibility) => { if (!visibility || [Visibility.VISIBILITY_UNSPECIFIED, Visibility.UNRECOGNIZED].includes(visibility)) { @@ -24,27 +23,6 @@ const WorkspaceSection = () => { const originalWorkspaceSetting = useRef(workspaceStore.setting); const allowSave = !isEqual(originalWorkspaceSetting.current, workspaceSetting); - const handleEnableSignUpChange = async (value: boolean) => { - setWorkspaceSetting({ - ...workspaceSetting, - enableSignup: value, - }); - }; - - const handleInstanceUrlChange = async (value: string) => { - setWorkspaceSetting({ - ...workspaceSetting, - instanceUrl: value, - }); - }; - - const handleFaviconProvierChange = async (value: string) => { - setWorkspaceSetting({ - ...workspaceSetting, - faviconProvider: value, - }); - }; - const handleCustomStyleChange = async (value: string) => { setWorkspaceSetting({ ...workspaceSetting, @@ -61,21 +39,12 @@ const WorkspaceSection = () => { const handleSaveWorkspaceSetting = async () => { const updateMask: string[] = []; - if (!isEqual(originalWorkspaceSetting.current.enableSignup, workspaceSetting.enableSignup)) { - updateMask.push("enable_signup"); - } - if (!isEqual(originalWorkspaceSetting.current.instanceUrl, workspaceSetting.instanceUrl)) { - updateMask.push("instance_url"); - } if (!isEqual(originalWorkspaceSetting.current.customStyle, workspaceSetting.customStyle)) { updateMask.push("custom_style"); } if (!isEqual(originalWorkspaceSetting.current.defaultVisibility, workspaceSetting.defaultVisibility)) { updateMask.push("default_visibility"); } - if (!isEqual(originalWorkspaceSetting.current.faviconProvider, workspaceSetting.faviconProvider)) { - updateMask.push("favicon_provider"); - } if (updateMask.length === 0) { toast.error("No changes made"); return; @@ -101,33 +70,6 @@ const WorkspaceSection = () => {

{t("settings.workspace.self")}

-
-
-

Instance URL

-

- {"Mainly used for SEO and social sharing. Leave empty to disallow crawlers."} -

-
- handleInstanceUrlChange(event.target.value)} - /> -
-
-
-

{t("settings.workspace.enable-user-signup.self")}

-

{t("settings.workspace.enable-user-signup.description")}

-
-
- handleEnableSignUpChange(event.target.checked)} - /> -
-

{t("settings.workspace.default-visibility")}

@@ -143,24 +85,6 @@ const WorkspaceSection = () => {
-
-
-

Favicon provider

- -
-

- e.g.{" "} - - yourselfhosted/favicons - -

- handleFaviconProvierChange(event.target.value)} - /> -

{t("settings.workspace.custom-style")}