##// END OF EJS Templates
goto-switcher: optimized performance and query capabilities....
goto-switcher: optimized performance and query capabilities. - Previous implementation had on significant bug. The use of LIMIT 20 was limiting results BEFORE auth checks. In case of large ammount of similarly named repositories user didn't had access too, the result goto search was empty. This was becuase first 20 items fetched didn't pass permission checks and final auth list was empty. To fix this we now use proper filtering for auth using SQL. It means we first check user allowed repositories, and add this as a filter so end result from database is already to only the accessible repositories.

File last commit:

r1891:485023e6 default
r2038:2bdf9d4d default
Show More
gist.py
250 lines | 8.6 KiB | text/x-python | PythonLexer
project: added all source files and assets
r1 # -*- coding: utf-8 -*-
license: updated copyright year to 2017
r1271 # Copyright (C) 2013-2017 RhodeCode GmbH
project: added all source files and assets
r1 #
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
"""
gist model for RhodeCode
"""
import os
import time
import logging
import traceback
import shutil
dan
gists: migrated gists controller to pyramid view.
r1891 from pyramid.threadlocal import get_current_request
project: added all source files and assets
r1 from rhodecode.lib.utils2 import (
safe_unicode, unique_id, safe_int, time_to_datetime, AttributeDict)
from rhodecode.lib.ext_json import json
from rhodecode.model import BaseModel
from rhodecode.model.db import Gist
from rhodecode.model.repo import RepoModel
from rhodecode.model.scm import ScmModel
log = logging.getLogger(__name__)
GIST_STORE_LOC = '.rc_gist_store'
GIST_METADATA_FILE = '.rc_gist_metadata'
class GistModel(BaseModel):
cls = Gist
def _get_gist(self, gist):
"""
Helper method to get gist by ID, or gist_access_id as a fallback
:param gist: GistID, gist_access_id, or Gist instance
"""
return self._get_instance(Gist, gist, callback=Gist.get_by_access_id)
def __delete_gist(self, gist):
"""
removes gist from filesystem
:param gist: gist object
"""
root_path = RepoModel().repos_path
rm_path = os.path.join(root_path, GIST_STORE_LOC, gist.gist_access_id)
log.info("Removing %s", rm_path)
shutil.rmtree(rm_path)
def _store_metadata(self, repo, gist_id, gist_access_id, user_id, username,
gist_type, gist_expires, gist_acl_level):
"""
store metadata inside the gist repo, this can be later used for imports
or gist identification. Currently we use this inside RhodeCode tools
to do cleanup of gists that are in storage but not in database.
"""
metadata = {
'metadata_version': '2',
'gist_db_id': gist_id,
'gist_access_id': gist_access_id,
'gist_owner_id': user_id,
'gist_owner_username': username,
'gist_type': gist_type,
'gist_expires': gist_expires,
'gist_updated': time.time(),
'gist_acl_level': gist_acl_level,
}
metadata_file = os.path.join(repo.path, '.hg', GIST_METADATA_FILE)
with open(metadata_file, 'wb') as f:
f.write(json.dumps(metadata))
def get_gist(self, gist):
return self._get_gist(gist)
def get_gist_files(self, gist_access_id, revision=None):
"""
Get files for given gist
:param gist_access_id:
"""
repo = Gist.get_by_access_id(gist_access_id)
commit = repo.scm_instance().get_commit(commit_id=revision)
return commit, [n for n in commit.get_node('/')]
def create(self, description, owner, gist_mapping,
gist_type=Gist.GIST_PUBLIC, lifetime=-1, gist_id=None,
gist_acl_level=Gist.ACL_LEVEL_PRIVATE):
"""
Create a gist
:param description: description of the gist
:param owner: user who created this gist
gists: use colander schema to validate input data....
r523 :param gist_mapping: mapping [{'filename': 'file1.txt', 'content': content}, ...}]
project: added all source files and assets
r1 :param gist_type: type of gist private/public
:param lifetime: in minutes, -1 == forever
:param gist_acl_level: acl level for this gist
"""
owner = self._get_user(owner)
gist_id = safe_unicode(gist_id or unique_id(20))
lifetime = safe_int(lifetime, -1)
gist_expires = time.time() + (lifetime * 60) if lifetime != -1 else -1
expiration = (time_to_datetime(gist_expires)
if gist_expires != -1 else 'forever')
log.debug('set GIST expiration date to: %s', expiration)
# create the Database version
gist = Gist()
gist.gist_description = description
gist.gist_access_id = gist_id
gist.gist_owner = owner.user_id
gist.gist_expires = gist_expires
gist.gist_type = safe_unicode(gist_type)
gist.acl_level = gist_acl_level
self.sa.add(gist)
self.sa.flush()
if gist_type == Gist.GIST_PUBLIC:
# use DB ID for easy to use GIST ID
gist_id = safe_unicode(gist.gist_id)
gist.gist_access_id = gist_id
self.sa.add(gist)
gist_repo_path = os.path.join(GIST_STORE_LOC, gist_id)
log.debug('Creating new %s GIST repo in %s', gist_type, gist_repo_path)
repo = RepoModel()._create_filesystem_repo(
repo_name=gist_id, repo_type='hg', repo_group=GIST_STORE_LOC,
use_global_config=True)
# now create single multifile commit
message = 'added file'
gists: use colander schema to validate input data....
r523 message += 's: ' if len(gist_mapping) > 1 else ': '
message += ', '.join([x for x in gist_mapping])
project: added all source files and assets
r1
# fake RhodeCode Repository object
fake_repo = AttributeDict({
'repo_name': gist_repo_path,
'scm_instance': lambda *args, **kwargs: repo,
})
ScmModel().create_nodes(
user=owner.user_id, repo=fake_repo,
message=message,
gists: use colander schema to validate input data....
r523 nodes=gist_mapping,
project: added all source files and assets
r1 trigger_push_hook=False
)
self._store_metadata(repo, gist.gist_id, gist.gist_access_id,
owner.user_id, owner.username, gist.gist_type,
gist.gist_expires, gist_acl_level)
return gist
def delete(self, gist, fs_remove=True):
gist = self._get_gist(gist)
try:
self.sa.delete(gist)
if fs_remove:
self.__delete_gist(gist)
else:
log.debug('skipping removal from filesystem')
except Exception:
log.error(traceback.format_exc())
raise
Martin Bornhold
gists: Remove gist_type from update method in model. #4243...
r851 def update(self, gist, description, owner, gist_mapping, lifetime,
gist_acl_level):
project: added all source files and assets
r1 gist = self._get_gist(gist)
gist_repo = gist.scm_instance()
if lifetime == 0: # preserve old value
gist_expires = gist.gist_expires
else:
gist_expires = (
time.time() + (lifetime * 60) if lifetime != -1 else -1)
# calculate operation type based on given data
gist_mapping_op = {}
for k, v in gist_mapping.items():
# add, mod, del
gists: use colander schema to validate input data....
r523 if not v['filename_org'] and v['filename']:
project: added all source files and assets
r1 op = 'add'
gists: use colander schema to validate input data....
r523 elif v['filename_org'] and not v['filename']:
project: added all source files and assets
r1 op = 'del'
else:
op = 'mod'
v['op'] = op
gist_mapping_op[k] = v
gist.gist_description = description
gist.gist_expires = gist_expires
gist.owner = owner
gist.acl_level = gist_acl_level
self.sa.add(gist)
self.sa.flush()
message = 'updated file'
message += 's: ' if len(gist_mapping) > 1 else ': '
message += ', '.join([x for x in gist_mapping])
# fake RhodeCode Repository object
fake_repo = AttributeDict({
'repo_name': gist_repo.path,
'scm_instance': lambda *args, **kwargs: gist_repo,
})
self._store_metadata(gist_repo, gist.gist_id, gist.gist_access_id,
owner.user_id, owner.username, gist.gist_type,
gist.gist_expires, gist_acl_level)
# this can throw NodeNotChangedError, if changes we're trying to commit
# are not actually changes...
ScmModel().update_nodes(
user=owner.user_id,
repo=fake_repo,
message=message,
nodes=gist_mapping_op,
trigger_push_hook=False
)
return gist
dan
gists: migrated gists controller to pyramid view.
r1891
def get_url(self, gist, request=None):
import rhodecode
if not request:
request = get_current_request()
alias_url = rhodecode.CONFIG.get('gist_alias_url')
if alias_url:
return alias_url.replace('{gistid}', gist.gist_access_id)
return request.route_url('gist_show', gist_id=gist.gist_access_id)