File: __init__.py

package info (click to toggle)
freedombox 26.2
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 82,976 kB
  • sloc: python: 48,504; javascript: 1,736; xml: 481; makefile: 290; sh: 167; php: 32
file content (182 lines) | stat: -rw-r--r-- 5,018 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# SPDX-License-Identifier: AGPL-3.0-or-later
"""
FreedomBox app for first boot wizard.
"""

import operator
import os
import sys

from django.urls import reverse
from django.utils.translation import gettext_noop

from plinth import app as app_module
from plinth import cfg
from plinth.signals import post_setup

first_boot_steps = [
    {
        'id': 'firstboot_welcome',
        'url': 'first_boot:welcome',
        'order': 0
    },
]

_all_first_boot_steps = None

_is_completed = None


class FirstBootApp(app_module.App):
    """FreedomBox app for First Boot."""

    app_id = 'first_boot'

    _version = 1

    def __init__(self) -> None:
        """Create components for the app."""
        super().__init__()

        info = app_module.Info(app_id=self.app_id, version=self._version,
                               is_essential=True)
        self.add(info)

    def post_init(self):
        """Perform post initialization operations."""
        post_setup.connect(_clear_first_boot_steps)

    def setup(self, old_version):
        """Install and configure the app."""
        super().setup(old_version)

        if not old_version:
            self._show_next_steps_notification()

        self.enable()

    def _show_next_steps_notification(self):
        """After first setup, show notification for next steps."""
        from plinth.notification import Notification
        title = gettext_noop('Setup complete! Next steps:')
        message = gettext_noop(
            'Initial setup has been completed. Perform the next steps to make '
            'your {box_name} operational.')
        data = {
            'app_name': 'translate:' + gettext_noop('Next steps'),
            'app_icon': 'fa-arrow-right',
            'box_name': 'translate:' + cfg.box_name
        }
        actions = [{
            'type': 'link',
            'class': 'primary',
            'text': gettext_noop('See next steps'),
            'url': 'first_boot:complete'
        }, {
            'type': 'dismiss'
        }]
        Notification.update_or_create(id='first-boot-complete',
                                      app_id='first_boot', severity='info',
                                      title=title, message=message,
                                      actions=actions, data=data,
                                      group='admin', dismissed=False)


def _clear_first_boot_steps(sender, module_name, **kwargs):
    """Flush the cache of first boot steps so it is recreated."""
    global _all_first_boot_steps
    _all_first_boot_steps = None


def is_firstboot_url(path):
    """Return whether a path is a firstboot step URL.

    :param path: path of url to be checked
    :return: true if its a first boot URL false otherwise
    """
    for step in _get_steps():
        if path.startswith(reverse(step['url'])):
            return True

    return False


def _get_steps():
    """Return list of all firstboot steps."""
    global _all_first_boot_steps
    if _all_first_boot_steps is not None:
        return _all_first_boot_steps

    steps = []
    for app in app_module.App.list():
        module = sys.modules[app.__module__]
        if getattr(module, 'first_boot_steps', None):
            if not app.needs_setup():
                steps.extend(module.first_boot_steps)

    _all_first_boot_steps = sorted(steps, key=operator.itemgetter('order'))
    return _all_first_boot_steps


def next_step():
    """Return the resolved next first boot step URL required to go to.

    If there are no more step remaining, return 'complete' page.
    """
    return next_step_or_none() or 'first_boot:complete'


def next_step_or_none():
    """Return the next first boot step required to run.

    If there are no more step remaining, return None.
    """
    from plinth import kvstore

    for step in _get_steps():
        done = kvstore.get_default(step['id'], 0)
        if not done:
            return step.get('url')


def mark_step_done(id):
    """Marks the status of a first boot step as done.

    :param id: id of the firstboot step
    """
    from plinth import kvstore

    kvstore.set(id, 1)
    if not next_step_or_none():
        set_completed()


def is_completed():
    """Return whether first boot process is completed."""
    from plinth import kvstore

    global _is_completed
    if _is_completed is None:
        _is_completed = kvstore.get_default('firstboot_completed', 0)

    return bool(_is_completed)


def set_completed():
    """Set the first boot process as completed."""
    from plinth import kvstore

    global _is_completed
    _is_completed = True
    kvstore.set('firstboot_completed', 1)


def get_secret_file_path():
    """Returns the path to the first boot wizard secret file."""
    return os.path.join(cfg.data_dir, 'firstboot-wizard-secret')


def firstboot_wizard_secret_exists():
    """Return whether a firstboot wizard secret exists."""
    secret_file = get_secret_file_path()
    return os.path.exists(secret_file) and os.path.getsize(secret_file) > 0