mirror of https://gitee.com/answerdev/answer.git
update install
This commit is contained in:
parent
0fe709d84b
commit
27f05ee63c
|
@ -27,10 +27,11 @@ COPY --from=node-builder /tmp/build ${BUILD_DIR}/web/html
|
|||
CMD ls -al ${BUILD_DIR}/web/html
|
||||
RUN make clean build && \
|
||||
cp answer /usr/bin/answer && \
|
||||
cp configs/config.yaml /etc/config.yaml && \
|
||||
mkdir -p /tmp/cache && chmod 777 /tmp/cache && \
|
||||
mkdir /data && chmod 777 /data && cp configs/config.yaml /data && \
|
||||
mkdir -p /data/upfiles && chmod 777 /data/upfiles && cp -r i18n /data
|
||||
|
||||
|
||||
FROM debian:bullseye
|
||||
|
||||
ENV TZ "Asia/Shanghai"
|
||||
|
@ -45,9 +46,8 @@ RUN sed -i 's/deb.debian.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.li
|
|||
COPY --from=golang-builder /data /data
|
||||
VOLUME /data
|
||||
|
||||
COPY --from=golang-builder /etc/config.yaml /etc/answer.yaml
|
||||
COPY --from=golang-builder /usr/bin/answer /usr/bin/answer
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
ENTRYPOINT ["dumb-init", "/usr/bin/answer", "-c", "/etc/answer.yaml"]
|
||||
CMD ["/usr/bin/answer", "init"]
|
||||
ENTRYPOINT ["dumb-init", "/usr/bin/answer", "-c", "/data/config.yaml"]
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
server:
|
||||
http:
|
||||
addr: 0.0.0.0:80
|
||||
data:
|
||||
database:
|
||||
connection: root:root@tcp(127.0.0.1:3306)/answer
|
||||
cache:
|
||||
file_path: "/tmp/cache/cache.db"
|
||||
i18n:
|
||||
bundle_dir: "/data/i18n"
|
||||
swaggerui:
|
||||
show: false
|
||||
protocol: http
|
||||
host: 127.0.0.1
|
||||
address: ':80'
|
||||
service_config:
|
||||
secret_key: "answer"
|
||||
web_host: "http://127.0.0.1"
|
||||
upload_path: "./upfiles"
|
|
@ -0,0 +1,160 @@
|
|||
base:
|
||||
success:
|
||||
other: "success"
|
||||
unknown:
|
||||
other: "unknown error"
|
||||
request_format_error:
|
||||
other: "request format is not valid"
|
||||
unauthorized_error:
|
||||
other: "unauthorized"
|
||||
database_error:
|
||||
other: "data server error"
|
||||
|
||||
email:
|
||||
other: "email"
|
||||
password:
|
||||
other: "password"
|
||||
|
||||
email_or_password_wrong_error: &email_or_password_wrong
|
||||
other: "email or password wrong"
|
||||
|
||||
error:
|
||||
admin:
|
||||
email_or_password_wrong: *email_or_password_wrong
|
||||
answer:
|
||||
not_found:
|
||||
other: "answer not found"
|
||||
comment:
|
||||
edit_without_permission:
|
||||
other: "comment not allowed to edit"
|
||||
not_found:
|
||||
other: "comment not found"
|
||||
email:
|
||||
duplicate:
|
||||
other: "email already exists"
|
||||
need_to_be_verified:
|
||||
other: "email should be verified"
|
||||
verify_url_expired:
|
||||
other: "email verified url is expired, please resend the email"
|
||||
lang:
|
||||
not_found:
|
||||
other: "language not found"
|
||||
object:
|
||||
captcha_verification_failed:
|
||||
other: "captcha wrong"
|
||||
disallow_follow:
|
||||
other: "You are not allowed to follow"
|
||||
disallow_vote:
|
||||
other: "You are not allowed to vote"
|
||||
disallow_vote_your_self:
|
||||
other: "You can't vote for your own post!"
|
||||
not_found:
|
||||
other: "object not found"
|
||||
question:
|
||||
not_found:
|
||||
other: "question not found"
|
||||
rank:
|
||||
fail_to_meet_the_condition:
|
||||
other: "rank fail to meet the condition"
|
||||
report:
|
||||
handle_failed:
|
||||
other: "report handle failed"
|
||||
not_found:
|
||||
other: "report not found"
|
||||
tag:
|
||||
not_found:
|
||||
other: "tag not found"
|
||||
theme:
|
||||
not_found:
|
||||
other: "theme not found"
|
||||
user:
|
||||
email_or_password_wrong:
|
||||
other: *email_or_password_wrong
|
||||
not_found:
|
||||
other: "user not found"
|
||||
suspended:
|
||||
other: "user is suspended"
|
||||
|
||||
|
||||
|
||||
report:
|
||||
spam:
|
||||
name:
|
||||
other: "spam"
|
||||
description:
|
||||
other: "This post is an advertisement,or vandalism.It is not useful or relevant to the current topic."
|
||||
rude:
|
||||
name:
|
||||
other: "rude or abusive"
|
||||
description:
|
||||
other: "A reasonable person would find this content inappropriate for respectful discourse."
|
||||
duplicate:
|
||||
name:
|
||||
other: "a duplicate"
|
||||
description:
|
||||
other: "This question has been asked before and already has an answer."
|
||||
not_answer:
|
||||
name:
|
||||
other: "not an answer"
|
||||
description:
|
||||
other: "This was posted as an answer,but it does not attempt to answer the question. It should possibly be an edit,a comment,another question,or deleted altogether."
|
||||
not_need:
|
||||
name:
|
||||
other: "no longer needed"
|
||||
description:
|
||||
other: "This comment is outdated,conversational or not relevant to this post."
|
||||
other:
|
||||
name:
|
||||
other: "something else"
|
||||
description:
|
||||
other: "This post requires staff attention for another reason not listed above."
|
||||
|
||||
question:
|
||||
close:
|
||||
duplicate:
|
||||
name:
|
||||
other: "spam"
|
||||
description:
|
||||
other: "This question has been asked before and already has an answer."
|
||||
guideline:
|
||||
name:
|
||||
other: "a community-specific reason"
|
||||
description:
|
||||
other: "This question doesn't meet a community guideline."
|
||||
multiple:
|
||||
name:
|
||||
other: "needs details or clarity"
|
||||
description:
|
||||
other: "This question currently includes multiple questions in one. It should focus on one problem only."
|
||||
other:
|
||||
name:
|
||||
other: "something else"
|
||||
description:
|
||||
other: "This post requires another reason not listed above."
|
||||
|
||||
notification:
|
||||
action:
|
||||
update_question:
|
||||
other: "update question"
|
||||
answer_the_question:
|
||||
other: "answer the question"
|
||||
update_answer:
|
||||
other: "update answer"
|
||||
adopt_answer:
|
||||
other: "adopt answer"
|
||||
comment_question:
|
||||
other: "comment question"
|
||||
comment_answer:
|
||||
other: "comment answer"
|
||||
reply_to_you:
|
||||
other: "reply to you"
|
||||
mention_you:
|
||||
other: "mention you"
|
||||
your_question_is_closed:
|
||||
other: "your question is closed"
|
||||
your_question_was_deleted:
|
||||
other: "your question was deleted"
|
||||
your_answer_was_deleted:
|
||||
other: "your answer was deleted"
|
||||
your_comment_was_deleted:
|
||||
other: "your comment was deleted"
|
|
@ -0,0 +1,25 @@
|
|||
base:
|
||||
success:
|
||||
other: "成功"
|
||||
unknown:
|
||||
other: "未知错误"
|
||||
request_format_error:
|
||||
other: "请求格式错误"
|
||||
unauthorized_error:
|
||||
other: "未登录"
|
||||
database_error:
|
||||
other: "数据服务异常"
|
||||
|
||||
email:
|
||||
other: "邮箱"
|
||||
password:
|
||||
other: "密码"
|
||||
|
||||
username_or_password_wrong_error: &username_or_password_wrong
|
||||
other: "用户名或密码错误"
|
||||
|
||||
error:
|
||||
user:
|
||||
username_or_password_wrong: *username_or_password_wrong
|
||||
admin:
|
||||
username_or_password_wrong: *username_or_password_wrong
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/segmentfault/answer/internal/base/conf"
|
||||
"github.com/segmentfault/answer/internal/cli"
|
||||
"github.com/segmentfault/pacman"
|
||||
"github.com/segmentfault/pacman/contrib/conf/viper"
|
||||
"github.com/segmentfault/pacman/contrib/log/zap"
|
||||
|
@ -37,6 +38,19 @@ func init() {
|
|||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
args := flag.Args()
|
||||
|
||||
if len(args) < 1 {
|
||||
cli.Usage()
|
||||
os.Exit(0)
|
||||
return
|
||||
}
|
||||
|
||||
if args[0] == "init" {
|
||||
cli.InitConfig()
|
||||
return
|
||||
}
|
||||
|
||||
log.SetLogger(zap.NewLogger(
|
||||
log.ParseLevel(logLevel), zap.WithName(Name), zap.WithPath(logPath), zap.WithCallerFullPath()))
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package configs
|
||||
|
||||
import _ "embed"
|
||||
|
||||
//go:embed config.yaml
|
||||
var Config []byte
|
|
@ -1,19 +1,19 @@
|
|||
server:
|
||||
http:
|
||||
addr: ""
|
||||
addr: 0.0.0.0:80
|
||||
data:
|
||||
database:
|
||||
connection: ""
|
||||
connection: root:root@tcp(127.0.0.1:3306)/answer
|
||||
cache:
|
||||
file_path: ""
|
||||
file_path: "/tmp/cache/cache.db"
|
||||
i18n:
|
||||
bundle_dir: ""
|
||||
bundle_dir: "/data/i18n"
|
||||
swaggerui:
|
||||
show: true
|
||||
show: false
|
||||
protocol: http
|
||||
host: 0
|
||||
address: ':'
|
||||
host: 127.0.0.1
|
||||
address: ':80'
|
||||
service_config:
|
||||
secret_key: ""
|
||||
web_host: ""
|
||||
upload_path: ""
|
||||
secret_key: "answer"
|
||||
web_host: "http://127.0.0.1"
|
||||
upload_path: "./upfiles"
|
||||
|
|
|
@ -4,4 +4,6 @@ services:
|
|||
build:
|
||||
context: .
|
||||
image: github.com/segmentfault/answer
|
||||
volumes:
|
||||
- ./data:/data
|
||||
restart: on-failure
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package I18n
|
||||
|
||||
import "embed"
|
||||
|
||||
//go:embed *.yaml
|
||||
var I18n embed.FS
|
|
@ -0,0 +1,89 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/segmentfault/answer/I18n"
|
||||
"github.com/segmentfault/answer/configs"
|
||||
"github.com/segmentfault/answer/pkg/dir"
|
||||
)
|
||||
|
||||
var SuccessMsg = `
|
||||
answer initialized successfully
|
||||
`
|
||||
|
||||
var HasBeenInitializedMsg = `
|
||||
Has been initialized.
|
||||
`
|
||||
|
||||
func InitConfig() {
|
||||
exist, err := PathExists("data/config.yaml")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
if exist {
|
||||
fmt.Println(HasBeenInitializedMsg)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
_, err = dir.CreatePathIsNotExist("data")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
WriterFile("data/config.yaml", string(configs.Config))
|
||||
_, err = dir.CreatePathIsNotExist("data/i18n")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
_, err = dir.CreatePathIsNotExist("data/upfiles")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
i18nList, err := I18n.I18n.ReadDir(".")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
for _, item := range i18nList {
|
||||
path := fmt.Sprintf("data/i18n/%s", item.Name())
|
||||
content, err := I18n.I18n.ReadFile(item.Name())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
WriterFile(path, string(content))
|
||||
}
|
||||
fmt.Println(SuccessMsg)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func WriterFile(filePath, content string) error {
|
||||
file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
write := bufio.NewWriter(file)
|
||||
write.WriteString(content)
|
||||
write.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
func PathExists(path string) (bool, error) {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package cli
|
||||
|
||||
import "fmt"
|
||||
|
||||
var usageDoc = `
|
||||
answer
|
||||
|
||||
USAGE
|
||||
answer command
|
||||
|
||||
COMMANDS
|
||||
init init answer config
|
||||
-c config path, eg: -c data/config.yaml
|
||||
`
|
||||
|
||||
func Usage() {
|
||||
fmt.Println(usageDoc)
|
||||
}
|
Loading…
Reference in New Issue