#!/usr/bin/env python3 # ***** BEGIN GPL LICENSE BLOCK ***** # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # 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 General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ***** END GPL LICENCE BLOCK ***** # ------------------ # Ensure module path import os import sys path = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "..", "modules")) if path not in sys.path: sys.path.append(path) del os, sys, path # -------- import os import json import svn.local import werkzeug import xml.etree.ElementTree import logging from flask import Flask, jsonify, abort, request, make_response, url_for, Response from flask.views import MethodView from flask.ext.restful import Api, Resource, reqparse, fields, marshal from flask.ext.httpauth import HTTPBasicAuth from flask.ext.sqlalchemy import SQLAlchemy app = Flask(__name__) api = Api(app) auth = HTTPBasicAuth() try: import config except ImportError: config = None if config is None: app.config["ALLOWED_EXTENSIONS"] = {'txt', 'mp4', 'png', 'jpg', 'jpeg', 'gif', 'blend', 'zip'} else: app.config.from_object(config.Development) db = SQLAlchemy(app) from application.modules.admin import backend from application.modules.admin import settings from application.modules.projects import admin from application.modules.projects.model import Project, ProjectSetting log = logging.getLogger("webservice") logging.basicConfig(level=logging.DEBUG) @auth.get_password def get_password(username): # Temporarily override API access # TODO (fsiddi) check against users table return '' if username == 'bam': return 'bam' return None @auth.error_handler def unauthorized(): return make_response(jsonify({'message': 'Unauthorized access'}), 403) # return 403 instead of 401 to prevent browsers from displaying # the default auth dialog class DirectoryAPI(Resource): """Displays list of files.""" decorators = [auth.login_required] def __init__(self): parser = reqparse.RequestParser() #parser.add_argument('rate', type=int, help='Rate cannot be converted') parser.add_argument('path', type=str) args = parser.parse_args() super(DirectoryAPI, self).__init__() def get(self, project_name): project = Project.query.filter_by(name=project_name).first() path = request.args['path'] if not path: path = '' path_root_abs = project.repository_path parent_path = '' if path != '': path_root_abs = os.path.join(path_root_abs, path) parent_path = os.pardir if not os.path.isdir(path_root_abs): return jsonify(message="Path is not a directory %r" % path_root_abs) items_list = [] for f in os.listdir(path_root_abs): f_rel = os.path.join(path, f) f_abs = os.path.join(path_root_abs, f) if os.path.isdir(f_abs): items_list.append((f, f_rel, "dir")) else: items_list.append((f, f_rel, "file")) project_files = { "parent_path": parent_path, "items_list": items_list, } return jsonify(project_files) #return {'message': 'Display files list'} class FileAPI(Resource): """Gives acces to a file. Currently requires 2 arguments: - filepath: the path of the file (relative to the project root) - the command (info, checkout) In the case of checkout we plan to support the following arguments: --dependencies --zip (eventually with a compression rate) Default behavior for file checkout is to retunr a zipfile with all dependencies. """ decorators = [auth.login_required] def __init__(self): parser = reqparse.RequestParser() parser.add_argument('filepath', type=str, help="Filepath cannot be blank!") parser.add_argument('command', type=str, required=True, help="Command cannot be blank!") parser.add_argument('arguments', type=str) parser.add_argument('files', type=werkzeug.datastructures.FileStorage, location='files') args = parser.parse_args() super(FileAPI, self).__init__() def get(self, project_name): filepath = request.args['filepath'] command = request.args['command'] project = Project.query.filter_by(name=project_name).first() if command == 'info': r = svn.local.LocalClient(project.repository_path) log = r.log_default(None, None, 5, filepath) log = [l for l in log] return jsonify( filepath=filepath, log=log) elif command == 'checkout': filepath = os.path.join(project.repository_path, filepath) if not os.path.exists(filepath): return jsonify(message="Path not found %r" % filepath) elif os.path.isdir(filepath): return jsonify(message="Path is a directory %r" % filepath) def response_message_iter(): ID_MESSAGE = 1 ID_PAYLOAD = 2 import struct def report(txt): txt_bytes = txt.encode('utf-8') return struct.pack('/file_list', endpoint='file_list') api.add_resource(FileAPI, '//file', endpoint='file')