Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/base url config #836

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions internal/base/constant/site_info.go
Expand Up @@ -19,6 +19,8 @@

package constant

import "os"

const (
DefaultGravatarBaseURL = "https://www.gravatar.com/avatar/"
DefaultAvatar = "system"
Expand All @@ -44,3 +46,8 @@ const (
ColorSchemeDark = "dark"
ColorSchemeSystem = "system"
)

var (
PublicUrl = os.Getenv("PUBLIC_URL")
BaseUrlPath = os.Getenv("REACT_APP_BASE_URL_PATH")
)
5 changes: 3 additions & 2 deletions internal/install/install_controller.go
Expand Up @@ -20,6 +20,7 @@
package install

import (
"github.com/apache/incubator-answer/internal/base/constant"
"net/http"
"os"
"path/filepath"
Expand Down Expand Up @@ -60,9 +61,9 @@ func LangOptions(ctx *gin.Context) {
// @Router / [get]
func CheckConfigFileAndRedirectToInstallPage(ctx *gin.Context) {
if cli.CheckConfigFile(confPath) {
ctx.Redirect(http.StatusFound, "/50x")
ctx.Redirect(http.StatusFound, constant.BaseUrlPath+"/50x")
} else {
ctx.Redirect(http.StatusFound, "/install")
ctx.Redirect(http.StatusFound, constant.BaseUrlPath+"/install")
}
}

Expand Down
3 changes: 2 additions & 1 deletion internal/install/install_main.go
Expand Up @@ -21,6 +21,7 @@ package install

import (
"fmt"
"github.com/apache/incubator-answer/internal/base/constant"
"os"

"github.com/apache/incubator-answer/internal/base/translator"
Expand Down Expand Up @@ -49,7 +50,7 @@ func Run(configPath string) {
if len(port) == 0 {
port = "80"
}
fmt.Printf("[SUCCESS] answer installation service will run at: http://localhost:%s/install/ \n", port)
fmt.Printf("[SUCCESS] answer installation service will run at: http://localhost:%s%s/install/ \n", port, constant.BaseUrlPath)
if err = installServer.Run(":" + port); err != nil {
panic(err)
}
Expand Down
14 changes: 7 additions & 7 deletions internal/install/install_server.go
Expand Up @@ -22,12 +22,12 @@ package install
import (
"embed"
"fmt"
"io/fs"
"net/http"

"github.com/apache/incubator-answer/internal/base/constant"
"github.com/apache/incubator-answer/ui"
"github.com/gin-gonic/gin"
"github.com/segmentfault/pacman/log"
"io/fs"
"net/http"
)

const UIStaticPath = "build/static"
Expand All @@ -48,14 +48,14 @@ func NewInstallHTTPServer() *gin.Engine {
gin.SetMode(gin.ReleaseMode)
r := gin.New()
r.GET("/healthz", func(ctx *gin.Context) { ctx.String(200, "OK") })
r.StaticFS("/static", http.FS(&_resource{
r.StaticFS(constant.PublicUrl+"/static", http.FS(&_resource{
fs: ui.Build,
}))

installApi := r.Group("")
installApi.GET("/", CheckConfigFileAndRedirectToInstallPage)
installApi.GET("/install", WebPage)
installApi.GET("/50x", WebPage)
installApi.GET(constant.BaseUrlPath+"/", CheckConfigFileAndRedirectToInstallPage)
installApi.GET(constant.BaseUrlPath+"/install", WebPage)
installApi.GET(constant.BaseUrlPath+"/50x", WebPage)
installApi.GET("/installation/language/options", LangOptions)
installApi.POST("/installation/db/check", CheckDatabase)
installApi.POST("/installation/config-file/check", CheckConfigFile)
Expand Down
25 changes: 13 additions & 12 deletions internal/migrations/init_data.go
Expand Up @@ -20,23 +20,24 @@
package migrations

import (
"github.com/apache/incubator-answer/internal/base/constant"
"github.com/apache/incubator-answer/internal/entity"
"github.com/apache/incubator-answer/internal/service/permission"
)

const (
var (
defaultSEORobotTxt = `User-agent: *
Disallow: /admin
Disallow: /search
Disallow: /install
Disallow: /review
Disallow: /users/login
Disallow: /users/register
Disallow: /users/account-recovery
Disallow: /users/oauth/*
Disallow: /users/*/*
Disallow: /answer/api
Disallow: /*?code*
Disallow: ` + constant.BaseUrlPath + `/admin
Disallow: ` + constant.BaseUrlPath + `/search
Disallow: ` + constant.BaseUrlPath + `/install
Disallow: ` + constant.BaseUrlPath + `/review
Disallow: ` + constant.BaseUrlPath + `/users/login
Disallow: ` + constant.BaseUrlPath + `/users/register
Disallow: ` + constant.BaseUrlPath + `/users/account-recovery
Disallow: ` + constant.BaseUrlPath + `/users/oauth/*
Disallow: ` + constant.BaseUrlPath + `/users/*/*
Disallow: ` + constant.BaseUrlPath + `/answer/api
Disallow: ` + constant.BaseUrlPath + `/*?code*

Sitemap: `
)
Expand Down
11 changes: 6 additions & 5 deletions internal/router/ui.go
Expand Up @@ -22,6 +22,7 @@ package router
import (
"embed"
"fmt"
"github.com/apache/incubator-answer/internal/base/constant"
"io/fs"
"net/http"
"os"
Expand Down Expand Up @@ -92,7 +93,7 @@ func (a *UIRouter) Register(r *gin.Engine) {
}

// handle the static file by default ui static files
r.StaticFS("/static", http.FS(&_resource{
r.StaticFS(constant.PublicUrl+"/static", http.FS(&_resource{
fs: ui.Build,
}))

Expand All @@ -101,7 +102,7 @@ func (a *UIRouter) Register(r *gin.Engine) {
urlPath := c.Request.URL.Path
filePath := ""
switch urlPath {
case "/favicon.ico":
case constant.BaseUrlPath + "/favicon.ico":
branding, err := a.siteInfoService.GetSiteBranding(c)
if err != nil {
log.Error(err)
Expand All @@ -117,13 +118,13 @@ func (a *UIRouter) Register(r *gin.Engine) {
filePath = UIRootFilePath + urlPath

}
case "/manifest.json":
case constant.BaseUrlPath + "/manifest.json":
// filePath = UIRootFilePath + urlPath
a.siteInfoController.GetManifestJson(c)
return
case "/install":
case constant.BaseUrlPath + "/install":
// if answer is running by run command user can not access install page.
c.Redirect(http.StatusFound, "/")
c.Redirect(http.StatusFound, constant.BaseUrlPath+"/")
return
default:
filePath = UIIndexFilePath
Expand Down
3 changes: 2 additions & 1 deletion ui/src/components/AccordionNav/index.tsx
Expand Up @@ -27,13 +27,14 @@ import classNames from 'classnames';
import { floppyNavigation } from '@/utils';
import { Icon } from '@/components';
import './index.css';
import { BASE_URL_PATH } from '@/router/alias';

function MenuNode({
menu,
callback,
activeKey,
expanding = false,
path = '/',
path = `${BASE_URL_PATH}/`,
}) {
const { t } = useTranslation('translation', { keyPrefix: 'nav_menus' });
const isLeaf = !menu.children.length;
Expand Down
3 changes: 2 additions & 1 deletion ui/src/components/BaseUserCard/index.tsx
Expand Up @@ -22,6 +22,7 @@ import { Link } from 'react-router-dom';

import { Avatar } from '@/components';
import { formatCount } from '@/utils';
import { BASE_URL_PATH } from '@/router/alias';

interface Props {
data: any;
Expand All @@ -48,7 +49,7 @@ const Index: FC<Props> = ({
<div className={`d-flex align-items-center text-secondary ${className}`}>
{data?.status !== 'deleted' ? (
<Link
to={`/users/${data?.username}`}
to={`${BASE_URL_PATH}/users/${data?.username}`}
className="d-flex align-items-center">
{showAvatar && (
<Avatar
Expand Down
3 changes: 2 additions & 1 deletion ui/src/components/Comment/components/ActionBar/index.tsx
Expand Up @@ -25,6 +25,7 @@ import { Link } from 'react-router-dom';
import classNames from 'classnames';

import { Icon, FormatTime } from '@/components';
import { BASE_URL_PATH } from '@/router/alias';

const ActionBar = ({
nickName,
Expand All @@ -45,7 +46,7 @@ const ActionBar = ({
<div className="d-flex align-items-center flex-wrap link-secondary">
{userStatus !== 'deleted' ? (
<Link
to={`/users/${username}`}
to={`${BASE_URL_PATH}/users/${username}`}
className="name-ellipsis"
style={{ maxWidth: '200px' }}>
{nickName}
Expand Down
15 changes: 9 additions & 6 deletions ui/src/components/Header/components/NavItems/index.tsx
Expand Up @@ -26,6 +26,7 @@ import type * as Type from '@/common/interface';
import { Avatar, Icon } from '@/components';
import { floppyNavigation } from '@/utils';
import { userCenterStore } from '@/stores';
import { BASE_URL_PATH } from '@/router/alias';

interface Props {
redDot: Type.NotificationStatus | undefined;
Expand All @@ -50,7 +51,7 @@ const Index: FC<Props> = ({ redDot, userInfo, logOut }) => {
<Nav className="flex-row">
<Nav.Link
as={NavLink}
to="/users/notifications/inbox"
to={`${BASE_URL_PATH}/users/notifications/inbox`}
title={t('inbox', { keyPrefix: 'notifications' })}
className="icon-link d-flex align-items-center justify-content-center p-0 me-3 position-relative">
<Icon name="bell-fill" className="fs-4" />
Expand All @@ -65,7 +66,7 @@ const Index: FC<Props> = ({ redDot, userInfo, logOut }) => {

<Nav.Link
as={NavLink}
to="/users/notifications/achievement"
to={`${BASE_URL_PATH}/users/notifications/achievement`}
title={t('achievement', { keyPrefix: 'notifications' })}
className="icon-link d-flex align-items-center justify-content-center p-0 me-3 position-relative">
<Icon name="trophy-fill" className="fs-4" />
Expand Down Expand Up @@ -96,22 +97,24 @@ const Index: FC<Props> = ({ redDot, userInfo, logOut }) => {

<Dropdown.Menu>
<Dropdown.Item
href={`/users/${userInfo.username}`}
href={`${BASE_URL_PATH}/users/${userInfo.username}`}
onClick={handleLinkClick}>
{t('header.nav.profile')}
</Dropdown.Item>
<Dropdown.Item
href={`/users/${userInfo.username}/bookmarks`}
href={`${BASE_URL_PATH}/users/${userInfo.username}/bookmarks`}
onClick={handleLinkClick}>
{t('header.nav.bookmark')}
</Dropdown.Item>
<Dropdown.Item
href="/users/settings/profile"
href={`${BASE_URL_PATH}/users/settings/profile`}
onClick={handleLinkClick}>
{t('header.nav.setting')}
</Dropdown.Item>
<Dropdown.Divider />
<Dropdown.Item href="/users/logout" onClick={(e) => logOut(e)}>
<Dropdown.Item
href={`${BASE_URL_PATH}/users/logout`}
onClick={(e) => logOut(e)}>
{t('header.nav.logout')}
</Dropdown.Item>
</Dropdown.Menu>
Expand Down
13 changes: 9 additions & 4 deletions ui/src/components/Header/index.tsx
Expand Up @@ -48,6 +48,7 @@ import {
sideNavStore,
} from '@/stores';
import { logout, useQueryNotificationStatus } from '@/services';
import { BASE_URL_PATH } from '@/router/alias';

import NavItems from './components/NavItems';

Expand All @@ -70,7 +71,7 @@ const Header: FC = () => {
* Automatically append `tag` information when creating a question
*/
const tagMatch = useMatch('/tags/:slugName');
let askUrl = '/questions/ask';
let askUrl = `${BASE_URL_PATH}/questions/ask`;
if (tagMatch && tagMatch.params.slugName) {
askUrl = `${askUrl}?tags=${encodeURIComponent(tagMatch.params.slugName)}`;
}
Expand All @@ -90,7 +91,9 @@ const Header: FC = () => {
if (!searchStr) {
return;
}
const searchUrl = `/search?q=${encodeURIComponent(searchStr)}`;
const searchUrl = `${BASE_URL_PATH}/search?q=${encodeURIComponent(
searchStr,
)}`;
navigate(searchUrl);
};

Expand Down Expand Up @@ -145,7 +148,10 @@ const Header: FC = () => {
/>

<div className="d-flex justify-content-between align-items-center nav-grow flex-nowrap">
<Navbar.Brand to="/" as={Link} className="lh-1 me-0 me-sm-5 p-0">
<Navbar.Brand
to={`${BASE_URL_PATH}/`}
as={Link}
className="lh-1 me-0 me-sm-5 p-0">
{brandingInfo.logo ? (
<>
<img
Expand Down Expand Up @@ -240,7 +246,6 @@ const Header: FC = () => {
{t('btns.add_question')}
</Link>
</Nav.Item>

<NavItems
redDot={redDot}
userInfo={user}
Expand Down
3 changes: 2 additions & 1 deletion ui/src/components/HttpErrorContent/index.tsx
Expand Up @@ -22,6 +22,7 @@ import { Link } from 'react-router-dom';
import { useTranslation } from 'react-i18next';

import { usePageTags } from '@/hooks';
import { BASE_URL_PATH } from '@/router/alias';

const Index = ({
httpCode = '',
Expand Down Expand Up @@ -63,7 +64,7 @@ const Index = ({
{errMsg || t(`desc_${httpCode}`)}
</div>
<div className="text-center">
<Link to="/" className="btn btn-link">
<Link to={`${BASE_URL_PATH}/`} className="btn btn-link">
{t('back_home')}
</Link>
</div>
Expand Down
5 changes: 3 additions & 2 deletions ui/src/components/Modal/LoginToContinueModal.tsx
Expand Up @@ -25,6 +25,7 @@ import { Link } from 'react-router-dom';
import { loginToContinueStore, siteInfoStore } from '@/stores';
import { floppyNavigation } from '@/utils';
import { WelcomeTitle } from '@/components';
import { BASE_URL_PATH } from '@/router/alias';

interface IProps {
visible: boolean;
Expand Down Expand Up @@ -59,13 +60,13 @@ const Index: React.FC<IProps> = ({ visible = false }) => {
</div>
<div className="d-grid gap-2">
<Link
to="/users/login"
to={`${BASE_URL_PATH}/users/login`}
className="btn btn-primary"
onClick={linkClick}>
{t('login', { keyPrefix: 'btns' })}
</Link>
<Link
to="/users/register"
to={`${BASE_URL_PATH}/users/register`}
className="btn btn-link"
onClick={linkClick}>
{t('signup', { keyPrefix: 'btns' })}
Expand Down
5 changes: 4 additions & 1 deletion ui/src/components/Operate/index.tsx
Expand Up @@ -38,6 +38,7 @@ import {
import { tryNormalLogged } from '@/utils/guard';
import { floppyNavigation } from '@/utils';
import { toastStore } from '@/stores';
import { BASE_URL_PATH } from '@/router/alias';

interface IProps {
type: 'answer' | 'question';
Expand Down Expand Up @@ -70,7 +71,9 @@ const Index: FC<IProps> = ({
};
const closeModal = useReportModal(refreshQuestion);
const editUrl =
type === 'answer' ? `/posts/${qid}/${aid}/edit` : `/posts/${qid}/edit`;
type === 'answer'
? `${BASE_URL_PATH}/posts/${qid}/${aid}/edit`
: `${BASE_URL_PATH}/posts/${qid}/edit`;

const handleReport = () => {
reportModal.onShow({
Expand Down