Package coprs :: Package views :: Package apiv3_ns
[hide private]
[frames] | no frames]

Source Code for Package coprs.views.apiv3_ns

  1  import json 
  2  import flask 
  3  import wtforms 
  4  import sqlalchemy 
  5  import inspect 
  6  from functools import wraps 
  7  from werkzeug.datastructures import ImmutableMultiDict 
  8  from coprs import app 
  9  from coprs.exceptions import CoprHttpException, ObjectNotFound, AccessRestricted, ActionInProgressException 
 10  from coprs.logic.complex_logic import ComplexLogic 
 11   
 12   
 13  apiv3_ns = flask.Blueprint("apiv3_ns", __name__, url_prefix="/api_3") 
 14   
 15   
 16  # HTTP methods 
 17  GET = ["GET"] 
 18  POST = ["POST"] 
 19  PUT = ["POST", "PUT"] 
 20  DELETE = ["POST", "DELETE"] 
21 22 23 -class APIErrorHandler(object):
24 - def handle_404(self, error):
25 if isinstance(error, ObjectNotFound): 26 return self.respond(str(error), 404) 27 return self.respond("Such API endpoint doesn't exist", 404)
28
29 - def handle_403(self, error):
30 return self.handle_xxx(error)
31
32 - def handle_400(self, error):
33 return self.handle_xxx(error)
34
35 - def handle_500(self, error):
36 if isinstance(error, ActionInProgressException): 37 return self.handle_xxx(error) 38 return self.respond("Request wasn't successful, there is probably a bug in the API code.", 500)
39
40 - def handle_504(self, error):
41 return self.respond("The API request timeouted", 504)
42
43 - def handle_xxx(self, error):
44 return self.respond(self.message(error), error.code)
45
46 - def respond(self, message, code):
47 response = flask.jsonify(error=message) 48 response.status_code = code 49 return response
50
51 - def message(self, error):
52 if isinstance(error, CoprHttpException): 53 return error.message 54 if hasattr(error, "description"): 55 return error.description 56 return str(error)
57
58 59 -def query_params():
60 def query_params_decorator(f): 61 @wraps(f) 62 def query_params_wrapper(*args, **kwargs): 63 sig = inspect.signature(f) 64 params = [x for x in sig.parameters] 65 params = list(set(params) - {"args", "kwargs"}) 66 for arg in params: 67 if arg not in flask.request.args: 68 # If parameter has a default value, it is not required 69 if sig.parameters[arg].default == sig.parameters[arg].empty: 70 raise CoprHttpException("Missing argument {}".format(arg)) 71 kwargs[arg] = flask.request.args.get(arg) 72 return f(*args, **kwargs)
73 return query_params_wrapper 74 return query_params_decorator 75
76 77 -def pagination():
78 def pagination_decorator(f): 79 @wraps(f) 80 def pagination_wrapper(*args, **kwargs): 81 form = PaginationForm(flask.request.args) 82 if not form.validate(): 83 raise CoprHttpException(form.errors) 84 kwargs.update(form.data) 85 return f(*args, **kwargs)
86 return pagination_wrapper 87 return pagination_decorator 88
89 90 -def file_upload():
91 def file_upload_decorator(f): 92 @wraps(f) 93 def file_upload_wrapper(*args, **kwargs): 94 if "json" in flask.request.files: 95 data = json.loads(flask.request.files["json"].read()) or {} 96 tuples = [(k, v) for k, v in data.items()] 97 flask.request.form = ImmutableMultiDict(tuples) 98 return f(*args, **kwargs)
99 return file_upload_wrapper 100 return file_upload_decorator 101
102 103 -class PaginationForm(wtforms.Form):
104 limit = wtforms.IntegerField("Limit", validators=[wtforms.validators.Optional()]) 105 offset = wtforms.IntegerField("Offset", validators=[wtforms.validators.Optional()]) 106 order = wtforms.StringField("Order by", validators=[wtforms.validators.Optional()]) 107 order_type = wtforms.SelectField("Order type", validators=[wtforms.validators.Optional()], 108 choices=[("ASC", "ASC"), ("DESC", "DESC")], default="ASC")
109
110 111 -def get_copr(ownername=None, projectname=None):
112 request = flask.request 113 ownername = ownername or request.form.get("ownername") or request.json["ownername"] 114 projectname = projectname or request.form.get("projectname") or request.json["projectname"] 115 return ComplexLogic.get_copr_by_owner_safe(ownername, projectname)
116
117 118 -class Paginator(object):
119 LIMIT = None 120 OFFSET = 0 121 ORDER = "id" 122
123 - def __init__(self, query, model, limit=None, offset=None, order=None, order_type=None, **kwargs):
124 self.query = query 125 self.model = model 126 self.limit = limit or self.LIMIT 127 self.offset = offset or self.OFFSET 128 self.order = order or self.ORDER 129 self.order_type = order_type 130 if not self.order_type: 131 # desc/asc unspecified, use some guessed defaults 132 if self.order == 'id': 133 self.order_type = 'DESC' 134 if self.order == 'name': 135 self.order_type = 'ASC'
136 137
138 - def get(self):
139 if not hasattr(self.model, self.order): 140 raise CoprHttpException("Can order by: {}".format(self.order)) 141 142 order_fun = (lambda x: x) 143 if self.order_type == 'ASC': 144 order_fun = sqlalchemy.asc 145 elif self.order_type == 'DESC': 146 order_fun = sqlalchemy.desc 147 148 return self.query.order_by(order_fun(self.order)).limit(self.limit).offset(self.offset)
149 150 @property
151 - def meta(self):
152 return {k: getattr(self, k) for k in ["limit", "offset", "order", "order_type"]}
153
154 - def map(self, fun):
155 return [fun(x) for x in self.get()]
156
157 - def to_dict(self):
158 return [x.to_dict() for x in self.get()]
159
160 -def editable_copr(f):
161 @wraps(f) 162 def wrapper(ownername, projectname, **kwargs): 163 copr = get_copr(ownername, projectname) 164 if not flask.g.user.can_edit(copr): 165 raise AccessRestricted( 166 "User '{0}' can not see permissions for project '{1}' "\ 167 "(missing admin rights)".format( 168 flask.g.user.name, 169 '/'.join([ownername, projectname]) 170 ) 171 ) 172 return f(copr, **kwargs)
173 return wrapper 174