From 70cece72d93e706564e51e8ef856b33a8aec1151 Mon Sep 17 00:00:00 2001 From: qwqcode Date: Sat, 8 Jun 2024 16:04:05 +0800 Subject: [PATCH] perf(gravatar): support both sha256 and md5 hashing algorithm for gravatar --- conf/artalk.example.simple.yml | 2 +- conf/artalk.example.yml | 2 +- conf/artalk.example.zh-CN.yml | 4 +- docs/docs/.vitepress/theme/Artalk.vue | 3 -- docs/docs/guide/env.md | 4 +- docs/docs/guide/frontend/config.md | 8 +++- internal/config/cache.go | 2 +- internal/config/utils.go | 19 ++++++++ internal/config/utils_test.go | 51 +++++++++++++++++++++ internal/core/base.go | 15 ++++-- internal/dao/cook.go | 13 +++++- ui/artalk-sidebar/src/components/Header.vue | 13 ++---- ui/artalk-sidebar/src/stores/user.ts | 20 ++++++++ ui/artalk/src/defaults.ts | 4 +- 14 files changed, 129 insertions(+), 31 deletions(-) create mode 100644 internal/config/utils.go create mode 100644 internal/config/utils_test.go diff --git a/conf/artalk.example.simple.yml b/conf/artalk.example.simple.yml index 87c8f657..ef1205df 100644 --- a/conf/artalk.example.simple.yml +++ b/conf/artalk.example.simple.yml @@ -236,7 +236,7 @@ frontend: nestSort: DATE_ASC gravatar: mirror: https://www.gravatar.com/avatar/ - params: d=mp&s=240 + params: sha256=1&d=mp&s=240 pagination: pageSize: 20 readMore: true diff --git a/conf/artalk.example.yml b/conf/artalk.example.yml index 7ac03392..c51c1dc6 100644 --- a/conf/artalk.example.yml +++ b/conf/artalk.example.yml @@ -419,7 +419,7 @@ frontend: # API URL mirror: https://www.gravatar.com/avatar/ # API parameters - params: d=mp&s=240 + params: sha256=1&d=mp&s=240 # Comment pagination pagination: # Number of comments per page diff --git a/conf/artalk.example.zh-CN.yml b/conf/artalk.example.zh-CN.yml index 9f04f483..ef2e6f00 100644 --- a/conf/artalk.example.zh-CN.yml +++ b/conf/artalk.example.zh-CN.yml @@ -425,9 +425,9 @@ frontend: # 头像 Gravatar gravatar: # API 地址 - mirror: https://cravatar.cn/avatar/ + mirror: https://weavatar.com/avatar/ # API 参数 - params: d=mp&s=240 + params: sha256=1&d=mp&s=240 # 评论分页 pagination: # 每页评论数 diff --git a/docs/docs/.vitepress/theme/Artalk.vue b/docs/docs/.vitepress/theme/Artalk.vue index 71232e52..441c09b2 100644 --- a/docs/docs/.vitepress/theme/Artalk.vue +++ b/docs/docs/.vitepress/theme/Artalk.vue @@ -42,9 +42,6 @@ function initArtalk(conf: any) { artalk = Artalk.init({ el: el.value, emoticons: '/assets/emoticons/default.json', - gravatar: { - mirror: 'https://cravatar.cn/avatar/', - }, ...conf, }) diff --git a/docs/docs/guide/env.md b/docs/docs/guide/env.md index b1f1842c..cefe2b50 100644 --- a/docs/docs/guide/env.md +++ b/docs/docs/guide/env.md @@ -251,8 +251,8 @@ ATK_TRUSTED_DOMAINS_0="https://a.com" | **ATK_FRONTEND_EDITORTRAVEL** | `true` | 评论框穿梭 | frontend.editorTravel (界面配置 > 评论框穿梭) | | **ATK_FRONTEND_EMOTICONS** | `"https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json"` | 表情包 | frontend.emoticons (界面配置 > 表情包) | | **ATK_FRONTEND_FLATMODE** | `"auto"` | 平铺模式 (可选:`["auto", "true", "false"]`) | frontend.flatMode (界面配置 > 平铺模式) | -| **ATK_FRONTEND_GRAVATAR_MIRROR** | `"https://cravatar.cn/avatar/"` | API 地址 | frontend.gravatar.mirror (界面配置 > 头像 Gravatar > API 地址) | -| **ATK_FRONTEND_GRAVATAR_PARAMS** | `"d=mp&s=240"` | API 参数 | frontend.gravatar.params (界面配置 > 头像 Gravatar > API 参数) | +| **ATK_FRONTEND_GRAVATAR_MIRROR** | `"https://weavatar.com/avatar/"` | API 地址 | frontend.gravatar.mirror (界面配置 > 头像 Gravatar > API 地址) | +| **ATK_FRONTEND_GRAVATAR_PARAMS** | `"sha256=1&d=mp&s=240"` | API 参数 | frontend.gravatar.params (界面配置 > 头像 Gravatar > API 参数) | | **ATK_FRONTEND_HEIGHTLIMIT_CHILDREN** | `400` | 子评论区域限高 (单位:px) | frontend.heightLimit.children (界面配置 > 内容限高 > 子评论区域限高) | | **ATK_FRONTEND_HEIGHTLIMIT_CONTENT** | `300` | 评论内容限高 (单位:px) | frontend.heightLimit.content (界面配置 > 内容限高 > 评论内容限高) | | **ATK_FRONTEND_HEIGHTLIMIT_SCROLLABLE** | `false` | 滚动限高 (允许限高区域滚动) | frontend.heightLimit.scrollable (界面配置 > 内容限高 > 滚动限高) | diff --git a/docs/docs/guide/frontend/config.md b/docs/docs/guide/frontend/config.md index 732ce080..1932569c 100644 --- a/docs/docs/guide/frontend/config.md +++ b/docs/docs/guide/frontend/config.md @@ -358,12 +358,14 @@ gravatar: { **Gravatar 镜像地址** - 类型:`String` -- 默认值:`"https://sdn.geekzu.org/avatar/"` +- 默认值:`"https://www.gravatar.com/avatar/"` 如果你觉得 Gravatar 头像加载速度不理想,可以尝试替换。 例如: +> WeAvatar:https://weavatar.com/avatar/ +> > Cravatar:https://cravatar.cn/avatar/ > > V2EX:https://cdn.v2ex.com/gravatar/ @@ -377,7 +379,7 @@ gravatar: { **Gravatar API 参数** - 类型:`String` -- 默认值:`"d=mp&s=240"` +- 默认值:`"sha256=1&d=mp&s=240"` 例如,你可以通过该配置项设置默认头像 (`d=mp`) 和头像尺寸 (`s=240`)。 @@ -387,6 +389,8 @@ gravatar: { ::: warning 更新注意 +v2.8.7 支持通过 SHA256 加密算法生成 Gravatar 头像链接,以提高用户隐私保护,请在 `params` 中填入 `sha256=1` 启用该加密([#874](https://github.com/ArtalkJS/Artalk/issues/874))。 + v2.5.5 已废弃 `gravatar.default` 配置项,请使用 `gravatar.params` 替代。 ::: diff --git a/internal/config/cache.go b/internal/config/cache.go index 6c71351e..72978628 100644 --- a/internal/config/cache.go +++ b/internal/config/cache.go @@ -8,4 +8,4 @@ import "github.com/ArtalkJS/Artalk/internal/config/meta" var EnvPathMapCache = map[string]string{"ATK_ADMIN_NOTIFY_BARK_ENABLED":"admin_notify.bark.enabled", "ATK_ADMIN_NOTIFY_BARK_SERVER":"admin_notify.bark.server", "ATK_ADMIN_NOTIFY_DING_TALK_ENABLED":"admin_notify.ding_talk.enabled", "ATK_ADMIN_NOTIFY_DING_TALK_SECRET":"admin_notify.ding_talk.secret", "ATK_ADMIN_NOTIFY_DING_TALK_TOKEN":"admin_notify.ding_talk.token", "ATK_ADMIN_NOTIFY_EMAIL":"admin_notify.email", "ATK_ADMIN_NOTIFY_EMAIL_ENABLED":"admin_notify.email.enabled", "ATK_ADMIN_NOTIFY_EMAIL_MAIL_SUBJECT":"admin_notify.email.mail_subject", "ATK_ADMIN_NOTIFY_EMAIL_MAIL_TPL":"admin_notify.email.mail_tpl", "ATK_ADMIN_NOTIFY_LARK_ENABLED":"admin_notify.lark.enabled", "ATK_ADMIN_NOTIFY_LARK_MSG_TYPE":"admin_notify.lark.msg_type", "ATK_ADMIN_NOTIFY_LARK_WEBHOOK_URL":"admin_notify.lark.webhook_url", "ATK_ADMIN_NOTIFY_LINE_CHANNEL_ACCESS_TOKEN":"admin_notify.line.channel_access_token", "ATK_ADMIN_NOTIFY_LINE_CHANNEL_SECRET":"admin_notify.line.channel_secret", "ATK_ADMIN_NOTIFY_LINE_ENABLED":"admin_notify.line.enabled", "ATK_ADMIN_NOTIFY_LINE_RECEIVERS":"admin_notify.line.receivers", "ATK_ADMIN_NOTIFY_LINE_RECEIVERS_$$":"admin_notify.line.receivers.$$", "ATK_ADMIN_NOTIFY_NOISE_MODE":"admin_notify.noise_mode", "ATK_ADMIN_NOTIFY_NOTIFY_PENDING":"admin_notify.notify_pending", "ATK_ADMIN_NOTIFY_NOTIFY_SUBJECT":"admin_notify.notify_subject", "ATK_ADMIN_NOTIFY_NOTIFY_TPL":"admin_notify.notify_tpl", "ATK_ADMIN_NOTIFY_SLACK_ENABLED":"admin_notify.slack.enabled", "ATK_ADMIN_NOTIFY_SLACK_OAUTH_TOKEN":"admin_notify.slack.oauth_token", "ATK_ADMIN_NOTIFY_SLACK_RECEIVERS":"admin_notify.slack.receivers", "ATK_ADMIN_NOTIFY_SLACK_RECEIVERS_$$":"admin_notify.slack.receivers.$$", "ATK_ADMIN_NOTIFY_TELEGRAM_API_TOKEN":"admin_notify.telegram.api_token", "ATK_ADMIN_NOTIFY_TELEGRAM_ENABLED":"admin_notify.telegram.enabled", "ATK_ADMIN_NOTIFY_TELEGRAM_RECEIVERS":"admin_notify.telegram.receivers", "ATK_ADMIN_NOTIFY_TELEGRAM_RECEIVERS_$$":"admin_notify.telegram.receivers.$$", "ATK_ADMIN_NOTIFY_WEBHOOK_ENABLED":"admin_notify.webhook.enabled", "ATK_ADMIN_NOTIFY_WEBHOOK_URL":"admin_notify.webhook.url", "ATK_ADMIN_USERS_$$_BADGE_COLOR":"admin_users.$$.badge_color", "ATK_ADMIN_USERS_$$_BADGE_NAME":"admin_users.$$.badge_name", "ATK_ADMIN_USERS_$$_EMAIL":"admin_users.$$.email", "ATK_ADMIN_USERS_$$_LINK":"admin_users.$$.link", "ATK_ADMIN_USERS_$$_NAME":"admin_users.$$.name", "ATK_ADMIN_USERS_$$_PASSWORD":"admin_users.$$.password", "ATK_ADMIN_USERS_$$_RECEIVE_EMAIL":"admin_users.$$.receive_email", "ATK_ADMIN__NOTIFY_BARK_ENABLED":"admin_notify.bark.enabled", "ATK_ADMIN__NOTIFY_BARK_SERVER":"admin_notify.bark.server", "ATK_ADMIN__NOTIFY_DING__TALK_ENABLED":"admin_notify.ding_talk.enabled", "ATK_ADMIN__NOTIFY_DING__TALK_SECRET":"admin_notify.ding_talk.secret", "ATK_ADMIN__NOTIFY_DING__TALK_TOKEN":"admin_notify.ding_talk.token", "ATK_ADMIN__NOTIFY_EMAIL":"admin_notify.email", "ATK_ADMIN__NOTIFY_LARK_ENABLED":"admin_notify.lark.enabled", "ATK_ADMIN__NOTIFY_LARK_MSG__TYPE":"admin_notify.lark.msg_type", "ATK_ADMIN__NOTIFY_LARK_WEBHOOK__URL":"admin_notify.lark.webhook_url", "ATK_ADMIN__NOTIFY_LINE_CHANNEL__ACCESS__TOKEN":"admin_notify.line.channel_access_token", "ATK_ADMIN__NOTIFY_LINE_CHANNEL__SECRET":"admin_notify.line.channel_secret", "ATK_ADMIN__NOTIFY_LINE_ENABLED":"admin_notify.line.enabled", "ATK_ADMIN__NOTIFY_LINE_RECEIVERS_$$":"admin_notify.line.receivers.$$", "ATK_ADMIN__NOTIFY_NOISE__MODE":"admin_notify.noise_mode", "ATK_ADMIN__NOTIFY_NOTIFY__PENDING":"admin_notify.notify_pending", "ATK_ADMIN__NOTIFY_NOTIFY__SUBJECT":"admin_notify.notify_subject", "ATK_ADMIN__NOTIFY_NOTIFY__TPL":"admin_notify.notify_tpl", "ATK_ADMIN__NOTIFY_SLACK_ENABLED":"admin_notify.slack.enabled", "ATK_ADMIN__NOTIFY_SLACK_OAUTH__TOKEN":"admin_notify.slack.oauth_token", "ATK_ADMIN__NOTIFY_SLACK_RECEIVERS_$$":"admin_notify.slack.receivers.$$", "ATK_ADMIN__NOTIFY_TELEGRAM_API__TOKEN":"admin_notify.telegram.api_token", "ATK_ADMIN__NOTIFY_TELEGRAM_ENABLED":"admin_notify.telegram.enabled", "ATK_ADMIN__NOTIFY_TELEGRAM_RECEIVERS_$$":"admin_notify.telegram.receivers.$$", "ATK_ADMIN__NOTIFY_WEBHOOK_ENABLED":"admin_notify.webhook.enabled", "ATK_ADMIN__NOTIFY_WEBHOOK_URL":"admin_notify.webhook.url", "ATK_ADMIN__USERS_$$_BADGE__COLOR":"admin_users.$$.badge_color", "ATK_ADMIN__USERS_$$_BADGE__NAME":"admin_users.$$.badge_name", "ATK_ADMIN__USERS_$$_EMAIL":"admin_users.$$.email", "ATK_ADMIN__USERS_$$_LINK":"admin_users.$$.link", "ATK_ADMIN__USERS_$$_NAME":"admin_users.$$.name", "ATK_ADMIN__USERS_$$_PASSWORD":"admin_users.$$.password", "ATK_ADMIN__USERS_$$_RECEIVE__EMAIL":"admin_users.$$.receive_email", "ATK_APP_KEY":"app_key", "ATK_APP__KEY":"app_key", "ATK_AUTH_ANONYMOUS":"auth.anonymous", "ATK_AUTH_APPLE_CLIENT_ID":"auth.apple.client_id", "ATK_AUTH_APPLE_CLIENT_SECRET":"auth.apple.client_secret", "ATK_AUTH_APPLE_CLIENT__ID":"auth.apple.client_id", "ATK_AUTH_APPLE_CLIENT__SECRET":"auth.apple.client_secret", "ATK_AUTH_APPLE_ENABLED":"auth.apple.enabled", "ATK_AUTH_AUTH0_CLIENT_ID":"auth.auth0.client_id", "ATK_AUTH_AUTH0_CLIENT_SECRET":"auth.auth0.client_secret", "ATK_AUTH_AUTH0_CLIENT__ID":"auth.auth0.client_id", "ATK_AUTH_AUTH0_CLIENT__SECRET":"auth.auth0.client_secret", "ATK_AUTH_AUTH0_DOMAIN":"auth.auth0.domain", "ATK_AUTH_AUTH0_ENABLED":"auth.auth0.enabled", "ATK_AUTH_CALLBACK":"auth.callback", "ATK_AUTH_DISCORD_CLIENT_ID":"auth.discord.client_id", "ATK_AUTH_DISCORD_CLIENT_SECRET":"auth.discord.client_secret", "ATK_AUTH_DISCORD_CLIENT__ID":"auth.discord.client_id", "ATK_AUTH_DISCORD_CLIENT__SECRET":"auth.discord.client_secret", "ATK_AUTH_DISCORD_ENABLED":"auth.discord.enabled", "ATK_AUTH_EMAIL_ENABLED":"auth.email.enabled", "ATK_AUTH_EMAIL_VERIFY_SUBJECT":"auth.email.verify_subject", "ATK_AUTH_EMAIL_VERIFY_TPL":"auth.email.verify_tpl", "ATK_AUTH_EMAIL_VERIFY__SUBJECT":"auth.email.verify_subject", "ATK_AUTH_EMAIL_VERIFY__TPL":"auth.email.verify_tpl", "ATK_AUTH_ENABLED":"auth.enabled", "ATK_AUTH_FACEBOOK_CLIENT_ID":"auth.facebook.client_id", "ATK_AUTH_FACEBOOK_CLIENT_SECRET":"auth.facebook.client_secret", "ATK_AUTH_FACEBOOK_CLIENT__ID":"auth.facebook.client_id", "ATK_AUTH_FACEBOOK_CLIENT__SECRET":"auth.facebook.client_secret", "ATK_AUTH_FACEBOOK_ENABLED":"auth.facebook.enabled", "ATK_AUTH_GITEA_CLIENT_ID":"auth.gitea.client_id", "ATK_AUTH_GITEA_CLIENT_SECRET":"auth.gitea.client_secret", "ATK_AUTH_GITEA_CLIENT__ID":"auth.gitea.client_id", "ATK_AUTH_GITEA_CLIENT__SECRET":"auth.gitea.client_secret", "ATK_AUTH_GITEA_ENABLED":"auth.gitea.enabled", "ATK_AUTH_GITHUB_CLIENT_ID":"auth.github.client_id", "ATK_AUTH_GITHUB_CLIENT_SECRET":"auth.github.client_secret", "ATK_AUTH_GITHUB_CLIENT__ID":"auth.github.client_id", "ATK_AUTH_GITHUB_CLIENT__SECRET":"auth.github.client_secret", "ATK_AUTH_GITHUB_ENABLED":"auth.github.enabled", "ATK_AUTH_GITLAB_CLIENT_ID":"auth.gitlab.client_id", "ATK_AUTH_GITLAB_CLIENT_SECRET":"auth.gitlab.client_secret", "ATK_AUTH_GITLAB_CLIENT__ID":"auth.gitlab.client_id", "ATK_AUTH_GITLAB_CLIENT__SECRET":"auth.gitlab.client_secret", "ATK_AUTH_GITLAB_ENABLED":"auth.gitlab.enabled", "ATK_AUTH_GOOGLE_CLIENT_ID":"auth.google.client_id", "ATK_AUTH_GOOGLE_CLIENT_SECRET":"auth.google.client_secret", "ATK_AUTH_GOOGLE_CLIENT__ID":"auth.google.client_id", "ATK_AUTH_GOOGLE_CLIENT__SECRET":"auth.google.client_secret", "ATK_AUTH_GOOGLE_ENABLED":"auth.google.enabled", "ATK_AUTH_LINE_CLIENT_ID":"auth.line.client_id", "ATK_AUTH_LINE_CLIENT_SECRET":"auth.line.client_secret", "ATK_AUTH_LINE_CLIENT__ID":"auth.line.client_id", "ATK_AUTH_LINE_CLIENT__SECRET":"auth.line.client_secret", "ATK_AUTH_LINE_ENABLED":"auth.line.enabled", "ATK_AUTH_MASTODON_CLIENT_ID":"auth.mastodon.client_id", "ATK_AUTH_MASTODON_CLIENT_SECRET":"auth.mastodon.client_secret", "ATK_AUTH_MASTODON_CLIENT__ID":"auth.mastodon.client_id", "ATK_AUTH_MASTODON_CLIENT__SECRET":"auth.mastodon.client_secret", "ATK_AUTH_MASTODON_ENABLED":"auth.mastodon.enabled", "ATK_AUTH_MICROSOFT_CLIENT_ID":"auth.microsoft.client_id", "ATK_AUTH_MICROSOFT_CLIENT_SECRET":"auth.microsoft.client_secret", "ATK_AUTH_MICROSOFT_CLIENT__ID":"auth.microsoft.client_id", "ATK_AUTH_MICROSOFT_CLIENT__SECRET":"auth.microsoft.client_secret", "ATK_AUTH_MICROSOFT_ENABLED":"auth.microsoft.enabled", "ATK_AUTH_PATREON_CLIENT_ID":"auth.patreon.client_id", "ATK_AUTH_PATREON_CLIENT_SECRET":"auth.patreon.client_secret", "ATK_AUTH_PATREON_CLIENT__ID":"auth.patreon.client_id", "ATK_AUTH_PATREON_CLIENT__SECRET":"auth.patreon.client_secret", "ATK_AUTH_PATREON_ENABLED":"auth.patreon.enabled", "ATK_AUTH_SLACK_CLIENT_ID":"auth.slack.client_id", "ATK_AUTH_SLACK_CLIENT_SECRET":"auth.slack.client_secret", "ATK_AUTH_SLACK_CLIENT__ID":"auth.slack.client_id", "ATK_AUTH_SLACK_CLIENT__SECRET":"auth.slack.client_secret", "ATK_AUTH_SLACK_ENABLED":"auth.slack.enabled", "ATK_AUTH_STEAM_API_KEY":"auth.steam.api_key", "ATK_AUTH_STEAM_API__KEY":"auth.steam.api_key", "ATK_AUTH_STEAM_ENABLED":"auth.steam.enabled", "ATK_AUTH_TIKTOK_CLIENT_ID":"auth.tiktok.client_id", "ATK_AUTH_TIKTOK_CLIENT_SECRET":"auth.tiktok.client_secret", "ATK_AUTH_TIKTOK_CLIENT__ID":"auth.tiktok.client_id", "ATK_AUTH_TIKTOK_CLIENT__SECRET":"auth.tiktok.client_secret", "ATK_AUTH_TIKTOK_ENABLED":"auth.tiktok.enabled", "ATK_AUTH_TWITTER_CLIENT_ID":"auth.twitter.client_id", "ATK_AUTH_TWITTER_CLIENT_SECRET":"auth.twitter.client_secret", "ATK_AUTH_TWITTER_CLIENT__ID":"auth.twitter.client_id", "ATK_AUTH_TWITTER_CLIENT__SECRET":"auth.twitter.client_secret", "ATK_AUTH_TWITTER_ENABLED":"auth.twitter.enabled", "ATK_AUTH_WECHAT_CLIENT_ID":"auth.wechat.client_id", "ATK_AUTH_WECHAT_CLIENT_SECRET":"auth.wechat.client_secret", "ATK_AUTH_WECHAT_CLIENT__ID":"auth.wechat.client_id", "ATK_AUTH_WECHAT_CLIENT__SECRET":"auth.wechat.client_secret", "ATK_AUTH_WECHAT_ENABLED":"auth.wechat.enabled", "ATK_CACHE_ENABLED":"cache.enabled", "ATK_CACHE_EXPIRES":"cache.expires", "ATK_CACHE_REDIS_DB":"cache.redis.db", "ATK_CACHE_REDIS_NETWORK":"cache.redis.network", "ATK_CACHE_REDIS_PASSWORD":"cache.redis.password", "ATK_CACHE_REDIS_USERNAME":"cache.redis.username", "ATK_CACHE_SERVER":"cache.server", "ATK_CACHE_TYPE":"cache.type", "ATK_CACHE_WARM_UP":"cache.warm_up", "ATK_CACHE_WARM__UP":"cache.warm_up", "ATK_CAPTCHA_ACTION_LIMIT":"captcha.action_limit", "ATK_CAPTCHA_ACTION_RESET":"captcha.action_reset", "ATK_CAPTCHA_ACTION__LIMIT":"captcha.action_limit", "ATK_CAPTCHA_ACTION__RESET":"captcha.action_reset", "ATK_CAPTCHA_ALWAYS":"captcha.always", "ATK_CAPTCHA_CAPTCHA_TYPE":"captcha.captcha_type", "ATK_CAPTCHA_CAPTCHA__TYPE":"captcha.captcha_type", "ATK_CAPTCHA_ENABLED":"captcha.enabled", "ATK_CAPTCHA_GEETEST_CAPTCHA_ID":"captcha.geetest.captcha_id", "ATK_CAPTCHA_GEETEST_CAPTCHA_KEY":"captcha.geetest.captcha_key", "ATK_CAPTCHA_GEETEST_CAPTCHA__ID":"captcha.geetest.captcha_id", "ATK_CAPTCHA_GEETEST_CAPTCHA__KEY":"captcha.geetest.captcha_key", "ATK_CAPTCHA_HCAPTCHA_SECRET_KEY":"captcha.hcaptcha.secret_key", "ATK_CAPTCHA_HCAPTCHA_SECRET__KEY":"captcha.hcaptcha.secret_key", "ATK_CAPTCHA_HCAPTCHA_SITE_KEY":"captcha.hcaptcha.site_key", "ATK_CAPTCHA_HCAPTCHA_SITE__KEY":"captcha.hcaptcha.site_key", "ATK_CAPTCHA_RECAPTCHA_SECRET_KEY":"captcha.recaptcha.secret_key", "ATK_CAPTCHA_RECAPTCHA_SECRET__KEY":"captcha.recaptcha.secret_key", "ATK_CAPTCHA_RECAPTCHA_SITE_KEY":"captcha.recaptcha.site_key", "ATK_CAPTCHA_RECAPTCHA_SITE__KEY":"captcha.recaptcha.site_key", "ATK_CAPTCHA_TURNSTILE_SECRET_KEY":"captcha.turnstile.secret_key", "ATK_CAPTCHA_TURNSTILE_SECRET__KEY":"captcha.turnstile.secret_key", "ATK_CAPTCHA_TURNSTILE_SITE_KEY":"captcha.turnstile.site_key", "ATK_CAPTCHA_TURNSTILE_SITE__KEY":"captcha.turnstile.site_key", "ATK_DB_CHARSET":"db.charset", "ATK_DB_DSN":"db.dsn", "ATK_DB_FILE":"db.file", "ATK_DB_HOST":"db.host", "ATK_DB_NAME":"db.name", "ATK_DB_PASSWORD":"db.password", "ATK_DB_PORT":"db.port", "ATK_DB_PREPARE_STMT":"db.prepare_stmt", "ATK_DB_PREPARE__STMT":"db.prepare_stmt", "ATK_DB_SSL":"db.ssl", "ATK_DB_TABLE_PREFIX":"db.table_prefix", "ATK_DB_TABLE__PREFIX":"db.table_prefix", "ATK_DB_TYPE":"db.type", "ATK_DB_USER":"db.user", "ATK_DEBUG":"debug", "ATK_EMAIL_ALI_DM_ACCESS_KEY_ID":"email.ali_dm.access_key_id", "ATK_EMAIL_ALI_DM_ACCESS_KEY_SECRET":"email.ali_dm.access_key_secret", "ATK_EMAIL_ALI_DM_ACCOUNT_NAME":"email.ali_dm.account_name", "ATK_EMAIL_ALI_DM_REGION":"email.ali_dm.region", "ATK_EMAIL_ALI__DM_ACCESS__KEY__ID":"email.ali_dm.access_key_id", "ATK_EMAIL_ALI__DM_ACCESS__KEY__SECRET":"email.ali_dm.access_key_secret", "ATK_EMAIL_ALI__DM_ACCOUNT__NAME":"email.ali_dm.account_name", "ATK_EMAIL_ALI__DM_REGION":"email.ali_dm.region", "ATK_EMAIL_ENABLED":"email.enabled", "ATK_EMAIL_MAIL_SUBJECT":"email.mail_subject", "ATK_EMAIL_MAIL_TPL":"email.mail_tpl", "ATK_EMAIL_MAIL__SUBJECT":"email.mail_subject", "ATK_EMAIL_MAIL__TPL":"email.mail_tpl", "ATK_EMAIL_QUEUE_BUFFER_SIZE":"email.queue.buffer_size", "ATK_EMAIL_QUEUE_BUFFER__SIZE":"email.queue.buffer_size", "ATK_EMAIL_SEND_ADDR":"email.send_addr", "ATK_EMAIL_SEND_NAME":"email.send_name", "ATK_EMAIL_SEND_TYPE":"email.send_type", "ATK_EMAIL_SEND__ADDR":"email.send_addr", "ATK_EMAIL_SEND__NAME":"email.send_name", "ATK_EMAIL_SEND__TYPE":"email.send_type", "ATK_EMAIL_SMTP_FROM":"email.smtp.from", "ATK_EMAIL_SMTP_HOST":"email.smtp.host", "ATK_EMAIL_SMTP_PASSWORD":"email.smtp.password", "ATK_EMAIL_SMTP_PORT":"email.smtp.port", "ATK_EMAIL_SMTP_USERNAME":"email.smtp.username", "ATK_FRONTEND":"frontend", "ATK_FRONTEND_DARKMODE":"frontend.darkMode", "ATK_FRONTEND_EDITORTRAVEL":"frontend.editorTravel", "ATK_FRONTEND_EMOTICONS":"frontend.emoticons", "ATK_FRONTEND_FLATMODE":"frontend.flatMode", "ATK_FRONTEND_GRAVATAR_MIRROR":"frontend.gravatar.mirror", "ATK_FRONTEND_GRAVATAR_PARAMS":"frontend.gravatar.params", "ATK_FRONTEND_HEIGHTLIMIT_CHILDREN":"frontend.heightLimit.children", "ATK_FRONTEND_HEIGHTLIMIT_CONTENT":"frontend.heightLimit.content", "ATK_FRONTEND_HEIGHTLIMIT_SCROLLABLE":"frontend.heightLimit.scrollable", "ATK_FRONTEND_IMGLAZYLOAD":"frontend.imgLazyLoad", "ATK_FRONTEND_LISTSORT":"frontend.listSort", "ATK_FRONTEND_NESTMAX":"frontend.nestMax", "ATK_FRONTEND_NESTSORT":"frontend.nestSort", "ATK_FRONTEND_NOCOMMENT":"frontend.noComment", "ATK_FRONTEND_PAGINATION_AUTOLOAD":"frontend.pagination.autoLoad", "ATK_FRONTEND_PAGINATION_PAGESIZE":"frontend.pagination.pageSize", "ATK_FRONTEND_PAGINATION_READMORE":"frontend.pagination.readMore", "ATK_FRONTEND_PLACEHOLDER":"frontend.placeholder", "ATK_FRONTEND_PLUGINURLS":"frontend.pluginURLs", "ATK_FRONTEND_PREVIEW":"frontend.preview", "ATK_FRONTEND_REQTIMEOUT":"frontend.reqTimeout", "ATK_FRONTEND_SENDBTN":"frontend.sendBtn", "ATK_FRONTEND_UABADGE":"frontend.uaBadge", "ATK_FRONTEND_VERSIONCHECK":"frontend.versionCheck", "ATK_FRONTEND_VOTE":"frontend.vote", "ATK_FRONTEND_VOTEDOWN":"frontend.voteDown", "ATK_HOST":"host", "ATK_HTTP_BODY_LIMIT":"http.body_limit", "ATK_HTTP_BODY__LIMIT":"http.body_limit", "ATK_HTTP_PROXY_HEADER":"http.proxy_header", "ATK_HTTP_PROXY__HEADER":"http.proxy_header", "ATK_IMG_UPLOAD_ENABLED":"img_upload.enabled", "ATK_IMG_UPLOAD_MAX_SIZE":"img_upload.max_size", "ATK_IMG_UPLOAD_PATH":"img_upload.path", "ATK_IMG_UPLOAD_PUBLIC_PATH":"img_upload.public_path", "ATK_IMG_UPLOAD_QUALITY":"img_upload.quality", "ATK_IMG_UPLOAD_UPGIT_DEL_LOCAL":"img_upload.upgit.del_local", "ATK_IMG_UPLOAD_UPGIT_ENABLED":"img_upload.upgit.enabled", "ATK_IMG_UPLOAD_UPGIT_EXEC":"img_upload.upgit.exec", "ATK_IMG__UPLOAD_ENABLED":"img_upload.enabled", "ATK_IMG__UPLOAD_MAX__SIZE":"img_upload.max_size", "ATK_IMG__UPLOAD_PATH":"img_upload.path", "ATK_IMG__UPLOAD_PUBLIC__PATH":"img_upload.public_path", "ATK_IMG__UPLOAD_QUALITY":"img_upload.quality", "ATK_IMG__UPLOAD_UPGIT_DEL__LOCAL":"img_upload.upgit.del_local", "ATK_IMG__UPLOAD_UPGIT_ENABLED":"img_upload.upgit.enabled", "ATK_IMG__UPLOAD_UPGIT_EXEC":"img_upload.upgit.exec", "ATK_IP_REGION_DB_PATH":"ip_region.db_path", "ATK_IP_REGION_ENABLED":"ip_region.enabled", "ATK_IP_REGION_PRECISION":"ip_region.precision", "ATK_IP__REGION_DB__PATH":"ip_region.db_path", "ATK_IP__REGION_ENABLED":"ip_region.enabled", "ATK_IP__REGION_PRECISION":"ip_region.precision", "ATK_LOCALE":"locale", "ATK_LOGIN_TIMEOUT":"login_timeout", "ATK_LOGIN__TIMEOUT":"login_timeout", "ATK_LOG_ENABLED":"log.enabled", "ATK_LOG_FILENAME":"log.filename", "ATK_MODERATOR_AKISMET_KEY":"moderator.akismet_key", "ATK_MODERATOR_AKISMET__KEY":"moderator.akismet_key", "ATK_MODERATOR_ALIYUN_ACCESS_KEY_ID":"moderator.aliyun.access_key_id", "ATK_MODERATOR_ALIYUN_ACCESS_KEY_SECRET":"moderator.aliyun.access_key_secret", "ATK_MODERATOR_ALIYUN_ACCESS__KEY__ID":"moderator.aliyun.access_key_id", "ATK_MODERATOR_ALIYUN_ACCESS__KEY__SECRET":"moderator.aliyun.access_key_secret", "ATK_MODERATOR_ALIYUN_ENABLED":"moderator.aliyun.enabled", "ATK_MODERATOR_ALIYUN_REGION":"moderator.aliyun.region", "ATK_MODERATOR_API_FAIL_BLOCK":"moderator.api_fail_block", "ATK_MODERATOR_API__FAIL__BLOCK":"moderator.api_fail_block", "ATK_MODERATOR_KEYWORDS_ENABLED":"moderator.keywords.enabled", "ATK_MODERATOR_KEYWORDS_FILES":"moderator.keywords.files", "ATK_MODERATOR_KEYWORDS_FILES_$$":"moderator.keywords.files.$$", "ATK_MODERATOR_KEYWORDS_FILE_SEP":"moderator.keywords.file_sep", "ATK_MODERATOR_KEYWORDS_FILE__SEP":"moderator.keywords.file_sep", "ATK_MODERATOR_KEYWORDS_PENDING":"moderator.keywords.pending", "ATK_MODERATOR_KEYWORDS_REPLACE_TO":"moderator.keywords.replace_to", "ATK_MODERATOR_KEYWORDS_REPLACE__TO":"moderator.keywords.replace_to", "ATK_MODERATOR_PENDING_DEFAULT":"moderator.pending_default", "ATK_MODERATOR_PENDING__DEFAULT":"moderator.pending_default", "ATK_MODERATOR_TENCENT_ENABLED":"moderator.tencent.enabled", "ATK_MODERATOR_TENCENT_REGION":"moderator.tencent.region", "ATK_MODERATOR_TENCENT_SECRET_ID":"moderator.tencent.secret_id", "ATK_MODERATOR_TENCENT_SECRET_KEY":"moderator.tencent.secret_key", "ATK_MODERATOR_TENCENT_SECRET__ID":"moderator.tencent.secret_id", "ATK_MODERATOR_TENCENT_SECRET__KEY":"moderator.tencent.secret_key", "ATK_PORT":"port", "ATK_SITE_DEFAULT":"site_default", "ATK_SITE__DEFAULT":"site_default", "ATK_SSL_CERT_PATH":"ssl.cert_path", "ATK_SSL_CERT__PATH":"ssl.cert_path", "ATK_SSL_ENABLED":"ssl.enabled", "ATK_SSL_KEY_PATH":"ssl.key_path", "ATK_SSL_KEY__PATH":"ssl.key_path", "ATK_TIMEZONE":"timezone", "ATK_TRUSTED_DOMAINS":"trusted_domains", "ATK_TRUSTED_DOMAINS_$$":"trusted_domains.$$", "ATK_TRUSTED__DOMAINS_$$":"trusted_domains.$$"} // Cache result of `meta.GetOptionsMetaData(config.Template("en"))` -var OptionsMetaCache = []meta.OptionsMeta{meta.OptionsMeta{Title:"Multi-Push", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY", Path:"admin_notify", PathText:"Multi-Push", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Multi-Push"}, meta.OptionsMeta{Title:"Bark", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_BARK", Path:"admin_notify.bark", PathText:"Multi-Push > Bark", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Bark"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_BARK_ENABLED", Path:"admin_notify.bark.enabled", PathText:"Multi-Push > Bark > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Server", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_BARK_SERVER", Path:"admin_notify.bark.server", PathText:"Multi-Push > Bark > Server", Default:"http://day.app/xxxxxxx/", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Server"}, meta.OptionsMeta{Title:"DingTalk", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_DING_TALK", Path:"admin_notify.ding_talk", PathText:"Multi-Push > DingTalk", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"DingTalk"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_DING_TALK_ENABLED", Path:"admin_notify.ding_talk.enabled", PathText:"Multi-Push > DingTalk > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Secret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_DING_TALK_SECRET", Path:"admin_notify.ding_talk.secret", PathText:"Multi-Push > DingTalk > Secret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Secret"}, meta.OptionsMeta{Title:"Token", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_DING_TALK_TOKEN", Path:"admin_notify.ding_talk.token", PathText:"Multi-Push > DingTalk > Token", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Token"}, meta.OptionsMeta{Title:"Notify admin", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_EMAIL", Path:"admin_notify.email", PathText:"Multi-Push > Notify admin", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Notify admin"}, meta.OptionsMeta{Title:"Enable", Desc:"can be disabled when using other push methods", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_EMAIL_ENABLED", Path:"admin_notify.email.enabled", PathText:"Multi-Push > Notify admin > Enable", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable (can be disabled when using other push methods)"}, meta.OptionsMeta{Title:"Email subject", Desc:"email subject sent to admin", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_EMAIL_MAIL_SUBJECT", Path:"admin_notify.email.mail_subject", PathText:"Multi-Push > Notify admin > Email subject", Default:"[{{site_name}}] Post \"{{page_title}}\" has new a comment", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Email subject (email subject sent to admin)"}, meta.OptionsMeta{Title:"Admin email template file", Desc:"set to file path to use custom template", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_EMAIL_MAIL_TPL", Path:"admin_notify.email.mail_tpl", PathText:"Multi-Push > Notify admin > Admin email template file", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Admin email template file (set to file path to use custom template)"}, meta.OptionsMeta{Title:"Lark", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_LARK", Path:"admin_notify.lark", PathText:"Multi-Push > Lark", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Lark"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_LARK_ENABLED", Path:"admin_notify.lark.enabled", PathText:"Multi-Push > Lark > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Message type", Desc:"", Type:"string", Options:[]string{"text", "card"}, Env:"ATK_ADMIN_NOTIFY_LARK_MSG_TYPE", Path:"admin_notify.lark.msg_type", PathText:"Multi-Push > Lark > Message type", Default:"text", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Message type [\"text\", \"card\"]"}, meta.OptionsMeta{Title:"WebhookUrl", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_LARK_WEBHOOK_URL", Path:"admin_notify.lark.webhook_url", PathText:"Multi-Push > Lark > WebhookUrl", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"WebhookUrl"}, meta.OptionsMeta{Title:"LINE", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_LINE", Path:"admin_notify.line", PathText:"Multi-Push > LINE", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"LINE"}, meta.OptionsMeta{Title:"ChannelAccessToken", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_LINE_CHANNEL_ACCESS_TOKEN", Path:"admin_notify.line.channel_access_token", PathText:"Multi-Push > LINE > ChannelAccessToken", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ChannelAccessToken"}, meta.OptionsMeta{Title:"ChannelSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_LINE_CHANNEL_SECRET", Path:"admin_notify.line.channel_secret", PathText:"Multi-Push > LINE > ChannelSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ChannelSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_LINE_ENABLED", Path:"admin_notify.line.enabled", PathText:"Multi-Push > LINE > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Receivers", Desc:"", Type:"[]interface {}", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_LINE_RECEIVERS", Path:"admin_notify.line.receivers", PathText:"Multi-Push > LINE > Receivers", Default:[]interface {}{"USER_ID_1", "GROUP_ID_1"}, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Receivers"}, meta.OptionsMeta{Title:"Noise mode", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_NOISE_MODE", Path:"admin_notify.noise_mode", PathText:"Multi-Push > Noise mode", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Noise mode -- noise_mode is disabled by default. -- -- When this option is set to `false`, only messages sent to the administrator will be notified, -- -- such as \"user A\" replies to \"user B\", the communication between these two users will not be notified to the administrator. --"}, meta.OptionsMeta{Title:"Pending comment still send notification", Desc:"notifications are still sent when comments are intercepted", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_NOTIFY_PENDING", Path:"admin_notify.notify_pending", PathText:"Multi-Push > Pending comment still send notification", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Pending comment still send notification (notifications are still sent when comments are intercepted)"}, meta.OptionsMeta{Title:"Notification template", Desc:"set to file path to use custom template", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_NOTIFY_TPL", Path:"admin_notify.notify_tpl", PathText:"Multi-Push > Notification template", Default:"default", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Notification template (set to file path to use custom template)"}, meta.OptionsMeta{Title:"Slack", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_SLACK", Path:"admin_notify.slack", PathText:"Multi-Push > Slack", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Slack"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_SLACK_ENABLED", Path:"admin_notify.slack.enabled", PathText:"Multi-Push > Slack > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"OauthToken", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_SLACK_OAUTH_TOKEN", Path:"admin_notify.slack.oauth_token", PathText:"Multi-Push > Slack > OauthToken", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"OauthToken"}, meta.OptionsMeta{Title:"Receivers", Desc:"", Type:"[]interface {}", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_SLACK_RECEIVERS", Path:"admin_notify.slack.receivers", PathText:"Multi-Push > Slack > Receivers", Default:[]interface {}{"CHANNEL_ID"}, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Receivers"}, meta.OptionsMeta{Title:"Telegram", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_TELEGRAM", Path:"admin_notify.telegram", PathText:"Multi-Push > Telegram", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Telegram"}, meta.OptionsMeta{Title:"ApiToken", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_TELEGRAM_API_TOKEN", Path:"admin_notify.telegram.api_token", PathText:"Multi-Push > Telegram > ApiToken", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ApiToken"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_TELEGRAM_ENABLED", Path:"admin_notify.telegram.enabled", PathText:"Multi-Push > Telegram > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Receivers", Desc:"", Type:"[]interface {}", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_TELEGRAM_RECEIVERS", Path:"admin_notify.telegram.receivers", PathText:"Multi-Push > Telegram > Receivers", Default:[]interface {}{0x76adf1}, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Receivers"}, meta.OptionsMeta{Title:"WebHook", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_WEBHOOK", Path:"admin_notify.webhook", PathText:"Multi-Push > WebHook", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"WebHook"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_WEBHOOK_ENABLED", Path:"admin_notify.webhook.enabled", PathText:"Multi-Push > WebHook > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Url", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_WEBHOOK_URL", Path:"admin_notify.webhook.url", PathText:"Multi-Push > WebHook > Url", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Url"}, meta.OptionsMeta{Title:"App Key", Desc:"for generation of JWT", Type:"string", Options:[]string(nil), Env:"ATK_APP_KEY", Path:"app_key", PathText:"App Key", Default:"", IsRoot:true, HasChild:false, AllowsSet:true, CommentRaw:"App Key (for generation of JWT)"}, meta.OptionsMeta{Title:"Social Login", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH", Path:"auth", PathText:"Social Login", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Social Login"}, meta.OptionsMeta{Title:"Allow anonymous commenting", Desc:"Allow skipping verification, only fill in an anonymous nickname and email", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_ANONYMOUS", Path:"auth.anonymous", PathText:"Social Login > Allow anonymous commenting", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Allow anonymous commenting (Allow skipping verification, only fill in an anonymous nickname and email)"}, meta.OptionsMeta{Title:"Apple", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_APPLE", Path:"auth.apple", PathText:"Social Login > Apple", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Apple"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_APPLE_CLIENT_ID", Path:"auth.apple.client_id", PathText:"Social Login > Apple > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_APPLE_CLIENT_SECRET", Path:"auth.apple.client_secret", PathText:"Social Login > Apple > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_APPLE_ENABLED", Path:"auth.apple.enabled", PathText:"Social Login > Apple > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Auth0", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_AUTH0", Path:"auth.auth0", PathText:"Social Login > Auth0", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Auth0"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_AUTH0_CLIENT_ID", Path:"auth.auth0.client_id", PathText:"Social Login > Auth0 > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_AUTH0_CLIENT_SECRET", Path:"auth.auth0.client_secret", PathText:"Social Login > Auth0 > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Domain", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_AUTH0_DOMAIN", Path:"auth.auth0.domain", PathText:"Social Login > Auth0 > Domain", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Domain"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_AUTH0_ENABLED", Path:"auth.auth0.enabled", PathText:"Social Login > Auth0 > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Callback URL", Desc:"https://example.com/api/v2/auth/{provider}/callback", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_CALLBACK", Path:"auth.callback", PathText:"Social Login > Callback URL", Default:"http://localhost:23366/api/v2/auth/{provider}/callback", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Callback URL (https://example.com/api/v2/auth/{provider}/callback)"}, meta.OptionsMeta{Title:"Discord", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_DISCORD", Path:"auth.discord", PathText:"Social Login > Discord", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Discord"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_DISCORD_CLIENT_ID", Path:"auth.discord.client_id", PathText:"Social Login > Discord > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_DISCORD_CLIENT_SECRET", Path:"auth.discord.client_secret", PathText:"Social Login > Discord > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_DISCORD_ENABLED", Path:"auth.discord.enabled", PathText:"Social Login > Discord > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Email", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_EMAIL", Path:"auth.email", PathText:"Social Login > Email", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Email"}, meta.OptionsMeta{Title:"Enable email password login", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_EMAIL_ENABLED", Path:"auth.email.enabled", PathText:"Social Login > Email > Enable email password login", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable email password login"}, meta.OptionsMeta{Title:"Verification email subject", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_EMAIL_VERIFY_SUBJECT", Path:"auth.email.verify_subject", PathText:"Social Login > Email > Verification email subject", Default:"Your Code - {{code}}", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Verification email subject"}, meta.OptionsMeta{Title:"Verification email template", Desc:"set to file path to use custom template", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_EMAIL_VERIFY_TPL", Path:"auth.email.verify_tpl", PathText:"Social Login > Email > Verification email template", Default:"default", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Verification email template (set to file path to use custom template)"}, meta.OptionsMeta{Title:"Enable Social Login", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_ENABLED", Path:"auth.enabled", PathText:"Social Login > Enable Social Login", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable Social Login"}, meta.OptionsMeta{Title:"Facebook", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_FACEBOOK", Path:"auth.facebook", PathText:"Social Login > Facebook", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Facebook"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_FACEBOOK_CLIENT_ID", Path:"auth.facebook.client_id", PathText:"Social Login > Facebook > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_FACEBOOK_CLIENT_SECRET", Path:"auth.facebook.client_secret", PathText:"Social Login > Facebook > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_FACEBOOK_ENABLED", Path:"auth.facebook.enabled", PathText:"Social Login > Facebook > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Gitea", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_GITEA", Path:"auth.gitea", PathText:"Social Login > Gitea", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Gitea"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_GITEA_CLIENT_ID", Path:"auth.gitea.client_id", PathText:"Social Login > Gitea > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_GITEA_CLIENT_SECRET", Path:"auth.gitea.client_secret", PathText:"Social Login > Gitea > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_GITEA_ENABLED", Path:"auth.gitea.enabled", PathText:"Social Login > Gitea > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"GitHub", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_GITHUB", Path:"auth.github", PathText:"Social Login > GitHub", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"GitHub"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_GITHUB_CLIENT_ID", Path:"auth.github.client_id", PathText:"Social Login > GitHub > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_GITHUB_CLIENT_SECRET", Path:"auth.github.client_secret", PathText:"Social Login > GitHub > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_GITHUB_ENABLED", Path:"auth.github.enabled", PathText:"Social Login > GitHub > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"GitLab", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_GITLAB", Path:"auth.gitlab", PathText:"Social Login > GitLab", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"GitLab"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_GITLAB_CLIENT_ID", Path:"auth.gitlab.client_id", PathText:"Social Login > GitLab > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_GITLAB_CLIENT_SECRET", Path:"auth.gitlab.client_secret", PathText:"Social Login > GitLab > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_GITLAB_ENABLED", Path:"auth.gitlab.enabled", PathText:"Social Login > GitLab > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Google", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_GOOGLE", Path:"auth.google", PathText:"Social Login > Google", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Google"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_GOOGLE_CLIENT_ID", Path:"auth.google.client_id", PathText:"Social Login > Google > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_GOOGLE_CLIENT_SECRET", Path:"auth.google.client_secret", PathText:"Social Login > Google > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_GOOGLE_ENABLED", Path:"auth.google.enabled", PathText:"Social Login > Google > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Line", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_LINE", Path:"auth.line", PathText:"Social Login > Line", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Line"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_LINE_CLIENT_ID", Path:"auth.line.client_id", PathText:"Social Login > Line > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_LINE_CLIENT_SECRET", Path:"auth.line.client_secret", PathText:"Social Login > Line > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_LINE_ENABLED", Path:"auth.line.enabled", PathText:"Social Login > Line > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Mastodon", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_MASTODON", Path:"auth.mastodon", PathText:"Social Login > Mastodon", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Mastodon"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_MASTODON_CLIENT_ID", Path:"auth.mastodon.client_id", PathText:"Social Login > Mastodon > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_MASTODON_CLIENT_SECRET", Path:"auth.mastodon.client_secret", PathText:"Social Login > Mastodon > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_MASTODON_ENABLED", Path:"auth.mastodon.enabled", PathText:"Social Login > Mastodon > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Microsoft", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_MICROSOFT", Path:"auth.microsoft", PathText:"Social Login > Microsoft", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Microsoft"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_MICROSOFT_CLIENT_ID", Path:"auth.microsoft.client_id", PathText:"Social Login > Microsoft > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_MICROSOFT_CLIENT_SECRET", Path:"auth.microsoft.client_secret", PathText:"Social Login > Microsoft > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_MICROSOFT_ENABLED", Path:"auth.microsoft.enabled", PathText:"Social Login > Microsoft > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Patreon", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_PATREON", Path:"auth.patreon", PathText:"Social Login > Patreon", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Patreon"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_PATREON_CLIENT_ID", Path:"auth.patreon.client_id", PathText:"Social Login > Patreon > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_PATREON_CLIENT_SECRET", Path:"auth.patreon.client_secret", PathText:"Social Login > Patreon > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_PATREON_ENABLED", Path:"auth.patreon.enabled", PathText:"Social Login > Patreon > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Slack", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_SLACK", Path:"auth.slack", PathText:"Social Login > Slack", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Slack"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_SLACK_CLIENT_ID", Path:"auth.slack.client_id", PathText:"Social Login > Slack > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_SLACK_CLIENT_SECRET", Path:"auth.slack.client_secret", PathText:"Social Login > Slack > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_SLACK_ENABLED", Path:"auth.slack.enabled", PathText:"Social Login > Slack > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Steam", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_STEAM", Path:"auth.steam", PathText:"Social Login > Steam", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Steam"}, meta.OptionsMeta{Title:"ApiKey", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_STEAM_API_KEY", Path:"auth.steam.api_key", PathText:"Social Login > Steam > ApiKey", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ApiKey"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_STEAM_ENABLED", Path:"auth.steam.enabled", PathText:"Social Login > Steam > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Tiktok", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_TIKTOK", Path:"auth.tiktok", PathText:"Social Login > Tiktok", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Tiktok"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_TIKTOK_CLIENT_ID", Path:"auth.tiktok.client_id", PathText:"Social Login > Tiktok > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_TIKTOK_CLIENT_SECRET", Path:"auth.tiktok.client_secret", PathText:"Social Login > Tiktok > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_TIKTOK_ENABLED", Path:"auth.tiktok.enabled", PathText:"Social Login > Tiktok > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Twitter", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_TWITTER", Path:"auth.twitter", PathText:"Social Login > Twitter", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Twitter"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_TWITTER_CLIENT_ID", Path:"auth.twitter.client_id", PathText:"Social Login > Twitter > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_TWITTER_CLIENT_SECRET", Path:"auth.twitter.client_secret", PathText:"Social Login > Twitter > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_TWITTER_ENABLED", Path:"auth.twitter.enabled", PathText:"Social Login > Twitter > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"WeChat", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_WECHAT", Path:"auth.wechat", PathText:"Social Login > WeChat", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"WeChat"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_WECHAT_CLIENT_ID", Path:"auth.wechat.client_id", PathText:"Social Login > WeChat > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_WECHAT_CLIENT_SECRET", Path:"auth.wechat.client_secret", PathText:"Social Login > WeChat > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_WECHAT_ENABLED", Path:"auth.wechat.enabled", PathText:"Social Login > WeChat > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Cache", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_CACHE", Path:"cache", PathText:"Cache", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Cache"}, meta.OptionsMeta{Title:"Enable cache", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_CACHE_ENABLED", Path:"cache.enabled", PathText:"Cache > Enable cache", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable cache"}, meta.OptionsMeta{Title:"Cache expiration time", Desc:"in minutes", Type:"uint64", Options:[]string(nil), Env:"ATK_CACHE_EXPIRES", Path:"cache.expires", PathText:"Cache > Cache expiration time", Default:0x1e, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Cache expiration time (in minutes)"}, meta.OptionsMeta{Title:"Redis config", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_CACHE_REDIS", Path:"cache.redis", PathText:"Cache > Redis config", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Redis config"}, meta.OptionsMeta{Title:"Redis database number", Desc:"e.g. 0", Type:"uint64", Options:[]string(nil), Env:"ATK_CACHE_REDIS_DB", Path:"cache.redis.db", PathText:"Cache > Redis config > Redis database number", Default:0x0, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Redis database number (e.g. 0)"}, meta.OptionsMeta{Title:"Connection type", Desc:"", Type:"string", Options:[]string{"tcp", "unix"}, Env:"ATK_CACHE_REDIS_NETWORK", Path:"cache.redis.network", PathText:"Cache > Redis config > Connection type", Default:"tcp", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Connection type [\"tcp\", \"unix\"]"}, meta.OptionsMeta{Title:"Redis password", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CACHE_REDIS_PASSWORD", Path:"cache.redis.password", PathText:"Cache > Redis config > Redis password", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Redis password"}, meta.OptionsMeta{Title:"Redis username", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CACHE_REDIS_USERNAME", Path:"cache.redis.username", PathText:"Cache > Redis config > Redis username", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Redis username"}, meta.OptionsMeta{Title:"Cache server address", Desc:"e.g. \"localhost:6379\"", Type:"string", Options:[]string(nil), Env:"ATK_CACHE_SERVER", Path:"cache.server", PathText:"Cache > Cache server address", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"-- The following is not necessary for `builtin` cache -- Cache server address (e.g. \"localhost:6379\")"}, meta.OptionsMeta{Title:"Cache type", Desc:"", Type:"string", Options:[]string{"redis", "memcache", "builtin"}, Env:"ATK_CACHE_TYPE", Path:"cache.type", PathText:"Cache > Cache type", Default:"builtin", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Cache type [\"redis\", \"memcache\", \"builtin\"]"}, meta.OptionsMeta{Title:"Cache warm up", Desc:"warm up cache when program starts", Type:"bool", Options:[]string(nil), Env:"ATK_CACHE_WARM_UP", Path:"cache.warm_up", PathText:"Cache > Cache warm up", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Cache warm up (warm up cache when program starts)"}, meta.OptionsMeta{Title:"Captcha", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_CAPTCHA", Path:"captcha", PathText:"Captcha", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Captcha"}, meta.OptionsMeta{Title:"Action limit", Desc:"the number of actions required to activate captcha", Type:"uint64", Options:[]string(nil), Env:"ATK_CAPTCHA_ACTION_LIMIT", Path:"captcha.action_limit", PathText:"Captcha > Action limit", Default:0x3, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Action limit (the number of actions required to activate captcha)"}, meta.OptionsMeta{Title:"Reset Timeout", Desc:"timeout to reset action counter. unit: s, set to -1 to disable", Type:"uint64", Options:[]string(nil), Env:"ATK_CAPTCHA_ACTION_RESET", Path:"captcha.action_reset", PathText:"Captcha > Reset Timeout", Default:0x3c, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Reset Timeout (timeout to reset action counter. unit: s, set to -1 to disable)"}, meta.OptionsMeta{Title:"Captcha is required always", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_CAPTCHA_ALWAYS", Path:"captcha.always", PathText:"Captcha > Captcha is required always", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Captcha is required always"}, meta.OptionsMeta{Title:"Captcha type", Desc:"", Type:"string", Options:[]string{"image", "turnstile", "recaptcha", "hcaptcha", "geetest"}, Env:"ATK_CAPTCHA_CAPTCHA_TYPE", Path:"captcha.captcha_type", PathText:"Captcha > Captcha type", Default:"image", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Captcha type [\"image\", \"turnstile\", \"recaptcha\", \"hcaptcha\", \"geetest\"]"}, meta.OptionsMeta{Title:"Enable captcha", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_CAPTCHA_ENABLED", Path:"captcha.enabled", PathText:"Captcha > Enable captcha", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable captcha"}, meta.OptionsMeta{Title:"Geetest", Desc:"https://www.geetest.com", Type:"", Options:[]string(nil), Env:"ATK_CAPTCHA_GEETEST", Path:"captcha.geetest", PathText:"Captcha > Geetest", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Geetest (https://www.geetest.com)"}, meta.OptionsMeta{Title:"CaptchaId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CAPTCHA_GEETEST_CAPTCHA_ID", Path:"captcha.geetest.captcha_id", PathText:"Captcha > Geetest > CaptchaId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"CaptchaId"}, meta.OptionsMeta{Title:"CaptchaKey", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CAPTCHA_GEETEST_CAPTCHA_KEY", Path:"captcha.geetest.captcha_key", PathText:"Captcha > Geetest > CaptchaKey", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"CaptchaKey"}, meta.OptionsMeta{Title:"hCaptcha", Desc:"https://www.hcaptcha.com/", Type:"", Options:[]string(nil), Env:"ATK_CAPTCHA_HCAPTCHA", Path:"captcha.hcaptcha", PathText:"Captcha > hCaptcha", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"hCaptcha (https://www.hcaptcha.com/)"}, meta.OptionsMeta{Title:"SecretKey", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CAPTCHA_HCAPTCHA_SECRET_KEY", Path:"captcha.hcaptcha.secret_key", PathText:"Captcha > hCaptcha > SecretKey", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"SecretKey"}, meta.OptionsMeta{Title:"SiteKey", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CAPTCHA_HCAPTCHA_SITE_KEY", Path:"captcha.hcaptcha.site_key", PathText:"Captcha > hCaptcha > SiteKey", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"SiteKey"}, meta.OptionsMeta{Title:"reCaptcha", Desc:"https://www.google.com/recaptcha/about/", Type:"", Options:[]string(nil), Env:"ATK_CAPTCHA_RECAPTCHA", Path:"captcha.recaptcha", PathText:"Captcha > reCaptcha", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"reCaptcha (https://www.google.com/recaptcha/about/)"}, meta.OptionsMeta{Title:"SecretKey", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CAPTCHA_RECAPTCHA_SECRET_KEY", Path:"captcha.recaptcha.secret_key", PathText:"Captcha > reCaptcha > SecretKey", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"SecretKey"}, meta.OptionsMeta{Title:"SiteKey", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CAPTCHA_RECAPTCHA_SITE_KEY", Path:"captcha.recaptcha.site_key", PathText:"Captcha > reCaptcha > SiteKey", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"SiteKey"}, meta.OptionsMeta{Title:"Turnstile", Desc:"https://www.cloudflare.com/products/turnstile/", Type:"", Options:[]string(nil), Env:"ATK_CAPTCHA_TURNSTILE", Path:"captcha.turnstile", PathText:"Captcha > Turnstile", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Turnstile (https://www.cloudflare.com/products/turnstile/)"}, meta.OptionsMeta{Title:"SecretKey", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CAPTCHA_TURNSTILE_SECRET_KEY", Path:"captcha.turnstile.secret_key", PathText:"Captcha > Turnstile > SecretKey", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"SecretKey"}, meta.OptionsMeta{Title:"SiteKey", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CAPTCHA_TURNSTILE_SITE_KEY", Path:"captcha.turnstile.site_key", PathText:"Captcha > Turnstile > SiteKey", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"SiteKey"}, meta.OptionsMeta{Title:"Database", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_DB", Path:"db", PathText:"Database", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Database"}, meta.OptionsMeta{Title:"Database charset", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_DB_CHARSET", Path:"db.charset", PathText:"Database > Database charset", Default:"utf8mb4", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Database charset"}, meta.OptionsMeta{Title:"Database file", Desc:"only for SQLite", Type:"string", Options:[]string(nil), Env:"ATK_DB_FILE", Path:"db.file", PathText:"Database > Database file", Default:"./data/artalk.db", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Database file (only for SQLite)"}, meta.OptionsMeta{Title:"Host address", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_DB_HOST", Path:"db.host", PathText:"Database > Host address", Default:"localhost", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Host address"}, meta.OptionsMeta{Title:"Database name", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_DB_NAME", Path:"db.name", PathText:"Database > Database name", Default:"artalk", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"-- The following is not necessary for SQLite -- Database name"}, meta.OptionsMeta{Title:"Database password", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_DB_PASSWORD", Path:"db.password", PathText:"Database > Database password", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Database password"}, meta.OptionsMeta{Title:"Host port", Desc:"", Type:"uint64", Options:[]string(nil), Env:"ATK_DB_PORT", Path:"db.port", PathText:"Database > Host port", Default:0xcea, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Host port"}, meta.OptionsMeta{Title:"Prepared Statement", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_DB_PREPARE_STMT", Path:"db.prepare_stmt", PathText:"Database > Prepared Statement", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Prepared Statement"}, meta.OptionsMeta{Title:"Enable SSL mode", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_DB_SSL", Path:"db.ssl", PathText:"Database > Enable SSL mode", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable SSL mode"}, meta.OptionsMeta{Title:"Table prefix", Desc:"e.g. \"atk_\"", Type:"string", Options:[]string(nil), Env:"ATK_DB_TABLE_PREFIX", Path:"db.table_prefix", PathText:"Database > Table prefix", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Table prefix (e.g. \"atk_\")"}, meta.OptionsMeta{Title:"Database type", Desc:"", Type:"string", Options:[]string{"sqlite", "mysql", "pgsql", "mssql"}, Env:"ATK_DB_TYPE", Path:"db.type", PathText:"Database > Database type", Default:"sqlite", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Database type [\"sqlite\", \"mysql\", \"pgsql\", \"mssql\"]"}, meta.OptionsMeta{Title:"Database user", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_DB_USER", Path:"db.user", PathText:"Database > Database user", Default:"root", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Database user"}, meta.OptionsMeta{Title:"Debug mode", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_DEBUG", Path:"debug", PathText:"Debug mode", Default:false, IsRoot:true, HasChild:false, AllowsSet:true, CommentRaw:"Debug mode"}, meta.OptionsMeta{Title:"Email", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_EMAIL", Path:"email", PathText:"Email", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Email"}, meta.OptionsMeta{Title:"Aliyun mail push", Desc:"set send method to \"ali_dm\" to enable; see: https://help.aliyun.com/document_detail/29444.html", Type:"", Options:[]string(nil), Env:"ATK_EMAIL_ALI_DM", Path:"email.ali_dm", PathText:"Email > Aliyun mail push", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Aliyun mail push (set send method to \"ali_dm\" to enable; see: https://help.aliyun.com/document_detail/29444.html)"}, meta.OptionsMeta{Title:"AccessKeyId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_ALI_DM_ACCESS_KEY_ID", Path:"email.ali_dm.access_key_id", PathText:"Email > Aliyun mail push > AccessKeyId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"AccessKeyId"}, meta.OptionsMeta{Title:"AccessKeySecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_ALI_DM_ACCESS_KEY_SECRET", Path:"email.ali_dm.access_key_secret", PathText:"Email > Aliyun mail push > AccessKeySecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"AccessKeySecret"}, meta.OptionsMeta{Title:"AccountName", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_ALI_DM_ACCOUNT_NAME", Path:"email.ali_dm.account_name", PathText:"Email > Aliyun mail push > AccountName", Default:"noreply@example.com", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"AccountName"}, meta.OptionsMeta{Title:"Enable email notification", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_EMAIL_ENABLED", Path:"email.enabled", PathText:"Email > Enable email notification", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable email notification"}, meta.OptionsMeta{Title:"Email subject", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_MAIL_SUBJECT", Path:"email.mail_subject", PathText:"Email > Email subject", Default:"[{{site_name}}] You got a reply from @{{reply_nick}}", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Email subject"}, meta.OptionsMeta{Title:"Email template file", Desc:"set to file path to use custom template", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_MAIL_TPL", Path:"email.mail_tpl", PathText:"Email > Email template file", Default:"default", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Email template file (set to file path to use custom template)"}, meta.OptionsMeta{Title:"Email address of sender", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_SEND_ADDR", Path:"email.send_addr", PathText:"Email > Email address of sender", Default:"noreply@example.com", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Email address of sender"}, meta.OptionsMeta{Title:"Nick name of sender", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_SEND_NAME", Path:"email.send_name", PathText:"Email > Nick name of sender", Default:"{{reply_nick}}", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Nick name of sender"}, meta.OptionsMeta{Title:"Send method", Desc:"", Type:"string", Options:[]string{"smtp", "ali_dm", "sendmail"}, Env:"ATK_EMAIL_SEND_TYPE", Path:"email.send_type", PathText:"Email > Send method", Default:"smtp", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Send method [\"smtp\", \"ali_dm\", \"sendmail\"]"}, meta.OptionsMeta{Title:"SMTP send", Desc:"set send method to \"smtp\" to enable", Type:"", Options:[]string(nil), Env:"ATK_EMAIL_SMTP", Path:"email.smtp", PathText:"Email > SMTP send", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"SMTP send (set send method to \"smtp\" to enable)"}, meta.OptionsMeta{Title:"Email address of sender", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_SMTP_HOST", Path:"email.smtp.host", PathText:"Email > SMTP send > Email address of sender", Default:"smtp.qq.com", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Email address of sender"}, meta.OptionsMeta{Title:"Password", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_SMTP_PASSWORD", Path:"email.smtp.password", PathText:"Email > SMTP send > Password", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Password"}, meta.OptionsMeta{Title:"Email port", Desc:"", Type:"uint64", Options:[]string(nil), Env:"ATK_EMAIL_SMTP_PORT", Path:"email.smtp.port", PathText:"Email > SMTP send > Email port", Default:0x24b, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Email port"}, meta.OptionsMeta{Title:"Email address of sender", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_SMTP_USERNAME", Path:"email.smtp.username", PathText:"Email > SMTP send > Email address of sender", Default:"example@qq.com", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Email address of sender"}, meta.OptionsMeta{Title:"UI Settings", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_FRONTEND", Path:"frontend", PathText:"UI Settings", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"UI Settings"}, meta.OptionsMeta{Title:"Dark mode", Desc:"", Type:"string", Options:[]string{"inherit", "auto"}, Env:"ATK_FRONTEND_DARKMODE", Path:"frontend.darkMode", PathText:"UI Settings > Dark mode", Default:"inherit", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Dark mode [\"inherit\", \"auto\"]"}, meta.OptionsMeta{Title:"Movable comment box", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_EDITORTRAVEL", Path:"frontend.editorTravel", PathText:"UI Settings > Movable comment box", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Movable comment box"}, meta.OptionsMeta{Title:"Emoticons", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_FRONTEND_EMOTICONS", Path:"frontend.emoticons", PathText:"UI Settings > Emoticons", Default:"https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Emoticons"}, meta.OptionsMeta{Title:"Flatten mode", Desc:"", Type:"string", Options:[]string{"auto", "true", "false"}, Env:"ATK_FRONTEND_FLATMODE", Path:"frontend.flatMode", PathText:"UI Settings > Flatten mode", Default:"auto", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Flatten mode [\"auto\", true, false]"}, meta.OptionsMeta{Title:"Gravatar", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_FRONTEND_GRAVATAR", Path:"frontend.gravatar", PathText:"UI Settings > Gravatar", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Gravatar"}, meta.OptionsMeta{Title:"API URL", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_FRONTEND_GRAVATAR_MIRROR", Path:"frontend.gravatar.mirror", PathText:"UI Settings > Gravatar > API URL", Default:"https://www.gravatar.com/avatar/", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"API URL"}, meta.OptionsMeta{Title:"API parameters", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_FRONTEND_GRAVATAR_PARAMS", Path:"frontend.gravatar.params", PathText:"UI Settings > Gravatar > API parameters", Default:"d=mp&s=240", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"API parameters"}, meta.OptionsMeta{Title:"Content height limit", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_FRONTEND_HEIGHTLIMIT", Path:"frontend.heightLimit", PathText:"UI Settings > Content height limit", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Content height limit"}, meta.OptionsMeta{Title:"Sub-comment area height limit", Desc:"unit: px", Type:"uint64", Options:[]string(nil), Env:"ATK_FRONTEND_HEIGHTLIMIT_CHILDREN", Path:"frontend.heightLimit.children", PathText:"UI Settings > Content height limit > Sub-comment area height limit", Default:0x190, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Sub-comment area height limit (unit: px)"}, meta.OptionsMeta{Title:"Comment content height limit", Desc:"unit: px", Type:"uint64", Options:[]string(nil), Env:"ATK_FRONTEND_HEIGHTLIMIT_CONTENT", Path:"frontend.heightLimit.content", PathText:"UI Settings > Content height limit > Comment content height limit", Default:0x12c, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Comment content height limit (unit: px)"}, meta.OptionsMeta{Title:"Scrollable", Desc:"scrollable height limit area", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_HEIGHTLIMIT_SCROLLABLE", Path:"frontend.heightLimit.scrollable", PathText:"UI Settings > Content height limit > Scrollable", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Scrollable (scrollable height limit area)"}, meta.OptionsMeta{Title:"Image lazy load", Desc:"", Type:"bool", Options:[]string{"false", "native", "data-src"}, Env:"ATK_FRONTEND_IMGLAZYLOAD", Path:"frontend.imgLazyLoad", PathText:"UI Settings > Image lazy load", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Image lazy load [false, \"native\", \"data-src\"]"}, meta.OptionsMeta{Title:"Comment sorting", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_LISTSORT", Path:"frontend.listSort", PathText:"UI Settings > Comment sorting", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Comment sorting"}, meta.OptionsMeta{Title:"Maximum nesting level", Desc:"", Type:"uint64", Options:[]string(nil), Env:"ATK_FRONTEND_NESTMAX", Path:"frontend.nestMax", PathText:"UI Settings > Maximum nesting level", Default:0x2, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Maximum nesting level"}, meta.OptionsMeta{Title:"Nesting comment sorting rules", Desc:"", Type:"string", Options:[]string{"DATE_ASC", "DATE_DESC", "VOTE_UP_DESC"}, Env:"ATK_FRONTEND_NESTSORT", Path:"frontend.nestSort", PathText:"UI Settings > Nesting comment sorting rules", Default:"DATE_ASC", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Nesting comment sorting rules [\"DATE_ASC\", \"DATE_DESC\", \"VOTE_UP_DESC\"]"}, meta.OptionsMeta{Title:"Text to display when there is", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_FRONTEND_NOCOMMENT", Path:"frontend.noComment", PathText:"UI Settings > Text to display when there is", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Text to display when there is"}, meta.OptionsMeta{Title:"Comment pagination", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_FRONTEND_PAGINATION", Path:"frontend.pagination", PathText:"UI Settings > Comment pagination", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Comment pagination"}, meta.OptionsMeta{Title:"Scroll loading", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_PAGINATION_AUTOLOAD", Path:"frontend.pagination.autoLoad", PathText:"UI Settings > Comment pagination > Scroll loading", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Scroll loading"}, meta.OptionsMeta{Title:"Number of comments per page", Desc:"", Type:"uint64", Options:[]string(nil), Env:"ATK_FRONTEND_PAGINATION_PAGESIZE", Path:"frontend.pagination.pageSize", PathText:"UI Settings > Comment pagination > Number of comments per page", Default:0x14, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Number of comments per page"}, meta.OptionsMeta{Title:"Load more mode", Desc:"disabled to use pagination bar", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_PAGINATION_READMORE", Path:"frontend.pagination.readMore", PathText:"UI Settings > Comment pagination > Load more mode", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Load more mode (disabled to use pagination bar)"}, meta.OptionsMeta{Title:"Comment box placeholder", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_FRONTEND_PLACEHOLDER", Path:"frontend.placeholder", PathText:"UI Settings > Comment box placeholder", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Comment box placeholder"}, meta.OptionsMeta{Title:"Plugins", Desc:"", Type:"[]interface {}", Options:[]string(nil), Env:"ATK_FRONTEND_PLUGINURLS", Path:"frontend.pluginURLs", PathText:"UI Settings > Plugins", Default:[]interface {}{}, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Plugins"}, meta.OptionsMeta{Title:"Editor real-time preview", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_PREVIEW", Path:"frontend.preview", PathText:"UI Settings > Editor real-time preview", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Editor real-time preview"}, meta.OptionsMeta{Title:"Request timeout", Desc:"unit: ms", Type:"uint64", Options:[]string(nil), Env:"ATK_FRONTEND_REQTIMEOUT", Path:"frontend.reqTimeout", PathText:"UI Settings > Request timeout", Default:0x3a98, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Request timeout (unit: ms)"}, meta.OptionsMeta{Title:"Text of the send button", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_FRONTEND_SENDBTN", Path:"frontend.sendBtn", PathText:"UI Settings > Text of the send button", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Text of the send button"}, meta.OptionsMeta{Title:"User UA badge", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_UABADGE", Path:"frontend.uaBadge", PathText:"UI Settings > User UA badge", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"User UA badge"}, meta.OptionsMeta{Title:"Version check", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_VERSIONCHECK", Path:"frontend.versionCheck", PathText:"UI Settings > Version check", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Version check"}, meta.OptionsMeta{Title:"Vote button", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_VOTE", Path:"frontend.vote", PathText:"UI Settings > Vote button", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Vote button"}, meta.OptionsMeta{Title:"Dislike button", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_VOTEDOWN", Path:"frontend.voteDown", PathText:"UI Settings > Dislike button", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Dislike button"}, meta.OptionsMeta{Title:"Listen host", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_HOST", Path:"host", PathText:"Listen host", Default:"0.0.0.0", IsRoot:true, HasChild:false, AllowsSet:true, CommentRaw:"Listen host"}, meta.OptionsMeta{Title:"Web server", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_HTTP", Path:"http", PathText:"Web server", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Web server"}, meta.OptionsMeta{Title:"Body size limit", Desc:"unit: MB", Type:"uint64", Options:[]string(nil), Env:"ATK_HTTP_BODY_LIMIT", Path:"http.body_limit", PathText:"Web server > Body size limit", Default:0x64, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Body size limit (unit: MB)"}, meta.OptionsMeta{Title:"Proxy Header", Desc:"fill `X-Forwarded-For` to get user real IP if behind a trusted reverse proxy or CDN", Type:"string", Options:[]string(nil), Env:"ATK_HTTP_PROXY_HEADER", Path:"http.proxy_header", PathText:"Web server > Proxy Header", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Proxy Header (fill `X-Forwarded-For` to get user real IP if behind a trusted reverse proxy or CDN)"}, meta.OptionsMeta{Title:"Upload", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_IMG_UPLOAD", Path:"img_upload", PathText:"Upload", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Upload"}, meta.OptionsMeta{Title:"Enable image upload", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_IMG_UPLOAD_ENABLED", Path:"img_upload.enabled", PathText:"Upload > Enable image upload", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable image upload"}, meta.OptionsMeta{Title:"Image size limit", Desc:"unit: MB", Type:"uint64", Options:[]string(nil), Env:"ATK_IMG_UPLOAD_MAX_SIZE", Path:"img_upload.max_size", PathText:"Upload > Image size limit", Default:0x5, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Image size limit (unit: MB)"}, meta.OptionsMeta{Title:"Image storage", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_IMG_UPLOAD_PATH", Path:"img_upload.path", PathText:"Upload > Image storage", Default:"./data/artalk-img/", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Image storage"}, meta.OptionsMeta{Title:"Image link base path", Desc:"default: \"/static/images/\"", Type:"", Options:[]string(nil), Env:"ATK_IMG_UPLOAD_PUBLIC_PATH", Path:"img_upload.public_path", PathText:"Upload > Image link base path", Default:interface {}(nil), IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Image link base path (default: \"/static/images/\")"}, meta.OptionsMeta{Title:"Upgit config", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_IMG_UPLOAD_UPGIT", Path:"img_upload.upgit", PathText:"Upload > Upgit config", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Upgit config"}, meta.OptionsMeta{Title:"Delete local image after upload success", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_IMG_UPLOAD_UPGIT_DEL_LOCAL", Path:"img_upload.upgit.del_local", PathText:"Upload > Upgit config > Delete local image after upload success", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Delete local image after upload success"}, meta.OptionsMeta{Title:"Enable Upgit", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_IMG_UPLOAD_UPGIT_ENABLED", Path:"img_upload.upgit.enabled", PathText:"Upload > Upgit config > Enable Upgit", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable Upgit"}, meta.OptionsMeta{Title:"Command line arguments", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_IMG_UPLOAD_UPGIT_EXEC", Path:"img_upload.upgit.exec", PathText:"Upload > Upgit config > Command line arguments", Default:"upgit -c UPGIT_CONF_FILE_PATH -t /artalk-img", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Command line arguments"}, meta.OptionsMeta{Title:"Language", Desc:"follow Unicode BCP 47", Type:"string", Options:[]string{"en", "zh-CN", "zh-TW", "jp", "fr", "ko", "ru"}, Env:"ATK_LOCALE", Path:"locale", PathText:"Language", Default:"en", IsRoot:true, HasChild:false, AllowsSet:true, CommentRaw:"Language (follow Unicode BCP 47) [\"en\", \"zh-CN\", \"zh-TW\", \"jp\", \"fr\", \"ko\", \"ru\"] -- see https://www.techonthenet.com/js/language_tags.php --"}, meta.OptionsMeta{Title:"Logging", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_LOG", Path:"log", PathText:"Logging", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Logging"}, meta.OptionsMeta{Title:"Enable logging", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_LOG_ENABLED", Path:"log.enabled", PathText:"Logging > Enable logging", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable logging"}, meta.OptionsMeta{Title:"Log file path", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_LOG_FILENAME", Path:"log.filename", PathText:"Logging > Log file path", Default:"./data/artalk.log", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Log file path"}, meta.OptionsMeta{Title:"Login timeout", Desc:"in seconds", Type:"uint64", Options:[]string(nil), Env:"ATK_LOGIN_TIMEOUT", Path:"login_timeout", PathText:"Login timeout", Default:0x3f480, IsRoot:true, HasChild:false, AllowsSet:true, CommentRaw:"Login timeout (in seconds)"}, meta.OptionsMeta{Title:"Moderator", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_MODERATOR", Path:"moderator", PathText:"Moderator", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Moderator -- Comment examination before being public --"}, meta.OptionsMeta{Title:"Akismet Key", Desc:"Akismet anti-spam service, https://akismet.com", Type:"string", Options:[]string(nil), Env:"ATK_MODERATOR_AKISMET_KEY", Path:"moderator.akismet_key", PathText:"Moderator > Akismet Key", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Akismet Key (Akismet anti-spam service, https://akismet.com)"}, meta.OptionsMeta{Title:"Aliyun Content Security", Desc:"Auto review comments with Aliyun Content Security", Type:"", Options:[]string(nil), Env:"ATK_MODERATOR_ALIYUN", Path:"moderator.aliyun", PathText:"Moderator > Aliyun Content Security", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Aliyun Content Security (Auto review comments with Aliyun Content Security) -- see https://help.aliyun.com/document_detail/28417.html --"}, meta.OptionsMeta{Title:"AccessKeyId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_MODERATOR_ALIYUN_ACCESS_KEY_ID", Path:"moderator.aliyun.access_key_id", PathText:"Moderator > Aliyun Content Security > AccessKeyId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"AccessKeyId"}, meta.OptionsMeta{Title:"AccessKeySecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_MODERATOR_ALIYUN_ACCESS_KEY_SECRET", Path:"moderator.aliyun.access_key_secret", PathText:"Moderator > Aliyun Content Security > AccessKeySecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"AccessKeySecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_MODERATOR_ALIYUN_ENABLED", Path:"moderator.aliyun.enabled", PathText:"Moderator > Aliyun Content Security > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Region", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_MODERATOR_ALIYUN_REGION", Path:"moderator.aliyun.region", PathText:"Moderator > Aliyun Content Security > Region", Default:"cn-shanghai", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Region"}, meta.OptionsMeta{Title:"Block when API request fails", Desc:"set to false to let comments pass when API request fails", Type:"bool", Options:[]string(nil), Env:"ATK_MODERATOR_API_FAIL_BLOCK", Path:"moderator.api_fail_block", PathText:"Moderator > Block when API request fails", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Block when API request fails (set to false to let comments pass when API request fails)"}, meta.OptionsMeta{Title:"Keyword filter", Desc:"local offline dictionary", Type:"", Options:[]string(nil), Env:"ATK_MODERATOR_KEYWORDS", Path:"moderator.keywords", PathText:"Moderator > Keyword filter", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Keyword filter (local offline dictionary)"}, meta.OptionsMeta{Title:"Enable keyword filter", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_MODERATOR_KEYWORDS_ENABLED", Path:"moderator.keywords.enabled", PathText:"Moderator > Keyword filter > Enable keyword filter", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable keyword filter"}, meta.OptionsMeta{Title:"FileSep", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_MODERATOR_KEYWORDS_FILE_SEP", Path:"moderator.keywords.file_sep", PathText:"Moderator > Keyword filter > FileSep", Default:"\n", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"FileSep"}, meta.OptionsMeta{Title:"Dictionary file", Desc:"support multiple dictionary files", Type:"[]interface {}", Options:[]string(nil), Env:"ATK_MODERATOR_KEYWORDS_FILES", Path:"moderator.keywords.files", PathText:"Moderator > Keyword filter > Dictionary file", Default:[]interface {}{"./data/keywords_1.txt"}, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Dictionary file (support multiple dictionary files)"}, meta.OptionsMeta{Title:"Set to pending when match", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_MODERATOR_KEYWORDS_PENDING", Path:"moderator.keywords.pending", PathText:"Moderator > Keyword filter > Set to pending when match", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Set to pending when match"}, meta.OptionsMeta{Title:"ReplaceTo", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_MODERATOR_KEYWORDS_REPLACE_TO", Path:"moderator.keywords.replace_to", PathText:"Moderator > Keyword filter > ReplaceTo", Default:"x", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ReplaceTo"}, meta.OptionsMeta{Title:"Default pending", Desc:"new comments need to be approved by admin", Type:"bool", Options:[]string(nil), Env:"ATK_MODERATOR_PENDING_DEFAULT", Path:"moderator.pending_default", PathText:"Moderator > Default pending", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Default pending (new comments need to be approved by admin)"}, meta.OptionsMeta{Title:"Tencent Cloud Content Security", Desc:"Auto review comments with Tencent Cloud Content Security", Type:"", Options:[]string(nil), Env:"ATK_MODERATOR_TENCENT", Path:"moderator.tencent", PathText:"Moderator > Tencent Cloud Content Security", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Tencent Cloud Content Security (Auto review comments with Tencent Cloud Content Security) -- see https://cloud.tencent.com/document/product/1124/64508 --"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_MODERATOR_TENCENT_ENABLED", Path:"moderator.tencent.enabled", PathText:"Moderator > Tencent Cloud Content Security > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Region", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_MODERATOR_TENCENT_REGION", Path:"moderator.tencent.region", PathText:"Moderator > Tencent Cloud Content Security > Region", Default:"ap-guangzhou", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Region"}, meta.OptionsMeta{Title:"SecretId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_MODERATOR_TENCENT_SECRET_ID", Path:"moderator.tencent.secret_id", PathText:"Moderator > Tencent Cloud Content Security > SecretId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"SecretId"}, meta.OptionsMeta{Title:"SecretKey", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_MODERATOR_TENCENT_SECRET_KEY", Path:"moderator.tencent.secret_key", PathText:"Moderator > Tencent Cloud Content Security > SecretKey", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"SecretKey"}, meta.OptionsMeta{Title:"Listen port", Desc:"", Type:"uint64", Options:[]string(nil), Env:"ATK_PORT", Path:"port", PathText:"Listen port", Default:0x5b46, IsRoot:true, HasChild:false, AllowsSet:true, CommentRaw:"Listen port"}, meta.OptionsMeta{Title:"Default site name", Desc:"create when app is first launched", Type:"string", Options:[]string(nil), Env:"ATK_SITE_DEFAULT", Path:"site_default", PathText:"Default site name", Default:"Default Site", IsRoot:true, HasChild:false, AllowsSet:true, CommentRaw:"Default site name (create when app is first launched)"}, meta.OptionsMeta{Title:"SSL", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_SSL", Path:"ssl", PathText:"SSL", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"SSL"}, meta.OptionsMeta{Title:"Certificate file path", Desc:"e.g. \"/etc/letsencrypt/live/example.com/fullchain.pem\"", Type:"string", Options:[]string(nil), Env:"ATK_SSL_CERT_PATH", Path:"ssl.cert_path", PathText:"SSL > Certificate file path", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Certificate file path (e.g. \"/etc/letsencrypt/live/example.com/fullchain.pem\")"}, meta.OptionsMeta{Title:"Enable SSL", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_SSL_ENABLED", Path:"ssl.enabled", PathText:"SSL > Enable SSL", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable SSL"}, meta.OptionsMeta{Title:"Key file path", Desc:"e.g. \"/etc/letsencrypt/live/example.com/privkey.pem\"", Type:"string", Options:[]string(nil), Env:"ATK_SSL_KEY_PATH", Path:"ssl.key_path", PathText:"SSL > Key file path", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Key file path (e.g. \"/etc/letsencrypt/live/example.com/privkey.pem\")"}, meta.OptionsMeta{Title:"Timezone", Desc:"follow IANA Time Zone Database", Type:"string", Options:[]string(nil), Env:"ATK_TIMEZONE", Path:"timezone", PathText:"Timezone", Default:"Asia/Shanghai", IsRoot:true, HasChild:false, AllowsSet:true, CommentRaw:"Timezone (follow IANA Time Zone Database) -- see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones --"}, meta.OptionsMeta{Title:"Trusted domains", Desc:"", Type:"[]interface {}", Options:[]string(nil), Env:"ATK_TRUSTED_DOMAINS", Path:"trusted_domains", PathText:"Trusted domains", Default:[]interface {}{}, IsRoot:true, HasChild:false, AllowsSet:true, CommentRaw:"Trusted domains -- e.g. [\"https://artalk.example.com:23366\"] add url of your site her --"}} +var OptionsMetaCache = []meta.OptionsMeta{meta.OptionsMeta{Title:"Multi-Push", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY", Path:"admin_notify", PathText:"Multi-Push", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Multi-Push"}, meta.OptionsMeta{Title:"Bark", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_BARK", Path:"admin_notify.bark", PathText:"Multi-Push > Bark", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Bark"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_BARK_ENABLED", Path:"admin_notify.bark.enabled", PathText:"Multi-Push > Bark > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Server", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_BARK_SERVER", Path:"admin_notify.bark.server", PathText:"Multi-Push > Bark > Server", Default:"http://day.app/xxxxxxx/", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Server"}, meta.OptionsMeta{Title:"DingTalk", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_DING_TALK", Path:"admin_notify.ding_talk", PathText:"Multi-Push > DingTalk", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"DingTalk"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_DING_TALK_ENABLED", Path:"admin_notify.ding_talk.enabled", PathText:"Multi-Push > DingTalk > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Secret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_DING_TALK_SECRET", Path:"admin_notify.ding_talk.secret", PathText:"Multi-Push > DingTalk > Secret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Secret"}, meta.OptionsMeta{Title:"Token", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_DING_TALK_TOKEN", Path:"admin_notify.ding_talk.token", PathText:"Multi-Push > DingTalk > Token", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Token"}, meta.OptionsMeta{Title:"Notify admin", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_EMAIL", Path:"admin_notify.email", PathText:"Multi-Push > Notify admin", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Notify admin"}, meta.OptionsMeta{Title:"Enable", Desc:"can be disabled when using other push methods", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_EMAIL_ENABLED", Path:"admin_notify.email.enabled", PathText:"Multi-Push > Notify admin > Enable", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable (can be disabled when using other push methods)"}, meta.OptionsMeta{Title:"Email subject", Desc:"email subject sent to admin", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_EMAIL_MAIL_SUBJECT", Path:"admin_notify.email.mail_subject", PathText:"Multi-Push > Notify admin > Email subject", Default:"[{{site_name}}] Post \"{{page_title}}\" has new a comment", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Email subject (email subject sent to admin)"}, meta.OptionsMeta{Title:"Admin email template file", Desc:"set to file path to use custom template", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_EMAIL_MAIL_TPL", Path:"admin_notify.email.mail_tpl", PathText:"Multi-Push > Notify admin > Admin email template file", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Admin email template file (set to file path to use custom template)"}, meta.OptionsMeta{Title:"Lark", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_LARK", Path:"admin_notify.lark", PathText:"Multi-Push > Lark", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Lark"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_LARK_ENABLED", Path:"admin_notify.lark.enabled", PathText:"Multi-Push > Lark > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Message type", Desc:"", Type:"string", Options:[]string{"text", "card"}, Env:"ATK_ADMIN_NOTIFY_LARK_MSG_TYPE", Path:"admin_notify.lark.msg_type", PathText:"Multi-Push > Lark > Message type", Default:"text", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Message type [\"text\", \"card\"]"}, meta.OptionsMeta{Title:"WebhookUrl", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_LARK_WEBHOOK_URL", Path:"admin_notify.lark.webhook_url", PathText:"Multi-Push > Lark > WebhookUrl", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"WebhookUrl"}, meta.OptionsMeta{Title:"LINE", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_LINE", Path:"admin_notify.line", PathText:"Multi-Push > LINE", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"LINE"}, meta.OptionsMeta{Title:"ChannelAccessToken", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_LINE_CHANNEL_ACCESS_TOKEN", Path:"admin_notify.line.channel_access_token", PathText:"Multi-Push > LINE > ChannelAccessToken", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ChannelAccessToken"}, meta.OptionsMeta{Title:"ChannelSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_LINE_CHANNEL_SECRET", Path:"admin_notify.line.channel_secret", PathText:"Multi-Push > LINE > ChannelSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ChannelSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_LINE_ENABLED", Path:"admin_notify.line.enabled", PathText:"Multi-Push > LINE > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Receivers", Desc:"", Type:"[]interface {}", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_LINE_RECEIVERS", Path:"admin_notify.line.receivers", PathText:"Multi-Push > LINE > Receivers", Default:[]interface {}{"USER_ID_1", "GROUP_ID_1"}, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Receivers"}, meta.OptionsMeta{Title:"Noise mode", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_NOISE_MODE", Path:"admin_notify.noise_mode", PathText:"Multi-Push > Noise mode", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Noise mode -- noise_mode is disabled by default. -- -- When this option is set to `false`, only messages sent to the administrator will be notified, -- -- such as \"user A\" replies to \"user B\", the communication between these two users will not be notified to the administrator. --"}, meta.OptionsMeta{Title:"Pending comment still send notification", Desc:"notifications are still sent when comments are intercepted", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_NOTIFY_PENDING", Path:"admin_notify.notify_pending", PathText:"Multi-Push > Pending comment still send notification", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Pending comment still send notification (notifications are still sent when comments are intercepted)"}, meta.OptionsMeta{Title:"Notification template", Desc:"set to file path to use custom template", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_NOTIFY_TPL", Path:"admin_notify.notify_tpl", PathText:"Multi-Push > Notification template", Default:"default", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Notification template (set to file path to use custom template)"}, meta.OptionsMeta{Title:"Slack", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_SLACK", Path:"admin_notify.slack", PathText:"Multi-Push > Slack", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Slack"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_SLACK_ENABLED", Path:"admin_notify.slack.enabled", PathText:"Multi-Push > Slack > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"OauthToken", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_SLACK_OAUTH_TOKEN", Path:"admin_notify.slack.oauth_token", PathText:"Multi-Push > Slack > OauthToken", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"OauthToken"}, meta.OptionsMeta{Title:"Receivers", Desc:"", Type:"[]interface {}", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_SLACK_RECEIVERS", Path:"admin_notify.slack.receivers", PathText:"Multi-Push > Slack > Receivers", Default:[]interface {}{"CHANNEL_ID"}, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Receivers"}, meta.OptionsMeta{Title:"Telegram", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_TELEGRAM", Path:"admin_notify.telegram", PathText:"Multi-Push > Telegram", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Telegram"}, meta.OptionsMeta{Title:"ApiToken", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_TELEGRAM_API_TOKEN", Path:"admin_notify.telegram.api_token", PathText:"Multi-Push > Telegram > ApiToken", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ApiToken"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_TELEGRAM_ENABLED", Path:"admin_notify.telegram.enabled", PathText:"Multi-Push > Telegram > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Receivers", Desc:"", Type:"[]interface {}", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_TELEGRAM_RECEIVERS", Path:"admin_notify.telegram.receivers", PathText:"Multi-Push > Telegram > Receivers", Default:[]interface {}{0x76adf1}, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Receivers"}, meta.OptionsMeta{Title:"WebHook", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_WEBHOOK", Path:"admin_notify.webhook", PathText:"Multi-Push > WebHook", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"WebHook"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_WEBHOOK_ENABLED", Path:"admin_notify.webhook.enabled", PathText:"Multi-Push > WebHook > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Url", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_ADMIN_NOTIFY_WEBHOOK_URL", Path:"admin_notify.webhook.url", PathText:"Multi-Push > WebHook > Url", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Url"}, meta.OptionsMeta{Title:"App Key", Desc:"for generation of JWT", Type:"string", Options:[]string(nil), Env:"ATK_APP_KEY", Path:"app_key", PathText:"App Key", Default:"", IsRoot:true, HasChild:false, AllowsSet:true, CommentRaw:"App Key (for generation of JWT)"}, meta.OptionsMeta{Title:"Social Login", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH", Path:"auth", PathText:"Social Login", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Social Login"}, meta.OptionsMeta{Title:"Allow anonymous commenting", Desc:"Allow skipping verification, only fill in an anonymous nickname and email", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_ANONYMOUS", Path:"auth.anonymous", PathText:"Social Login > Allow anonymous commenting", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Allow anonymous commenting (Allow skipping verification, only fill in an anonymous nickname and email)"}, meta.OptionsMeta{Title:"Apple", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_APPLE", Path:"auth.apple", PathText:"Social Login > Apple", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Apple"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_APPLE_CLIENT_ID", Path:"auth.apple.client_id", PathText:"Social Login > Apple > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_APPLE_CLIENT_SECRET", Path:"auth.apple.client_secret", PathText:"Social Login > Apple > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_APPLE_ENABLED", Path:"auth.apple.enabled", PathText:"Social Login > Apple > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Auth0", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_AUTH0", Path:"auth.auth0", PathText:"Social Login > Auth0", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Auth0"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_AUTH0_CLIENT_ID", Path:"auth.auth0.client_id", PathText:"Social Login > Auth0 > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_AUTH0_CLIENT_SECRET", Path:"auth.auth0.client_secret", PathText:"Social Login > Auth0 > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Domain", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_AUTH0_DOMAIN", Path:"auth.auth0.domain", PathText:"Social Login > Auth0 > Domain", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Domain"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_AUTH0_ENABLED", Path:"auth.auth0.enabled", PathText:"Social Login > Auth0 > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Callback URL", Desc:"https://example.com/api/v2/auth/{provider}/callback", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_CALLBACK", Path:"auth.callback", PathText:"Social Login > Callback URL", Default:"http://localhost:23366/api/v2/auth/{provider}/callback", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Callback URL (https://example.com/api/v2/auth/{provider}/callback)"}, meta.OptionsMeta{Title:"Discord", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_DISCORD", Path:"auth.discord", PathText:"Social Login > Discord", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Discord"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_DISCORD_CLIENT_ID", Path:"auth.discord.client_id", PathText:"Social Login > Discord > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_DISCORD_CLIENT_SECRET", Path:"auth.discord.client_secret", PathText:"Social Login > Discord > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_DISCORD_ENABLED", Path:"auth.discord.enabled", PathText:"Social Login > Discord > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Email", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_EMAIL", Path:"auth.email", PathText:"Social Login > Email", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Email"}, meta.OptionsMeta{Title:"Enable email password login", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_EMAIL_ENABLED", Path:"auth.email.enabled", PathText:"Social Login > Email > Enable email password login", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable email password login"}, meta.OptionsMeta{Title:"Verification email subject", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_EMAIL_VERIFY_SUBJECT", Path:"auth.email.verify_subject", PathText:"Social Login > Email > Verification email subject", Default:"Your Code - {{code}}", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Verification email subject"}, meta.OptionsMeta{Title:"Verification email template", Desc:"set to file path to use custom template", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_EMAIL_VERIFY_TPL", Path:"auth.email.verify_tpl", PathText:"Social Login > Email > Verification email template", Default:"default", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Verification email template (set to file path to use custom template)"}, meta.OptionsMeta{Title:"Enable Social Login", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_ENABLED", Path:"auth.enabled", PathText:"Social Login > Enable Social Login", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable Social Login"}, meta.OptionsMeta{Title:"Facebook", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_FACEBOOK", Path:"auth.facebook", PathText:"Social Login > Facebook", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Facebook"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_FACEBOOK_CLIENT_ID", Path:"auth.facebook.client_id", PathText:"Social Login > Facebook > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_FACEBOOK_CLIENT_SECRET", Path:"auth.facebook.client_secret", PathText:"Social Login > Facebook > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_FACEBOOK_ENABLED", Path:"auth.facebook.enabled", PathText:"Social Login > Facebook > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Gitea", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_GITEA", Path:"auth.gitea", PathText:"Social Login > Gitea", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Gitea"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_GITEA_CLIENT_ID", Path:"auth.gitea.client_id", PathText:"Social Login > Gitea > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_GITEA_CLIENT_SECRET", Path:"auth.gitea.client_secret", PathText:"Social Login > Gitea > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_GITEA_ENABLED", Path:"auth.gitea.enabled", PathText:"Social Login > Gitea > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"GitHub", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_GITHUB", Path:"auth.github", PathText:"Social Login > GitHub", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"GitHub"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_GITHUB_CLIENT_ID", Path:"auth.github.client_id", PathText:"Social Login > GitHub > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_GITHUB_CLIENT_SECRET", Path:"auth.github.client_secret", PathText:"Social Login > GitHub > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_GITHUB_ENABLED", Path:"auth.github.enabled", PathText:"Social Login > GitHub > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"GitLab", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_GITLAB", Path:"auth.gitlab", PathText:"Social Login > GitLab", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"GitLab"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_GITLAB_CLIENT_ID", Path:"auth.gitlab.client_id", PathText:"Social Login > GitLab > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_GITLAB_CLIENT_SECRET", Path:"auth.gitlab.client_secret", PathText:"Social Login > GitLab > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_GITLAB_ENABLED", Path:"auth.gitlab.enabled", PathText:"Social Login > GitLab > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Google", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_GOOGLE", Path:"auth.google", PathText:"Social Login > Google", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Google"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_GOOGLE_CLIENT_ID", Path:"auth.google.client_id", PathText:"Social Login > Google > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_GOOGLE_CLIENT_SECRET", Path:"auth.google.client_secret", PathText:"Social Login > Google > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_GOOGLE_ENABLED", Path:"auth.google.enabled", PathText:"Social Login > Google > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Line", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_LINE", Path:"auth.line", PathText:"Social Login > Line", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Line"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_LINE_CLIENT_ID", Path:"auth.line.client_id", PathText:"Social Login > Line > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_LINE_CLIENT_SECRET", Path:"auth.line.client_secret", PathText:"Social Login > Line > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_LINE_ENABLED", Path:"auth.line.enabled", PathText:"Social Login > Line > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Mastodon", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_MASTODON", Path:"auth.mastodon", PathText:"Social Login > Mastodon", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Mastodon"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_MASTODON_CLIENT_ID", Path:"auth.mastodon.client_id", PathText:"Social Login > Mastodon > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_MASTODON_CLIENT_SECRET", Path:"auth.mastodon.client_secret", PathText:"Social Login > Mastodon > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_MASTODON_ENABLED", Path:"auth.mastodon.enabled", PathText:"Social Login > Mastodon > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Microsoft", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_MICROSOFT", Path:"auth.microsoft", PathText:"Social Login > Microsoft", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Microsoft"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_MICROSOFT_CLIENT_ID", Path:"auth.microsoft.client_id", PathText:"Social Login > Microsoft > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_MICROSOFT_CLIENT_SECRET", Path:"auth.microsoft.client_secret", PathText:"Social Login > Microsoft > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_MICROSOFT_ENABLED", Path:"auth.microsoft.enabled", PathText:"Social Login > Microsoft > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Patreon", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_PATREON", Path:"auth.patreon", PathText:"Social Login > Patreon", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Patreon"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_PATREON_CLIENT_ID", Path:"auth.patreon.client_id", PathText:"Social Login > Patreon > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_PATREON_CLIENT_SECRET", Path:"auth.patreon.client_secret", PathText:"Social Login > Patreon > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_PATREON_ENABLED", Path:"auth.patreon.enabled", PathText:"Social Login > Patreon > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Slack", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_SLACK", Path:"auth.slack", PathText:"Social Login > Slack", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Slack"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_SLACK_CLIENT_ID", Path:"auth.slack.client_id", PathText:"Social Login > Slack > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_SLACK_CLIENT_SECRET", Path:"auth.slack.client_secret", PathText:"Social Login > Slack > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_SLACK_ENABLED", Path:"auth.slack.enabled", PathText:"Social Login > Slack > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Steam", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_STEAM", Path:"auth.steam", PathText:"Social Login > Steam", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Steam"}, meta.OptionsMeta{Title:"ApiKey", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_STEAM_API_KEY", Path:"auth.steam.api_key", PathText:"Social Login > Steam > ApiKey", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ApiKey"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_STEAM_ENABLED", Path:"auth.steam.enabled", PathText:"Social Login > Steam > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Tiktok", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_TIKTOK", Path:"auth.tiktok", PathText:"Social Login > Tiktok", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Tiktok"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_TIKTOK_CLIENT_ID", Path:"auth.tiktok.client_id", PathText:"Social Login > Tiktok > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_TIKTOK_CLIENT_SECRET", Path:"auth.tiktok.client_secret", PathText:"Social Login > Tiktok > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_TIKTOK_ENABLED", Path:"auth.tiktok.enabled", PathText:"Social Login > Tiktok > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Twitter", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_TWITTER", Path:"auth.twitter", PathText:"Social Login > Twitter", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Twitter"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_TWITTER_CLIENT_ID", Path:"auth.twitter.client_id", PathText:"Social Login > Twitter > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_TWITTER_CLIENT_SECRET", Path:"auth.twitter.client_secret", PathText:"Social Login > Twitter > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_TWITTER_ENABLED", Path:"auth.twitter.enabled", PathText:"Social Login > Twitter > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"WeChat", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_AUTH_WECHAT", Path:"auth.wechat", PathText:"Social Login > WeChat", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"WeChat"}, meta.OptionsMeta{Title:"ClientId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_WECHAT_CLIENT_ID", Path:"auth.wechat.client_id", PathText:"Social Login > WeChat > ClientId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientId"}, meta.OptionsMeta{Title:"ClientSecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_AUTH_WECHAT_CLIENT_SECRET", Path:"auth.wechat.client_secret", PathText:"Social Login > WeChat > ClientSecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ClientSecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_AUTH_WECHAT_ENABLED", Path:"auth.wechat.enabled", PathText:"Social Login > WeChat > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Cache", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_CACHE", Path:"cache", PathText:"Cache", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Cache"}, meta.OptionsMeta{Title:"Enable cache", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_CACHE_ENABLED", Path:"cache.enabled", PathText:"Cache > Enable cache", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable cache"}, meta.OptionsMeta{Title:"Cache expiration time", Desc:"in minutes", Type:"uint64", Options:[]string(nil), Env:"ATK_CACHE_EXPIRES", Path:"cache.expires", PathText:"Cache > Cache expiration time", Default:0x1e, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Cache expiration time (in minutes)"}, meta.OptionsMeta{Title:"Redis config", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_CACHE_REDIS", Path:"cache.redis", PathText:"Cache > Redis config", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Redis config"}, meta.OptionsMeta{Title:"Redis database number", Desc:"e.g. 0", Type:"uint64", Options:[]string(nil), Env:"ATK_CACHE_REDIS_DB", Path:"cache.redis.db", PathText:"Cache > Redis config > Redis database number", Default:0x0, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Redis database number (e.g. 0)"}, meta.OptionsMeta{Title:"Connection type", Desc:"", Type:"string", Options:[]string{"tcp", "unix"}, Env:"ATK_CACHE_REDIS_NETWORK", Path:"cache.redis.network", PathText:"Cache > Redis config > Connection type", Default:"tcp", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Connection type [\"tcp\", \"unix\"]"}, meta.OptionsMeta{Title:"Redis password", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CACHE_REDIS_PASSWORD", Path:"cache.redis.password", PathText:"Cache > Redis config > Redis password", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Redis password"}, meta.OptionsMeta{Title:"Redis username", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CACHE_REDIS_USERNAME", Path:"cache.redis.username", PathText:"Cache > Redis config > Redis username", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Redis username"}, meta.OptionsMeta{Title:"Cache server address", Desc:"e.g. \"localhost:6379\"", Type:"string", Options:[]string(nil), Env:"ATK_CACHE_SERVER", Path:"cache.server", PathText:"Cache > Cache server address", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"-- The following is not necessary for `builtin` cache -- Cache server address (e.g. \"localhost:6379\")"}, meta.OptionsMeta{Title:"Cache type", Desc:"", Type:"string", Options:[]string{"redis", "memcache", "builtin"}, Env:"ATK_CACHE_TYPE", Path:"cache.type", PathText:"Cache > Cache type", Default:"builtin", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Cache type [\"redis\", \"memcache\", \"builtin\"]"}, meta.OptionsMeta{Title:"Cache warm up", Desc:"warm up cache when program starts", Type:"bool", Options:[]string(nil), Env:"ATK_CACHE_WARM_UP", Path:"cache.warm_up", PathText:"Cache > Cache warm up", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Cache warm up (warm up cache when program starts)"}, meta.OptionsMeta{Title:"Captcha", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_CAPTCHA", Path:"captcha", PathText:"Captcha", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Captcha"}, meta.OptionsMeta{Title:"Action limit", Desc:"the number of actions required to activate captcha", Type:"uint64", Options:[]string(nil), Env:"ATK_CAPTCHA_ACTION_LIMIT", Path:"captcha.action_limit", PathText:"Captcha > Action limit", Default:0x3, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Action limit (the number of actions required to activate captcha)"}, meta.OptionsMeta{Title:"Reset Timeout", Desc:"timeout to reset action counter. unit: s, set to -1 to disable", Type:"uint64", Options:[]string(nil), Env:"ATK_CAPTCHA_ACTION_RESET", Path:"captcha.action_reset", PathText:"Captcha > Reset Timeout", Default:0x3c, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Reset Timeout (timeout to reset action counter. unit: s, set to -1 to disable)"}, meta.OptionsMeta{Title:"Captcha is required always", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_CAPTCHA_ALWAYS", Path:"captcha.always", PathText:"Captcha > Captcha is required always", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Captcha is required always"}, meta.OptionsMeta{Title:"Captcha type", Desc:"", Type:"string", Options:[]string{"image", "turnstile", "recaptcha", "hcaptcha", "geetest"}, Env:"ATK_CAPTCHA_CAPTCHA_TYPE", Path:"captcha.captcha_type", PathText:"Captcha > Captcha type", Default:"image", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Captcha type [\"image\", \"turnstile\", \"recaptcha\", \"hcaptcha\", \"geetest\"]"}, meta.OptionsMeta{Title:"Enable captcha", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_CAPTCHA_ENABLED", Path:"captcha.enabled", PathText:"Captcha > Enable captcha", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable captcha"}, meta.OptionsMeta{Title:"Geetest", Desc:"https://www.geetest.com", Type:"", Options:[]string(nil), Env:"ATK_CAPTCHA_GEETEST", Path:"captcha.geetest", PathText:"Captcha > Geetest", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Geetest (https://www.geetest.com)"}, meta.OptionsMeta{Title:"CaptchaId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CAPTCHA_GEETEST_CAPTCHA_ID", Path:"captcha.geetest.captcha_id", PathText:"Captcha > Geetest > CaptchaId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"CaptchaId"}, meta.OptionsMeta{Title:"CaptchaKey", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CAPTCHA_GEETEST_CAPTCHA_KEY", Path:"captcha.geetest.captcha_key", PathText:"Captcha > Geetest > CaptchaKey", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"CaptchaKey"}, meta.OptionsMeta{Title:"hCaptcha", Desc:"https://www.hcaptcha.com/", Type:"", Options:[]string(nil), Env:"ATK_CAPTCHA_HCAPTCHA", Path:"captcha.hcaptcha", PathText:"Captcha > hCaptcha", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"hCaptcha (https://www.hcaptcha.com/)"}, meta.OptionsMeta{Title:"SecretKey", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CAPTCHA_HCAPTCHA_SECRET_KEY", Path:"captcha.hcaptcha.secret_key", PathText:"Captcha > hCaptcha > SecretKey", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"SecretKey"}, meta.OptionsMeta{Title:"SiteKey", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CAPTCHA_HCAPTCHA_SITE_KEY", Path:"captcha.hcaptcha.site_key", PathText:"Captcha > hCaptcha > SiteKey", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"SiteKey"}, meta.OptionsMeta{Title:"reCaptcha", Desc:"https://www.google.com/recaptcha/about/", Type:"", Options:[]string(nil), Env:"ATK_CAPTCHA_RECAPTCHA", Path:"captcha.recaptcha", PathText:"Captcha > reCaptcha", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"reCaptcha (https://www.google.com/recaptcha/about/)"}, meta.OptionsMeta{Title:"SecretKey", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CAPTCHA_RECAPTCHA_SECRET_KEY", Path:"captcha.recaptcha.secret_key", PathText:"Captcha > reCaptcha > SecretKey", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"SecretKey"}, meta.OptionsMeta{Title:"SiteKey", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CAPTCHA_RECAPTCHA_SITE_KEY", Path:"captcha.recaptcha.site_key", PathText:"Captcha > reCaptcha > SiteKey", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"SiteKey"}, meta.OptionsMeta{Title:"Turnstile", Desc:"https://www.cloudflare.com/products/turnstile/", Type:"", Options:[]string(nil), Env:"ATK_CAPTCHA_TURNSTILE", Path:"captcha.turnstile", PathText:"Captcha > Turnstile", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Turnstile (https://www.cloudflare.com/products/turnstile/)"}, meta.OptionsMeta{Title:"SecretKey", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CAPTCHA_TURNSTILE_SECRET_KEY", Path:"captcha.turnstile.secret_key", PathText:"Captcha > Turnstile > SecretKey", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"SecretKey"}, meta.OptionsMeta{Title:"SiteKey", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_CAPTCHA_TURNSTILE_SITE_KEY", Path:"captcha.turnstile.site_key", PathText:"Captcha > Turnstile > SiteKey", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"SiteKey"}, meta.OptionsMeta{Title:"Database", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_DB", Path:"db", PathText:"Database", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Database"}, meta.OptionsMeta{Title:"Database charset", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_DB_CHARSET", Path:"db.charset", PathText:"Database > Database charset", Default:"utf8mb4", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Database charset"}, meta.OptionsMeta{Title:"Database file", Desc:"only for SQLite", Type:"string", Options:[]string(nil), Env:"ATK_DB_FILE", Path:"db.file", PathText:"Database > Database file", Default:"./data/artalk.db", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Database file (only for SQLite)"}, meta.OptionsMeta{Title:"Host address", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_DB_HOST", Path:"db.host", PathText:"Database > Host address", Default:"localhost", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Host address"}, meta.OptionsMeta{Title:"Database name", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_DB_NAME", Path:"db.name", PathText:"Database > Database name", Default:"artalk", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"-- The following is not necessary for SQLite -- Database name"}, meta.OptionsMeta{Title:"Database password", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_DB_PASSWORD", Path:"db.password", PathText:"Database > Database password", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Database password"}, meta.OptionsMeta{Title:"Host port", Desc:"", Type:"uint64", Options:[]string(nil), Env:"ATK_DB_PORT", Path:"db.port", PathText:"Database > Host port", Default:0xcea, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Host port"}, meta.OptionsMeta{Title:"Prepared Statement", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_DB_PREPARE_STMT", Path:"db.prepare_stmt", PathText:"Database > Prepared Statement", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Prepared Statement"}, meta.OptionsMeta{Title:"Enable SSL mode", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_DB_SSL", Path:"db.ssl", PathText:"Database > Enable SSL mode", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable SSL mode"}, meta.OptionsMeta{Title:"Table prefix", Desc:"e.g. \"atk_\"", Type:"string", Options:[]string(nil), Env:"ATK_DB_TABLE_PREFIX", Path:"db.table_prefix", PathText:"Database > Table prefix", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Table prefix (e.g. \"atk_\")"}, meta.OptionsMeta{Title:"Database type", Desc:"", Type:"string", Options:[]string{"sqlite", "mysql", "pgsql", "mssql"}, Env:"ATK_DB_TYPE", Path:"db.type", PathText:"Database > Database type", Default:"sqlite", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Database type [\"sqlite\", \"mysql\", \"pgsql\", \"mssql\"]"}, meta.OptionsMeta{Title:"Database user", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_DB_USER", Path:"db.user", PathText:"Database > Database user", Default:"root", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Database user"}, meta.OptionsMeta{Title:"Debug mode", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_DEBUG", Path:"debug", PathText:"Debug mode", Default:false, IsRoot:true, HasChild:false, AllowsSet:true, CommentRaw:"Debug mode"}, meta.OptionsMeta{Title:"Email", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_EMAIL", Path:"email", PathText:"Email", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Email"}, meta.OptionsMeta{Title:"Aliyun mail push", Desc:"set send method to \"ali_dm\" to enable; see: https://help.aliyun.com/document_detail/29444.html", Type:"", Options:[]string(nil), Env:"ATK_EMAIL_ALI_DM", Path:"email.ali_dm", PathText:"Email > Aliyun mail push", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Aliyun mail push (set send method to \"ali_dm\" to enable; see: https://help.aliyun.com/document_detail/29444.html)"}, meta.OptionsMeta{Title:"AccessKeyId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_ALI_DM_ACCESS_KEY_ID", Path:"email.ali_dm.access_key_id", PathText:"Email > Aliyun mail push > AccessKeyId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"AccessKeyId"}, meta.OptionsMeta{Title:"AccessKeySecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_ALI_DM_ACCESS_KEY_SECRET", Path:"email.ali_dm.access_key_secret", PathText:"Email > Aliyun mail push > AccessKeySecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"AccessKeySecret"}, meta.OptionsMeta{Title:"AccountName", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_ALI_DM_ACCOUNT_NAME", Path:"email.ali_dm.account_name", PathText:"Email > Aliyun mail push > AccountName", Default:"noreply@example.com", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"AccountName"}, meta.OptionsMeta{Title:"Enable email notification", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_EMAIL_ENABLED", Path:"email.enabled", PathText:"Email > Enable email notification", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable email notification"}, meta.OptionsMeta{Title:"Email subject", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_MAIL_SUBJECT", Path:"email.mail_subject", PathText:"Email > Email subject", Default:"[{{site_name}}] You got a reply from @{{reply_nick}}", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Email subject"}, meta.OptionsMeta{Title:"Email template file", Desc:"set to file path to use custom template", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_MAIL_TPL", Path:"email.mail_tpl", PathText:"Email > Email template file", Default:"default", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Email template file (set to file path to use custom template)"}, meta.OptionsMeta{Title:"Email address of sender", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_SEND_ADDR", Path:"email.send_addr", PathText:"Email > Email address of sender", Default:"noreply@example.com", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Email address of sender"}, meta.OptionsMeta{Title:"Nick name of sender", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_SEND_NAME", Path:"email.send_name", PathText:"Email > Nick name of sender", Default:"{{reply_nick}}", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Nick name of sender"}, meta.OptionsMeta{Title:"Send method", Desc:"", Type:"string", Options:[]string{"smtp", "ali_dm", "sendmail"}, Env:"ATK_EMAIL_SEND_TYPE", Path:"email.send_type", PathText:"Email > Send method", Default:"smtp", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Send method [\"smtp\", \"ali_dm\", \"sendmail\"]"}, meta.OptionsMeta{Title:"SMTP send", Desc:"set send method to \"smtp\" to enable", Type:"", Options:[]string(nil), Env:"ATK_EMAIL_SMTP", Path:"email.smtp", PathText:"Email > SMTP send", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"SMTP send (set send method to \"smtp\" to enable)"}, meta.OptionsMeta{Title:"Email address of sender", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_SMTP_HOST", Path:"email.smtp.host", PathText:"Email > SMTP send > Email address of sender", Default:"smtp.qq.com", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Email address of sender"}, meta.OptionsMeta{Title:"Password", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_SMTP_PASSWORD", Path:"email.smtp.password", PathText:"Email > SMTP send > Password", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Password"}, meta.OptionsMeta{Title:"Email port", Desc:"", Type:"uint64", Options:[]string(nil), Env:"ATK_EMAIL_SMTP_PORT", Path:"email.smtp.port", PathText:"Email > SMTP send > Email port", Default:0x24b, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Email port"}, meta.OptionsMeta{Title:"Email address of sender", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_EMAIL_SMTP_USERNAME", Path:"email.smtp.username", PathText:"Email > SMTP send > Email address of sender", Default:"example@qq.com", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Email address of sender"}, meta.OptionsMeta{Title:"UI Settings", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_FRONTEND", Path:"frontend", PathText:"UI Settings", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"UI Settings"}, meta.OptionsMeta{Title:"Dark mode", Desc:"", Type:"string", Options:[]string{"inherit", "auto"}, Env:"ATK_FRONTEND_DARKMODE", Path:"frontend.darkMode", PathText:"UI Settings > Dark mode", Default:"inherit", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Dark mode [\"inherit\", \"auto\"]"}, meta.OptionsMeta{Title:"Movable comment box", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_EDITORTRAVEL", Path:"frontend.editorTravel", PathText:"UI Settings > Movable comment box", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Movable comment box"}, meta.OptionsMeta{Title:"Emoticons", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_FRONTEND_EMOTICONS", Path:"frontend.emoticons", PathText:"UI Settings > Emoticons", Default:"https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Emoticons"}, meta.OptionsMeta{Title:"Flatten mode", Desc:"", Type:"string", Options:[]string{"auto", "true", "false"}, Env:"ATK_FRONTEND_FLATMODE", Path:"frontend.flatMode", PathText:"UI Settings > Flatten mode", Default:"auto", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Flatten mode [\"auto\", true, false]"}, meta.OptionsMeta{Title:"Gravatar", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_FRONTEND_GRAVATAR", Path:"frontend.gravatar", PathText:"UI Settings > Gravatar", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Gravatar"}, meta.OptionsMeta{Title:"API URL", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_FRONTEND_GRAVATAR_MIRROR", Path:"frontend.gravatar.mirror", PathText:"UI Settings > Gravatar > API URL", Default:"https://www.gravatar.com/avatar/", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"API URL"}, meta.OptionsMeta{Title:"API parameters", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_FRONTEND_GRAVATAR_PARAMS", Path:"frontend.gravatar.params", PathText:"UI Settings > Gravatar > API parameters", Default:"sha256=1&d=mp&s=240", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"API parameters"}, meta.OptionsMeta{Title:"Content height limit", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_FRONTEND_HEIGHTLIMIT", Path:"frontend.heightLimit", PathText:"UI Settings > Content height limit", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Content height limit"}, meta.OptionsMeta{Title:"Sub-comment area height limit", Desc:"unit: px", Type:"uint64", Options:[]string(nil), Env:"ATK_FRONTEND_HEIGHTLIMIT_CHILDREN", Path:"frontend.heightLimit.children", PathText:"UI Settings > Content height limit > Sub-comment area height limit", Default:0x190, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Sub-comment area height limit (unit: px)"}, meta.OptionsMeta{Title:"Comment content height limit", Desc:"unit: px", Type:"uint64", Options:[]string(nil), Env:"ATK_FRONTEND_HEIGHTLIMIT_CONTENT", Path:"frontend.heightLimit.content", PathText:"UI Settings > Content height limit > Comment content height limit", Default:0x12c, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Comment content height limit (unit: px)"}, meta.OptionsMeta{Title:"Scrollable", Desc:"scrollable height limit area", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_HEIGHTLIMIT_SCROLLABLE", Path:"frontend.heightLimit.scrollable", PathText:"UI Settings > Content height limit > Scrollable", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Scrollable (scrollable height limit area)"}, meta.OptionsMeta{Title:"Image lazy load", Desc:"", Type:"bool", Options:[]string{"false", "native", "data-src"}, Env:"ATK_FRONTEND_IMGLAZYLOAD", Path:"frontend.imgLazyLoad", PathText:"UI Settings > Image lazy load", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Image lazy load [false, \"native\", \"data-src\"]"}, meta.OptionsMeta{Title:"Comment sorting", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_LISTSORT", Path:"frontend.listSort", PathText:"UI Settings > Comment sorting", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Comment sorting"}, meta.OptionsMeta{Title:"Maximum nesting level", Desc:"", Type:"uint64", Options:[]string(nil), Env:"ATK_FRONTEND_NESTMAX", Path:"frontend.nestMax", PathText:"UI Settings > Maximum nesting level", Default:0x2, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Maximum nesting level"}, meta.OptionsMeta{Title:"Nesting comment sorting rules", Desc:"", Type:"string", Options:[]string{"DATE_ASC", "DATE_DESC", "VOTE_UP_DESC"}, Env:"ATK_FRONTEND_NESTSORT", Path:"frontend.nestSort", PathText:"UI Settings > Nesting comment sorting rules", Default:"DATE_ASC", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Nesting comment sorting rules [\"DATE_ASC\", \"DATE_DESC\", \"VOTE_UP_DESC\"]"}, meta.OptionsMeta{Title:"Text to display when there is", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_FRONTEND_NOCOMMENT", Path:"frontend.noComment", PathText:"UI Settings > Text to display when there is", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Text to display when there is"}, meta.OptionsMeta{Title:"Comment pagination", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_FRONTEND_PAGINATION", Path:"frontend.pagination", PathText:"UI Settings > Comment pagination", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Comment pagination"}, meta.OptionsMeta{Title:"Scroll loading", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_PAGINATION_AUTOLOAD", Path:"frontend.pagination.autoLoad", PathText:"UI Settings > Comment pagination > Scroll loading", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Scroll loading"}, meta.OptionsMeta{Title:"Number of comments per page", Desc:"", Type:"uint64", Options:[]string(nil), Env:"ATK_FRONTEND_PAGINATION_PAGESIZE", Path:"frontend.pagination.pageSize", PathText:"UI Settings > Comment pagination > Number of comments per page", Default:0x14, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Number of comments per page"}, meta.OptionsMeta{Title:"Load more mode", Desc:"disabled to use pagination bar", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_PAGINATION_READMORE", Path:"frontend.pagination.readMore", PathText:"UI Settings > Comment pagination > Load more mode", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Load more mode (disabled to use pagination bar)"}, meta.OptionsMeta{Title:"Comment box placeholder", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_FRONTEND_PLACEHOLDER", Path:"frontend.placeholder", PathText:"UI Settings > Comment box placeholder", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Comment box placeholder"}, meta.OptionsMeta{Title:"Plugins", Desc:"", Type:"[]interface {}", Options:[]string(nil), Env:"ATK_FRONTEND_PLUGINURLS", Path:"frontend.pluginURLs", PathText:"UI Settings > Plugins", Default:[]interface {}{}, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Plugins"}, meta.OptionsMeta{Title:"Editor real-time preview", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_PREVIEW", Path:"frontend.preview", PathText:"UI Settings > Editor real-time preview", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Editor real-time preview"}, meta.OptionsMeta{Title:"Request timeout", Desc:"unit: ms", Type:"uint64", Options:[]string(nil), Env:"ATK_FRONTEND_REQTIMEOUT", Path:"frontend.reqTimeout", PathText:"UI Settings > Request timeout", Default:0x3a98, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Request timeout (unit: ms)"}, meta.OptionsMeta{Title:"Text of the send button", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_FRONTEND_SENDBTN", Path:"frontend.sendBtn", PathText:"UI Settings > Text of the send button", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Text of the send button"}, meta.OptionsMeta{Title:"User UA badge", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_UABADGE", Path:"frontend.uaBadge", PathText:"UI Settings > User UA badge", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"User UA badge"}, meta.OptionsMeta{Title:"Version check", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_VERSIONCHECK", Path:"frontend.versionCheck", PathText:"UI Settings > Version check", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Version check"}, meta.OptionsMeta{Title:"Vote button", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_VOTE", Path:"frontend.vote", PathText:"UI Settings > Vote button", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Vote button"}, meta.OptionsMeta{Title:"Dislike button", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_FRONTEND_VOTEDOWN", Path:"frontend.voteDown", PathText:"UI Settings > Dislike button", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Dislike button"}, meta.OptionsMeta{Title:"Listen host", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_HOST", Path:"host", PathText:"Listen host", Default:"0.0.0.0", IsRoot:true, HasChild:false, AllowsSet:true, CommentRaw:"Listen host"}, meta.OptionsMeta{Title:"Web server", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_HTTP", Path:"http", PathText:"Web server", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Web server"}, meta.OptionsMeta{Title:"Body size limit", Desc:"unit: MB", Type:"uint64", Options:[]string(nil), Env:"ATK_HTTP_BODY_LIMIT", Path:"http.body_limit", PathText:"Web server > Body size limit", Default:0x64, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Body size limit (unit: MB)"}, meta.OptionsMeta{Title:"Proxy Header", Desc:"fill `X-Forwarded-For` to get user real IP if behind a trusted reverse proxy or CDN", Type:"string", Options:[]string(nil), Env:"ATK_HTTP_PROXY_HEADER", Path:"http.proxy_header", PathText:"Web server > Proxy Header", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Proxy Header (fill `X-Forwarded-For` to get user real IP if behind a trusted reverse proxy or CDN)"}, meta.OptionsMeta{Title:"Upload", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_IMG_UPLOAD", Path:"img_upload", PathText:"Upload", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Upload"}, meta.OptionsMeta{Title:"Enable image upload", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_IMG_UPLOAD_ENABLED", Path:"img_upload.enabled", PathText:"Upload > Enable image upload", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable image upload"}, meta.OptionsMeta{Title:"Image size limit", Desc:"unit: MB", Type:"uint64", Options:[]string(nil), Env:"ATK_IMG_UPLOAD_MAX_SIZE", Path:"img_upload.max_size", PathText:"Upload > Image size limit", Default:0x5, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Image size limit (unit: MB)"}, meta.OptionsMeta{Title:"Image storage", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_IMG_UPLOAD_PATH", Path:"img_upload.path", PathText:"Upload > Image storage", Default:"./data/artalk-img/", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Image storage"}, meta.OptionsMeta{Title:"Image link base path", Desc:"default: \"/static/images/\"", Type:"", Options:[]string(nil), Env:"ATK_IMG_UPLOAD_PUBLIC_PATH", Path:"img_upload.public_path", PathText:"Upload > Image link base path", Default:interface {}(nil), IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Image link base path (default: \"/static/images/\")"}, meta.OptionsMeta{Title:"Upgit config", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_IMG_UPLOAD_UPGIT", Path:"img_upload.upgit", PathText:"Upload > Upgit config", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Upgit config"}, meta.OptionsMeta{Title:"Delete local image after upload success", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_IMG_UPLOAD_UPGIT_DEL_LOCAL", Path:"img_upload.upgit.del_local", PathText:"Upload > Upgit config > Delete local image after upload success", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Delete local image after upload success"}, meta.OptionsMeta{Title:"Enable Upgit", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_IMG_UPLOAD_UPGIT_ENABLED", Path:"img_upload.upgit.enabled", PathText:"Upload > Upgit config > Enable Upgit", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable Upgit"}, meta.OptionsMeta{Title:"Command line arguments", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_IMG_UPLOAD_UPGIT_EXEC", Path:"img_upload.upgit.exec", PathText:"Upload > Upgit config > Command line arguments", Default:"upgit -c UPGIT_CONF_FILE_PATH -t /artalk-img", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Command line arguments"}, meta.OptionsMeta{Title:"Language", Desc:"follow Unicode BCP 47", Type:"string", Options:[]string{"en", "zh-CN", "zh-TW", "jp", "fr", "ko", "ru"}, Env:"ATK_LOCALE", Path:"locale", PathText:"Language", Default:"en", IsRoot:true, HasChild:false, AllowsSet:true, CommentRaw:"Language (follow Unicode BCP 47) [\"en\", \"zh-CN\", \"zh-TW\", \"jp\", \"fr\", \"ko\", \"ru\"] -- see https://www.techonthenet.com/js/language_tags.php --"}, meta.OptionsMeta{Title:"Logging", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_LOG", Path:"log", PathText:"Logging", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Logging"}, meta.OptionsMeta{Title:"Enable logging", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_LOG_ENABLED", Path:"log.enabled", PathText:"Logging > Enable logging", Default:true, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable logging"}, meta.OptionsMeta{Title:"Log file path", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_LOG_FILENAME", Path:"log.filename", PathText:"Logging > Log file path", Default:"./data/artalk.log", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Log file path"}, meta.OptionsMeta{Title:"Login timeout", Desc:"in seconds", Type:"uint64", Options:[]string(nil), Env:"ATK_LOGIN_TIMEOUT", Path:"login_timeout", PathText:"Login timeout", Default:0x3f480, IsRoot:true, HasChild:false, AllowsSet:true, CommentRaw:"Login timeout (in seconds)"}, meta.OptionsMeta{Title:"Moderator", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_MODERATOR", Path:"moderator", PathText:"Moderator", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"Moderator -- Comment examination before being public --"}, meta.OptionsMeta{Title:"Akismet Key", Desc:"Akismet anti-spam service, https://akismet.com", Type:"string", Options:[]string(nil), Env:"ATK_MODERATOR_AKISMET_KEY", Path:"moderator.akismet_key", PathText:"Moderator > Akismet Key", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Akismet Key (Akismet anti-spam service, https://akismet.com)"}, meta.OptionsMeta{Title:"Aliyun Content Security", Desc:"Auto review comments with Aliyun Content Security", Type:"", Options:[]string(nil), Env:"ATK_MODERATOR_ALIYUN", Path:"moderator.aliyun", PathText:"Moderator > Aliyun Content Security", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Aliyun Content Security (Auto review comments with Aliyun Content Security) -- see https://help.aliyun.com/document_detail/28417.html --"}, meta.OptionsMeta{Title:"AccessKeyId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_MODERATOR_ALIYUN_ACCESS_KEY_ID", Path:"moderator.aliyun.access_key_id", PathText:"Moderator > Aliyun Content Security > AccessKeyId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"AccessKeyId"}, meta.OptionsMeta{Title:"AccessKeySecret", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_MODERATOR_ALIYUN_ACCESS_KEY_SECRET", Path:"moderator.aliyun.access_key_secret", PathText:"Moderator > Aliyun Content Security > AccessKeySecret", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"AccessKeySecret"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_MODERATOR_ALIYUN_ENABLED", Path:"moderator.aliyun.enabled", PathText:"Moderator > Aliyun Content Security > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Region", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_MODERATOR_ALIYUN_REGION", Path:"moderator.aliyun.region", PathText:"Moderator > Aliyun Content Security > Region", Default:"cn-shanghai", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Region"}, meta.OptionsMeta{Title:"Block when API request fails", Desc:"set to false to let comments pass when API request fails", Type:"bool", Options:[]string(nil), Env:"ATK_MODERATOR_API_FAIL_BLOCK", Path:"moderator.api_fail_block", PathText:"Moderator > Block when API request fails", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Block when API request fails (set to false to let comments pass when API request fails)"}, meta.OptionsMeta{Title:"Keyword filter", Desc:"local offline dictionary", Type:"", Options:[]string(nil), Env:"ATK_MODERATOR_KEYWORDS", Path:"moderator.keywords", PathText:"Moderator > Keyword filter", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Keyword filter (local offline dictionary)"}, meta.OptionsMeta{Title:"Enable keyword filter", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_MODERATOR_KEYWORDS_ENABLED", Path:"moderator.keywords.enabled", PathText:"Moderator > Keyword filter > Enable keyword filter", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable keyword filter"}, meta.OptionsMeta{Title:"FileSep", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_MODERATOR_KEYWORDS_FILE_SEP", Path:"moderator.keywords.file_sep", PathText:"Moderator > Keyword filter > FileSep", Default:"\n", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"FileSep"}, meta.OptionsMeta{Title:"Dictionary file", Desc:"support multiple dictionary files", Type:"[]interface {}", Options:[]string(nil), Env:"ATK_MODERATOR_KEYWORDS_FILES", Path:"moderator.keywords.files", PathText:"Moderator > Keyword filter > Dictionary file", Default:[]interface {}{"./data/keywords_1.txt"}, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Dictionary file (support multiple dictionary files)"}, meta.OptionsMeta{Title:"Set to pending when match", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_MODERATOR_KEYWORDS_PENDING", Path:"moderator.keywords.pending", PathText:"Moderator > Keyword filter > Set to pending when match", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Set to pending when match"}, meta.OptionsMeta{Title:"ReplaceTo", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_MODERATOR_KEYWORDS_REPLACE_TO", Path:"moderator.keywords.replace_to", PathText:"Moderator > Keyword filter > ReplaceTo", Default:"x", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"ReplaceTo"}, meta.OptionsMeta{Title:"Default pending", Desc:"new comments need to be approved by admin", Type:"bool", Options:[]string(nil), Env:"ATK_MODERATOR_PENDING_DEFAULT", Path:"moderator.pending_default", PathText:"Moderator > Default pending", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Default pending (new comments need to be approved by admin)"}, meta.OptionsMeta{Title:"Tencent Cloud Content Security", Desc:"Auto review comments with Tencent Cloud Content Security", Type:"", Options:[]string(nil), Env:"ATK_MODERATOR_TENCENT", Path:"moderator.tencent", PathText:"Moderator > Tencent Cloud Content Security", Default:interface {}(nil), IsRoot:false, HasChild:true, AllowsSet:false, CommentRaw:"Tencent Cloud Content Security (Auto review comments with Tencent Cloud Content Security) -- see https://cloud.tencent.com/document/product/1124/64508 --"}, meta.OptionsMeta{Title:"Enabled", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_MODERATOR_TENCENT_ENABLED", Path:"moderator.tencent.enabled", PathText:"Moderator > Tencent Cloud Content Security > Enabled", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enabled"}, meta.OptionsMeta{Title:"Region", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_MODERATOR_TENCENT_REGION", Path:"moderator.tencent.region", PathText:"Moderator > Tencent Cloud Content Security > Region", Default:"ap-guangzhou", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Region"}, meta.OptionsMeta{Title:"SecretId", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_MODERATOR_TENCENT_SECRET_ID", Path:"moderator.tencent.secret_id", PathText:"Moderator > Tencent Cloud Content Security > SecretId", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"SecretId"}, meta.OptionsMeta{Title:"SecretKey", Desc:"", Type:"string", Options:[]string(nil), Env:"ATK_MODERATOR_TENCENT_SECRET_KEY", Path:"moderator.tencent.secret_key", PathText:"Moderator > Tencent Cloud Content Security > SecretKey", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"SecretKey"}, meta.OptionsMeta{Title:"Listen port", Desc:"", Type:"uint64", Options:[]string(nil), Env:"ATK_PORT", Path:"port", PathText:"Listen port", Default:0x5b46, IsRoot:true, HasChild:false, AllowsSet:true, CommentRaw:"Listen port"}, meta.OptionsMeta{Title:"Default site name", Desc:"create when app is first launched", Type:"string", Options:[]string(nil), Env:"ATK_SITE_DEFAULT", Path:"site_default", PathText:"Default site name", Default:"Default Site", IsRoot:true, HasChild:false, AllowsSet:true, CommentRaw:"Default site name (create when app is first launched)"}, meta.OptionsMeta{Title:"SSL", Desc:"", Type:"", Options:[]string(nil), Env:"ATK_SSL", Path:"ssl", PathText:"SSL", Default:interface {}(nil), IsRoot:true, HasChild:true, AllowsSet:false, CommentRaw:"SSL"}, meta.OptionsMeta{Title:"Certificate file path", Desc:"e.g. \"/etc/letsencrypt/live/example.com/fullchain.pem\"", Type:"string", Options:[]string(nil), Env:"ATK_SSL_CERT_PATH", Path:"ssl.cert_path", PathText:"SSL > Certificate file path", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Certificate file path (e.g. \"/etc/letsencrypt/live/example.com/fullchain.pem\")"}, meta.OptionsMeta{Title:"Enable SSL", Desc:"", Type:"bool", Options:[]string(nil), Env:"ATK_SSL_ENABLED", Path:"ssl.enabled", PathText:"SSL > Enable SSL", Default:false, IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Enable SSL"}, meta.OptionsMeta{Title:"Key file path", Desc:"e.g. \"/etc/letsencrypt/live/example.com/privkey.pem\"", Type:"string", Options:[]string(nil), Env:"ATK_SSL_KEY_PATH", Path:"ssl.key_path", PathText:"SSL > Key file path", Default:"", IsRoot:false, HasChild:false, AllowsSet:true, CommentRaw:"Key file path (e.g. \"/etc/letsencrypt/live/example.com/privkey.pem\")"}, meta.OptionsMeta{Title:"Timezone", Desc:"follow IANA Time Zone Database", Type:"string", Options:[]string(nil), Env:"ATK_TIMEZONE", Path:"timezone", PathText:"Timezone", Default:"Asia/Shanghai", IsRoot:true, HasChild:false, AllowsSet:true, CommentRaw:"Timezone (follow IANA Time Zone Database) -- see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones --"}, meta.OptionsMeta{Title:"Trusted domains", Desc:"", Type:"[]interface {}", Options:[]string(nil), Env:"ATK_TRUSTED_DOMAINS", Path:"trusted_domains", PathText:"Trusted domains", Default:[]interface {}{}, IsRoot:true, HasChild:false, AllowsSet:true, CommentRaw:"Trusted domains -- e.g. [\"https://artalk.example.com:23366\"] add url of your site her --"}} diff --git a/internal/config/utils.go b/internal/config/utils.go new file mode 100644 index 00000000..5fa299a4 --- /dev/null +++ b/internal/config/utils.go @@ -0,0 +1,19 @@ +package config + +import ( + "strings" + + "github.com/ArtalkJS/Artalk/internal/utils" +) + +// Get the hash function according to the frontend gravatar.params configuration +func GetHashFuncByFrontendConf(conf *Config) func(string) string { + if gravatar, ok := conf.Frontend["gravatar"].(map[string]interface{}); ok { + if params, ok := gravatar["params"].(string); ok { + if strings.Contains(params, "sha256=1") { + return utils.GetSha256Hash + } + } + } + return utils.GetMD5Hash +} diff --git a/internal/config/utils_test.go b/internal/config/utils_test.go new file mode 100644 index 00000000..1d13865c --- /dev/null +++ b/internal/config/utils_test.go @@ -0,0 +1,51 @@ +package config + +import ( + "reflect" + "testing" + + "github.com/ArtalkJS/Artalk/internal/utils" + "github.com/stretchr/testify/assert" +) + +func Test_GetHashFuncByFrontendConf(t *testing.T) { + tests := map[string]struct { + config *Config + expected any + }{ + "nil frontend conf": { + config: &Config{Frontend: nil}, + expected: utils.GetMD5Hash, + }, + "empty frontend conf": { + config: &Config{Frontend: map[string]interface{}{}}, + expected: utils.GetMD5Hash, + }, + "frontend conf without hash func": { + config: &Config{Frontend: map[string]interface{}{ + "gravatar": false, + }}, + expected: utils.GetMD5Hash, + }, + "frontend conf with gravatar params but without hash func": { + config: &Config{Frontend: map[string]interface{}{ + "gravatar": map[string]interface{}{"params": "a=1&b=2"}, + }}, + expected: utils.GetMD5Hash, + }, + "frontend conf with gravatar params containing hash func": { + config: &Config{Frontend: map[string]interface{}{ + "gravatar": map[string]interface{}{"params": "a=1&sha256=1&b=2"}, + }}, + expected: utils.GetSha256Hash, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + expect := reflect.ValueOf(tc.expected).Pointer() + actual := reflect.ValueOf(GetHashFuncByFrontendConf(tc.config)).Pointer() + assert.Equal(t, expect, actual) + }) + } +} diff --git a/internal/core/base.go b/internal/core/base.go index a9d6c8c4..f5d1abca 100644 --- a/internal/core/base.go +++ b/internal/core/base.go @@ -42,11 +42,11 @@ func NewApp(conf *config.Config) *App { } func (app *App) injectDefaultServices() { - // 请勿依赖注入顺序 - AppInject[*EmailService](app, NewEmailService(app)) - AppInject[*IPRegionService](app, NewIPRegionService(app)) - AppInject[*NotifyService](app, NewNotifyService(app)) - AppInject[*AntiSpamService](app, NewAntiSpamService(app)) + // Please do not depend on the order of dependency injection + AppInject(app, NewEmailService(app)) + AppInject(app, NewIPRegionService(app)) + AppInject(app, NewNotifyService(app)) + AppInject(app, NewAntiSpamService(app)) } func (app *App) registerDefaultHooks() { @@ -270,6 +270,11 @@ func (app *App) initDao() error { // create new dao instance app.SetDao(dao.NewDao(dbInstance)) + // patch: switch comment email hash algorithm by config + app.Dao().SetCommentEmailHashFunc(func(email string) string { + return config.GetHashFuncByFrontendConf(app.Conf())(strings.ToLower(email)) + }) + return nil } diff --git a/internal/dao/cook.go b/internal/dao/cook.go index 06336d9f..857f0008 100644 --- a/internal/dao/cook.go +++ b/internal/dao/cook.go @@ -1,3 +1,5 @@ +// Convert Entity to JSON Response Data Structure for API +// TODO: (refactor) consider to extract this file to a new package package dao import ( @@ -10,6 +12,13 @@ import ( const CommonDateTimeFormat = "2006-01-02 15:04:05" +// TODO: (refactor) remove this global variable +var getCommentEmailHash = func(email string) string { return utils.GetMD5Hash(strings.ToLower(email)) } + +func (dao *Dao) SetCommentEmailHashFunc(fn func(string) string) { + getCommentEmailHash = fn +} + // =============== // Comment // =============== @@ -40,7 +49,7 @@ func (dao *Dao) CookComment(c *entity.Comment) entity.CookedComment { ContentMarked: markedContent, UserID: c.UserID, Nick: user.Name, - EmailEncrypted: utils.GetSha256Hash(strings.ToLower(user.Email)), + EmailEncrypted: getCommentEmailHash(user.Email), Link: user.Link, UA: c.UA, Date: c.CreatedAt.Local().Format(CommonDateTimeFormat), @@ -92,7 +101,7 @@ func (dao *Dao) CookCommentForEmail(c *entity.Comment) entity.CookedCommentForEm Site: dao.CookSite(&site), CookedComment: entity.CookedComment{ ID: c.ID, - EmailEncrypted: utils.GetSha256Hash(strings.ToLower(user.Email)), + EmailEncrypted: getCommentEmailHash(user.Email), Link: user.Link, UA: c.UA, IsCollapsed: c.IsCollapsed, diff --git a/ui/artalk-sidebar/src/components/Header.vue b/ui/artalk-sidebar/src/components/Header.vue index 4c05cfea..b9fcaa7c 100644 --- a/ui/artalk-sidebar/src/components/Header.vue +++ b/ui/artalk-sidebar/src/components/Header.vue @@ -1,21 +1,14 @@