1TODO: documentation
2===================
3Miscelaneous notes abotu things to be documented.
4
5Unordered list of topics to be documented
6-----------------------------------------
7- routing
8
9  - common regular expressions examples
10
11- sessions
12
13  - basic usage & configuration
14  - using multiple sessions in the same request
15  - using different backends
16  - using flashes
17  - updating session arguments (max_age etc)
18  - purging db sessions
19
20- i18n (increment existing tutorial)
21
22  - basic usage & configuration
23  - loading locale/timezone automatically for each request
24  - formatting date/time/datetime
25  - formatting currency
26  - using i18n in templates
27
28- jinja2 & mako
29
30  - basic usage & configuration
31  - setting global filters and variables (using config or factory)
32
33- auth
34
35  - basic usage & configuration
36  - setting up 'own auth'
37  - making user available automatically on each request
38  - purging tokens
39
40- config
41
42  - configuration conventions ("namespaced" configuration for webapp2_extras
43    modules)
44
45- tricks
46
47  - configuration in a separate file
48  - routes in a separate file
49  - reduce verbosity when defining routes (R = webapp2.Route)
50
51Common errors
52-------------
53- "TypeError: 'unicode' object is not callable": one possible reason is that
54  the ``RequestHandler`` returned a string. If the handler returns anything, it
55  **must** be a :class:`webapp2.Response` object. Or it must not return
56  anything and write to the response instead using ``self.response.write()``.
57
58Secret keys
59-----------
60Add a note about how to generate strong session secret keys::
61
62    $ openssl genrsa -out ${PWD}/private_rsa_key.pem 2048
63
64Jinja2 factory
65--------------
66To create Jinja2 with custom filters and global variables::
67
68    from webapp2_extras import jinja2
69
70    def jinja2_factory(app):
71        j = jinja2.Jinja2(app)
72        j.environment.filters.update({
73            'my_filter': my_filter,
74        })
75        j.environment.globals.update({
76            'my_global': my_global,
77        })
78        return j
79
80    # When you need jinja, get it passing the factory.
81    j = jinja2.get_jinja2(factory=jinja2_factory)
82
83Debugging Jinja2
84----------------
85http://stackoverflow.com/questions/3086091/debug-jinja2-in-google-app-engine/3694434#3694434
86
87Configuration notes
88-------------------
89Notice that configuration is set primarily in the application. See:
90
91    http://webapp-improved.appspot.com/guide/app.html#config
92
93By convention, modules that are configurable in webapp2 use the module
94name as key, to avoid name clashes. Their configuration is then set in
95a nested dict. So, e.g., i18n, jinja2 and sessions are configured like this::
96
97    config = {}
98    config['webapp2_extras.i18n'] = {
99        'default_locale': ...,
100    }
101    config['webapp2_extras.jinja2'] = {
102        'template_path': ...,
103    }
104    config['webapp2_extras.sessions'] = {
105        'secret_key': ...,
106    }
107    app = webapp2.WSGIApplication(..., config=config)
108
109You only need to set the configuration keys that differ from the default
110ones. For convenience, configurable modules have a 'default_config'
111variable just for the purpose of documenting the default values, e.g.:
112
113    http://webapp-improved.appspot.com/api/extras.i18n.html#webapp2_extras.i18n.default_config
114
115Cookies, quoting & unicode
116--------------------------
117http://groups.google.com/group/webapp2/msg/985092351378c43e
118http://stackoverflow.com/questions/6839922/unicodedecodeerror-is-raised-when-getting-a-cookie-in-google-app-engine
119
120Marketplace integration
121-----------------------
122
123.. code-block:: xml
124
125   <?xml version="1.0" encoding="UTF-8" ?>
126   <ApplicationManifest xmlns="http://schemas.google.com/ApplicationManifest/2009">
127     <!-- Name and description pulled from message bundles -->
128     <Name>Tipfy</Name>
129     <Description>A simple application for testing the marketplace.</Description>
130
131     <!-- Support info to show in the marketplace & control panel -->
132     <Support>
133       <!-- URL for application setup as an optional redirect during the install -->
134       <Link rel="setup" href="https://app-id.appspot.com/a/${DOMAIN_NAME}/setup" />
135
136       <!-- URL for application configuration, accessed from the app settings page in the control panel -->
137       <Link rel="manage" href="https://app-id.appspot.com/a/${DOMAIN_NAME}/manage" />
138
139       <!-- URL explaining how customers get support. -->
140       <Link rel="support" href="https://app-id.appspot.com/a/${DOMAIN_NAME}/support" />
141
142       <!-- URL that is displayed to admins during the deletion process, to specify policies such as data retention, how to claim accounts, etc. -->
143       <Link rel="deletion-policy" href="https://app-id.appspot.com/a/${DOMAIN_NAME}/deletion-policy" />
144     </Support>
145
146     <!-- Show this link in Google's universal navigation for all users -->
147     <Extension id="navLink" type="link">
148       <Name>Tipfy</Name>
149       <Url>https://app-id.appspot.com/a/${DOMAIN_NAME}/</Url>
150       <!-- This app also uses the Calendar API -->
151       <Scope ref="Users"/>
152       <!--
153       <Scope ref="Groups"/>
154       <Scope ref="Nicknames"/>
155       -->
156     </Extension>
157
158     <!-- Declare our OpenID realm so our app is white listed -->
159     <Extension id="realm" type="openIdRealm">
160       <Url>https://app-id.appspot.com</Url>
161     </Extension>
162
163     <!-- Special access to APIs -->
164     <Scope id="Users">
165       <Url>https://apps-apis.google.com/a/feeds/user/#readonly</Url>
166       <Reason>Users can be selected to gain special permissions to access or modify content.</Reason>
167     </Scope>
168     <!--
169       <Scope id="Groups">
170       <Url>https://apps-apis.google.com/a/feeds/group/#readonly</Url>
171       <Reason></Reason>
172     </Scope>
173     <Scope id="Nicknames">
174       <Url>https://apps-apis.google.com/a/feeds/nickname/#readonly</Url>
175       <Reason></Reason>
176     </Scope>
177     -->
178   </ApplicationManifest>
179