Skip to content

Commit

Permalink
moved extra pages to MD/Gitbook
Browse files Browse the repository at this point in the history
  • Loading branch information
rafalp committed Jan 28, 2017
1 parent e0510da commit 81cb7da
Show file tree
Hide file tree
Showing 10 changed files with 386 additions and 1 deletion.
30 changes: 30 additions & 0 deletions docs/ContextProcessors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Context processors
==================

Context Processors are simple python functions that receive HttpRequest object and extend template context with additional values. In addition to [default context processors defined by Django])https://docs.djangoproject.com/en/dev/ref/templates/api/#subclassing-context-requestcontext), Misago defines its own context processors:


## `misago.core.context_processors.frontend_context`

Exposes `frontend_context` to templates, allowing you to JSON serialize and pass it to JavaScript frontend:

```
{% load misago_json %}
<script type="text/javascript">
const context = {{ frontend_context|as_json }};
misago.init(context);
</script>
```


## `misago.core.context_processors.site_address`

This function adds `SITE_ADDRESS` value to template context that you can use to build absolue links in your templates:

```
# Will become "http://mysite.com/users/"
{{ SITE_ADDRESS }}{% url 'misago:users' %}
```

This is most useful for links in e-mail templates.
49 changes: 49 additions & 0 deletions docs/Decorators.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
Views decorators
================

Misago apps define plenty of decorators for you to wrap your views with.


## `misago.core.decorators.require_POST`

Function that checks if request made to access view is POST. If it's not, decorator renders `wrong_way.html` template and returns it in 405 response. This is its only difference to Django's counterpart.


## `misago.core.errorpages.shared_403_exception_handler`

If your project has different error handler for 403 errors defined, you can use this decorator to make your function shared handler between Misago and other views. This will make Misago handle 403 exceptions coming from under its path while leaving alone exceptions coming from your site.


## `misago.core.errorpages.shared_404_exception_handler`

Same as above but for custom 404 error handler.


## `misago.users.decorators.deny_authenticated`

This decorator will block requests made to view if user is authenticated, displaying page with error message or returning JSON/XML in its stead.


## `misago.users.decorators.deny_guests`

This decorator will block requests made to view if user is not authenticated, displaying page with error message or returning JSON/XML in its stead.


## `misago.users.decorators.deny_banned_ips`

This decorator will block requests made to view if user IP is banned, displaying page with error message or returning JSON/XML in its stead.


## `misago.users.decorators.deflect_authenticated`

This decorator will return redirect to forum index if user is authenticated.


## `misago.users.decorators.deflect_guests`

This decorator will return redirect to forum index if user is not authenticated.


## `misago.users.decorators.deflect_banned_ips`

This decorator will return redirect to forum index if user IP is banned.
37 changes: 37 additions & 0 deletions docs/ExtendingPages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
Adding sections to existing pages
=================================

Certain pages in Misago are simple containers for sections:

* User Control Panel
* User Profiles List
* User Profile

Each of those consists of its own layout and list of sections. For example, user profiles display user name, information about user status, and sections (tabs) with lists of user threads, posts, followers, name history, etc. ect..

Each section is associated to instance of special object, `misago.core.page.Page`, which contains list of all sections belonging to it. Those instances are `misago.users.sites.usercp`, `misago.users.sites.users_list` and `misago.users.sites.user_profile`.

`misago.core.page.Page` instances expose following API:


### `add_section(link, after=None, before=None, visible_if=None, get_metadata=None, **kwargs)`

Adds section to page. `after` and `before` arguments should be value of other page `link`. `visible_if` argument accepts callable that will be called with args passed to `get_pages` function on page render to resolve if link to page should be displayed. `get_metadata` can be callable returning additional computed metadata for this page. All other values passed to function call get preserved in order to make it easy for 3rd party developers to reuse mechanic for their apps.

`visible_if` and `get_metadata` functions are called with arguments that were passed to `get_sections` method.


### `get_sections(request, *args)`

Returns list of sections assigned to this page. Each section is a dict of kwargs passed to `add_section` with additional `is_active` argument that controls if selected page is displayed one and `metadata` dict if one is defined.


### `get_default_link()`

Returns default link name that should be used as argument for `{% url %}` template tag.

Default links for Misago user pages are available in templates through following variables:

* `USERCP_URL` - Default link to user control panel site.
* `USERS_LIST_URL` - Default link to users lists site.
* `USER_PROFILE_URL` - Default link to user profile site.
65 changes: 65 additions & 0 deletions docs/Forms.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
Forms
=====

Purpose of this document is to introduce you to differences and features of forms module available in `misago.core.forms` package.

For proper introduction to forms, see [Django documentation](https://docs.djangoproject.com/en/{{ book.django_version }}/topics/forms/).

Because Misago relies on JSON API endpoints to change application state by users, bulk of forms are be written as React.js components making AJAX requests to different `/api/` edges, either bypassing the forms altogether, or using them purely for data validation and cleaning.

Misago's admin uses [Crispy Forms](http://django-crispy-forms.readthedocs.org/en/latest/) app that allows to easily display forms using `Bootstrap 3` markup.

Finally, Misago defines few custom field types:

### `misago.core.forms.YesNoSwitch`

Thin wrapper around Django's `TypedChoiceField`. In admin this field renders nice yes/no switch as its input.

##### Warning!

`YesNoSwitch` coerces its value to `int` (eg. `0` or `1`)! Remember about this when writing code dealing with forms containing this field!


## `misago.forums.forms`

This module defines two fields you may use for making forum selections in your forms:

* `ForumChoiceField` that extends `django.core.forms.ModelChoiceField`
* `ModelMultipleChoiceField` that extends `django.core.forms.ModelMultipleChoiceField`

Because those fields need to know ACL, you are required to call their `set_acl` method from your form's `__init__`:

```python
class MoveThreadsForm(forms.Form):
new_forum = ForumChoiceField(label=_("Move threads to forum"))

def __init__(self, *args, **kwargs):
self.forum = kwargs.pop('forum')
acl = kwargs.pop('acl')

super(MoveThreadsForm, self).__init__(*args, **kwargs)

self.fields['new_forum'].set_acl(acl)
```


## Template tags

Misago defines custom templates extension named `misago_forms`. This extension contains two template tags for rendering form fields:


### `form_row`

This tag takes form field as its first argument and renders field complete with label, help and errors. Accepts two extra arguments: label class and field class, allowing you to control size of horizontal forms:

```
{% load misago_forms %}
{% form_row form.somefield %}
{% form_row form.otherfield 'col-md-3' 'col-md-9' %}
```


### `form_input`

This tag takes form field as its only argument and renders it's input.
18 changes: 18 additions & 0 deletions docs/FrontendContext.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Using frontend context
=========================================

When user visits Misago site for first time, his/hers HTTP request is handled by Django which outputs basic version of requested page. If user has JavaScript enabled in the browser, read-only UI is then swapped with React.js components that provide interactivity.

To enable those components easy access to application's state, Misago provides simple "frontend context".


## Exposing Data to JavaScript UI

Misago creates empty dict and makes it available as `frontend_context` attribute on current `HttpRequest` object. This dict is converted into JSON when page is rendered by Django.

This means that as long as initial page wasn't rendered yet, you can preload data in any place that has access to request object, but for performance reasons views and context processors are best to do this.


## Accessing Preloaded Data

The data exposed to React.js by Misago lives in plain JavaScript object available through `misago.get('KEY')`.
40 changes: 40 additions & 0 deletions docs/Mails.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
Sending mails
=============


Misago provides its own API for sending e-mails to forum users thats layer of abstraction over the default [Django mailer](https://docs.djangoproject.com/en/dev/topics/email/).

This API lives in `misago.core.mail` and provides following functions:


## `build_mail`(request, recipient, subject, template, context=None)

Build e-mail message using supplied template name and (optionally) context. Template name shouldn't contain file extension, as Misago will automatically append `.html` for html content and `.txt` for plaintext content of the message. Message templates will have access to same request context as other templates, additional context you've provided and two extra context values: `recipient` and `sender`.

* `request` - HttpRequest object instance.
* `recipient` - User model instance.
* `subject` - A string.
* `template` - A string.
* `context` - The optional dictionary with extra context values that should be available for message templates.


## mail_user(request, recipient, subject, template, context=None)

Shortcut function that calls `build_mail` to build message, then sends it to user.

* `request` - HttpRequest object instance.
* `recipient` - User model instance.
* `subject` - A string.
* `template` - A string.
* `context` - The optional dictionary with extra context values that should be available for message templates.


## mail_users(request, recipients, subject, template, context=None)

Same as above, but instead of sending message to one recipient, it sends it to many recipients at same time. Keep on mind this may be memory intensitive as this function creates one Mail object instance for every recipient specified, so you may want to split recipients into smaller groups as you are sending them emails.

* `request` - HttpRequest object instance.
* `recipients` - Iterable of User models.
* `subject` - A string.
* `template` - A string.
* `context` - The optional dictionary with extra context values that should be available for message templates.
47 changes: 47 additions & 0 deletions docs/Markup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
Markup
======

Misago defines custom `misago.markup` module that provides facilities for parsing strings.

This module exposes following functions as its public API:


### misago.markup.parse(text, author=None, allow_mentions=True, allow_links=True, allow_images=True, allow_blocks=True)

Parses Misago-flavoured Markdown text according to settings provided. Returns dictionary with following keys:

* `original_text` - original text that was parsed
* `parsed_text` - parsed text
* `markdown` - markdown instance


### misago.markup.common_flavour(text, author=None, allow_mentions=True)

Convenience function that wraps `parse()`. This function is used for parsing messages.


## Extending Markup

To extend Misago markup, create custom module defining one or both of following functions:


### `extend_markdown(md)`

Defining this function will allow you to register new extensions in markdown used to parse text.


### `process_result(result, soup)`

This function is called to allow additional changes in result dict as well as extra instrospection and cleanup of parsed text, which is provided as [Beautiful Soup](http://www.crummy.com/software/BeautifulSoup/bs4/doc/) class instance.


Both functions should modify provided arguments in place.

Once your functions are done, add path to your module to `MISAGO_MARKUP_EXTENSIONS` setting like this:

```python
# inside your settings.py...
MISAGO_MARKUP_EXTENSIONS = [
'mymodule.markupextensions',
]
```
91 changes: 91 additions & 0 deletions docs/PostingProcess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
Posting process
===============

Process of posting and editing messages in Misago is fully modular and extensible.

Whenever there is a need to allow user to post or edit existing message, special pipeline object is initialized and passed `HttpRequest` object istance as well as instances of current user, forum, thread, post and post you are replying to. This pipeline then instiates classes defined in `MISAGO_POSTING_MIDDLEWARES` setting.

This pipeline then asks its middlewares if they have any forms they want to display on posting page, or if they have any actions to perform before, on, or after save to database.

Pipeline itself performs no changes in models or database state, delegating all tasks to its middlewares.

Pipeline is also isolated in database transaction with locks on database rows taking part in posting process. This means that its protected from eventual race conditions and in cause of eventual errors or interruptions, can be rolled back without any downsides.


##### Note

Attachments and any other extra data stored outside of Database that was changed before rollback was called is excluded from this.


## Writing custom middlewares

Middlewares are classes extending `PostingMiddleware` class defined in `misago.threads.posting` package.

During pipeline's initialization each class defined in `MISAGO_POSTING_MIDDLEWARES` setting is initialized and passed current context, which is then stored on its object attributes:

* `mode` - Integer used to identify type of action. You can compare it with `START`, `REPLY` and `EDIT` constants defined in `misago.threads.posting` package.
* `request` - HttpRequest using pipeline.
* `user` - Authenticated user writing message.
* `category` - Category in which message will be posted.
* `thread` - Depending on `mode` and phase in posting process, this may be thread loaded from database, or empty model that is yet to be saved in database.
* `post` - Depending on `mode` and phase in posting process, this may be post loaded from database, or empty model that is yet to be saved in database.
* `quote` - If `mode` is `REPLY`, this may be `None` or instance of message to which reply is written by `user`.
* `datetime` - Instance of `datetime` returned by `django.utils.timezone.now` call. You can use it to avoid subtle differences betwen dates stored on different models generated by new calls to `timezone.now`.
* `parsing_result` - dictionary containing result of parsing message entered by user.

After middleware object has been created, its `use_this_middleware` method is called with no arguments to let middleware make decision if it wants to participate in process and return `True` or `False` accordingly. If you don't define this method yourself, default definition always returns `True`.

In addition to `use_this_middleware` method mentioned ealier, each middleware may define following methods to participate in different phases of posting process:


### `make_form()`

Allows middlewares to display and bind to data their own forms. This function is expected to return None (default behaviour) or Form class instance.

Forms returned by middlewares need to have two special attributes:

* `legend` - Name of form (eg. "Poll").
* `template` - String with path to template that will be used to render this form.

In addition to this form has to declare itself as either main or supporting form via defining `is_main` or `is_supporting` attribute with value being `True`.

If form requires inclusion of JavaScript to work, `js_template` may be defined with path to template to be rendered before document's `</body>`.


### `pre_save(form)`

This method is called with either middleware's form instance or `None` before any state was saved to database.


### `save(form)`

This method is called with either middleware's form instance or `None` to save state to database.


### `post_save(form)`

This method is called with either middleware's form instance or `None` to perform additional actions like sending notifications, etc. ect..


## Reducing number of database saves

Misago provides custom `SaveChangesMiddleware` middleware that allows other middlewares to combine database saves. This middleware is called at the end of `save` and `post_save` phrases, meaning its possible for other middlewares to delegate saves to it during any time of posting process.

This middleware works by defining two extra attributes on `User`, `Forum`, `Thread` and `Post` models: `update_all` and `update_fields`.

If middleware made changes to many fields on model, changing it's `update_all` attribute to `True` will make `SaveChangesMiddleware` call model's `save` method with no arguments at the end of either `save` or `post_save` phase.

However if middleware changed only few fields, it may be better to append their names to model's `update_fields` attribute instead.

When different middlewares add custom fields to `update_fields` and set `update_all` flag at same time, Misago will perform one `save()` call updating whole model.

##### Note

Do not make assumptions or "piggyback" on other middlewares save orders. Introspecting either `update_all` or `update_fields` is bad practice. If your middlware wants its changes saved to database, it should add changed fields names to `update_fields` list even if it already contains them, or set `update_all` to `True`.


## Interrupting posting process from middleware

Middlewares can always interrupt (and rollback) posting process during `interrupt_posting` phrase by raising `misago.threads.posting.PostingInterrupt` exception with error message as its only argument.

All `PostingInterrupt`s raised outside that phase will be escalated to `ValueError` that will result in 500 error response from Misago. However as this will happen inside database transaction, there is chance that no data loss has occured in the process.
Loading

0 comments on commit 81cb7da

Please sign in to comment.