|
1 .. -*- coding: utf-8 -*- |
|
2 |
|
3 Frequently Asked Questions (FAQ) |
|
4 ================================ |
|
5 |
|
6 |
|
7 Generalities |
|
8 ```````````` |
|
9 |
|
10 Why do you use the LGPL license to prevent me from doing X ? |
|
11 ------------------------------------------------------------ |
|
12 |
|
13 LGPL means that *if* you redistribute your application, you need to |
|
14 redistribute the changes you made to CubicWeb under the LGPL licence. |
|
15 |
|
16 Publishing a web site has nothing to do with redistributing source |
|
17 code according to the terms of the LGPL. A fair amount of companies |
|
18 use modified LGPL code for internal use. And someone could publish a |
|
19 *CubicWeb* component under a BSD licence for others to plug into a |
|
20 LGPL framework without any problem. The only thing we are trying to |
|
21 prevent here is someone taking the framework and packaging it as |
|
22 closed source to his own clients. |
|
23 |
|
24 Why does not CubicWeb have a template language ? |
|
25 ------------------------------------------------ |
|
26 |
|
27 There are enough template languages out there. You can use your |
|
28 preferred template language if you want. [explain how to use a |
|
29 template language] |
|
30 |
|
31 *CubicWeb* does not define its own templating language as this was |
|
32 not our goal. Based on our experience, we realized that |
|
33 we could gain productivity by letting designers use design tools |
|
34 and developpers develop without the use of the templating language |
|
35 as an intermediary that could not be anyway efficient for both parties. |
|
36 Python is the templating language that we use in *CubicWeb*, but again, |
|
37 it does not prevent you from using a templating language. |
|
38 |
|
39 Moreover, CubicWeb currently supports `simpletal`_ out of the box and |
|
40 it is also possible to use the `cwtags`_ library to build html trees |
|
41 using the `with statement`_ with more comfort than raw strings. |
|
42 |
|
43 .. _`simpletal`: http://www.owlfish.com/software/simpleTAL/ |
|
44 .. _`cwtags`: http://www.cubicweb.org/project/cwtags |
|
45 .. _`with statement`: http://www.python.org/dev/peps/pep-0343/ |
|
46 |
|
47 Why do you think using pure python is better than using a template language ? |
|
48 ----------------------------------------------------------------------------- |
|
49 |
|
50 Python is an Object Oriented Programming language and as such it |
|
51 already provides a consistent and strong architecture and syntax |
|
52 a templating language would not reach. |
|
53 |
|
54 Using Python instead of a template langage for describing the user interface |
|
55 makes it to maintain with real functions/classes/contexts without the need of |
|
56 learning a new dialect. By using Python, we use standard OOP techniques and |
|
57 this is a key factor in a robust application. |
|
58 |
|
59 CubicWeb looks pretty recent. Is it stable ? |
|
60 -------------------------------------------- |
|
61 |
|
62 It is constantly evolving, piece by piece. The framework has evolved since |
|
63 2001 and data has been migrated from one schema to the other ever since. There |
|
64 is a well-defined way to handle data and schema migration. |
|
65 |
|
66 You can see the roadmap there: |
|
67 http://www.cubicweb.org/project/cubicweb?tab=projectroadmap_tab. |
|
68 |
|
69 |
|
70 Why is the RQL query language looking similar to X ? |
|
71 ---------------------------------------------------- |
|
72 |
|
73 It may remind you of SQL but it is higher level than SQL, more like |
|
74 SPARQL. Except that SPARQL did not exist when we started the project. |
|
75 With version 3.4, CubicWeb has support for SPARQL. |
|
76 |
|
77 The RQL language is what is going to make a difference with django- |
|
78 like frameworks for several reasons. |
|
79 |
|
80 1. accessing data is *much* easier with it. One can write complex |
|
81 queries with RQL that would be tedious to define and hard to maintain |
|
82 using an object/filter suite of method calls. |
|
83 |
|
84 2. it offers an abstraction layer allowing your applications to run |
|
85 on multiple back-ends. That means not only various SQL backends |
|
86 (postgresql, sqlite, sqlserver, mysql), but also non-SQL data stores like |
|
87 LDAP directories and subversion/mercurial repositories (see the `vcsfile` |
|
88 component). |
|
89 |
|
90 Which ajax library is CubicWeb using ? |
|
91 -------------------------------------- |
|
92 |
|
93 CubicWeb uses jQuery_ and provides a few helpers on top of that. Additionally, |
|
94 some jQuery plugins are provided (some are provided in specific cubes). |
|
95 |
|
96 .. _jQuery: http://jquery.com |
|
97 |
|
98 |
|
99 Development |
|
100 ``````````` |
|
101 |
|
102 How to change the instance logo ? |
|
103 --------------------------------- |
|
104 |
|
105 The logo is managed by css. You must provide a custom css that will contain |
|
106 the code below: |
|
107 |
|
108 :: |
|
109 |
|
110 #logo { |
|
111 background-image: url("logo.jpg"); |
|
112 } |
|
113 |
|
114 |
|
115 ``logo.jpg`` is in ``mycube/data`` directory. |
|
116 |
|
117 How to create an anonymous user ? |
|
118 --------------------------------- |
|
119 |
|
120 This allows to browse the site without being authenticated. In the |
|
121 ``all-in-one.conf`` file of your instance, define the anonymous user |
|
122 as follows :: |
|
123 |
|
124 # login of the CubicWeb user account to use for anonymous user (if you want to |
|
125 # allow anonymous) |
|
126 anonymous-user=anon |
|
127 |
|
128 # password of the CubicWeb user account matching login |
|
129 anonymous-password=anon |
|
130 |
|
131 You also must ensure that this `anon` user is a registered user of |
|
132 the DB backend. If not, you can create through the administation |
|
133 interface of your instance by adding a user with in the group `guests`. |
|
134 |
|
135 .. note:: |
|
136 While creating a new instance, you can decide to allow access |
|
137 to anonymous user, which will automatically execute what is |
|
138 decribed above. |
|
139 |
|
140 How to load data from a python script ? |
|
141 --------------------------------------- |
|
142 Please, refer to :ref:`UsingPyro`. |
|
143 |
|
144 |
|
145 How to format an entity date attribute ? |
|
146 ---------------------------------------- |
|
147 |
|
148 If your schema has an attribute of type `Date` or `Datetime`, you usually want to |
|
149 format it when displaying it. First, you should define your preferred format |
|
150 using the site configuration panel |
|
151 ``http://appurl/view?vid=systempropertiesform`` and then set ``ui.date`` and/or |
|
152 ``ui.datetime``. Then in the view code, use: |
|
153 |
|
154 .. sourcecode:: python |
|
155 |
|
156 entity.printable_value(date_attribute) |
|
157 |
|
158 which will always return a string whatever the attribute's type (so it's |
|
159 recommended also for other attribute types). By default it expects to generate |
|
160 HTML, so it deals with rich text formating, xml escaping... |
|
161 |
|
162 How to update a database after a schema modification ? |
|
163 ------------------------------------------------------ |
|
164 |
|
165 It depends on what has been modified in the schema. |
|
166 |
|
167 * update the permissions and properties of an entity or a relation: |
|
168 ``sync_schema_props_perms('MyEntityOrRelation')``. |
|
169 |
|
170 * add an attribute: ``add_attribute('MyEntityType', 'myattr')``. |
|
171 |
|
172 * add a relation: ``add_relation_definition('SubjRelation', 'MyRelation', 'ObjRelation')``. |
|
173 |
|
174 I get `NoSelectableObject` exceptions, how do I debug selectors ? |
|
175 ----------------------------------------------------------------- |
|
176 |
|
177 You just need to put the appropriate context manager around view/component |
|
178 selection. One standard place for components is in cubicweb/vregistry.py: |
|
179 |
|
180 .. sourcecode:: python |
|
181 |
|
182 def possible_objects(self, *args, **kwargs): |
|
183 """return an iterator on possible objects in this registry for the given |
|
184 context |
|
185 """ |
|
186 from logilab.common.registry import traced_selection |
|
187 with traced_selection(): |
|
188 for appobjects in self.itervalues(): |
|
189 try: |
|
190 yield self._select_best(appobjects, *args, **kwargs) |
|
191 except NoSelectableObject: |
|
192 continue |
|
193 |
|
194 This will yield additional WARNINGs, like this:: |
|
195 |
|
196 2009-01-09 16:43:52 - (cubicweb.selectors) WARNING: selector one_line_rset returned 0 for <class 'cubicweb.web.views.basecomponents.WFHistoryVComponent'> |
|
197 |
|
198 For views, you can put this context in `cubicweb/web/views/basecontrollers.py` in |
|
199 the `ViewController`: |
|
200 |
|
201 .. sourcecode:: python |
|
202 |
|
203 def _select_view_and_rset(self, rset): |
|
204 ... |
|
205 try: |
|
206 from logilab.common.registry import traced_selection |
|
207 with traced_selection(): |
|
208 view = self._cw.vreg['views'].select(vid, req, rset=rset) |
|
209 except ObjectNotFound: |
|
210 self.warning("the view %s could not be found", vid) |
|
211 req.set_message(req._("The view %s could not be found") % vid) |
|
212 vid = vid_from_rset(req, rset, self._cw.vreg.schema) |
|
213 view = self._cw.vreg['views'].select(vid, req, rset=rset) |
|
214 ... |
|
215 |
|
216 I get "database is locked" when executing tests |
|
217 ----------------------------------------------- |
|
218 |
|
219 If you have "database is locked" as error when you are executing security tests, |
|
220 it is usually because commit or rollback are missing before login() calls. |
|
221 |
|
222 You can also use a context manager, to avoid such errors, as described |
|
223 here: :ref:`securitytest`. |
|
224 |
|
225 |
|
226 What are hooks used for ? |
|
227 ------------------------- |
|
228 |
|
229 Hooks are executed around (actually before or after) events. The most common |
|
230 events are data creation, update and deletion. They permit additional constraint |
|
231 checking (those not expressible at the schema level), pre and post computations |
|
232 depending on data movements. |
|
233 |
|
234 As such, they are a vital part of the framework. |
|
235 |
|
236 Other kinds of hooks, called Operations, are available |
|
237 for execution just before commit. |
|
238 |
|
239 For more information, read :ref:`hooks` section. |
|
240 |
|
241 |
|
242 Configuration |
|
243 ````````````` |
|
244 |
|
245 How to configure a LDAP source ? |
|
246 -------------------------------- |
|
247 |
|
248 See :ref:`LDAP`. |
|
249 |
|
250 How to import LDAP users in |cubicweb| ? |
|
251 ---------------------------------------- |
|
252 |
|
253 Here is a useful script which enables you to import LDAP users |
|
254 into your *CubicWeb* instance by running the following: |
|
255 |
|
256 .. sourcecode:: python |
|
257 |
|
258 import os |
|
259 import pwd |
|
260 import sys |
|
261 |
|
262 from logilab.database import get_connection |
|
263 |
|
264 def getlogin(): |
|
265 """avoid using os.getlogin() because of strange tty/stdin problems |
|
266 (man 3 getlogin) |
|
267 Another solution would be to use $LOGNAME, $USER or $USERNAME |
|
268 """ |
|
269 return pwd.getpwuid(os.getuid())[0] |
|
270 |
|
271 |
|
272 try: |
|
273 database = sys.argv[1] |
|
274 except IndexError: |
|
275 print 'USAGE: python ldap2system.py <database>' |
|
276 sys.exit(1) |
|
277 |
|
278 if raw_input('update %s db ? [y/n]: ' % database).strip().lower().startswith('y'): |
|
279 cnx = get_connection(user=getlogin(), database=database) |
|
280 cursor = cnx.cursor() |
|
281 |
|
282 insert = ('INSERT INTO euser (creation_date, eid, modification_date, login, ' |
|
283 ' firstname, surname, last_login_time, upassword) ' |
|
284 "VALUES (%(mtime)s, %(eid)s, %(mtime)s, %(login)s, %(firstname)s, " |
|
285 "%(surname)s, %(mtime)s, './fqEz5LeZnT6');") |
|
286 update = "UPDATE entities SET source='system' WHERE eid=%(eid)s;" |
|
287 cursor.execute("SELECT eid,type,source,extid,mtime FROM entities WHERE source!='system'") |
|
288 for eid, type, source, extid, mtime in cursor.fetchall(): |
|
289 if type != 'CWUser': |
|
290 print "don't know what to do with entity type", type |
|
291 continue |
|
292 if source != 'ldapuser': |
|
293 print "don't know what to do with source type", source |
|
294 continue |
|
295 ldapinfos = dict(x.strip().split('=') for x in extid.split(',')) |
|
296 login = ldapinfos['uid'] |
|
297 firstname = ldapinfos['uid'][0].upper() |
|
298 surname = ldapinfos['uid'][1:].capitalize() |
|
299 if login != 'jcuissinat': |
|
300 args = dict(eid=eid, type=type, source=source, login=login, |
|
301 firstname=firstname, surname=surname, mtime=mtime) |
|
302 print args |
|
303 cursor.execute(insert, args) |
|
304 cursor.execute(update, args) |
|
305 |
|
306 cnx.commit() |
|
307 cnx.close() |
|
308 |
|
309 |
|
310 Security |
|
311 ```````` |
|
312 |
|
313 How to reset the password for user joe ? |
|
314 ---------------------------------------- |
|
315 |
|
316 If you want to reset the admin password for ``myinstance``, do:: |
|
317 |
|
318 $ cubicweb-ctl reset-admin-pwd myinstance |
|
319 |
|
320 You need to generate a new encrypted password:: |
|
321 |
|
322 $ python |
|
323 >>> from cubicweb.server.utils import crypt_password |
|
324 >>> crypt_password('joepass') |
|
325 'qHO8282QN5Utg' |
|
326 >>> |
|
327 |
|
328 and paste it in the database:: |
|
329 |
|
330 $ psql mydb |
|
331 mydb=> update cw_cwuser set cw_upassword='qHO8282QN5Utg' where cw_login='joe'; |
|
332 UPDATE 1 |
|
333 |
|
334 if you're running over SQL Server, you need to use the CONVERT |
|
335 function to convert the string to varbinary(255). The SQL query is |
|
336 therefore:: |
|
337 |
|
338 update cw_cwuser set cw_upassword=CONVERT(varbinary(255), 'qHO8282QN5Utg') where cw_login='joe'; |
|
339 |
|
340 Be careful, the encryption algorithm is different on Windows and on |
|
341 Unix. You cannot therefore use a hash generated on Unix to fill in a |
|
342 Windows database, nor the other way round. |
|
343 |
|
344 |
|
345 You can prefer use a migration script similar to this shell invocation instead:: |
|
346 |
|
347 $ cubicweb-ctl shell <instance> |
|
348 >>> from cubicweb import Binary |
|
349 >>> from cubicweb.server.utils import crypt_password |
|
350 >>> crypted = crypt_password('joepass') |
|
351 >>> rset = rql('Any U WHERE U is CWUser, U login "joe"') |
|
352 >>> joe = rset.get_entity(0,0) |
|
353 >>> joe.cw_set(upassword=Binary(crypted)) |
|
354 |
|
355 Please, refer to the script example is provided in the `misc/examples/chpasswd.py` file. |
|
356 |
|
357 The more experimented people would use RQL request directly:: |
|
358 |
|
359 >>> rql('SET X upassword %(a)s WHERE X is CWUser, X login "joe"', |
|
360 ... {'a': crypted}) |
|
361 |
|
362 I've just created a user in a group and it doesn't work ! |
|
363 --------------------------------------------------------- |
|
364 |
|
365 You are probably getting errors such as :: |
|
366 |
|
367 remove {'PR': 'Project', 'C': 'CWUser'} from solutions since your_user has no read access to cost |
|
368 |
|
369 This is because you have to put your user in the "users" group. The user has to |
|
370 be in both groups. |
|
371 |
|
372 How is security implemented ? |
|
373 ------------------------------ |
|
374 |
|
375 The basis for security is a mapping from operations to groups or |
|
376 arbitrary RQL expressions. These mappings are scoped to entities and |
|
377 relations. |
|
378 |
|
379 This is an example for an Entity Type definition: |
|
380 |
|
381 .. sourcecode:: python |
|
382 |
|
383 class Version(EntityType): |
|
384 """a version is defining the content of a particular project's |
|
385 release""" |
|
386 # definition of attributes is voluntarily missing |
|
387 __permissions__ = {'read': ('managers', 'users', 'guests',), |
|
388 'update': ('managers', 'logilab', 'owners'), |
|
389 'delete': ('managers',), |
|
390 'add': ('managers', 'logilab', |
|
391 ERQLExpression('X version_of PROJ, U in_group G, ' |
|
392 'PROJ require_permission P, ' |
|
393 'P name "add_version", P require_group G'),)} |
|
394 |
|
395 The above means that permission to read a Version is granted to any |
|
396 user that is part of one of the groups 'managers', 'users', 'guests'. |
|
397 The 'add' permission is granted to users in group 'managers' or |
|
398 'logilab' or to users in group G, if G is linked by a permission |
|
399 entity named "add_version" to the version's project. |
|
400 |
|
401 An example for a Relation Definition (RelationType both defines a |
|
402 relation type and implicitly one relation definition, on which the |
|
403 permissions actually apply): |
|
404 |
|
405 .. sourcecode:: python |
|
406 |
|
407 class version_of(RelationType): |
|
408 """link a version to its project. A version is necessarily linked |
|
409 to one and only one project. """ |
|
410 # some lines voluntarily missing |
|
411 __permissions__ = {'read': ('managers', 'users', 'guests',), |
|
412 'delete': ('managers', ), |
|
413 'add': ('managers', 'logilab', |
|
414 RRQLExpression('O require_permission P, P name "add_version", ' |
|
415 'U in_group G, P require_group G'),) } |
|
416 |
|
417 The main difference lies in the basic available operations (there is |
|
418 no 'update' operation) and the usage of an RRQLExpression (rql |
|
419 expression for a relation) instead of an ERQLExpression (rql |
|
420 expression for an entity). |
|
421 |
|
422 You can find additional information in the section :ref:`securitymodel`. |
|
423 |
|
424 Is it possible to bypass security from the UI (web front) part ? |
|
425 ---------------------------------------------------------------- |
|
426 |
|
427 No. Only Hooks/Operations can do that. |
|
428 |
|
429 Can PostgreSQL and CubicWeb authentication work with kerberos ? |
|
430 ---------------------------------------------------------------- |
|
431 |
|
432 If you have PostgreSQL set up to accept kerberos authentication, you can set |
|
433 the db-host, db-name and db-user parameters in the `sources` configuration |
|
434 file while leaving the password blank. It should be enough for your |
|
435 instance to connect to postgresql with a kerberos ticket. |
|
436 |
|
437 |