ForgeFiles/forgefiles/model/files.py (163 lines of code) (raw):

# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. ''' This is the Collection module for the Files plugin. Upload, UploadFolder & UploadFile are the collections''' from datetime import datetime from urllib.parse import quote import re import typing from ming import schema as S from ming.odm import Mapper from ming.odm import FieldProperty, ForeignIdProperty, RelationProperty from bson import ObjectId from tg import tmpl_context as c from allura.model.artifact import VersionedArtifact from allura.model.auth import AlluraUserProperty, User from allura.model.session import project_orm_session, artifact_orm_session from allura.model.filesystem import File from allura.model.timeline import ActivityObject from allura.lib import helpers as h if typing.TYPE_CHECKING: from ming.odm.mapper import Query README_RE = re.compile(r'^README(\.[^.]*)?$', re.IGNORECASE) class Upload(VersionedArtifact, ActivityObject): ''' The Upload collection for files. ''' class __mongometa__: name = 'upload' session = project_orm_session query: 'Query[Upload]' type_s = 'Upload' _id = FieldProperty(S.ObjectId) filename = FieldProperty(str) filetype = FieldProperty(str) project_id = ForeignIdProperty('Project', if_missing=lambda: c.project._id) created_date = FieldProperty(datetime, if_missing=datetime.utcnow) project = RelationProperty('Project', via='project_id') file_url = None @classmethod def attachment_class(cls): return UploadFiles @property def activity_name(self): return self.filename @property def activity_url(self): return self.file_url class UploadFolder(VersionedArtifact, ActivityObject): ''' The UploadFolder collection is for the Folders. Every folder is an object of this class.''' class __mongometa__: name = 'upload_folder' session = project_orm_session query: 'Query[UploadFolder]' type_s = 'UploadFolder' _id = FieldProperty(S.ObjectId) folder_name = FieldProperty(str) project_id = ForeignIdProperty('Project', if_missing=lambda: c.project._id) parent_folder_id = ForeignIdProperty('UploadFolder') created_date = FieldProperty(datetime, if_missing=datetime.utcnow) author_id = ForeignIdProperty('User', if_missing=lambda: c.user._id) parent_folder = RelationProperty('UploadFolder', via='parent_folder_id') project = RelationProperty('Project', via='project_id') path = FieldProperty(str) published = FieldProperty(bool, if_missing=False) remarks = FieldProperty(str) disabled = FieldProperty(bool, if_missing=False) folder_ids = FieldProperty([str]) file_ids = FieldProperty([str]) author = RelationProperty(User, via='author_id') def url(self): parent_folder = self.parent_folder if parent_folder: string = '' while parent_folder: string += parent_folder.folder_name + '/' parent_folder = parent_folder.parent_folder list_obj = string.rsplit('/')[::-1] string = '/'.join(list_obj) string = string.lstrip('/') url_str = c.app.url + string + '/' + self.folder_name self.path = string + '/' + self.folder_name else: url_str = c.app.url + self.folder_name self.path = self.folder_name return quote(url_str) def folder_id(self): return str(self._id) @property def activity_name(self): return self.folder_name @property def activity_url(self): parent_folder = self.parent_folder if parent_folder: return parent_folder.url() else: return c.app.url class UploadFiles(File): '''The UploadFiles collection is for the Files. Any file which is uploaded is treated as an Upload object''' thumbnail_size = (255, 255) ArtifactType = Upload class __mongometa__: name = 'upload_files' session = project_orm_session indexes = [ ('app_config_id', 'parent_folder_id', 'filename'), ('app_config_id', 'linked_to_download', 'disabled'), ('app_config_id', 'filename', 'path'), ] def before_save(data): _session = artifact_orm_session._get() skip_last_updated = getattr(_session, 'skip_last_updated', False) data['mod_date'] = datetime.utcnow() if c.project and not skip_last_updated: c.project.last_updated = datetime.utcnow() query: 'Query[UploadFiles]' artifact_id = FieldProperty(S.ObjectId) app_config_id = FieldProperty(S.ObjectId) type = FieldProperty(str) project_id = FieldProperty(S.ObjectId) parent_folder_id = ForeignIdProperty('UploadFolder') created_date = FieldProperty(datetime, if_missing=datetime.utcnow) mod_date = FieldProperty(datetime, if_missing=datetime.utcnow) author_id: ObjectId = AlluraUserProperty(if_missing=lambda: c.user._id) parent_folder = RelationProperty('UploadFolder', via='parent_folder_id') linked_to_download = FieldProperty(bool, if_missing=False) path = FieldProperty(str) disabled = FieldProperty(bool, if_missing=False) author = RelationProperty(User, via='author_id') @property def artifact(self): '''Returns the Artifact object''' return self.ArtifactType.query.get(_id=self.artifact_id) def url(self): '''Returns the URL of the uploaded file''' parent_folder = self.parent_folder if parent_folder: string = '' while parent_folder: string += parent_folder.folder_name + '/' parent_folder = parent_folder.parent_folder list_obj = string.rsplit('/')[::-1] string = '/'.join(list_obj) string = string.lstrip('/') url_str = c.app.url + string + '/' + self.filename self.path = string + '/' + self.filename else: url_str = c.app.url + self.filename self.path = self.filename return quote(url_str) def readme(self): 'returns (filename, unicode text) if a readme file is found' if README_RE.match(self.filename): name = self.filename obj_content = self.rfile().read(self.rfile().length) return (self.filename, h.really_unicode(obj_content)) return None, None @classmethod def save_attachment(cls, filename, fp, content_type=None, **kwargs): filename = h.really_unicode(filename) original_meta = dict(type="project_file", app_config_id=c.app.config._id, project_id=c.project._id) original_meta.update(kwargs) fp.seek(0) return cls.from_stream( filename, fp, content_type=content_type, **original_meta) Mapper.compile_all()