Add Template Gallery support

This commit is contained in:
yu-i-i
2026-07-17 17:56:04 +02:00
parent e0050414d6
commit 2a8b0bef67
68 changed files with 3063 additions and 31 deletions
@@ -783,11 +783,16 @@ const _ProjectController = {
)
}
console.log("Features.hasFeature('templates-server-pro') = ", Features.hasFeature('templates-server-pro'))
console.log("Settings.templates?.nonAdminCanManage", Settings.templates?.nonAdminCanManage)
const isAdminOrTemplateOwner =
hasAdminAccess(user) || Settings.templates?.user_id === userId
hasAdminAccess(user) || Settings.templates?.nonAdminCanManage
const showTemplatesServerPro =
Features.hasFeature('templates-server-pro') && isAdminOrTemplateOwner
console.log("showTemplatesServerPro = ", showTemplatesServerPro )
const debugPdfDetach = shouldDisplayFeature('debug_pdf_detach')
const detachRole = req.params.detachRole
@@ -7,21 +7,22 @@ import { expressify } from '@overleaf/promise-utils'
const TemplatesController = {
async getV1Template(req, res) {
const templateVersionId = req.params.Template_version_id
const templateId = req.query.id
if (!/^[0-9]+$/.test(templateVersionId) || !/^[0-9]+$/.test(templateId)) {
logger.err(
{ templateVersionId, templateId },
'invalid template id or version'
)
return res.sendStatus(400)
}
const templateId = req.params.Template_version_id
const templateVersionId = req.query.version
// if (!/^[0-9]+$/.test(templateVersionId) || !/^[0-9]+$/.test(templateId)) {
// logger.err(
// { templateVersionId, templateId },
// 'invalid template id or version'
// )
// return res.sendStatus(400)
// }
const data = {
templateVersionId,
templateId,
name: req.query.templateName,
compiler: ProjectHelper.compilerFromV1Engine(req.query.latexEngine),
imageName: req.query.texImage,
name: req.query.name,
compiler: req.query.compiler,
language: req.query.language,
imageName: req.query.imageName,
mainFile: req.query.mainFile,
brandVariationId: req.query.brandVariationId,
}
@@ -36,6 +37,7 @@ const TemplatesController = {
async createProjectFromV1Template(req, res) {
const userId = SessionManager.getLoggedInUserId(req.session)
const project = await TemplatesManager.promises.createProjectFromV1Template(
req.body.brandVariationId,
req.body.compiler,
@@ -44,7 +46,8 @@ const TemplatesController = {
req.body.templateName,
req.body.templateVersionId,
userId,
req.body.imageName
req.body.imageName,
req.body.language
)
delete req.session.templateData
if (!project) {
@@ -20,6 +20,7 @@ import OError from '@overleaf/o-error'
const { promises: ProjectRootDocManager } = ProjectRootDocManagerModule
const { promises: ProjectOptionsHandler } = ProjectOptionsHandlerModule
const TIMEOUT = 30000 // 30 sec
const TemplatesManager = {
async createProjectFromV1Template(
@@ -30,7 +31,8 @@ const TemplatesManager = {
templateName,
templateVersionId,
userId,
imageName
imageName,
spellCheckLanguage
) {
compiler = ProjectOptionsHandler.normalizeCompiler(
compiler || settings.defaultLatexCompiler
@@ -39,13 +41,9 @@ const TemplatesManager = {
imageName || 'wl_texlive:2018.1'
)
const zipUrl = `${settings.apis.v1.url}/api/v1/overleaf/templates/${templateVersionId}`
const zipUrl = `${settings.apis.filestore.url}/template/${templateId}/v/${templateVersionId}/zip`
const zipReq = await fetchStreamWithResponse(zipUrl, {
basicAuth: {
user: settings.apis.v1.user,
password: settings.apis.v1.pass,
},
signal: AbortSignal.timeout(settings.apis.v1.timeout),
signal: AbortSignal.timeout(TIMEOUT),
})
const projectName = ProjectDetailsHandler.fixProjectName(templateName)
@@ -53,10 +51,9 @@ const TemplatesManager = {
const writeStream = fs.createWriteStream(dumpPath)
try {
const attributes = {
fromV1TemplateId: templateId,
fromV1TemplateVersionId: templateVersionId,
compiler,
imageName,
spellCheckLanguage
}
if (brandVariationId) attributes.brandVariationId = brandVariationId
@@ -413,7 +413,7 @@ export default async function (webRouter, privateApiRouter, publicApiRouter) {
labsEnabled: Settings.labs && Settings.labs.enable,
wikiEnabled: Settings.overleaf != null || Settings.proxyLearn,
templatesEnabled:
Settings.overleaf != null || Settings.templates?.user_id != null,
Settings.overleaf != null || Boolean(Settings.moduleImportSequence.includes('template-gallery')),
cioWriteKey: Settings.analytics?.cio?.writeKey,
cioSiteId: Settings.analytics?.cio?.siteId,
linkedInInsightsPartnerId: Settings.analytics?.linkedIn?.partnerId,
@@ -68,7 +68,7 @@ const Features = {
case 'oauth':
return Boolean(Settings.oauth)
case 'templates-server-pro':
return Boolean(Settings.templates?.user_id)
return Boolean(Settings.moduleImportSequence.includes('template-gallery'))
case 'affiliations':
case 'analytics':
return Boolean(_.get(Settings, ['apis', 'v1', 'url']))
+2
View File
@@ -283,6 +283,8 @@ async function initialize(webRouter, privateApiRouter, publicApiRouter) {
'/read-only/one-time-login'
)
await Modules.applyRouter(webRouter, privateApiRouter, publicApiRouter)
webRouter.get('/logout', UserPagesController.logout)
webRouter.post('/logout', UserController.logout)
@@ -151,6 +151,17 @@ nav.navbar.navbar-default.navbar-main.navbar-expand-lg(
// logged out
if !getSessionUser()
// templates link
li
a(
href="/templates"
event-tracking="menu-click"
event-tracking-action="clicked"
event-tracking-trigger="click"
event-tracking-mb="true"
event-segmentation={ page: currentUrl, item: 'templates', location: 'top-menu' }
) #{translate('templates')}
// register link
if hasFeature('registration-page')
+nav-item.primary
@@ -29,8 +29,10 @@ block content
input(type="hidden" name="templateVersionId" value=templateVersionId)
input(type="hidden" name="templateName" value=name)
input(type="hidden" name="compiler" value=compiler)
input(type="hidden" name="imageName" value=imageName)
if imageName
input(type="hidden" name="imageName" value=imageName)
input(type="hidden" name="mainFile" value=mainFile)
input(type="hidden" name="language" value=language)
if brandVariationId
input(type="hidden" name="brandVariationId" value=brandVariationId)
input(hidden type="submit")
@@ -0,0 +1,18 @@
extends ../layout-react
block entrypointVar
- entrypoint = 'pages/template-gallery'
block vars
block vars
- const suppressNavContentLinks = true
- const suppressNavbar = true
- const suppressFooter = true
- bootstrap5PageStatus = 'enabled' // One of 'disabled', 'enabled', and 'queryStringOnly'
- isWebsiteRedesign = false
block append meta
meta(name="ol-templateCategory" data-type="string" content=category)
block content
#template-gallery-root
@@ -0,0 +1,20 @@
extends ../layout-react
block entrypointVar
- entrypoint = 'pages/template'
block vars
- const suppressNavContentLinks = true
- const suppressNavbar = true
- const suppressFooter = true
- bootstrap5PageStatus = 'enabled' // One of 'disabled', 'enabled', and 'queryStringOnly'
- isWebsiteRedesign = false
block append meta
meta(name="ol-template" data-type="json" content=template)
meta(name="ol-languages" data-type="json" content=languages)
meta(name="ol-userIsAdmin" data-type="boolean" content=hasAdminAccess())
block content
#template-root