From e53a24f8f51598abe9bcbf903a41325d83fe76e9 Mon Sep 17 00:00:00 2001 From: Nate Stemen Date: Wed, 4 Oct 2017 17:56:43 +0100 Subject: [PATCH] starting to generalize from labels to metadata --- .../ProjectMetadata/MetadataController.coffee | 36 +++++++++++++ .../ProjectMetadata/MetadataHandler.coffee | 50 +++++++++++++++++++ services/web/app/coffee/router.coffee | 3 ++ .../ide/metadata/MetadataManager.coffee | 13 +++++ .../ide/metadata/services/metadata.coffee | 46 +++++++++++++++++ 5 files changed, 148 insertions(+) create mode 100644 services/web/app/coffee/Features/ProjectMetadata/MetadataController.coffee create mode 100644 services/web/app/coffee/Features/ProjectMetadata/MetadataHandler.coffee create mode 100644 services/web/public/coffee/ide/metadata/MetadataManager.coffee create mode 100644 services/web/public/coffee/ide/metadata/services/metadata.coffee diff --git a/services/web/app/coffee/Features/ProjectMetadata/MetadataController.coffee b/services/web/app/coffee/Features/ProjectMetadata/MetadataController.coffee new file mode 100644 index 0000000000..81baa2bf93 --- /dev/null +++ b/services/web/app/coffee/Features/ProjectMetadata/MetadataController.coffee @@ -0,0 +1,36 @@ +EditorRealTimeController = require "../Editor/EditorRealTimeController" +MetadataHandler = require './MetadataHandler' +logger = require 'logger-sharelatex' + + +module.exports = MetadataController = + + getAllMetadata: (req, res, next) -> + project_id = req.params.project_id + logger.log {project_id}, "getting metadata for project" + MetadataHandler.getMetadataForProject project_id, (err, projectMetadata) -> + if err? + logger.err {project_id, err}, "[MetadataController] error getting metadata from project" + return next(err) + res.json { + projectId: project_id + projectLabels: projectMetadata["labels"] + projectPackages: projectMetadata["packages"] + } + + broadcastMetadataForDoc: (req, res, next) -> + project_id = req.params.project_id + doc_id = req.params.doc_id + logger.log {project_id, doc_id}, "getting metadata for doc" + MetadataHandler.getMetadataForDoc project_id, doc_id, (err, docMetadata) -> + if err? + logger.err {project_id, doc_id, err}, "[MetadataController] error getting metadata from doc" + return next(err) + EditorRealTimeController.emitToRoom project_id, "broadcastDocMetadata", { + docId: doc_id + metadata: { + labels: docMetadata["labels"] + packages: docMetadata["packages"] + } + } + res.sendStatus(200) diff --git a/services/web/app/coffee/Features/ProjectMetadata/MetadataHandler.coffee b/services/web/app/coffee/Features/ProjectMetadata/MetadataHandler.coffee new file mode 100644 index 0000000000..6637b382b3 --- /dev/null +++ b/services/web/app/coffee/Features/ProjectMetadata/MetadataHandler.coffee @@ -0,0 +1,50 @@ +ProjectEntityHandler = require "../Project/ProjectEntityHandler" +DocumentUpdaterHandler = require '../DocumentUpdater/DocumentUpdaterHandler' + + +module.exports = MetadataHandler = + + labelCaptureRegex: () -> + /\\label\{([^\}\n\\]{0,80})\}/g + + packageCaptureRegex: () -> + /\\usepackage(?:\[((?:.|\n)*?)])?\s*?{((?:.|\n)*?)}/gm + + getMetadataForProject: (projectId, callback=(err, projectMetadata)->) -> + DocumentUpdaterHandler.flushProjectToMongo projectId. (err) -> + if err? + return callback(err) + ProjectEntityHandler.getAllDocs projectId, (err, docs) -> + if err? + return callback(err) + projectMetadata = MetadataHandler.extractMetadataFromProjectDocs docs + callback(null, projectMetadata) + + getMetadataForDoc: (projectId, docId, callback=(err, docMetadata)->) -> + DocumentUpdaterHandler.flushDocToMongo projectId, docId, (err) -> + if err? + return callback(err) + ProjectEntityHandler.getDoc projectId, docId, (err, lines) -> + if err? + return callback(err) + docMetadata = MetadataHandler.extractMetadataFromDoc lines + callback(null, docMetadata) + + extractMetadataFromProjectDocs: (projectDocs) -> + projectMetadata = {} + for _path, doc of projectDocs + projectMetadata[doc._id] = MetadataHandler.extractMetadataFromDoc doc.lines + return projectMetadata + + extractMetadataFromDoc: (lines) -> + docMetadata = {labels: [] packages: []} + label_re = MetadataHandler.labelCaptureRegex() + package_re = MetadataHandler.packageCaptureRegex() + for line in lines # FIXME: usepackage can run over multiple lines + while labelMatch = label_re.exec line + if labelMatch[1] + docMetadata.labels.push labelMatch[1] + while packageMatch = package_re.exec line + if packageMatch[2] + docMetadata.packages.push packageMatch[2] + return docMetadata diff --git a/services/web/app/coffee/router.coffee b/services/web/app/coffee/router.coffee index 2ebde53748..075fbc8905 100644 --- a/services/web/app/coffee/router.coffee +++ b/services/web/app/coffee/router.coffee @@ -204,6 +204,9 @@ module.exports = class Router webRouter.get '/project/:project_id/labels', AuthorizationMiddlewear.ensureUserCanReadProject, AuthenticationController.requireLogin(), LabelsController.getAllLabels webRouter.post '/project/:project_id/doc/:doc_id/labels', AuthorizationMiddlewear.ensureUserCanReadProject, AuthenticationController.requireLogin(), LabelsController.broadcastLabelsForDoc + webRouter.get '/project/:project_id/metadata', AuthorizationMiddlewear.ensureUserCanReadProject, AuthenticationController.requireLogin(), MetadataController.getAllMetadata + webRouter.post '/project/:project_id/doc/:doc_id/metadata'. AuthorizationMiddlewear.ensureUserCanReadProject, AuthenticationController.requireLogin(), MetadataController.broadcastMetadataForDoc + webRouter.get '/tag', AuthenticationController.requireLogin(), TagsController.getAllTags webRouter.post '/tag', AuthenticationController.requireLogin(), TagsController.createTag webRouter.post '/tag/:tag_id/rename', AuthenticationController.requireLogin(), TagsController.renameTag diff --git a/services/web/public/coffee/ide/metadata/MetadataManager.coffee b/services/web/public/coffee/ide/metadata/MetadataManager.coffee new file mode 100644 index 0000000000..fa908e7dd8 --- /dev/null +++ b/services/web/public/coffee/ide/metadata/MetadataManager.coffee @@ -0,0 +1,13 @@ +define [], () -> + + class MetadataManager + + constructor: (@ide, @$scope, @metadata) -> + + @ide.socket.on 'broadcastDocMetadata', (data) => + @metadata.onBroadcastDocMetadata(data) + @$scope.$on 'entity:deleted', @metadata.onEntityDeleted + @$scope.$on 'file:upload:complete', @metadata.fileUploadComplete + + loadProjectMetadataFromServer: () -> + @metadata.loadProjectMetadataFromServer() diff --git a/services/web/public/coffee/ide/metadata/services/metadata.coffee b/services/web/public/coffee/ide/metadata/services/metadata.coffee new file mode 100644 index 0000000000..e6ad3aec43 --- /dev/null +++ b/services/web/public/coffee/ide/metadata/services/metadata.coffee @@ -0,0 +1,46 @@ +define [ + "base" +], (App) -> + + App.factory 'metadata', ($http, ide) -> + + state = {documents: {}} + + metadata = { + state: state + } + + metadata.onBroadcastDocMetadata = (data) -> + if data.docId and data.metadata + state.documents[data.docId] = data.metadata + + metadata.onEntityDeleted = (e, entity) -> + if entity.type == 'doc' + delete state.documents[entity.id] + + metadata.onFileUploadComplete = (e, upload) -> + if upload.entity_type == 'doc' + metadata.loadDocMetadataFromServer(upload.entity_id) + + metadata.getAllMetadata = () -> + labels = _.flatten(meta['labels'] for docId, meta of state.documents) + packages = _.flatten(meta['packages'] for docId, meta of state.documents) + {labels: labels, packages: packages} + + metadata.loadProjectMetadataFromServer = () -> + $http + .get("/project/#{window.project_id}/metadata") + .then (response) -> + { data } = response + if data.projectMetadata + for docId, docMetadata of data.projectMetadata + state.documents[docId] = docMetadata + + metadata.loadDocMetadataFromServer = (docId) -> + $http + .post( + "/project/#{window.project_id}/doc/#{docId}/metadata", + {_csrf: window.csrfToken} + ) + + return metadata