Browse Source

moved rest of docs over to markdown/gitbook

Rafał Pitoń 8 years ago
parent
commit
e604f0208b

+ 4 - 2
docs/Cache.md

@@ -8,7 +8,7 @@ Misago uses caching aggressivelly to save costful operations results like users
 
 You can make Misago use its own cache instead of sharing cache with rest of your Django site. To do so, add new cache named `misago` to your `CACHES` setting:
 
-``python
+```python
 CACHES = {
     'default': {
         'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
@@ -19,7 +19,8 @@ CACHES = {
         'LOCATION': '127.0.0.1:11212',
     }
 }
-``
+```
+
 
 ## Cache buster
 
@@ -63,6 +64,7 @@ if not cachebuster.is_valid('bans', ban['version']):
 
 You may add and remove your own cache names to cache buster by using following commands:
 
+
 ##### Note
 
 Don't forget to call `invalidate_all` function after adding or removing cache name from buster to force it to rebuild its own cache.

+ 1 - 1
docs/PermissionsFramework.md

@@ -121,7 +121,7 @@ This will not work for instances of User model, that already reserves `acl` attr
 
 Serializers are functions called when ACL-aware object is being prepared for JSON serialization. Because python's `dict` type isnt 1:1 interchangeable with JSON, serializers allow ACL extensions to perform additional convertion or cleanup before model's ACL is serialized. They always receive single argument:
 
-* ``serialized_acl`` - ACL that will be JSON serialized
+* `serialized_acl` - ACL that will be JSON serialized
 
 Example serializer for extension setting dict using integers for keys could for example remove this dictionary from ACL to avoid problems during ACL serialization:
 

+ 5 - 0
docs/SUMMARY.md

@@ -15,9 +15,14 @@
 * [Sending mails](./Mails.md)
 * [Markup](./Markup.md)
 * [Posting process](./PostingProcess.md)
+* [Threads types](./ThreadTypes.md)
 * [Extending pages](./ExtendingPages.md)
+* [Validating registrations](./ValidatingRegistrations.md)
+* [Validators](./Validators.md)
 * [Template tags](./TemplateTags.md)
 * [Shortcuts](./Shortcuts.md)
+* [Thread store](./ThreadStore.md)
+* [View errors](./ViewErrors.md)
 * [Settings](./settings/README.md)
   * [Core settings](./settings/Core.md)
   * [Database settings](./settings/Database.md)

+ 2 - 2
docs/Shortcuts.md

@@ -25,7 +25,7 @@ def index(request, page=None):
 ```
 
 
-#### Note
+##### Note
 
 Giving `page` argument default value of 1 will make `paginate` function assume that first page was reached via link with explicit first page number and cause redirect loop.
 
@@ -50,7 +50,7 @@ def cake_fans(request, cake_id, cake_slug):
 ```
 
 
-#### Notes
+##### Notes
 
 You may have noticed that there's no exception handling for either `Http404` exception raised by `get_object_or_404`, nor `OutdatedSlug` exception raised by `validate_slug`. This is by design. Both exceptions are handled by Misago for you so you don't have to spend time writing exception handling boiler plate on every view that fetches objects from database and validates their links.
 

+ 39 - 0
docs/ThreadStore.md

@@ -0,0 +1,39 @@
+Thread store
+============
+
+Thread store is simple memory-based store that some Misago features use to maintain and pass around state for request duration.
+
+Thread store lives in `misago.core.threadstore` and offers subset of standard cache API known from Django
+
+
+##### Note
+
+Never use thread store for messaging between parts of your code. Usage of this feature for this is considered bad practice that leads to code with flow that is hard to understand.
+
+
+## `get(key, default=None)`
+
+Get value for key from thread store or fallback value if key is undefined:
+
+```python
+from misago.core import threadstore
+
+threadstore.get('peach')
+# returns None
+
+threadstore.get('peach', 'no peach!')
+# returns "no peach!"
+```
+
+
+`get()` never raises an exception for non-existant value which is why you should avoid storing `None` values and use custom default values to spot non-existant keys.
+
+
+## `set(key, value)`
+
+Set value for a key on thread store. This value will then be stored until you overwrite it with new value, thread is killed, `misago.core.middleware.ThreadStoreMiddleware` `process_response` method is called, or you explictly call `clear()` function, clearing thread store.
+
+
+## `clear()`
+
+Delete all values from thread store. This function is automatically called by `ThreadStoreMiddleware` to make sure contents of thread store won't have effect on next request.

+ 120 - 0
docs/ThreadsTypes.md

@@ -0,0 +1,120 @@
+Threads types
+=============
+
+
+All user-published content in Misago follows basic hierarchy: Categories have threads which have (optionally) polls and posts that have attachments.
+
+Whenever user creates new discussion in category, sends private message to other user, or reports offensive post, mechanics behind UI are largery the same and result in thread of certain kind being posted in destined section of site.
+
+This system was designed to be extensible to enable developers using Misago as foundation for their community sites to add new content types such as blogs, articles or galleries.
+
+
+## Writing custom thread types
+
+Thread type is basically UI for users to interact with and Python code implementing features behind it, plus strategy object for customizing specific behaviours like link building.
+
+Thread type is decided by value of `special_role` attribute of category model instance that content (thread, post, attachment, etc. ect.) belongs to. Using this value model is able to call `misago.threads.threadtypes.get(thread_type)` in order to obtain its strategoy object.
+
+
+## Type objects
+
+Paths to type objects definitions are specified in `MISAGO_THREAD_TYPES` settings. Each type class is expected to define `type_name` attribute corresponding to its category's `special_role` attribute.
+
+Once strategy class is defined, it's available as `thread_type` attribute on category, thread and post models.
+
+Depending on features used by thread type, its strategy is expected to define different of the following methods:
+
+
+##### Note
+
+If `special_role` is not defined, Misago falls back to `role` attribute.
+
+
+### `get_category_name(category)`
+
+Used to obtain category name. Useful when thread type uses single category with predefined name. Should return string.
+
+
+### `get_category_absolute_url(category)`
+
+Used to obtain category absolute url.
+
+
+### `get_new_thread_url(category)`
+
+Used to obtain "post new thread" url for category.
+
+
+### `get_reply_url(thread)`
+
+Used to obtain "post reply" url for thread.
+
+
+### `get_edit_post_url(post)`
+
+Used to obtain edit url for post.
+
+
+### `get_thread_absolute_url(thread)`
+
+Used to obtain thread absolute url.
+
+
+### `get_thread_post_url(thread, post_id, page)`
+
+Used by "go to post" views to build links pointing user to posts. Should return URL to specified thread page with fragment containing specified post.
+
+
+### `get_thread_last_reply_url(thread)`
+
+Should return url to view redirecting to last post in thread.
+
+
+### `get_thread_new_reply_url(thread)`
+
+Should return url to view redirecting to first unread post in thread.
+
+
+### `get_thread_moderated_url(thread)`
+
+Should return url to view returning list of posts in thread that are pending moderator review.
+
+
+### `get_thread_reported_url(thread)`
+
+Should return url to view returning list of reported posts in thread.
+
+
+### `get_post_absolute_url(post)`
+
+Used to obtain post absolute url.
+
+
+### `get_post_approve_url(post)`
+
+Used to obtain url that moderator should follow to approve post.
+
+
+### `get_post_unhide_url(post)`
+
+Used to obtain url that will make hidden post visible.
+
+
+### `get_post_hide_url(post)`
+
+Used to obtain url that will make visible post hidden.
+
+
+### `get_post_delete_url(post)`
+
+Used to obtain url that will delete post.
+
+
+### `get_post_report_url(post)`
+
+Used to obtain url for reporting post.
+
+
+### `get_event_edit_url(event)`
+
+Used to obtain url that will handle API calls for hiding/unhiding and deleting thread events.

+ 1 - 1
docs/UpgradingFrom05.md

@@ -57,7 +57,7 @@ Its good idea to create superuser accounts for all site administrators. Don't wo
 To move configuration over to new forum, run `python manage.py movesettings` command.
 
 
-#### Note:
+##### Note:
 
 Some settings have been moved from admin to configuration file or removed. Those will not be migrated. Please consult the [reference](./settings/README.md) for available settings that you will need to add yourself.
 

+ 16 - 0
docs/ValidatingRegistrations.md

@@ -0,0 +1,16 @@
+Validating registrations
+========================
+
+Misago implements simple framework for extending process of new user registration with additional checks.
+
+When user submits registration form, within its `clean` method form calls functions defined in `MISAGO_NEW_REGISTRATIONS_VALIDATORS` setting.
+
+Each function is called with following arguments:
+
+* `request` - current HttpRequest instance. You may use it to obtain IP address using form, via `request.user_ip` attribute.
+* `form` - registration form instance. Allows you to set errors on field via `form.add_error` utility that Django provides.
+* `cleaned_data` - dict containing cleaned data. Use it too look up user's input that you wish to validate.
+
+If function decides to interrup registration process and thus stop user from registering account, it can raise either `django.core.exceptions.ValidationError`, `django.core.exceptions.PermissionDenied`, or set errors on form via `form.add_error` utility.
+
+This validation framework provides you with plenty of power, for example allowing you to write custom validator that queries database for number of registrations that occured for specific IP in last 8 hours, and banning both users and IP address via  `ban_ip` or `ban_user` utils from `misago.users.bans` module.

+ 75 - 0
docs/Validators.md

@@ -0,0 +1,75 @@
+Validators
+==========
+
+Misago apps implement plenty of validators, some of which are considered public API. Those validators are per convention contained within `validators` module of their respective apps.
+
+
+## `misago.core.validators.validate_sluggable`
+
+Callable class that validates if string can be converted to non-empty slug thats no longer than 255 characters.
+
+To you use it, first instantiate it. If you want to define custom error messages, you can pass them using `error_short` and `error_long` arguments on initializer. After that you can simply call the class like other validator functions to see if it raises `ValidationError`:
+
+```python
+from misago.core.validators import validate_sluggable
+validator = validate_sluggable()
+validator(some_value)
+```
+
+
+## `misago.users.validators`
+
+
+### `validate_email.misago.users.validators.validate_email(value, exclude=None)`
+
+Function that takes email address and runs content, availability and ban check validation in this order via calling dedicated validators. Optional `exclude` argument can be `User` instance to exclude from certain validation like uniqueness checks.
+
+
+### `validate_email_banned.misago.users.validators.validate_email_banned(value)`
+
+Function that accepts email string as its only argument and raises Validation error if it's banned.
+
+
+### `validate_email_content.misago.users.validators.validate_email_content(value)`
+
+Callable instance of `django.core.validators.EmailValidator` that checks if email address has valid structure and contents.
+
+
+### `validate_password.misago.users.validators.validate_password(value)`
+
+Function that takes plaintext password and runs length and complexity validation in this order via calling dedicated validators.
+
+
+### `validate_password_complexity.misago.users.validators.validate_password_complexity(value)`
+
+Validates password complexity against tests specified in `password_complexity` setting.
+
+
+### `validate_password_length.misago.users.validators.validate_password_length(value)`
+
+Validates password length and raises ValidationError if specified plaintext password is shorter than `password_length_min`.
+
+
+### `validate_username.misago.users.validators.validate_username(value, exclude=None)`
+
+Function that takes username and runs content, length, availability and ban check validation in this order via calling dedicated validators. Optional `exclude` argument can be `User` instance to exclude from certain validation like uniqueness checks.
+
+
+### `validate_username_available.misago.users.validators.validate_username_available(value, exclude=None)`
+
+Function that accepts username string as its only argument and raises ValidationError if it's already taken. Optional `exclude` argument can be `User` instance to exclude from certain validation like uniqueness checks.
+
+
+### `validate_username_banned.misago.users.validators.validate_username_banned(value)`
+
+Function that accepts username string as its only argument and raises Validation error if it's banned.
+
+
+### `validate_username_content.misago.users.validators.validate_username_content(value)`
+
+Function that accepts username string as its only argument and raises Validation error if username contains disallowed characters (eg. those that are not matched by `[0-9a-z]+` regex).
+
+
+### `validate_username_length.misago.users.validators.validate_username_length(value)`
+
+Function that accepts username string as its only argument and raises Validation error if it's shorter than `username_length_min` setting or longer than `username_length_max` setting.

+ 50 - 0
docs/ViewErrors.md

@@ -0,0 +1,50 @@
+View errors
+===========
+
+Modern forum software is busy place where access content is decided by many factors. This means that your users may frequently be trying to follow links that has been outdated, deleted or simply restricted and each of those scenarios must be handled by your views.
+
+While Django provides [plenty of approaches](https://docs.djangoproject.com/en/{{ book.django_version }}/topics/http/views/#returning-errors>) to handling those situations, those can hardly be named fit for internet forum usecases. For example, you may want to communicate to your user a reason why he is not able to reply in selected thread at the moment. This brings need for custom error handling in your code.
+
+And what to do if user reached page using outdated link? You will have to compare link to model's slug field and return 301 redirect to valid address on every view that has friendly link.
+
+To solve this problem you would have to write custom error views and handlers that then you would have to add in every view that needs it. Depending on number of views you are writing, number of lines would quickly add up becoming annoying boilerplate.
+
+Misago views too have to solve this problem and this reason is why error handling boilerplate is part of framework.
+
+
+## Views Exceptions
+
+While Misago raises plenty of exceptions, only four are allowed to leave views. Two of those are django's `Http404` and `PermissionDenied` exceptions. Misago defines its own two exceptions that act as "messages" for it's own error handler that link user followed to reach view is not up-to-date and could use 301 redirect to make sure bookmarks and crawlers get current link.
+
+
+##### Note
+
+You should never raise those exceptions yourself. If you want to redirect user to certain page, return proper redirect response instead.
+
+
+### `misago.core.exceptions.Banned`
+
+Raising this exception with `Ban` or `BanCache` instance as its only argument will cause Misago to display "You are banned" error page to the user.
+
+
+
+### `misago.core.exceptions.ExplicitFirstPage`
+
+This exception is raised by `misago.core.shortcuts.paginate` helper function that creates pagination for given data, page number and configuration. If first page is explicit (`user-blog/1/`) instead implicit (`user-blog/`), this exception is raised for error handler to return redirect to link with implicit first page.
+
+
+##### Warning
+
+This is reason why Misago views pass `None` as page number to `misago.core.shortcuts.paginate` when no page was passed through link.
+
+
+### `misago.core.exceptions.OutdatedSlug`
+
+This exception is raised by `misago.core.shortcuts.validate_slug` helper function that compares link's "slug" part against one from database. If check fails OutdatedSlug exception is raised with parameter name and valid slug as message that Misago's exception handler then uses to construct redirection response to valid link.
+
+
+## The `misago.core.exceptionhandler` exception handler
+
+Exception handler is lightweight system that pairs exceptions with special handling functions that turn those exceptions into valid HTTP responses that are then served back to client.
+
+This system has been designed exlusively for handling exceptions listed in this document and is was not intended to be universal and extensible solution. If you need special handling for your own exception, depending on how wide is its usage, consider writing custom exception handler decorator or [middleware](https://docs.djangoproject.com/en/{{ book.django_version }}/topics/http/middleware/#process-exception) for it.

+ 10 - 10
misago/core/cachebuster.py

@@ -81,24 +81,24 @@ _controller = CacheBusterController()
 
 
 # Expose controller API
-def register(cache):
-    _controller.register_cache(cache)
+def register(cache_name):
+    _controller.register_cache(cache_name)
 
 
-def unregister(cache):
-    _controller.unregister_cache(cache)
+def unregister(cache_name):
+    _controller.unregister_cache(cache_name)
 
 
-def get_version(cache):
-    return _controller.get_cache_version(cache)
+def get_version(cache_name):
+    return _controller.get_cache_version(cache_name)
 
 
-def is_valid(cache, version):
-    return _controller.is_cache_valid(cache, version)
+def is_valid(cache_name, version):
+    return _controller.is_cache_valid(cache_name, version)
 
 
-def invalidate(cache):
-    _controller.invalidate_cache(cache)
+def invalidate(cache_name):
+    _controller.invalidate_cache(cache_name)
 
 
 def invalidate_all():