Python bottle.request.forms() Examples

The following are 29 code examples of bottle.request.forms(). You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may also want to check out all available functions/classes of the module bottle.request , or try the search function .
Example #1
Source File: restapi.py    From lokun-record with GNU Affero General Public License v3.0 7 votes vote down vote up
def vpn_report(name):
    keyinfo= key_auth()
    user = model.User.get(name)
    if not 'dl' in request.forms:
        abort(400, "Must include dl")
    dl = int(request.forms['dl'])
    if dl < 0:
        abort(400, "dl must be >= 0")
    user.dl_left = user.dl_left - dl
    if user.dl_left < 0:
        logger.email("dl_finished: " + ",".join(user.username, user.sub_end))
    user.save()
    log("Report for a user recieved (user disconnected from {0})".format(keyinfo.name))
    return {}


#----------
# /nodes/
#---------- 
Example #2
Source File: restapi.py    From lokun-record with GNU Affero General Public License v3.0 6 votes vote down vote up
def dalpay():
    # Since deciding to create lokun-billing, this got a
    # bit.. hacky. 
    try:
        passwd = request.forms["SilentPostPassword"]
        if not sec.compare(passwd, config.dalpay_passwd):
            log("DalPay: Invalid SilentPostPassword")
            abort(401, "Unauthorized")
        message = request.forms["user1"]

        dalpay = DalPay.read(message, key=config.dalpay_key)
        cardtype = request.forms["pay_type"]
        fees = calculate_fees(cardtype, dalpay.amount)

        model.Deposit.new(dalpay.username, dalpay.amount, cardtype,
                          vsk=25.5, fees=fees, deposit=True)

        logger.email("DalPay: {0},{1}".format(dalpay.username, dalpay.amount))

        return config.dalpay_return
    except ValueError as ve:
        logger.email("DalPay: " + str(ve))
        # Do i need to log something more? BK 22.03.2014
        return "<!-- error: {0} -->".format(str(ve)) 
Example #3
Source File: bottleroutes.py    From anvio with GNU General Public License v3.0 6 votes vote down vote up
def search_functions(self):
        try:
            requested_sources = request.forms.getall('sources[]')

            if not len(requested_sources):
                requested_sources = None

            items, full_report = self.interactive.search_for_functions(request.forms.get('terms'), requested_sources)

            items_unique = set([])
            for search_term in items:
                items_unique = items_unique.union(set(items[search_term]))

            return json.dumps({'status': 0, 'results': full_report, 'item_count': len(items_unique)})
        except Exception as e:
            message = str(e.clear_text()) if hasattr(e, 'clear_text') else str(e)
            return json.dumps({'status': 1, 'message': message}) 
Example #4
Source File: bottleroutes.py    From anvio with GNU General Public License v3.0 6 votes vote down vote up
def reroot_tree(self):
        newick = request.forms.get('newick')
        tree = Tree(newick, format=1)

        left_most = tree.search_nodes(name=request.forms.get('left_most'))[0]
        right_most = tree.search_nodes(name=request.forms.get('right_most'))[0]

        new_root = tree.get_common_ancestor(left_most, right_most)
        tree.set_outgroup(new_root)

        # Ete3 tree.write function replaces some charachters that we support in the interface.
        # As a workaround we are going to encode node names with base32, after serialization
        # we are going to decode them back.
        for node in tree.traverse('preorder'):
            node.name = 'base32' + base64.b32encode(node.name.encode('utf-8')).decode('utf-8')

        new_newick = tree.write(format=1)

        # ete also converts base32 padding charachter "=" to "_" so we need to replace it.
        new_newick = re.sub(r"base32(\w*)", lambda m: base64.b32decode(m.group(1).replace('_','=')).decode('utf-8'), new_newick)

        return json.dumps({'newick': new_newick}) 
Example #5
Source File: bottleroutes.py    From anvio with GNU General Public License v3.0 6 votes vote down vote up
def get_taxonomy(self):
        collection = json.loads(request.forms.get('collection'))

        if not self.scg_taxonomy:
            message = "You first need to run `anvi-run-scg-taxonomy` on your contigs database for this to work :("
            run.warning(message)
            return json.dumps({'status': 1, 'message': message})

        output = {}
        try:
            for bin_name in collection:
                output[bin_name] = self.scg_taxonomy.estimate_for_list_of_splits(collection[bin_name], bin_name=bin_name)

            run.info_single('Taxonomy estimation has been requested for bin(s) "%s".' % (", ".join(collection.keys())))
        except Exception as e:
            message = str(e.clear_text()) if hasattr(e, 'clear_text') else str(e)
            return json.dumps({'status': 1, 'message': message})

        return json.dumps(output) 
Example #6
Source File: webRequestHandler.py    From LED-bot with MIT License 6 votes vote down vote up
def routes(self):

		@self.www.route('/')
		def index():
		    return static_file('index.html', root=join(self.here,"www/"))

		@self.www.post('/show-text/')
		def show_text():
			color = (0,255,0)
			if 'message' in request.forms: 
				if 'color' in request.forms:
					color = tuple([int(i) for i in request.forms.color.split(",")])
					background = tuple([int(i) for i in request.forms.background.split(",")])
				self.send_text(request.forms.message,color,background)
				print 'Your message %s! In color %s</b>' % (request.forms.message, color)

		@self.www.post('/show-image/')
		def show_image():
			self.send_image(request.forms.url)
			print 'image URL: %s' % (request.forms.url)

		@self.www.get('/static/<filename:path>')
		def send_static(filename):
		    return static_file(filename, root=join(self.here,"www/")) 
Example #7
Source File: bsc.py    From AIT-Core with MIT License 5 votes vote down vote up
def _add_logger_by_name(self, name):
        ''' Handles POST requests for adding a new logger.

        Expects logger configuration to be passed in the request's query string.
        The logger name is included in the URL and the address components and
        connection type should be included as well. The loc attribute is
        defaulted to "localhost" when making the socket connection if not
        defined.

        loc = IP / interface
        port = port / protocol
        conn_type = udp or ethernet

        Raises:
            ValueError:
                if the port or connection type are not supplied.
        '''
        data = dict(request.forms)
        loc = data.pop('loc', '')
        port = data.pop('port', None)
        conn_type = data.pop('conn_type', None)

        if not port or not conn_type:
            e = 'Port and/or conn_type not set'
            raise ValueError(e)
        address = [loc, int(port)]

        if 'rotate_log' in data:
            data['rotate_log'] = True if data == 'true' else False

        if 'rotate_log_delta' in data:
            data['rotate_log_delta'] = int(data['rotate_log_delta'])

        self._logger_manager.add_logger(name, address, conn_type, **data) 
Example #8
Source File: restapi.py    From lokun-record with GNU Affero General Public License v3.0 5 votes vote down vote up
def auth(name):
    if not 'password' in request.forms:
        abort(400, "Must include a password")
    try:
        return model.User.auth(name, request.forms['password'])
    except ValueError as e:
        abort(errstatus(e), e.message) 
Example #9
Source File: restapi.py    From lokun-record with GNU Affero General Public License v3.0 5 votes vote down vote up
def key_auth(name=""):
    """Authenticates a API key."""
    if 'secret' in request.forms:
        secret = request.forms["secret"]
    elif 'X-Lokun-Secret' in request.headers:
        secret = request.headers["X-Lokun-Secret"]
    else:
        abort(401, "Must include a secret")
    try:
        return model.APIKey.auth(secret, name=name)
    except ValueError:
        log("Not accepted: " + repr(request.forms['secret']))
        abort(403, "Secret not accepted")    

# ------------
# /users/
# ------------ 
Example #10
Source File: restapi.py    From lokun-record with GNU Affero General Public License v3.0 5 votes vote down vote up
def putuser(name):
    if not 'password' in request.forms:
        abort(400, "Must include a password")
    if model.User.exists(name):
        try:
            user = auth(name)
            if request.forms.newpassword:
                user.set_passwd(request.forms['newpassword'])
            if request.forms.email:
                user.email = request.forms.email
        except ValueError as e:
            errstatus(e)
            log(str(e))
            return {'error': e.message}
    else:
        try:
            user = model.User.new(name, request.forms['password'],
                                  request.forms.invite_key,
                                  email=request.forms.email)
            log("Created a new user")
            # temporarily added for fun and profit
            if request.forms.invite_key:
                logger.email("Invite key used: " + request.forms.invite_key)
        except ValueError as e:
            errstatus(e)
            log(str(e))
            return {'error': e.message}
    return dict(user) 
Example #11
Source File: restapi.py    From lokun-record with GNU Affero General Public License v3.0 5 votes vote down vote up
def putisk(name):
    key_auth("billing")
    if 'isk' not in request.forms:
        abort(400, "Must include 'isk'")
    try:
        user = model.User.get(name)
        isk = int(request.forms.isk)
        user.credit_isk += isk
        user.save()
        return str(user.credit_isk)
    except ValueError as ve:
        abort(errstatus(ve), ve.message) 
Example #12
Source File: restapi.py    From lokun-record with GNU Affero General Public License v3.0 5 votes vote down vote up
def postusers():
    if not 'username' in request.forms:
        abort(400, "Must include a username")
    name = request.forms.username
    return putuser(name)


# -------------
# /vpn/
# ------------- 
Example #13
Source File: restapi.py    From lokun-record with GNU Affero General Public License v3.0 5 votes vote down vote up
def node_auth(name):
    """Authorizes and _Authenticates_ a VPN node.

    Used when a node reports its health Used for correctness,
    a VPN node can only report its own health.""" 
    if not 'secret' in request.forms:
        abort(400, "Must include a secret")
    try:
        return model.Node.auth(name, request.forms['secret'])
    except ValueError as e:
        abort(errstatus(e), e.message) 
Example #14
Source File: restapi.py    From lokun-record with GNU Affero General Public License v3.0 5 votes vote down vote up
def postnode(name):
    node = node_auth(name)
    old_usercount = int(node.usercount)
    old_total = int(node.total_throughput) # deep copy
    try:
        # coercing the types since sqlite doesn't give a shit
        # about types
        node.update(usercount = int(request.forms['usercount']),
                    selfcheck = bool(request.forms['selfcheck'].lower() == "true"),
                    throughput = int(request.forms['throughput']),
                    total_throughput = int(request.forms.total_throughput),
                    uptime = request.forms.uptime,
                    cpu = float(request.forms['cpu']))
        log("Updated {0}".format(node.name))
        
        if node.within_limit and old_total < node.throughput_limit:
            message = "throughput_limit: {0}, {1} GB\n\n{2}"
            pretty = pformat(dict(node))
            logger.email(message.format(node.name, node.total_throughput, pretty))

        return {'status': 'ok',
                'userdiff': node.usercount - old_usercount,
                'score': node.score,
                'heartbeat': node.heartbeat}

    except (ValueError, KeyError) as error:
        abort(400, str(error)) 
Example #15
Source File: restapi.py    From lokun-record with GNU Affero General Public License v3.0 5 votes vote down vote up
def putnode(name):
    if 'ip' not in request.forms:
        abort(400, "Must include IP address")
    if model.Node.exists(name):
        try:
            node = node_auth(name)
            node.ip = request.forms["ip"]
            node.save()
            log("Changed IP for a node")
            return dict(node)
        except ValueError as e:
            errstatus(e)
            return {'error': e.message}
    else:
        try:
            is_exit = request.forms.is_exit.lower() == "true"
            max_t = int(request.forms.max_throughput or 0)
            node = model.Node.new(name, request.forms["ip"], is_exit, max_t)
            apikey = model.APIKey.new(name, status="new")
            log("Created a new node: {0}. API key status set to 'new'".format(name))
            return dict({'secret': apikey.key}, **dict(node))
        except ValueError as e:
            errstatus(e)
            return {'error': e.message}
    return {}

# ---------------
# /exits/
# --------------- 
Example #16
Source File: bottleroutes.py    From anvio with GNU General Public License v3.0 5 votes vote down vote up
def save_tree(self):
        try:
            order_full_name = request.forms.get('name')
            order_data = request.forms.get('data')
            tree_type = request.forms.get('tree_type')
            additional = request.forms.get('additional')

            if tree_type == 'samples':
                order_name = order_full_name
                distance = 'NA'
                linkage = 'NA'

                if order_name in self.interactive.layers_order_data_dict:
                    raise ConfigError("Tree name '%s' already exists, overwriting currently not supported." % order_name)

                self.interactive.layers_order_data_dict[order_name] = {'newick': order_data, 'basic': ''}
                TableForLayerOrders(self.interactive.args).add({order_name: {'data_type': 'newick', 'data_value': order_data}})
            else:
                self.interactive.p_meta['item_orders'][order_full_name] = {'type': 'newick', 'data': order_data, 'additional': additional}

                order_name, distance, linkage = order_full_name.split(':')
                anvio_db_path = self.interactive.pan_db_path or self.interactive.profile_db_path

                dbops.add_items_order_to_db(anvio_db_path, order_name, order_data, order_data_type_newick=True, distance=distance, linkage=linkage, additional_data=additional, dont_overwrite=True)

            return json.dumps({'status': 0, 'message': 'New order "%s (D: %s; L: %s)" successfully saved to the database.' % (order_name, distance, linkage)})

        except ConfigError as e:
            message = str(e.clear_text()) if hasattr(e, 'clear_text') else str(e)
            return json.dumps({'status': 1, 'message': message}) 
Example #17
Source File: bottleroutes.py    From anvio with GNU General Public License v3.0 5 votes vote down vote up
def save_state(self, state_name):
        if self.read_only:
            return json.dumps({'status_code': '0'})

        content = request.forms.get('content')
        last_modified = datetime.datetime.now().strftime("%d.%m.%Y %H:%M:%S")

        self.interactive.states_table.store_state(state_name, content, last_modified)

        return json.dumps({'status_code': '1'}) 
Example #18
Source File: bottleroutes.py    From anvio with GNU General Public License v3.0 5 votes vote down vote up
def search_items_by_name(self):
        items_per_page = 30

        query = request.forms.get('search-query')
        page = int(request.forms.get('page') or 0)

        if query and len(query) > 0:
            query = query.lower()
            results = []
            for name in self.interactive.displayed_item_names_ordered:
                if query in name.lower():
                    results.append(name)
        else:
            results = self.interactive.displayed_item_names_ordered

        page_start = max(0, page * items_per_page)
        page_end = min(len(results), (page + 1) * items_per_page)

        total_page = math.ceil(len(results) / items_per_page)

        results = results[page_start:page_end]

        return json.dumps({
            'search-query': query,
            'results': results,
            'page': page,
            'total_page': total_page
            }) 
Example #19
Source File: bottleroutes.py    From anvio with GNU General Public License v3.0 5 votes vote down vote up
def completeness(self):
        completeness_sources = {}
        completeness_data = {}
        if not self.interactive.completeness:
            return json.dumps(completeness_sources)

        split_names = json.loads(request.forms.get('split_names'))
        bin_name = json.loads(request.forms.get('bin_name'))

        run.info_single('Completeness info has been requested for %d splits in %s' % (len(split_names), bin_name))

        p_completion, p_redundancy, scg_domain, domain_probabilities, info_text, results_dict = self.interactive.completeness.get_info_for_splits(set(split_names))

        # convert results_dict (where domains are the highest order items) into a dict that is compatible with the
        # previous format of the dict (where hmm scg source names are the higher order items).
        for domain in results_dict:
            for source in results_dict[domain]:
                completeness_sources[source] = results_dict[domain][source]

        completeness_data['percent_completion'] = p_completion
        completeness_data['percent_redundancy'] = p_redundancy
        completeness_data['domain'] = scg_domain
        completeness_data['info_text'] = info_text
        completeness_data['domain_probabilities'] = domain_probabilities

        # FIXME: We need to look into what we are sending and sort out what needs to be shown:
        return json.dumps({'stats': completeness_sources, 'averages': completeness_data, 'refs': self.interactive.completeness.http_refs}) 
Example #20
Source File: bottleroutes.py    From anvio with GNU General Public License v3.0 5 votes vote down vote up
def store_refined_bins(self):
        data = json.loads(request.forms.get('data'))
        colors = json.loads(request.forms.get('colors'))

        bins_info_dict = {}
        for bin_name in data:
            bins_info_dict[bin_name] = {'html_color': colors[bin_name], 'source': "anvi-refine"}

        try:
            self.interactive.store_refined_bins(data, bins_info_dict)
        except RefineError as e:
            return json.dumps({'status': -1, 'message': e.clear_text()})

        message = 'Done! Collection %s is updated in the database. You can close your browser window (or continue updating).' % (self.interactive.collection_name)
        return json.dumps({'status': 0, 'message': message}) 
Example #21
Source File: bottleroutes.py    From anvio with GNU General Public License v3.0 5 votes vote down vote up
def generate_tree(self):
        gene_cluster_names = set(request.forms.getall('gene_clusters[]'))
        gene_clusters = self.interactive.filter_gene_clusters_dict(argparse.Namespace(gene_clusters_names_of_interest=gene_cluster_names))
        name = request.forms.get('name')
        program = request.forms.get('program')
        aligner = request.forms.get('aligner')
        store_tree = request.forms.get('store_tree')

        temp_fasta_file = filesnpaths.get_temp_file_path()
        temp_tree_file = filesnpaths.get_temp_file_path()
        tree_text = None

        try:
            self.interactive.write_sequences_in_gene_clusters_for_phylogenomics(gene_clusters_dict=gene_clusters, output_file_path=temp_fasta_file, align_with=aligner)
            drivers.driver_modules['phylogeny'][program]().run_command(temp_fasta_file, temp_tree_file)
            tree_text = open(temp_tree_file,'rb').read().decode()

            if store_tree:
                TableForLayerOrders(self.interactive.args).add({name: {'data_type': 'newick', 'data_value': tree_text}})

                # TO DO: instead of injecting new newick tree, we can use TableForLayerOrders.get()
                self.interactive.layers_order_data_dict[name] = {'newick': tree_text, 'basic': None}
        except Exception as e:
            message = str(e.clear_text()) if 'clear_text' in dir(e) else str(e)
            return json.dumps({'status': 1, 'message': message})

        return json.dumps({'status': 0, 'tree': tree_text}) 
Example #22
Source File: bottleroutes.py    From anvio with GNU General Public License v3.0 5 votes vote down vote up
def get_column_info(self):
        gene_callers_id = int(request.forms.get('gene_callers_id'))
        engine = request.forms.get('engine')

        return json.dumps(self.interactive.get_column_info(gene_callers_id, engine)) 
Example #23
Source File: bottleroutes.py    From anvio with GNU General Public License v3.0 5 votes vote down vote up
def get_variability(self):
        options = json.loads(request.forms.get('options'))
        return self.interactive.get_variability(options) 
Example #24
Source File: bottleroutes.py    From anvio with GNU General Public License v3.0 5 votes vote down vote up
def store_structure_as_pdb(self):
        options = json.loads(request.forms.get('options'))
        return self.interactive.store_structure_as_pdb(options) 
Example #25
Source File: bottleroutes.py    From anvio with GNU General Public License v3.0 5 votes vote down vote up
def filter_gene_clusters(self):
        try:
            parameters = {}
            for key in request.forms:
                parameters[key] = float(request.forms.get(key))

            gene_clusters_dict, _ = self.interactive.filter_gene_clusters_from_gene_clusters_dict(copy.deepcopy(self.interactive.gene_clusters), **parameters)
            return json.dumps({'status': 0, 'gene_clusters_list': list(gene_clusters_dict.keys())})
        except Exception as e:
            message = str(e.clear_text()) if hasattr(e, 'clear_text') else str(e)
            return json.dumps({'status': 1, 'message': message}) 
Example #26
Source File: app.py    From opentapioca with Apache License 2.0 5 votes vote down vote up
def jsonp(view):
    """
    Decorator for views that return JSON
    """
    def wrapped(*posargs, **kwargs):
        args = {}
        # if we access the args via get(),
        # we can get encoding errors...
        for k in request.forms:
            args[k] = getattr(request.forms, k)
        for k in request.query:
            args[k] = getattr(request.query, k)
        callback = args.get('callback')
        status_code = 200
        try:
            result = view(args, *posargs, **kwargs)
        except (KeyError) as e:#ValueError, AttributeError, KeyError) as e:
            import traceback, sys
            traceback.print_exc(file=sys.stdout)
            result = {'status':'error',
                    'message':'invalid query',
                    'details': str(e)}
            status_code = 403
        if callback:
            result = '%s(%s);' % (callback, json.dumps(result))

        if status_code == 200:
            return result
        else:
            abort(status_code, result)

    return wrapped 
Example #27
Source File: web.py    From mailur with GNU General Public License v3.0 4 votes vote down vote up
def editor():
    draft_id = request.forms['draft_id']
    with lock.user_scope('editor:%s' % draft_id, wait=5):
        if request.forms.get('delete'):
            local.data_drafts({draft_id: None})
            uids = local.data_msgids.key(draft_id)
            uid = uids[0] if uids else None
            if uid:
                local.msgs_flag([uid], [], ['#trash'])
            return {}

        files = request.files.getall('files')

        draft, related = compose(draft_id)
        updated = {
            k: v for k, v in draft.items()
            if k in ('draft_id', 'parent', 'forward')
        }
        updated.update({
            k: v.strip() for k, v in request.forms.items()
            if k in ('from', 'to')
        })
        updated.update({
            k: v for k, v in request.forms.items()
            if k in ('subject', 'txt')
        })
        updated['time'] = time.time()
        local.data_drafts({draft_id: updated})
        draft.update(updated)
        if files:
            if not related:
                related = message.new()
                related.make_mixed()
            for f in files:
                maintype, subtype = f.content_type.split('/')
                related.add_attachment(
                    f.file.read(), filename=f.filename,
                    maintype=maintype, subtype=subtype
                )
        uid = draft['uid']
        if not uid or files:
            draft['flags'] = draft.get('flags') or '\\Draft \\Seen'
            msg = message.new_draft(draft, related)
            oid, _ = local.new_msg(msg, draft['flags'], no_parse=True)
            if uid:
                local.del_msg(uid)
            local.parse()
            uid = local.pair_origin_uids([oid])[0]
        else:
            oid = local.pair_parsed_uids([uid])[0]
    return {'uid': uid} 
Example #28
Source File: bottleroutes.py    From anvio with GNU General Public License v3.0 4 votes vote down vote up
def store_collections_dict(self):
        if self.read_only:
            return json.dumps("Sorry! This is a read-only instance.")

        source = request.forms.get('source')
        data = json.loads(request.forms.get('data'))
        colors = json.loads(request.forms.get('colors'))

        if not len(source):
            run.info_single('Lousy attempt from the user to store their collection under an empty source identifier name :/')
            return json.dumps("Error: Collection name cannot be empty.")

        num_splits = sum(len(l) for l in list(data.values()))
        if not num_splits:
            run.info_single('The user to store 0 splits as a collection :/')
            return json.dumps("Error: There are no selections to store (you haven't selected anything).")

        if source in self.interactive.collections.collections_dict:
            e = self.interactive.collections.collections_dict[source]
            if e['read_only']:
                run.info_single('Lousy attempt from the user to store their collection under "%s" :/' % source)
                return json.dumps("Well, '%s' is a read-only collection, so you need to come up with a different name... Sorry!" % source)

        run.info_single('A request to store %d bins that describe %d splits under the collection id "%s" '
                        'has been made.' % (len(data), num_splits, source), cut_after=None)

        bins_info_dict = {}
        for bin_name in data:
            bins_info_dict[bin_name] = {'html_color': colors[bin_name], 'source': "anvi-interactive"}

        # the db here is either a profile db, or a pan db, but it can't be both:
        if self.interactive.mode == 'gene':
            db_path = self.interactive.genes_db_path
        else:
            db_path = self.interactive.pan_db_path or self.interactive.profile_db_path

        collections = TablesForCollections(db_path)

        try:
            collections.append(source, data, bins_info_dict)
        except ConfigError as e:
            return json.dumps(e.clear_text())

        # a new collection is stored in the database, but the interactive object
        # does not know about that and needs updatin'
        self.interactive.collections.populate_collections_dict(db_path)

        msg = "New collection '%s' with %d bin%s been stored." % (source, len(data), 's have' if len(data) > 1 else ' has')
        run.info_single(msg)
        return json.dumps(msg) 
Example #29
Source File: api.py    From infrabox with MIT License 4 votes vote down vote up
def get_commit():
    query = dict(request.forms)

    project = query.get('project', None)
    if not project:
        return error(400, "project not set")

    branch_or_sha = query.get('branch_or_sha', None)
    if not branch_or_sha:
        return error(400, "branch_or_sha not set")

    gerrit_port = int(get_env('INFRABOX_GERRIT_PORT'))
    gerrit_hostname = get_env('INFRABOX_GERRIT_HOSTNAME')
    gerrit_username = get_env('INFRABOX_GERRIT_USERNAME')
    gerrit_key_filename = get_env('INFRABOX_GERRIT_KEY_FILENAME')

    client = paramiko.SSHClient()
    client.load_system_host_keys()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    client.connect(username=gerrit_username,
                   hostname=gerrit_hostname,
                   port=gerrit_port,
                   key_filename=gerrit_key_filename)
    client.get_transport().set_keepalive(60)

    change = get_branch(branch_or_sha, client, project)
    branch = None
    if not change:
        change = get_sha(branch_or_sha, client, project)
    else:
        branch = branch_or_sha

    if not change:
        error(404, 'change not found')

    client.close()

    return {
        "sha": change['currentPatchSet']['revision'],
        "branch": branch,
        "url": change['url'],
        "clone_url": "ssh://%s@%s:%s/%s" % (get_env('INFRABOX_GERRIT_USERNAME'),
                                            get_env('INFRABOX_GERRIT_HOSTNAME'),
                                            get_env('INFRABOX_GERRIT_PORT'),
                                            project),
        "author": {
            "name": change['owner']['name'],
            "email": change['owner']['email']
        },
        "message": change['commitMessage']
    }