feat: site login bg upload

parent 9a4ac686
...@@ -59,6 +59,14 @@ router.get('/_site/:siteId?/:resource', async (req, res, next) => { ...@@ -59,6 +59,14 @@ router.get('/_site/:siteId?/:resource', async (req, res, next) => {
} }
break break
} }
case 'loginbg': {
if (site.config.assets.loginBg) {
res.sendFile(path.join(siteAssetsPath, `loginbg-${site.id}.jpg`))
} else {
res.sendFile(path.join(WIKI.ROOTPATH, 'assets/_assets/bg/login.jpg'))
}
break
}
default: { default: {
return res.status(404).send('Invalid Site Resource') return res.status(404).send('Invalid Site Resource')
} }
......
...@@ -489,7 +489,8 @@ exports.up = async knex => { ...@@ -489,7 +489,8 @@ exports.up = async knex => {
logo: false, logo: false,
logoExt: 'svg', logoExt: 'svg',
favicon: false, favicon: false,
faviconExt: 'svg' faviconExt: 'svg',
loginBg: false
}, },
theme: { theme: {
dark: false, dark: false,
......
...@@ -248,6 +248,55 @@ module.exports = { ...@@ -248,6 +248,55 @@ module.exports = {
WIKI.logger.warn(err) WIKI.logger.warn(err)
return graphHelper.generateError(err) return graphHelper.generateError(err)
} }
},
/**
* UPLOAD LOGIN BG
*/
async uploadSiteLoginBg (obj, args) {
try {
const { filename, mimetype, createReadStream } = await args.image
WIKI.logger.info(`Processing site login bg ${filename} of type ${mimetype}...`)
if (!WIKI.extensions.ext.sharp.isInstalled) {
throw new Error('This feature requires the Sharp extension but it is not installed.')
}
if (!['.png', '.jpg', '.webp'].some(s => filename.endsWith(s))) {
throw new Error('Invalid File Extension. Must be png, jpg or webp.')
}
const destFolder = path.resolve(
process.cwd(),
WIKI.config.dataPath,
`assets`
)
const destPath = path.join(destFolder, `loginbg-${args.id}.jpg`)
await fs.ensureDir(destFolder)
// -> Resize
await WIKI.extensions.ext.sharp.resize({
format: 'jpg',
inputStream: createReadStream(),
outputPath: destPath,
width: 1920
})
// -> Save login bg meta to DB
const site = await WIKI.models.sites.query().findById(args.id)
if (!site.config.assets.loginBg) {
site.config.assets.loginBg = uuid()
await WIKI.models.sites.query().findById(args.id).patch({ config: site.config })
await WIKI.models.sites.reloadCache()
}
// -> Save image data to DB
const imgBuffer = await fs.readFile(destPath)
await WIKI.models.knex('assetData').insert({
id: site.config.assets.loginBg,
data: imgBuffer
}).onConflict('id').merge()
WIKI.logger.info('New site login bg processed successfully.')
return {
operation: graphHelper.generateSuccess('Site login bg uploaded successfully')
}
} catch (err) {
WIKI.logger.warn(err)
return graphHelper.generateError(err)
}
} }
} }
} }
...@@ -36,6 +36,11 @@ extend type Mutation { ...@@ -36,6 +36,11 @@ extend type Mutation {
image: Upload! image: Upload!
): DefaultResponse ): DefaultResponse
uploadSiteLoginBg (
id: UUID!
image: Upload!
): DefaultResponse
deleteSite ( deleteSite (
id: UUID! id: UUID!
): DefaultResponse ): DefaultResponse
......
...@@ -87,7 +87,9 @@ module.exports = class Site extends Model { ...@@ -87,7 +87,9 @@ module.exports = class Site extends Model {
assets: { assets: {
logo: false, logo: false,
logoExt: 'svg', logoExt: 'svg',
favicon: false favicon: false,
faviconExt: 'svg',
loginBg: false
}, },
theme: { theme: {
dark: false, dark: false,
......
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
...@@ -13,11 +13,17 @@ q-header.bg-header.text-white.site-header( ...@@ -13,11 +13,17 @@ q-header.bg-header.text-white.site-header(
to='/' to='/'
) )
q-avatar( q-avatar(
v-if='siteStore.logoText'
size='34px' size='34px'
square square
) )
img(src='/_assets/logo-wikijs.svg') img(src='/_site/logo')
q-toolbar-title.text-h6 {{siteStore.title}} img(
v-else
src='/_site/logo'
style='height: 34px'
)
q-toolbar-title.text-h6(v-if='siteStore.logoText') {{siteStore.title}}
q-toolbar.gt-sm( q-toolbar.gt-sm(
style='height: 64px;' style='height: 64px;'
dark dark
......
...@@ -1496,5 +1496,7 @@ ...@@ -1496,5 +1496,7 @@
"admin.terminal.connectError": "Connection Error:", "admin.terminal.connectError": "Connection Error:",
"admin.utilities.disconnectWS": "Disconnect WebSocket Sessions", "admin.utilities.disconnectWS": "Disconnect WebSocket Sessions",
"admin.utilities.disconnectWSHint": "Force all active websocket connections to be closed.", "admin.utilities.disconnectWSHint": "Force all active websocket connections to be closed.",
"admin.utilities.disconnectWSSuccess": "All active websocket connections have been terminated." "admin.utilities.disconnectWSSuccess": "All active websocket connections have been terminated.",
"admin.login.bgUploadSuccess": "Login background image uploaded successfully.",
"admin.login.saveSuccess": "Login configuration saved successfully."
} }
...@@ -51,6 +51,7 @@ q-page.admin-login ...@@ -51,6 +51,7 @@ q-page.admin-login
icon='las la-upload' icon='las la-upload'
color='primary' color='primary'
text-color='white' text-color='white'
@click='uploadBg'
) )
q-separator.q-my-sm(inset) q-separator.q-my-sm(inset)
q-item(tag='label') q-item(tag='label')
...@@ -254,46 +255,95 @@ async function load () { ...@@ -254,46 +255,95 @@ async function load () {
} }
async function save () { async function save () {
state.loading++
try { try {
await APOLLO_CLIENT.mutate({ await APOLLO_CLIENT.mutate({
mutation: gql` mutation: gql`
mutation saveLoginSettings ( mutation saveLoginConfig (
$authAutoLogin: Boolean $id: UUID!
$authEnforce2FA: Boolean $patch: SiteUpdateInput!
) { ) {
site { updateSite (
updateConfig( id: $id
authAutoLogin: $authAutoLogin, patch: $patch
authEnforce2FA: $authEnforce2FA ) {
) { operation {
responseResult { succeeded
succeeded message
errorCode
slug
message
}
} }
} }
} }
`, `,
variables: { variables: {
authAutoLogin: state.config.authAutoLogin ?? false, id: adminStore.currentSiteId,
authEnforce2FA: state.config.authEnforce2FA ?? false patch: {
}, authAutoLogin: state.config.authAutoLogin ?? false,
watchLoading (isLoading) { authEnforce2FA: state.config.authEnforce2FA ?? false
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-site-update') }
} }
}) })
$q.notify({ $q.notify({
type: 'positive', type: 'positive',
message: 'Configuration saved successfully.' message: t('admin.login.saveSuccess')
}) })
} catch (err) { } catch (err) {
$q.notify({ $q.notify({
type: 'negative', type: 'negative',
message: err.message message: 'Failed to save login configuration.',
caption: err.message
}) })
} }
state.loading--
}
async function uploadBg () {
const input = document.createElement('input')
input.type = 'file'
input.onchange = async e => {
state.loading++
try {
const resp = await APOLLO_CLIENT.mutate({
mutation: gql`
mutation uploadLoginBg (
$id: UUID!
$image: Upload!
) {
uploadSiteLoginBg (
id: $id
image: $image
) {
operation {
succeeded
message
}
}
}
`,
variables: {
id: adminStore.currentSiteId,
image: e.target.files[0]
}
})
if (resp?.data?.uploadSiteLoginBg?.operation?.succeeded) {
$q.notify({
type: 'positive',
message: t('admin.login.bgUploadSuccess')
})
} else {
throw new Error(resp?.data?.uploadSiteLoginBg?.operation?.message || 'An unexpected error occured.')
}
} catch (err) {
$q.notify({
type: 'negative',
message: 'Failed to upload login background image.',
caption: err.message
})
}
state.loading--
}
input.click()
} }
// MOUNTED // MOUNTED
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
p.text-grey-7 Login to continue p.text-grey-7 Login to continue
auth-login-panel auth-login-panel
.auth-bg(aria-hidden="true") .auth-bg(aria-hidden="true")
img(src='https://docs.requarks.io/_assets/img/splash/1.jpg' alt='') img(src='/_site/loginbg' alt='')
</template> </template>
<script setup> <script setup>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment