Revision 0931fc44
ID | 0931fc4433c34cb270a9a357877c2f252310f8e3 |
Child | 4cdb7492 |
tburguie: ajout du nouveau module vigigraph
git-svn-id: https://vigilo-dev.si.c-s.fr/svn@901 b22e2e97-25c9-44ff-b637-2e5ceca36478
MANIFEST.in | ||
---|---|---|
1 |
recursive-include vigigraph/public * |
|
2 |
include vigigraph/public/favicon.ico |
|
3 |
recursive-include vigigraph/i18n * |
|
4 |
recursive-include vigigraph/templates * |
Makefile | ||
---|---|---|
1 |
NAME := vigigraph |
|
2 |
include ../glue/Makefile.common |
|
3 |
all: build |
|
4 |
MODULE := $(NAME) |
|
5 |
CODEPATH := $(NAME) |
|
6 |
lint: lint_pylint |
|
7 |
tests: tests_tg |
README.txt | ||
---|---|---|
1 |
This file is for you to describe the vigigraph application. Typically |
|
2 |
you would include information such as the information below: |
|
3 |
|
|
4 |
Installation and Setup |
|
5 |
====================== |
|
6 |
|
|
7 |
Install ``vigigraph`` using the setup.py script:: |
|
8 |
|
|
9 |
$ cd vigigraph |
|
10 |
$ python setup.py install |
|
11 |
|
|
12 |
Create the project database for any model classes defined:: |
|
13 |
|
|
14 |
$ paster setup-app development.ini |
|
15 |
|
|
16 |
Start the paste http server:: |
|
17 |
|
|
18 |
$ paster serve development.ini |
|
19 |
|
|
20 |
While developing you may want the server to reload after changes in package files (or its dependencies) are saved. This can be achieved easily by adding the --reload option:: |
|
21 |
|
|
22 |
$ paster serve --reload development.ini |
|
23 |
|
|
24 |
Then you are ready to go. |
buildout.cfg | ||
---|---|---|
1 |
[buildout] |
|
2 |
extends = ../glue/buildout.cfg |
|
3 |
eggs += vigigraph |
|
4 |
|
|
5 |
# vim: set noexpandtab : |
development.ini | ||
---|---|---|
1 |
# |
|
2 |
# vigigraph - Pylons development environment configuration |
|
3 |
# |
|
4 |
# The %(here)s variable will be replaced with the parent directory of this file |
|
5 |
# |
|
6 |
# This file is for deployment specific config options -- other configuration |
|
7 |
# that is always required for the app is done in the config directory, |
|
8 |
# and generally should not be modified by end users. |
|
9 |
|
|
10 |
[DEFAULT] |
|
11 |
debug = true |
|
12 |
# Uncomment and replace with the address which should receive any error reports |
|
13 |
#email_to = you@yourdomain.com |
|
14 |
smtp_server = localhost |
|
15 |
error_email_from = paste@localhost |
|
16 |
|
|
17 |
[server:main] |
|
18 |
use = egg:Paste#http |
|
19 |
host = 127.0.0.1 |
|
20 |
port = 8080 |
|
21 |
|
|
22 |
[app:main] |
|
23 |
use = egg:vigigraph |
|
24 |
full_stack = true |
|
25 |
#lang = ru |
|
26 |
cache_dir = %(here)s/data |
|
27 |
beaker.session.key = vigigraph |
|
28 |
beaker.session.secret = somesecret |
|
29 |
|
|
30 |
# If you'd like to fine-tune the individual locations of the cache data dirs |
|
31 |
# for the Cache data, or the Session saves, un-comment the desired settings |
|
32 |
# here: |
|
33 |
#beaker.cache.data_dir = %(here)s/data/cache |
|
34 |
#beaker.session.data_dir = %(here)s/data/sessions |
|
35 |
|
|
36 |
# pick the form for your database |
|
37 |
# %(here) may include a ':' character on Windows environments; this can |
|
38 |
# invalidate the URI when specifying a SQLite db via path name |
|
39 |
# sqlalchemy.url=postgres://username:password@hostname:port/databasename |
|
40 |
# sqlalchemy.url=mysql://username:password@hostname:port/databasename |
|
41 |
|
|
42 |
|
|
43 |
# If you have sqlite, here's a simple default to get you started |
|
44 |
# in development |
|
45 |
|
|
46 |
sqlalchemy.url = sqlite:///%(here)s/devdata.db |
|
47 |
#echo shouldn't be used together with the logging module. |
|
48 |
sqlalchemy.echo = false |
|
49 |
sqlalchemy.echo_pool = false |
|
50 |
sqlalchemy.pool_recycle = 3600 |
|
51 |
|
|
52 |
# if you are using Mako and want to be able to reload |
|
53 |
# the mako template from disk during the development phase |
|
54 |
# you should say 'true' here |
|
55 |
# This option is only used for mako templating engine |
|
56 |
# WARNING: if you want to deploy your application using a zipped egg |
|
57 |
# (ie: if your application's setup.py defines zip-safe=True, then you |
|
58 |
# MUST put "false" for the production environment because there will |
|
59 |
# be no disk and real files to compare time with. |
|
60 |
# On the contrary if your application defines zip-safe=False and is |
|
61 |
# deployed in an unzipped manner, then you can leave this option to true |
|
62 |
templating.mako.reloadfromdisk = true |
|
63 |
|
|
64 |
# the compiled template dir is a directory that must be readable by your |
|
65 |
# webserver. It will be used to store the resulting templates once compiled |
|
66 |
# by the TemplateLookup system. |
|
67 |
# During development you generally don't need this option since paste's HTTP |
|
68 |
# server will have access to you development directories, but in production |
|
69 |
# you'll most certainly want to have apache or nginx to write in a directory |
|
70 |
# that does not contain any source code in any form for obvious security reasons. |
|
71 |
# |
|
72 |
#templating.mako.compiled_templates_dir = /some/dir/where/webserver/has/access |
|
73 |
|
|
74 |
# WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* |
|
75 |
# Debug mode will enable the interactive debugging tool, allowing ANYONE to |
|
76 |
# execute malicious code after an exception is raised. |
|
77 |
#set debug = false |
|
78 |
|
|
79 |
# Logging configuration |
|
80 |
# Add additional loggers, handlers, formatters here |
|
81 |
# Uses python's logging config file format |
|
82 |
# http://docs.python.org/lib/logging-config-fileformat.html |
|
83 |
|
|
84 |
[loggers] |
|
85 |
keys = root, vigigraph, sqlalchemy, auth |
|
86 |
|
|
87 |
[handlers] |
|
88 |
keys = console |
|
89 |
|
|
90 |
[formatters] |
|
91 |
keys = generic |
|
92 |
|
|
93 |
# If you create additional loggers, add them as a key to [loggers] |
|
94 |
[logger_root] |
|
95 |
level = INFO |
|
96 |
handlers = console |
|
97 |
|
|
98 |
[logger_vigigraph] |
|
99 |
level = DEBUG |
|
100 |
handlers = |
|
101 |
qualname = vigigraph |
|
102 |
|
|
103 |
[logger_sqlalchemy] |
|
104 |
level = INFO |
|
105 |
handlers = |
|
106 |
qualname = sqlalchemy.engine |
|
107 |
# "level = INFO" logs SQL queries. |
|
108 |
# "level = DEBUG" logs SQL queries and results. |
|
109 |
# "level = WARN" logs neither. (Recommended for production systems.) |
|
110 |
|
|
111 |
|
|
112 |
# A logger for authentication, identification and authorization -- this is |
|
113 |
# repoze.who and repoze.what: |
|
114 |
[logger_auth] |
|
115 |
level = WARN |
|
116 |
handlers = |
|
117 |
qualname = auth |
|
118 |
|
|
119 |
# If you create additional handlers, add them as a key to [handlers] |
|
120 |
[handler_console] |
|
121 |
class = StreamHandler |
|
122 |
args = (sys.stderr,) |
|
123 |
level = NOTSET |
|
124 |
formatter = generic |
|
125 |
|
|
126 |
# If you create additional formatters, add them as a key to [formatters] |
|
127 |
[formatter_generic] |
|
128 |
format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s |
|
129 |
datefmt = %H:%M:%S |
ez_setup/README.txt | ||
---|---|---|
1 |
This directory exists so that Subversion-based projects can share a single |
|
2 |
copy of the ``ez_setup`` bootstrap module for ``setuptools``, and have it |
|
3 |
automatically updated in their projects when ``setuptools`` is updated. |
|
4 |
|
|
5 |
For your convenience, you may use the following svn:externals definition:: |
|
6 |
|
|
7 |
ez_setup svn://svn.eby-sarna.com/svnroot/ez_setup |
|
8 |
|
|
9 |
You can set this by executing this command in your project directory:: |
|
10 |
|
|
11 |
svn propedit svn:externals . |
|
12 |
|
|
13 |
And then adding the line shown above to the file that comes up for editing. |
|
14 |
Then, whenever you update your project, ``ez_setup`` will be updated as well. |
ez_setup/__init__.py | ||
---|---|---|
1 |
#!python |
|
2 |
"""Bootstrap setuptools installation |
|
3 |
|
|
4 |
If you want to use setuptools in your package's setup.py, just include this |
|
5 |
file in the same directory with it, and add this to the top of your setup.py:: |
|
6 |
|
|
7 |
from ez_setup import use_setuptools |
|
8 |
use_setuptools() |
|
9 |
|
|
10 |
If you want to require a specific version of setuptools, set a download |
|
11 |
mirror, or use an alternate download directory, you can do so by supplying |
|
12 |
the appropriate options to ``use_setuptools()``. |
|
13 |
|
|
14 |
This file can also be run as a script to install or upgrade setuptools. |
|
15 |
""" |
|
16 |
import sys |
|
17 |
DEFAULT_VERSION = "0.6c7" |
|
18 |
DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] |
|
19 |
|
|
20 |
md5_data = { |
|
21 |
'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', |
|
22 |
'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', |
|
23 |
'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', |
|
24 |
'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', |
|
25 |
'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', |
|
26 |
'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', |
|
27 |
'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', |
|
28 |
'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', |
|
29 |
'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', |
|
30 |
'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', |
|
31 |
'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', |
|
32 |
'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', |
|
33 |
'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', |
|
34 |
'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', |
|
35 |
'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', |
|
36 |
'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', |
|
37 |
'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', |
|
38 |
'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', |
|
39 |
'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', |
|
40 |
'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', |
|
41 |
'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', |
|
42 |
'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20', |
|
43 |
'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab', |
|
44 |
'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53', |
|
45 |
'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2', |
|
46 |
'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e', |
|
47 |
'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372', |
|
48 |
} |
|
49 |
|
|
50 |
import sys, os |
|
51 |
|
|
52 |
def _validate_md5(egg_name, data): |
|
53 |
if egg_name in md5_data: |
|
54 |
from md5 import md5 |
|
55 |
digest = md5(data).hexdigest() |
|
56 |
if digest != md5_data[egg_name]: |
|
57 |
print >>sys.stderr, ( |
|
58 |
"md5 validation of %s failed! (Possible download problem?)" |
|
59 |
% egg_name |
|
60 |
) |
|
61 |
sys.exit(2) |
|
62 |
return data |
|
63 |
|
|
64 |
|
|
65 |
def use_setuptools( |
|
66 |
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, |
|
67 |
download_delay=15 |
|
68 |
): |
|
69 |
"""Automatically find/download setuptools and make it available on sys.path |
|
70 |
|
|
71 |
`version` should be a valid setuptools version number that is available |
|
72 |
as an egg for download under the `download_base` URL (which should end with |
|
73 |
a '/'). `to_dir` is the directory where setuptools will be downloaded, if |
|
74 |
it is not already available. If `download_delay` is specified, it should |
|
75 |
be the number of seconds that will be paused before initiating a download, |
|
76 |
should one be required. If an older version of setuptools is installed, |
|
77 |
this routine will print a message to ``sys.stderr`` and raise SystemExit in |
|
78 |
an attempt to abort the calling script. |
|
79 |
""" |
|
80 |
try: |
|
81 |
import setuptools |
|
82 |
if setuptools.__version__ == '0.0.1': |
|
83 |
print >>sys.stderr, ( |
|
84 |
"You have an obsolete version of setuptools installed. Please\n" |
|
85 |
"remove it from your system entirely before rerunning this script." |
|
86 |
) |
|
87 |
sys.exit(2) |
|
88 |
except ImportError: |
|
89 |
egg = download_setuptools(version, download_base, to_dir, download_delay) |
|
90 |
sys.path.insert(0, egg) |
|
91 |
import setuptools; setuptools.bootstrap_install_from = egg |
|
92 |
|
|
93 |
import pkg_resources |
|
94 |
try: |
|
95 |
pkg_resources.require("setuptools>="+version) |
|
96 |
|
|
97 |
except pkg_resources.VersionConflict, e: |
|
98 |
# XXX could we install in a subprocess here? |
|
99 |
print >>sys.stderr, ( |
|
100 |
"The required version of setuptools (>=%s) is not available, and\n" |
|
101 |
"can't be installed while this script is running. Please install\n" |
|
102 |
" a more recent version first.\n\n(Currently using %r)" |
|
103 |
) % (version, e.args[0]) |
|
104 |
sys.exit(2) |
|
105 |
|
|
106 |
def download_setuptools( |
|
107 |
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, |
|
108 |
delay = 15 |
|
109 |
): |
|
110 |
"""Download setuptools from a specified location and return its filename |
|
111 |
|
|
112 |
`version` should be a valid setuptools version number that is available |
|
113 |
as an egg for download under the `download_base` URL (which should end |
|
114 |
with a '/'). `to_dir` is the directory where the egg will be downloaded. |
|
115 |
`delay` is the number of seconds to pause before an actual download attempt. |
|
116 |
""" |
|
117 |
import urllib2, shutil |
|
118 |
egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) |
|
119 |
url = download_base + egg_name |
|
120 |
saveto = os.path.join(to_dir, egg_name) |
|
121 |
src = dst = None |
|
122 |
if not os.path.exists(saveto): # Avoid repeated downloads |
|
123 |
try: |
|
124 |
from distutils import log |
|
125 |
if delay: |
|
126 |
log.warn(""" |
|
127 |
--------------------------------------------------------------------------- |
|
128 |
This script requires setuptools version %s to run (even to display |
|
129 |
help). I will attempt to download it for you (from |
|
130 |
%s), but |
|
131 |
you may need to enable firewall access for this script first. |
|
132 |
I will start the download in %d seconds. |
|
133 |
|
|
134 |
(Note: if this machine does not have network access, please obtain the file |
|
135 |
|
|
136 |
%s |
|
137 |
|
|
138 |
and place it in this directory before rerunning this script.) |
|
139 |
---------------------------------------------------------------------------""", |
|
140 |
version, download_base, delay, url |
|
141 |
); from time import sleep; sleep(delay) |
|
142 |
log.warn("Downloading %s", url) |
|
143 |
src = urllib2.urlopen(url) |
|
144 |
# Read/write all in one block, so we don't create a corrupt file |
|
145 |
# if the download is interrupted. |
|
146 |
data = _validate_md5(egg_name, src.read()) |
|
147 |
dst = open(saveto,"wb"); dst.write(data) |
|
148 |
finally: |
|
149 |
if src: src.close() |
|
150 |
if dst: dst.close() |
|
151 |
return os.path.realpath(saveto) |
|
152 |
|
|
153 |
def main(argv, version=DEFAULT_VERSION): |
|
154 |
"""Install or upgrade setuptools and EasyInstall""" |
|
155 |
|
|
156 |
try: |
|
157 |
import setuptools |
|
158 |
except ImportError: |
|
159 |
egg = None |
|
160 |
try: |
|
161 |
egg = download_setuptools(version, delay=0) |
|
162 |
sys.path.insert(0,egg) |
|
163 |
from setuptools.command.easy_install import main |
|
164 |
return main(list(argv)+[egg]) # we're done here |
|
165 |
finally: |
|
166 |
if egg and os.path.exists(egg): |
|
167 |
os.unlink(egg) |
|
168 |
else: |
|
169 |
if setuptools.__version__ == '0.0.1': |
|
170 |
# tell the user to uninstall obsolete version |
|
171 |
use_setuptools(version) |
|
172 |
|
|
173 |
req = "setuptools>="+version |
|
174 |
import pkg_resources |
|
175 |
try: |
|
176 |
pkg_resources.require(req) |
|
177 |
except pkg_resources.VersionConflict: |
|
178 |
try: |
|
179 |
from setuptools.command.easy_install import main |
|
180 |
except ImportError: |
|
181 |
from easy_install import main |
|
182 |
main(list(argv)+[download_setuptools(delay=0)]) |
|
183 |
sys.exit(0) # try to force an exit |
|
184 |
else: |
|
185 |
if argv: |
|
186 |
from setuptools.command.easy_install import main |
|
187 |
main(argv) |
|
188 |
else: |
|
189 |
print "Setuptools version",version,"or greater has been installed." |
|
190 |
print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' |
|
191 |
|
|
192 |
|
|
193 |
|
|
194 |
def update_md5(filenames): |
|
195 |
"""Update our built-in md5 registry""" |
|
196 |
|
|
197 |
import re |
|
198 |
from md5 import md5 |
|
199 |
|
|
200 |
for name in filenames: |
|
201 |
base = os.path.basename(name) |
|
202 |
f = open(name,'rb') |
|
203 |
md5_data[base] = md5(f.read()).hexdigest() |
|
204 |
f.close() |
|
205 |
|
|
206 |
data = [" %r: %r,\n" % it for it in md5_data.items()] |
|
207 |
data.sort() |
|
208 |
repl = "".join(data) |
|
209 |
|
|
210 |
import inspect |
|
211 |
srcfile = inspect.getsourcefile(sys.modules[__name__]) |
|
212 |
f = open(srcfile, 'rb'); src = f.read(); f.close() |
|
213 |
|
|
214 |
match = re.search("\nmd5_data = {\n([^}]+)}", src) |
|
215 |
if not match: |
|
216 |
print >>sys.stderr, "Internal error!" |
|
217 |
sys.exit(2) |
|
218 |
|
|
219 |
src = src[:match.start(1)] + repl + src[match.end(1):] |
|
220 |
f = open(srcfile,'w') |
|
221 |
f.write(src) |
|
222 |
f.close() |
|
223 |
|
|
224 |
|
|
225 |
if __name__=='__main__': |
|
226 |
if len(sys.argv)>2 and sys.argv[1]=='--md5update': |
|
227 |
update_md5(sys.argv[2:]) |
|
228 |
else: |
|
229 |
main(sys.argv[1:]) |
setup.cfg | ||
---|---|---|
1 |
[egg_info] |
|
2 |
tag_build = dev |
|
3 |
tag_svn_revision = true |
|
4 |
|
|
5 |
[easy_install] |
|
6 |
find_links = http://vigilo-dev.si.c-s.fr/python/eggs |
|
7 |
allow_hosts = *.si.c-s.fr |
|
8 |
#find_links = http://www.pylonshq.com/download/ |
|
9 |
|
|
10 |
[nosetests] |
|
11 |
with-pylons=test.ini |
|
12 |
|
|
13 |
# Babel configuration |
|
14 |
[compile_catalog] |
|
15 |
domain = vigigraph |
|
16 |
directory = vigigraph/i18n |
|
17 |
statistics = true |
|
18 |
|
|
19 |
[extract_messages] |
|
20 |
add_comments = TRANSLATORS: |
|
21 |
msgid_bugs_address = contact@projet-vigilo.org |
|
22 |
output_file = vigigraph/i18n/vigigraph.pot |
|
23 |
width = 80 |
|
24 |
keywords = l_ |
|
25 |
|
|
26 |
[init_catalog] |
|
27 |
domain = vigigraph |
|
28 |
input_file = vigigraph/i18n/vigigraph.pot |
|
29 |
output_dir = vigigraph/i18n |
|
30 |
|
|
31 |
[update_catalog] |
|
32 |
domain = vigigraph |
|
33 |
input_file = vigigraph/i18n/vigigraph.pot |
|
34 |
output_dir = vigigraph/i18n |
|
35 |
previous = true |
setup.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
try: |
|
3 |
from setuptools import setup, find_packages |
|
4 |
except ImportError: |
|
5 |
from ez_setup import use_setuptools |
|
6 |
use_setuptools() |
|
7 |
from setuptools import setup, find_packages |
|
8 |
|
|
9 |
setup( |
|
10 |
name='vigigraph', |
|
11 |
version='0.1', |
|
12 |
description='', |
|
13 |
author='', |
|
14 |
author_email='', |
|
15 |
#url='', |
|
16 |
install_requires=[ |
|
17 |
"TurboGears2 >= 2.0b7", |
|
18 |
"Catwalk >= 2.0.2", |
|
19 |
"Babel >=0.9.4", |
|
20 |
#can be removed iif use_toscawidgets = False |
|
21 |
"toscawidgets >= 0.9.7.1", |
|
22 |
"zope.sqlalchemy >= 0.4 ", |
|
23 |
"repoze.tm2 >= 1.0a4", |
|
24 |
|
|
25 |
"repoze.what-quickstart >= 1.0", |
|
26 |
], |
|
27 |
paster_plugins=['PasteScript', 'Pylons', 'TurboGears2', 'tg.devtools'], |
|
28 |
packages=find_packages(exclude=['ez_setup']), |
|
29 |
include_package_data=True, |
|
30 |
test_suite='nose.collector', |
|
31 |
tests_require=['WebTest', 'BeautifulSoup'], |
|
32 |
package_data={'vigigraph': ['i18n/*/LC_MESSAGES/*.mo', |
|
33 |
'templates/*/*', |
|
34 |
'public/*/*']}, |
|
35 |
message_extractors={'vigigraph': [ |
|
36 |
('**.py', 'python', None), |
|
37 |
('templates/**.mako', 'mako', None), |
|
38 |
('templates/**.html', 'genshi', None), |
|
39 |
('public/**', 'ignore', None)]}, |
|
40 |
|
|
41 |
entry_points=""" |
|
42 |
[paste.app_factory] |
|
43 |
main = vigigraph.config.middleware:make_app |
|
44 |
|
|
45 |
[paste.app_install] |
|
46 |
main = pylons.util:PylonsInstaller |
|
47 |
""", |
|
48 |
) |
test.ini | ||
---|---|---|
1 |
# |
|
2 |
# vigigraph - TurboGears 2 testing environment configuration |
|
3 |
# |
|
4 |
# The %(here)s variable will be replaced with the parent directory of this file |
|
5 |
# |
|
6 |
[DEFAULT] |
|
7 |
debug = true |
|
8 |
# Uncomment and replace with the address which should receive any error reports |
|
9 |
# email_to = you@yourdomain.com |
|
10 |
smtp_server = localhost |
|
11 |
error_email_from = paste@localhost |
|
12 |
|
|
13 |
[server:main] |
|
14 |
use = egg:Paste#http |
|
15 |
host = 0.0.0.0 |
|
16 |
port = 5000 |
|
17 |
|
|
18 |
[app:main] |
|
19 |
sqlalchemy.url = sqlite:///:memory: |
|
20 |
use = config:development.ini |
|
21 |
|
|
22 |
[app:main_without_authn] |
|
23 |
use = main |
|
24 |
skip_authentication = True |
|
25 |
|
|
26 |
# Add additional test specific configuration options as necessary. |
vigigraph/__init__.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
"""The vigigraph package""" |
vigigraph/config/__init__.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
|
vigigraph/config/app_cfg.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
""" |
|
3 |
Global configuration file for TG2-specific settings in vigigraph. |
|
4 |
|
|
5 |
This file complements development/deployment.ini. |
|
6 |
|
|
7 |
Please note that **all the argument values are strings**. If you want to |
|
8 |
convert them into boolean, for example, you should use the |
|
9 |
:func:`paste.deploy.converters.asbool` function, as in:: |
|
10 |
|
|
11 |
from paste.deploy.converters import asbool |
|
12 |
setting = asbool(global_conf.get('the_setting')) |
|
13 |
|
|
14 |
""" |
|
15 |
|
|
16 |
from tg.configuration import AppConfig |
|
17 |
|
|
18 |
import vigigraph |
|
19 |
from vigigraph import model |
|
20 |
from vigigraph.lib import app_globals, helpers |
|
21 |
|
|
22 |
base_config = AppConfig() |
|
23 |
base_config.renderers = [] |
|
24 |
|
|
25 |
base_config.package = vigigraph |
|
26 |
|
|
27 |
#Set the default renderer |
|
28 |
base_config.default_renderer = 'genshi' |
|
29 |
base_config.renderers.append('genshi') |
|
30 |
# if you want raw speed and have installed chameleon.genshi |
|
31 |
# you should try to use this renderer instead. |
|
32 |
# warning: for the moment chameleon does not handle i18n translations |
|
33 |
#base_config.renderers.append('chameleon_genshi') |
|
34 |
|
|
35 |
#Configure the base SQLALchemy Setup |
|
36 |
base_config.use_sqlalchemy = True |
|
37 |
base_config.model = vigigraph.model |
|
38 |
base_config.DBSession = vigigraph.model.DBSession |
|
39 |
|
|
40 |
# Configure the authentication backend |
|
41 |
base_config.auth_backend = 'sqlalchemy' |
|
42 |
base_config.sa_auth.dbsession = model.DBSession |
|
43 |
# what is the class you want to use to search for users in the database |
|
44 |
base_config.sa_auth.user_class = model.User |
|
45 |
# what is the class you want to use to search for groups in the database |
|
46 |
base_config.sa_auth.group_class = model.Group |
|
47 |
# what is the class you want to use to search for permissions in the database |
|
48 |
base_config.sa_auth.permission_class = model.Permission |
|
49 |
|
|
50 |
# override this if you would like to provide a different who plugin for |
|
51 |
# managing login and logout of your application |
|
52 |
base_config.sa_auth.form_plugin = None |
|
53 |
|
|
54 |
# You may optionally define a page where you want users to be redirected to |
|
55 |
# on login: |
|
56 |
base_config.sa_auth.post_login_url = '/post_login' |
|
57 |
|
|
58 |
# You may optionally define a page where you want users to be redirected to |
|
59 |
# on logout: |
|
60 |
base_config.sa_auth.post_logout_url = '/post_logout' |
vigigraph/config/deployment.ini_tmpl | ||
---|---|---|
1 |
# |
|
2 |
# vigigraph - TurboGears configuration |
|
3 |
# |
|
4 |
# The %(here)s variable will be replaced with the parent directory of this file |
|
5 |
# |
|
6 |
[DEFAULT] |
|
7 |
# WARGING == If debug is not set to false, you'll get the interactive |
|
8 |
# debugger on production, which is a huge security hole. |
|
9 |
|
|
10 |
debug = false |
|
11 |
email_to = you@yourdomain.com |
|
12 |
smtp_server = localhost |
|
13 |
error_email_from = paste@localhost |
|
14 |
|
|
15 |
[server:main] |
|
16 |
use = egg:Paste#http |
|
17 |
host = 0.0.0.0 |
|
18 |
port = 8080 |
|
19 |
|
|
20 |
[app:main] |
|
21 |
use = egg:vigigraph |
|
22 |
full_stack = true |
|
23 |
cache_dir = %(here)s/data |
|
24 |
beaker.session.key = vigigraph |
|
25 |
beaker.session.secret = ${app_instance_secret} |
|
26 |
app_instance_uuid = ${app_instance_uuid} |
|
27 |
|
|
28 |
# If you'd like to fine-tune the individual locations of the cache data dirs |
|
29 |
# for the Cache data, or the Session saves, un-comment the desired settings |
|
30 |
# here: |
|
31 |
#beaker.cache.data_dir = %(here)s/data/cache |
|
32 |
#beaker.session.data_dir = %(here)s/data/sessions |
|
33 |
# Specify the database for SQLAlchemy to use via |
|
34 |
# turbogears.database |
|
35 |
# %(here) may include a ':' character on Windows environments; this can |
|
36 |
# invalidate the URI when specifying a SQLite db via path name |
|
37 |
sqlalchemy.url = sqlite:///%(here)s/somedb.db |
|
38 |
sqlalchemy.echo = False |
|
39 |
|
|
40 |
# WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* |
|
41 |
# Debug mode will enable the interactive debugging tool, allowing ANYONE to |
|
42 |
# execute malicious code after an exception is raised. |
|
43 |
#set debug = false |
|
44 |
|
|
45 |
# Logging configuration |
|
46 |
# Add additional loggers, handlers, formatters here |
|
47 |
# Uses python's logging config file format |
|
48 |
# http://docs.python.org/lib/logging-config-fileformat.html |
|
49 |
|
|
50 |
[loggers] |
|
51 |
keys = root, vigigraph, sqlalchemy, auth |
|
52 |
|
|
53 |
[handlers] |
|
54 |
keys = console |
|
55 |
|
|
56 |
[formatters] |
|
57 |
keys = generic |
|
58 |
|
|
59 |
# If you create additional loggers, add them as a key to [loggers] |
|
60 |
[logger_root] |
|
61 |
level = INFO |
|
62 |
handlers = console |
|
63 |
|
|
64 |
[logger_vigigraph] |
|
65 |
level = INFO |
|
66 |
handlers = |
|
67 |
qualname = vigigraph |
|
68 |
|
|
69 |
[logger_sqlalchemy] |
|
70 |
level = WARN |
|
71 |
handlers = |
|
72 |
qualname = sqlalchemy.engine |
|
73 |
# "level = INFO" logs SQL queries. |
|
74 |
# "level = DEBUG" logs SQL queries and results. |
|
75 |
# "level = WARN" logs neither. (Recommended for production systems.) |
|
76 |
|
|
77 |
|
|
78 |
# A logger for authentication, identification and authorization -- this is |
|
79 |
# repoze.who and repoze.what: |
|
80 |
[logger_auth] |
|
81 |
level = WARN |
|
82 |
handlers = |
|
83 |
qualname = auth |
|
84 |
|
|
85 |
# If you create additional handlers, add them as a key to [handlers] |
|
86 |
[handler_console] |
|
87 |
class = StreamHandler |
|
88 |
args = (sys.stderr,) |
|
89 |
level = NOTSET |
|
90 |
formatter = generic |
|
91 |
|
|
92 |
# If you create additional formatters, add them as a key to [formatters] |
|
93 |
[formatter_generic] |
|
94 |
format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s |
|
95 |
datefmt = %H:%M:%S |
vigigraph/config/environment.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
"""WSGI environment setup for vigigraph.""" |
|
3 |
|
|
4 |
from vigigraph.config.app_cfg import base_config |
|
5 |
|
|
6 |
__all__ = ['load_environment'] |
|
7 |
|
|
8 |
#Use base_config to setup the environment loader function |
|
9 |
load_environment = base_config.make_load_environment() |
vigigraph/config/middleware.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
"""WSGI middleware initialization for the vigigraph application.""" |
|
3 |
|
|
4 |
from vigigraph.config.app_cfg import base_config |
|
5 |
from vigigraph.config.environment import load_environment |
|
6 |
|
|
7 |
|
|
8 |
__all__ = ['make_app'] |
|
9 |
|
|
10 |
# Use base_config to setup the necessary PasteDeploy application factory. |
|
11 |
# make_base_app will wrap the TG2 app with all the middleware it needs. |
|
12 |
make_base_app = base_config.setup_tg_wsgi_app(load_environment) |
|
13 |
|
|
14 |
|
|
15 |
def make_app(global_conf, full_stack=True, **app_conf): |
|
16 |
""" |
|
17 |
Set vigigraph up with the settings found in the PasteDeploy configuration |
|
18 |
file used. |
|
19 |
|
|
20 |
:param global_conf: The global settings for vigigraph (those |
|
21 |
defined under the ``[DEFAULT]`` section). |
|
22 |
:type global_conf: dict |
|
23 |
:param full_stack: Should the whole TG2 stack be set up? |
|
24 |
:type full_stack: str or bool |
|
25 |
:return: The vigigraph application with all the relevant middleware |
|
26 |
loaded. |
|
27 |
|
|
28 |
This is the PasteDeploy factory for the vigigraph application. |
|
29 |
|
|
30 |
``app_conf`` contains all the application-specific settings (those defined |
|
31 |
under ``[app:main]``. |
|
32 |
|
|
33 |
|
|
34 |
""" |
|
35 |
app = make_base_app(global_conf, full_stack=True, **app_conf) |
|
36 |
|
|
37 |
# Wrap your base TurboGears 2 application with custom middleware here |
|
38 |
|
|
39 |
return app |
vigigraph/controllers/__init__.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
"""Controllers for the vigigraph application.""" |
vigigraph/controllers/controller.template | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
"""Sample controller module""" |
|
3 |
|
|
4 |
# turbogears imports |
|
5 |
from tg import expose |
|
6 |
#from tg import redirect, validate, flash |
|
7 |
|
|
8 |
# third party imports |
|
9 |
#from pylons.i18n import ugettext as _ |
|
10 |
#from repoze.what import predicates |
|
11 |
|
|
12 |
# project specific imports |
|
13 |
from vigigraph.lib.base import BaseController |
|
14 |
#from vigigraph.model import DBSession, metadata |
|
15 |
|
|
16 |
|
|
17 |
class SampleController(BaseController): |
|
18 |
#Uncomment this line if your controller requires an authenticated user |
|
19 |
#allow_only = authorize.not_anonymous() |
|
20 |
|
|
21 |
@expose('vigigraph.templates.index') |
|
22 |
def index(self): |
|
23 |
return dict(page='index') |
vigigraph/controllers/error.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
"""Error controller""" |
|
3 |
|
|
4 |
from tg import request, expose |
|
5 |
|
|
6 |
__all__ = ['ErrorController'] |
|
7 |
|
|
8 |
|
|
9 |
class ErrorController(object): |
|
10 |
""" |
|
11 |
Generates error documents as and when they are required. |
|
12 |
|
|
13 |
The ErrorDocuments middleware forwards to ErrorController when error |
|
14 |
related status codes are returned from the application. |
|
15 |
|
|
16 |
This behaviour can be altered by changing the parameters to the |
|
17 |
ErrorDocuments middleware in your config/middleware.py file. |
|
18 |
|
|
19 |
""" |
|
20 |
|
|
21 |
@expose('vigigraph.templates.error') |
|
22 |
def document(self, *args, **kwargs): |
|
23 |
"""Render the error document""" |
|
24 |
resp = request.environ.get('pylons.original_response') |
|
25 |
default_message = ("<p>We're sorry but we weren't able to process " |
|
26 |
" this request.</p>") |
|
27 |
values = dict(prefix=request.environ.get('SCRIPT_NAME', ''), |
|
28 |
code=request.params.get('code', resp.status_int), |
|
29 |
message=request.params.get('message', default_message)) |
|
30 |
return values |
vigigraph/controllers/root.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
"""Main Controller""" |
|
3 |
|
|
4 |
from tg import expose, flash, require, url, request, redirect |
|
5 |
from pylons.i18n import ugettext as _, lazy_ugettext as l_ |
|
6 |
from catwalk.tg2 import Catwalk |
|
7 |
from repoze.what import predicates |
|
8 |
|
|
9 |
from vigigraph.lib.base import BaseController |
|
10 |
from vigigraph.model import DBSession, metadata |
|
11 |
from vigigraph.controllers.error import ErrorController |
|
12 |
from vigigraph import model |
|
13 |
from vigigraph.controllers.secure import SecureController |
|
14 |
|
|
15 |
__all__ = ['RootController'] |
|
16 |
|
|
17 |
|
|
18 |
class RootController(BaseController): |
|
19 |
""" |
|
20 |
The root controller for the vigigraph application. |
|
21 |
|
|
22 |
All the other controllers and WSGI applications should be mounted on this |
|
23 |
controller. For example:: |
|
24 |
|
|
25 |
panel = ControlPanelController() |
|
26 |
another_app = AnotherWSGIApplication() |
|
27 |
|
|
28 |
Keep in mind that WSGI applications shouldn't be mounted directly: They |
|
29 |
must be wrapped around with :class:`tg.controllers.WSGIAppController`. |
|
30 |
|
|
31 |
""" |
|
32 |
secc = SecureController() |
|
33 |
|
|
34 |
admin = Catwalk(model, DBSession) |
|
35 |
|
|
36 |
error = ErrorController() |
|
37 |
|
|
38 |
@expose('vigigraph.templates.index') |
|
39 |
def index(self): |
|
40 |
"""Handle the front-page.""" |
|
41 |
return dict(page='index') |
|
42 |
|
|
43 |
@expose('vigigraph.templates.about') |
|
44 |
def about(self): |
|
45 |
"""Handle the 'about' page.""" |
|
46 |
return dict(page='about') |
|
47 |
|
|
48 |
@expose('vigigraph.templates.authentication') |
|
49 |
def auth(self): |
|
50 |
"""Display some information about auth* on this application.""" |
|
51 |
return dict(page='auth') |
|
52 |
|
|
53 |
@expose('vigigraph.templates.index') |
|
54 |
@require(predicates.has_permission('manage', msg=l_('Only for managers'))) |
|
55 |
def manage_permission_only(self, **kw): |
|
56 |
"""Illustrate how a page for managers only works.""" |
|
57 |
return dict(page='managers stuff') |
|
58 |
|
|
59 |
@expose('vigigraph.templates.index') |
|
60 |
@require(predicates.is_user('editor', msg=l_('Only for the editor'))) |
|
61 |
def editor_user_only(self, **kw): |
|
62 |
"""Illustrate how a page exclusive for the editor works.""" |
|
63 |
return dict(page='editor stuff') |
|
64 |
|
|
65 |
@expose('vigigraph.templates.login') |
|
66 |
def login(self, came_from=url('/')): |
|
67 |
"""Start the user login.""" |
|
68 |
login_counter = request.environ['repoze.who.logins'] |
|
69 |
if login_counter > 0: |
|
70 |
flash(_('Wrong credentials'), 'warning') |
|
71 |
return dict(page='login', login_counter=str(login_counter), |
|
72 |
came_from=came_from) |
|
73 |
|
|
74 |
@expose() |
|
75 |
def post_login(self, came_from=url('/')): |
|
76 |
""" |
|
77 |
Redirect the user to the initially requested page on successful |
|
78 |
authentication or redirect her back to the login page if login failed. |
|
79 |
|
|
80 |
""" |
|
81 |
if not request.identity: |
|
82 |
login_counter = request.environ['repoze.who.logins'] + 1 |
|
83 |
redirect(url('/login', came_from=came_from, __logins=login_counter)) |
|
84 |
userid = request.identity['repoze.who.userid'] |
|
85 |
flash(_('Welcome back, %s!') % userid) |
|
86 |
redirect(came_from) |
|
87 |
|
|
88 |
@expose() |
|
89 |
def post_logout(self, came_from=url('/')): |
|
90 |
""" |
|
91 |
Redirect the user to the initially requested page on logout and say |
|
92 |
goodbye as well. |
|
93 |
|
|
94 |
""" |
|
95 |
flash(_('We hope to see you soon!')) |
|
96 |
redirect(came_from) |
vigigraph/controllers/secure.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
"""Sample controller with all its actions protected.""" |
|
3 |
from tg import expose, flash |
|
4 |
from pylons.i18n import ugettext as _, lazy_ugettext as l_ |
|
5 |
from repoze.what.predicates import has_permission |
|
6 |
#from dbsprockets.dbmechanic.frameworks.tg2 import DBMechanic |
|
7 |
#from dbsprockets.saprovider import SAProvider |
|
8 |
|
|
9 |
from vigigraph.lib.base import BaseController |
|
10 |
#from vigigraph.model import DBSession, metadata |
|
11 |
|
|
12 |
__all__ = ['SecureController'] |
|
13 |
|
|
14 |
|
|
15 |
class SecureController(BaseController): |
|
16 |
"""Sample controller-wide authorization""" |
|
17 |
|
|
18 |
# The predicate that must be met for all the actions in this controller: |
|
19 |
allow_only = has_permission('manage', |
|
20 |
msg=l_('Only for people with the "manage" permission')) |
|
21 |
|
|
22 |
@expose('vigigraph.templates.index') |
|
23 |
def index(self): |
|
24 |
"""Let the user know that's visiting a protected controller.""" |
|
25 |
flash(_("Secure Controller here")) |
|
26 |
return dict(page='index') |
|
27 |
|
|
28 |
@expose('vigigraph.templates.index') |
|
29 |
def some_where(self): |
|
30 |
"""Let the user know that this action is protected too.""" |
|
31 |
return dict(page='some_where') |
vigigraph/controllers/template.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
"""Fallback controller.""" |
|
3 |
|
|
4 |
from vigigraph.lib.base import BaseController |
|
5 |
|
|
6 |
__all__ = ['TemplateController'] |
|
7 |
|
|
8 |
|
|
9 |
class TemplateController(BaseController): |
|
10 |
""" |
|
11 |
The fallback controller for vigigraph. |
|
12 |
|
|
13 |
By default, the final controller tried to fulfill the request |
|
14 |
when no other routes match. It may be used to display a template |
|
15 |
when all else fails, e.g.:: |
|
16 |
|
|
17 |
def view(self, url): |
|
18 |
return render('/%s' % url) |
|
19 |
|
|
20 |
Or if you're using Mako and want to explicitly send a 404 (Not |
|
21 |
Found) response code when the requested template doesn't exist:: |
|
22 |
|
|
23 |
import mako.exceptions |
|
24 |
|
|
25 |
def view(self, url): |
|
26 |
try: |
|
27 |
return render('/%s' % url) |
|
28 |
except mako.exceptions.TopLevelLookupException: |
|
29 |
abort(404) |
|
30 |
|
|
31 |
""" |
|
32 |
|
|
33 |
def view(self, url): |
|
34 |
"""Abort the request with a 404 HTTP status code.""" |
|
35 |
abort(404) |
vigigraph/i18n/ru/LC_MESSAGES/vigigraph.po | ||
---|---|---|
1 |
# Russian translations for ${package}. |
|
2 |
# Copyright (C) 2008 ORGANIZATION |
|
3 |
# This file is distributed under the same license as the ${package} project. |
|
4 |
# FIRST AUTHOR <EMAIL@ADDRESS>, 2008. |
|
5 |
# |
|
6 |
msgid "" |
|
7 |
msgstr "" |
|
8 |
"Project-Id-Version: ${package} 0.0.0\n" |
|
9 |
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" |
|
10 |
"POT-Creation-Date: 2008-01-13 14:00+0200\n" |
|
11 |
"PO-Revision-Date: 2008-01-13 14:00+0200\n" |
|
12 |
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
|
13 |
"Language-Team: ru <LL@li.org>\n" |
|
14 |
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " |
|
15 |
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" |
|
16 |
"MIME-Version: 1.0\n" |
|
17 |
"Content-Type: text/plain; charset=utf-8\n" |
|
18 |
"Content-Transfer-Encoding: 8bit\n" |
|
19 |
"Generated-By: Babel 0.9.1\n" |
|
20 |
|
|
21 |
#: ${package}/controllers/root.py:13 |
|
22 |
msgid "Your application is now running" |
|
23 |
msgstr "Ваши приложение успешно запущено" |
|
24 |
|
vigigraph/lib/__init__.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
|
vigigraph/lib/app_globals.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
|
|
3 |
"""The application's Globals object""" |
|
4 |
|
|
5 |
__all__ = ['Globals'] |
|
6 |
|
|
7 |
|
|
8 |
class Globals(object): |
|
9 |
"""Container for objects available throughout the life of the application. |
|
10 |
|
|
11 |
One instance of Globals is created during application initialization and |
|
12 |
is available during requests via the 'app_globals' variable. |
|
13 |
|
|
14 |
""" |
|
15 |
|
|
16 |
def __init__(self): |
|
17 |
"""Do nothing, by default.""" |
|
18 |
pass |
vigigraph/lib/base.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
|
|
3 |
"""The base Controller API.""" |
|
4 |
|
|
5 |
from tg import TGController, tmpl_context |
|
6 |
from tg.render import render |
|
7 |
from tg import request |
|
8 |
from pylons.i18n import _, ungettext, N_ |
|
9 |
from tw.api import WidgetBunch |
|
10 |
import vigigraph.model as model |
|
11 |
|
|
12 |
__all__ = ['Controller', 'BaseController'] |
|
13 |
|
|
14 |
|
|
15 |
class BaseController(TGController): |
|
16 |
""" |
|
17 |
Base class for the controllers in the application. |
|
18 |
|
|
19 |
Your web application should have one of these. The root of |
|
20 |
your application is used to compute URLs used by your app. |
|
21 |
|
|
22 |
""" |
|
23 |
|
|
24 |
def __call__(self, environ, start_response): |
|
25 |
"""Invoke the Controller""" |
|
26 |
# TGController.__call__ dispatches to the Controller method |
|
27 |
# the request is routed to. This routing information is |
|
28 |
# available in environ['pylons.routes_dict'] |
|
29 |
|
|
30 |
request.identity = request.environ.get('repoze.who.identity') |
|
31 |
tmpl_context.identity = request.identity |
|
32 |
return TGController.__call__(self, environ, start_response) |
vigigraph/lib/helpers.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
|
|
3 |
"""WebHelpers used in vigigraph.""" |
|
4 |
|
|
5 |
from webhelpers import date, feedgenerator, html, number, misc, text |
vigigraph/model/__init__.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
"""The application's model objects""" |
|
3 |
|
|
4 |
from zope.sqlalchemy import ZopeTransactionExtension |
|
5 |
from sqlalchemy.orm import scoped_session, sessionmaker |
|
6 |
#from sqlalchemy import MetaData |
|
7 |
from sqlalchemy.ext.declarative import declarative_base |
|
8 |
|
|
9 |
# Global session manager: DBSession() returns the Thread-local |
|
10 |
# session object appropriate for the current web request. |
|
11 |
maker = sessionmaker(autoflush=True, autocommit=False, |
|
12 |
extension=ZopeTransactionExtension()) |
|
13 |
DBSession = scoped_session(maker) |
|
14 |
|
|
15 |
# Base class for all of our model classes: By default, the data model is |
|
16 |
# defined with SQLAlchemy's declarative extension, but if you need more |
|
17 |
# control, you can switch to the traditional method. |
|
18 |
DeclarativeBase = declarative_base() |
|
19 |
|
|
20 |
# There are two convenient ways for you to spare some typing. |
|
21 |
# You can have a query property on all your model classes by doing this: |
|
22 |
# DeclarativeBase.query = DBSession.query_property() |
|
23 |
# Or you can use a session-aware mapper as it was used in TurboGears 1: |
|
24 |
# DeclarativeBase = declarative_base(mapper=DBSession.mapper) |
|
25 |
|
|
26 |
# Global metadata. |
|
27 |
# The default metadata is the one from the declarative base. |
|
28 |
metadata = DeclarativeBase.metadata |
|
29 |
|
|
30 |
# If you have multiple databases with overlapping table names, you'll need a |
|
31 |
# metadata for each database. Feel free to rename 'metadata2'. |
|
32 |
#metadata2 = MetaData() |
|
33 |
|
|
34 |
##### |
|
35 |
# Generally you will not want to define your table's mappers, and data objects |
|
36 |
# here in __init__ but will want to create modules them in the model directory |
|
37 |
# and import them at the bottom of this file. |
|
38 |
# |
|
39 |
###### |
|
40 |
|
|
41 |
def init_model(engine): |
|
42 |
"""Call me before using any of the tables or classes in the model.""" |
|
43 |
|
|
44 |
DBSession.configure(bind=engine) |
|
45 |
# If you are using reflection to introspect your database and create |
|
46 |
# table objects for you, your tables must be defined and mapped inside |
|
47 |
# the init_model function, so that the engine is available if you |
|
48 |
# use the model outside tg2, you need to make sure this is called before |
|
49 |
# you use the model. |
|
50 |
|
|
51 |
# |
|
52 |
# See the following example: |
|
53 |
|
|
54 |
#global t_reflected |
|
55 |
|
|
56 |
#t_reflected = Table("Reflected", metadata, |
|
57 |
# autoload=True, autoload_with=engine) |
|
58 |
|
|
59 |
#mapper(Reflected, t_reflected) |
|
60 |
|
|
61 |
# Import your model modules here. |
|
62 |
from vigigraph.model.auth import User, Group, Permission |
vigigraph/model/auth.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
""" |
|
3 |
Auth* related model. |
|
4 |
|
|
5 |
This is where the models used by :mod:`repoze.who` and :mod:`repoze.what` are |
|
6 |
defined. |
|
7 |
|
|
8 |
It's perfectly fine to re-use this definition in the vigigraph application, |
|
9 |
though. |
|
10 |
|
|
11 |
""" |
|
12 |
import os |
|
13 |
from datetime import datetime |
|
14 |
import sys |
|
15 |
try: |
|
16 |
from hashlib import sha1 |
|
17 |
except ImportError: |
|
18 |
sys.exit('ImportError: No module named hashlib\n' |
|
19 |
'If you are on python2.4 this library is not part of python. ' |
|
20 |
'Please install it. Example: easy_install hashlib') |
|
21 |
|
|
22 |
from sqlalchemy import Table, ForeignKey, Column |
|
23 |
from sqlalchemy.types import Unicode, Integer, DateTime |
|
24 |
from sqlalchemy.orm import relation, synonym |
|
25 |
|
|
26 |
from vigigraph.model import DeclarativeBase, metadata, DBSession |
|
27 |
|
|
28 |
__all__ = ['User', 'Group', 'Permission'] |
|
29 |
|
|
30 |
|
|
31 |
#{ Association tables |
|
32 |
|
|
33 |
|
|
34 |
# This is the association table for the many-to-many relationship between |
|
35 |
# groups and permissions. This is required by repoze.what. |
|
36 |
group_permission_table = Table('tg_group_permission', metadata, |
|
37 |
Column('group_id', Integer, ForeignKey('tg_group.group_id', |
|
38 |
onupdate="CASCADE", ondelete="CASCADE")), |
|
39 |
Column('permission_id', Integer, ForeignKey('tg_permission.permission_id', |
|
40 |
onupdate="CASCADE", ondelete="CASCADE")) |
|
41 |
) |
|
42 |
|
|
43 |
# This is the association table for the many-to-many relationship between |
|
44 |
# groups and members - this is, the memberships. It's required by repoze.what. |
|
45 |
user_group_table = Table('tg_user_group', metadata, |
|
46 |
Column('user_id', Integer, ForeignKey('tg_user.user_id', |
|
47 |
onupdate="CASCADE", ondelete="CASCADE")), |
|
48 |
Column('group_id', Integer, ForeignKey('tg_group.group_id', |
|
49 |
onupdate="CASCADE", ondelete="CASCADE")) |
|
50 |
) |
|
51 |
|
|
52 |
|
|
53 |
#{ The auth* model itself |
|
54 |
|
|
55 |
|
|
56 |
class Group(DeclarativeBase): |
|
57 |
""" |
|
58 |
Group definition for :mod:`repoze.what`. |
|
59 |
|
|
60 |
Only the ``group_name`` column is required by :mod:`repoze.what`. |
|
61 |
|
|
62 |
""" |
|
63 |
|
|
64 |
__tablename__ = 'tg_group' |
|
65 |
|
|
66 |
#{ Columns |
|
67 |
|
|
68 |
group_id = Column(Integer, autoincrement=True, primary_key=True) |
|
69 |
|
|
70 |
group_name = Column(Unicode(16), unique=True, nullable=False) |
|
71 |
|
|
72 |
display_name = Column(Unicode(255)) |
|
73 |
|
|
74 |
created = Column(DateTime, default=datetime.now) |
|
75 |
|
|
76 |
#{ Relations |
|
77 |
|
|
78 |
users = relation('User', secondary=user_group_table, backref='groups') |
|
79 |
|
|
80 |
#{ Special methods |
|
81 |
|
|
82 |
def __repr__(self): |
|
83 |
return '<Group: name=%s>' % self.group_name |
|
84 |
|
|
85 |
def __unicode__(self): |
|
86 |
return self.group_name |
|
87 |
|
|
88 |
#} |
|
89 |
|
|
90 |
|
|
91 |
# The 'info' argument we're passing to the email_address and password columns |
|
92 |
# contain metadata that Rum (http://python-rum.org/) can use generate an |
|
93 |
# admin interface for your models. |
|
94 |
class User(DeclarativeBase): |
|
95 |
""" |
|
96 |
User definition. |
|
97 |
|
|
98 |
This is the user definition used by :mod:`repoze.who`, which requires at |
|
99 |
least the ``user_name`` column. |
|
100 |
|
|
101 |
""" |
|
102 |
__tablename__ = 'tg_user' |
|
103 |
|
|
104 |
#{ Columns |
|
105 |
|
|
106 |
user_id = Column(Integer, autoincrement=True, primary_key=True) |
|
107 |
|
|
108 |
user_name = Column(Unicode(16), unique=True, nullable=False) |
|
109 |
|
|
110 |
email_address = Column(Unicode(255), unique=True, nullable=False, |
|
111 |
info={'rum': {'field':'Email'}}) |
|
112 |
|
|
113 |
display_name = Column(Unicode(255)) |
|
114 |
|
|
115 |
_password = Column('password', Unicode(80), |
|
116 |
info={'rum': {'field':'Password'}}) |
|
117 |
|
|
118 |
created = Column(DateTime, default=datetime.now) |
|
119 |
|
|
120 |
#{ Special methods |
|
121 |
|
|
122 |
def __repr__(self): |
|
123 |
return '<User: email="%s", display name="%s">' % ( |
|
124 |
self.email_address, self.display_name) |
|
125 |
|
|
126 |
def __unicode__(self): |
|
127 |
return self.display_name or self.user_name |
|
128 |
|
|
129 |
#{ Getters and setters |
|
130 |
|
|
131 |
@property |
|
132 |
def permissions(self): |
|
133 |
"""Return a set of strings for the permissions granted.""" |
|
134 |
perms = set() |
|
135 |
for g in self.groups: |
|
136 |
perms = perms | set(g.permissions) |
|
137 |
return perms |
|
138 |
|
|
139 |
@classmethod |
|
140 |
def by_email_address(cls, email): |
|
141 |
"""Return the user object whose email address is ``email``.""" |
|
142 |
return DBSession.query(cls).filter(cls.email_address==email).first() |
|
143 |
|
|
144 |
@classmethod |
|
145 |
def by_user_name(cls, username): |
|
146 |
"""Return the user object whose user name is ``username``.""" |
|
147 |
return DBSession.query(cls).filter(cls.user_name==username).first() |
|
148 |
|
|
149 |
def _set_password(self, password): |
|
150 |
"""Hash ``password`` on the fly and store its hashed version.""" |
|
151 |
hashed_password = password |
|
152 |
|
|
153 |
if isinstance(password, unicode): |
|
154 |
password_8bit = password.encode('UTF-8') |
|
155 |
else: |
|
156 |
password_8bit = password |
|
157 |
|
|
158 |
salt = sha1() |
|
159 |
salt.update(os.urandom(60)) |
|
160 |
hash = sha1() |
|
161 |
hash.update(password_8bit + salt.hexdigest()) |
|
162 |
hashed_password = salt.hexdigest() + hash.hexdigest() |
|
163 |
|
|
164 |
# Make sure the hashed password is an UTF-8 object at the end of the |
|
165 |
# process because SQLAlchemy _wants_ a unicode object for Unicode |
|
166 |
# columns |
|
167 |
if not isinstance(hashed_password, unicode): |
|
168 |
hashed_password = hashed_password.decode('UTF-8') |
|
169 |
|
|
170 |
self._password = hashed_password |
|
171 |
|
|
172 |
def _get_password(self): |
|
173 |
"""Return the hashed version of the password.""" |
|
174 |
return self._password |
|
175 |
|
|
176 |
password = synonym('_password', descriptor=property(_get_password, |
|
177 |
_set_password)) |
|
178 |
|
|
179 |
#} |
|
180 |
|
|
181 |
def validate_password(self, password): |
|
182 |
""" |
|
183 |
Check the password against existing credentials. |
|
184 |
|
|
185 |
:param password: the password that was provided by the user to |
|
186 |
try and authenticate. This is the clear text version that we will |
|
187 |
need to match against the hashed one in the database. |
|
188 |
:type password: unicode object. |
|
189 |
:return: Whether the password is valid. |
|
190 |
:rtype: bool |
|
191 |
|
|
192 |
""" |
|
193 |
hashed_pass = sha1() |
|
194 |
hashed_pass.update(password + self.password[:40]) |
|
195 |
return self.password[40:] == hashed_pass.hexdigest() |
|
196 |
|
|
197 |
|
|
198 |
class Permission(DeclarativeBase): |
|
199 |
""" |
|
200 |
Permission definition for :mod:`repoze.what`. |
|
201 |
|
|
202 |
Only the ``permission_name`` column is required by :mod:`repoze.what`. |
|
203 |
|
|
204 |
""" |
|
205 |
|
|
206 |
__tablename__ = 'tg_permission' |
|
207 |
|
|
208 |
#{ Columns |
|
209 |
|
|
210 |
permission_id = Column(Integer, autoincrement=True, primary_key=True) |
|
211 |
|
|
212 |
permission_name = Column(Unicode(16), unique=True, nullable=False) |
|
213 |
|
|
214 |
description = Column(Unicode(255)) |
|
215 |
|
|
216 |
#{ Relations |
|
217 |
|
|
218 |
groups = relation(Group, secondary=group_permission_table, |
|
219 |
backref='permissions') |
|
220 |
|
|
221 |
#{ Special methods |
|
222 |
|
|
223 |
def __repr__(self): |
|
224 |
return '<Permission: name=%s>' % self.permission_name |
|
225 |
|
|
226 |
def __unicode__(self): |
|
227 |
return self.permission_name |
|
228 |
|
|
229 |
#} |
|
230 |
|
Also available in: Unified diff