1
|
|
|
# -*- coding: utf-8 -*- |
2
|
|
|
from tzlocal import get_localzone |
3
|
|
|
from datetime import datetime |
4
|
|
|
from sqlalchemy import func |
5
|
|
|
|
6
|
|
|
from pyjobsweb.model import DBSession |
7
|
|
|
from pyjobsweb.model import JobAlchemy, CompanyAlchemy |
8
|
|
|
|
9
|
|
|
|
10
|
|
|
def _find_type(sqlalchemy_table_class, column_name): |
11
|
|
|
if hasattr(sqlalchemy_table_class, '__table__') \ |
12
|
|
|
and column_name in sqlalchemy_table_class.__table__.c: |
13
|
|
|
return sqlalchemy_table_class.__table__.c[column_name].type |
14
|
|
|
for base in sqlalchemy_table_class.__bases__: |
15
|
|
|
return _find_type(base, column_name) |
16
|
|
|
raise NameError(column_name) |
17
|
|
|
|
18
|
|
|
|
19
|
|
|
def is_dirty(old_model, new_model): |
20
|
|
|
for column in old_model.__table__.columns: |
21
|
|
|
column = column.name |
22
|
|
|
if getattr(old_model, column, None) != getattr(new_model, column, None): |
23
|
|
|
return True |
24
|
|
|
|
25
|
|
|
return False |
26
|
|
|
|
27
|
|
|
|
28
|
|
|
def kw_to_sqlalchemy(sqlalchemy_table_cls, kw): |
29
|
|
|
sqlalchemy_table = sqlalchemy_table_cls() |
30
|
|
|
|
31
|
|
|
for column, value in kw.iteritems(): |
32
|
|
|
try: |
33
|
|
|
column_type = _find_type(sqlalchemy_table_cls, column) |
34
|
|
|
python_type = column_type.python_type |
35
|
|
|
except NameError: |
36
|
|
|
continue |
37
|
|
|
|
38
|
|
|
try: |
39
|
|
|
if not issubclass(type(value), python_type): |
40
|
|
|
if issubclass(python_type, bool): |
41
|
|
|
column_value = True if value.lower() == 'true' else False |
42
|
|
|
else: |
43
|
|
|
column_value = python_type(value) |
44
|
|
|
else: |
45
|
|
|
column_value = value |
46
|
|
|
except UnicodeEncodeError: |
47
|
|
|
column_value = unicode(value) |
48
|
|
|
finally: |
49
|
|
|
if issubclass(python_type, datetime): |
50
|
|
|
if column_type.timezone: |
51
|
|
|
# Convert to local time |
52
|
|
|
tz = get_localzone() |
53
|
|
|
column_value = tz.localize(column_value, is_dst=None) |
54
|
|
|
setattr(sqlalchemy_table, column, column_value) |
55
|
|
|
|
56
|
|
|
return sqlalchemy_table |
57
|
|
|
|
58
|
|
|
|
59
|
|
|
def sqlalchemy_to_kw(sqlalchemy_obj): |
60
|
|
|
res = {} |
61
|
|
|
for column in sqlalchemy_obj.__table__.columns: |
62
|
|
|
res[column.name] = getattr(sqlalchemy_obj, column.name) |
63
|
|
|
|
64
|
|
|
return res |
65
|
|
|
|
66
|
|
|
|
67
|
|
|
def prepare_job_for_address_update(job_offer): |
68
|
|
|
assert isinstance(job_offer, JobAlchemy) |
69
|
|
|
|
70
|
|
|
# The address has been modified, therefore the geolocation should be |
71
|
|
|
# recomputed, so we mark the address as valid, so that the geolocation |
72
|
|
|
# program will try and recompute it later on. |
73
|
|
|
job_offer.address_is_valid = True |
74
|
|
|
|
75
|
|
|
# We reset the geolocation related fields to their default values too. |
76
|
|
|
# This bit isn't necessary, because the controller can only alter the |
77
|
|
|
# content of rows with invalid addresses, and therefore rows which |
78
|
|
|
# geolocation isn't valid by definition. But it doesn't hurt to put this |
79
|
|
|
# additional code here. It just makes the manipulation of the Companies |
80
|
|
|
# table consistent across the geocoding issues controller and the |
81
|
|
|
# general crud controller. |
82
|
|
|
job_offer.latitude = 0.0 |
83
|
|
|
job_offer.longitude = 0.0 |
84
|
|
|
job_offer.geolocation_is_valid = False |
85
|
|
|
|
86
|
|
|
|
87
|
|
|
def prepare_company_for_address_update(company): |
88
|
|
|
assert isinstance(company, CompanyAlchemy) |
89
|
|
|
|
90
|
|
|
# The address has been modified, therefore the geolocation should be |
91
|
|
|
# recomputed, so we mark the address as valid, so that the geolocation |
92
|
|
|
# program will try and recompute it later on. |
93
|
|
|
company.address_is_valid = True |
94
|
|
|
|
95
|
|
|
# We reset the geolocation related fields to their default values too. |
96
|
|
|
# This bit isn't necessary, because the controller can only alter the |
97
|
|
|
# content of rows with invalid addresses, and therefore rows which |
98
|
|
|
# geolocation isn't valid by definition. But it doesn't hurt to put this |
99
|
|
|
# additional code here. It just makes the manipulation of the Companies |
100
|
|
|
# table consistent across the geocoding issues controller and the |
101
|
|
|
# general crud controller. |
102
|
|
|
company.latitude = 0.0 |
103
|
|
|
company.longitude = 0.0 |
104
|
|
|
company.geolocation_is_valid = False |
105
|
|
|
|
106
|
|
|
|
107
|
|
|
def prepare_company_for_validation(company): |
108
|
|
|
assert isinstance(company, CompanyAlchemy) |
109
|
|
|
|
110
|
|
|
# Someone just validated this company. Therefore, mark it as such. |
111
|
|
|
company.validated = True |
112
|
|
|
|
113
|
|
|
|
114
|
|
|
def current_server_timestamp(): |
115
|
|
|
return DBSession.execute(func.current_timestamp()).scalar() |
116
|
|
|
|