1
|
|
|
import datetime |
2
|
|
|
import functools |
3
|
|
|
from decimal import Decimal |
4
|
|
|
import decimal |
5
|
|
|
from sqlalchemy import ( |
6
|
|
|
LargeBinary, |
7
|
|
|
Column, |
8
|
|
|
Index, |
9
|
|
|
Integer, |
10
|
|
|
String, |
11
|
|
|
Numeric, |
12
|
|
|
Text, |
13
|
|
|
Enum, |
14
|
|
|
ForeignKey, |
15
|
|
|
Boolean, |
16
|
|
|
LargeBinary, |
17
|
|
|
desc |
18
|
|
|
) |
19
|
|
|
|
20
|
|
|
from sqlalchemy.ext.declarative import declarative_base |
21
|
|
|
|
22
|
|
|
from sqlalchemy.orm import ( |
23
|
|
|
scoped_session, |
24
|
|
|
sessionmaker, |
25
|
|
|
validates, |
26
|
|
|
relationship, |
27
|
|
|
object_session, |
28
|
|
|
backref |
29
|
|
|
) |
30
|
|
|
|
31
|
|
|
from sqlalchemy.ext.hybrid import hybrid_property, hybrid_method |
32
|
|
|
from sqlalchemy.orm import synonym |
33
|
|
|
from sqlalchemy.sql.expression import or_, and_, func, exists |
34
|
|
|
from sqlalchemy.sql.functions import coalesce |
35
|
|
|
from zope.sqlalchemy import ZopeTransactionExtension |
36
|
|
|
|
37
|
|
|
from .history_meta import Versioned, versioned_session |
38
|
|
|
|
39
|
|
|
from pyramid.security import Allow, Everyone |
40
|
|
|
|
41
|
|
|
DBSession = versioned_session(scoped_session(sessionmaker(extension=ZopeTransactionExtension()))) |
42
|
|
|
Base = declarative_base() |
43
|
|
|
|
44
|
|
|
class RootFactory(object): |
45
|
|
|
__name__ = None |
46
|
|
|
__parent__ = None |
47
|
|
|
__acl__ = [ |
48
|
|
|
(Allow, 'user', 'user'), |
49
|
|
|
(Allow, 'serviceaccount', 'service'), |
50
|
|
|
(Allow, 'manager', 'manage'), |
51
|
|
|
(Allow, 'admin', 'admin'), |
52
|
|
|
] |
53
|
|
|
|
54
|
|
|
def __init__(self, request): |
55
|
|
|
pass |
56
|
|
|
|
57
|
|
|
# Decorator that adds optional limit parameter to any all() query |
58
|
|
|
def limitable_all(fn_being_decorated): |
59
|
|
|
@functools.wraps(fn_being_decorated) |
60
|
|
|
def wrapped_fn(*args, limit=None, offset=None, count=False, **kwargs): |
61
|
|
|
q = fn_being_decorated(*args, **kwargs) |
62
|
|
|
if offset: |
63
|
|
|
q = q.offset(offset) |
64
|
|
|
if limit: |
65
|
|
|
if count: |
66
|
|
|
return q.limit(limit).all(), q.count() |
67
|
|
|
else: |
68
|
|
|
return q.limit(limit).all() |
69
|
|
|
else: |
70
|
|
|
if count: |
71
|
|
|
return q.all(), q.count() |
72
|
|
|
else: |
73
|
|
|
return q.all() |
74
|
|
|
return wrapped_fn |
75
|
|
|
|
76
|
|
|
# Helper that checks for common get parameters for limitable queries |
77
|
|
|
def limitable_request(request, fn, prefix=None, limit=None, count=False): |
78
|
|
|
if prefix: |
79
|
|
|
limit_str = prefix + '_limit' |
80
|
|
|
offset_str = prefix + '_offset' |
81
|
|
|
else: |
82
|
|
|
limit_str = 'limit' |
83
|
|
|
offset_str = 'offset' |
84
|
|
|
try: |
85
|
|
|
LIMIT = int(request.GET[limit_str ]) if limit_str in request.GET else limit |
86
|
|
|
except ValueError: |
87
|
|
|
LIMIT = limit |
88
|
|
|
try: |
89
|
|
|
OFFSET = int(request.GET[offset_str]) if offset_str in request.GET else None |
90
|
|
|
except ValueError: |
91
|
|
|
OFFSET = None |
92
|
|
|
|
93
|
|
|
if count: |
94
|
|
|
r, r_tot = fn(limit=LIMIT, offset=OFFSET, count=count) |
95
|
|
|
if LIMIT is None or r_tot <= LIMIT: |
96
|
|
|
r_tot = 0 |
97
|
|
|
return r, r_tot |
98
|
|
|
else: |
99
|
|
|
return fn(limit=LIMIT, offset=OFFSET, count=count) |
100
|
|
|
|
101
|
|
|
|