Commit Graph

971 Commits

Author SHA1 Message Date
Olivier Gayot f0e5c19ee7 loop: replace use of asyncio.get_event_loop
The behavior of asyncio.get_event_loop() will change in a future Python
version. It is deprecated starting Python 3.10.

The functions that we can use instead are:

 * asyncio.new_event_loop() - which creates a new event loop
 * asyncio.get_running_loop() - which returns the event loop only if it
   is already running

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-10-07 18:45:11 +02:00
Michael Hudson-Doyle faf78a1be1 Revert "Merge pull request #1442 from mwhudson/main"
This reverts commit cc33a668a2, reversing
changes made to f219cd717e.
2022-10-05 15:28:39 +13:00
Michael Hudson-Doyle 1a68b4759c Revert "Merge pull request #1435 from mwhudson/snapdapi"
This reverts commit f219cd717e, reversing
changes made to 7fe070dec3.
2022-10-05 14:37:34 +13:00
Michael Hudson-Doyle 521e7026de tweak AsyncSnapd api slightly
also remove dry-run delay for requests to /v2/change/{id}
2022-10-04 16:15:19 +13:00
Dan Bungert 9e0a90fc22 network: use routes instead of gateway directives 2022-09-06 16:44:12 -06:00
Dan Bungert 943ea53fbc
Merge pull request #1402 from dbungert/terminology
fix some easier cases of impolite language
2022-08-29 18:00:35 -06:00
Michael Hudson-Doyle 60953951fe
Merge pull request #1394 from CarlosNihelton/style-help-gray
Defaults help text style to gray
2022-08-30 11:34:42 +12:00
Dan Bungert d73772258d fix some easier cases of impolite language 2022-08-29 12:30:39 -06:00
Carlos Nihelton 6d51deedb6
Assign style if a str is passed
Otherwise assign self.help as passed.

Co-authored-by: Dan Bungert <danielbungert@gmail.com>
2022-08-29 13:55:07 -03:00
J-P Nurmi 05ca22b320 Log NetworkModel.has_network changes 2022-08-26 15:06:15 +02:00
Dan Bungert d3275c3e90
Merge pull request #1393 from CarlosNihelton/fix-gray-contrast
Makes our gray ligther to increase contrast.
2022-08-24 08:44:45 -06:00
Carlos Nihelton eb722fef0b
Defaults help text style to gray
Per
https://github.com/canonical/ubuntu-desktop-installer/issues/1073#issuecomment-1224493840.
Custom styles can still be applied.
2022-08-24 11:24:24 -03:00
Carlos Nihelton 5763f33813
Makes our gray ligther to increase contrast.
Per Design's recommendation in:
https://github.com/canonical/ubuntu-desktop-installer/issues/1073#issuecomment-1225569053
2022-08-24 10:16:59 -03:00
Olivier Gayot eb69f23ce7 ubuntu-pro: update the view to include magic-attach
We now have the view display the user-code fetched via u-a-c and
automatically validate the contract token when the contract selection
succeeds.

If the magic token expires (i.e., u-a-c times out), a new contract
selection is initiated.

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-08-18 16:10:44 +02:00
Chad Smith ddaf48b334 models: subiquitycore.network.rendered_config_paths to list generated files 2022-07-14 21:48:51 -06:00
Chad Smith a531ade6c3 file_util: generate_timestamped_header function to any subiquity written files 2022-07-14 21:48:51 -06:00
Olivier Gayot 384e4b62ac ui: move confirmation mechanism in subiquitycore.ui
Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-06-24 17:24:20 +02:00
Dan Bungert dffb155203 tests: s/run_coro/IsolatedAsyncioTestCase/
Tests that use run_coro are at risk of being broken by the introduction
of another test using IsolatedAsyncioTestCase.  Switch over to only use
IsolatedAsyncioTestCase.
2022-06-23 17:43:14 -06:00
Olivier Gayot 2ee5550c9e ui: add ability to change button label in SomethingFailed message box
Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-06-15 11:54:32 +02:00
Olivier Gayot a93202e0a1
Merge pull request #1307 from ogayot/subforms-recurse-validation
Check child forms status when disabling/enabling Done button of a form
2022-06-14 15:23:05 +02:00
Dan Bungert 5b30732f14 debug shell: restore orig environment 2022-06-13 14:02:32 -06:00
Olivier Gayot c72e7eec87 form: use subclass of BoundFormField that overrides is_in_error
Instead of using isinstance(self.widget, SubFormWidget) in
BoundFormField.is_in_error, we now implement a BoundSubFormField
class that inherits from BoundFormField. It is meant to be instantianted
for subforms fields only.

This class overrides is_in_error() to perform the additional checks in
the forms' sub-fields.

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-06-09 11:28:36 +02:00
Olivier Gayot 348195b4d6 form: disable Done button on validation failure of a child form
When the validation of a field fails in a form, we disable the Done
button. With child forms, however, it did not work because they have
their own set of hidden buttons ; that are not the ones the users
interacts with.

This patch makes parent forms recurse on the child forms when checking
if any field is in error. Also, when a child form undertakes validation,
it now propagates to the parent, so that the done button can be
immediately enabled/disabled.

Having a validation error in a child form that is not currently enabled
should not prevent the user from moving forward, so we disable recursion
for child forms that are disabled.

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-06-09 11:28:36 +02:00
Dan Bungert 77119a8e0b SingleInstanceTask: add cancel_restart
cancel_restart is a mode for SingleInstanceTask that changes the
behavior when starting the task - if the task is already running, do not
cancel it to start another.
2022-05-25 10:25:00 -06:00
Dan Bungert 884f1c87ae pubsub: fix test fragility 2022-05-24 13:36:02 -06:00
Olivier Gayot 37de61f245 snaplist: display starred indication (✪) in orange
Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-05-10 09:45:25 +02:00
Olivier Gayot 2fdeb55218 snaplist: improve hack to display double stars instead of ✓
We used to rely on the narrow non-breakable space to be displayed as a
star in basic mode. This is not great and could impact other screens.

We now make use of two check-marks (each replaced by a star in basic
mode) and mask one of them in rich mode using display attributes.

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-05-10 09:45:25 +02:00
Olivier Gayot fcb33b8a0a snaplist: do not use green color for stars in basic mode
The "**" signs replace the check-mark for a verified publisher when in
basic mode.

These "**" signs where still used green foreground color. This was the
only place where we tried to display colors in basic mode.

Keep the default colors instead. This should be more compatible.

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-05-04 10:32:32 +02:00
Olivier Gayot e5017256a2 snaplist: add visual indication for starred publishers
In addition to verified publishers being indicated by a check-mark, we
now have starred publishers indicated with a circled star.

If unicode support is not available, for instance with serial
connections, we use a different number of stars to represent:

 * verified publishers: 2 stars
 * starred publishers: 1 star
 * others: no star

Because our mechanism to substitute unicode characters with ascii
equivalents expect a 1:1 mapping, we cannot simply replace the circled
start by two stars. To workaround the issue, we added a narrow
non-breakable space.

When support of unicode is available, this character shows up as a
normal space.
When support of unicode is not available, it gets replaced by a star.

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-05-04 10:32:32 +02:00
Olivier Gayot cb132611c2 ui: get rid of unreachable else block
The following commit added an unconditional return statement in the try
block of _move_screen, effectively making the associated else block
unreachable.

  a7bcc7fa add a way to wait for something with notification after 0.1s

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-04-13 18:34:46 +02:00
Olivier Gayot 014d9d0d01 ui: introduce an optional level of indirection in make_ui
The make_ui() function / coroutine returns a BaseView (i.e., a
screen to display to the user).

That being said, when the application calls, make_ui(), it does not come
with a guarantee that the view returned will be displayed to the user
immediately.

One of the reason is that there are multiple await statements before the
we call the ui.set_body function. Therefore, tasks running concurrently
cannot reliably expect that they execute after the display is refreshed.

Perhaps more importantly, when the make_ui() function takes more than .1
second to execute, we display a "Progress" screen that stays visible for
at least one second. This can effectively delay a lot the moment when
the view returned by make_ui() is shown to the user. A lot can happen in
the meantime.

As the result, the view returned by make_ui can be outdated by the time
we show it on the screen.

One way to work around this problem is to store in the controller a
reference to the view that it returns in make_ui(). This way, the
controller can modify the view and keep it up-to-date until it gets
shown to the user.

Unfortunately, some controllers (e.g., the storage controller) do not
modify / mutate the existing view object when a modification is needed ;
but instead instantiate a new view object.

This patch introduces a level of indirection that can be used by these
controllers. Instead of returning a view object from make_ui(), the
controllers are now allowed to return a callback ; which in turn will
return a view object.

https://bugs.launchpad.net/subiquity/+bug/1968161

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-04-13 18:34:46 +02:00
Michael Hudson-Doyle b07405a744
Merge pull request #1257 from ogayot/mypy-fixes
Some more code cleanup
2022-04-13 12:09:04 +12:00
Olivier Gayot a63a3ef753 utils: accept sequences of strings as commands
We used to only accept lists of strings for commands. We now accept
sequences of strings instead ; which are lists of strings or tuple of
strings.

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-04-12 10:04:16 +02:00
Olivier Gayot dd788f9eee add assert statements following .communicate() to help type checkers
After calling .communicate() on an asyncio.subprocess.Process object,
the attribute returncode gets set to a non-None value. Type checkers are
not able to figure this out.

Fixed by adding an assert to help type checkers out.

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-04-12 10:04:16 +02:00
Olivier Gayot f0ea1d16c2 network: initialize bond, vlan & wlan to None to avoid changing type
Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-04-12 09:50:21 +02:00
Dan Bungert 8ca83aa9cf file_util: genericize copy routine 2022-04-11 12:51:26 -06:00
Olivier Gayot f3634dc242 Add type hints where necessary to make mypy happy
Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-04-06 11:23:34 +02:00
Olivier Gayot 56192938a9 network: fixed typo addressesses -> addresses
Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-04-06 11:23:10 +02:00
Dan Bungert a3e1cfa6e4 probert: implement os prober arg 2022-03-29 15:09:21 -06:00
Dan Bungert 4b1277ae2d console-conf: fix crash on network info
If you run dryrun for console-conf, go to the network page, go to an
interface, then info, a crash of the form
TypeError: object str can't be used in 'await' expression
can be seen. The signature for the core version of get_info_for_netdev
is not async, but a non-async method returning str.

So mark the core version of the function async.

Co-authored-by: Michael Hudson-Doyle <michael.hudson@canonical.com>
2022-03-14 15:09:23 -06:00
Dan Bungert 4698dcd935 logging: raise warning when not adjusting perms 2022-03-14 09:48:19 -06:00
Dan Bungert 953998b23a logging: 0770 log dir in install env, 0750 later 2022-03-11 12:44:22 -07:00
Olivier Gayot 87c249d5d0 Add type annotations for command execution methods
Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-02-28 14:05:56 +01:00
Olivier Gayot 812bba1de1 Use logger names consistent with directory structure
Refreshed name of loggers to make them consistent with the directory
structure.

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-02-25 17:35:45 +01:00
Dan Bungert 42db747a0d file_util: remove omode / copy_mode
omode used to be in use, but has been standardized to 'w'.
copy_mode was unused.  Remove both.
2022-02-14 11:23:39 -07:00
Dan Bungert f4a9836143 file_util generate_config -> generate_config_yaml
The two usages of generate_config were both for yaml, so make that
simpler.
2022-02-14 11:21:56 -07:00
Dan Bungert b7349241a9 standardize on useage of file_util methods 2022-02-14 11:14:10 -07:00
Dan Bungert fae24f3247 logging: log files 0640 root:adm 2022-02-14 11:14:10 -07:00
Dan Bungert 9b5513f311 file_util: add open_perms and generate_config
Create open_perms context manager for custom or multiple writes.
Create generate_config for a small removal of redundancy.
0640 root:adm the resulting files.
2022-02-14 11:14:10 -07:00
Dan Bungert 0f9c9eef3f options: add output_base for dryrun use
To enable parallel API testing, add an output_base argument to replace
the default '.subiquity' that is sprinkled everywhere.
2022-01-26 10:39:23 -07:00
Olivier Gayot de19b3abee Add type hinting for controller base class attributes
Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-01-14 13:02:44 +01:00
Olivier Gayot 475d71e166 Allow to pass dry_run boolean to lsb_release
So that we consistently return the same value from lsb_release() across
all calls that use dry-run, the function now accepts a dry_run argument
(defaulting to False). This way, in dry-run mode, the caller does not
need to supply the path to a specific example file anymore.

  lsb_release(dry_run=True) -> will load examples/lsb-release-focal

Having said that, the caller is still left with the possibility to
specify the example file by using the path argument:

  lsb_release(path="example/lsb-release-impish")

The path and dry_run arguments are mutually exclusive: providing both
will result in a ValueError.

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2021-12-17 16:00:52 +01:00
Olivier Gayot 68b9c42fac Fix exception messages not interpolated properly
Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2021-12-16 11:35:40 +01:00
Dan Bungert 0308fa49b1 core test_view: don't prefix local class w/ Test
Fix warning:
  subiquitycore/tests/test_view.py:24
    subiquity/subiquitycore/tests/test_view.py:24:
    PytestCollectionWarning: cannot collect test class 'TestStretchy'
    because it has a __init__ constructor
2021-10-15 16:12:44 -06:00
Michael Hudson-Doyle 744269d074 remove stdlib backports from Python 3.8 2021-10-12 18:55:09 -06:00
Michael Hudson-Doyle 7cfc7d1215 close the session object after each request to the snapd API
As reported in https://bugs.launchpad.net/snapd/+bug/1946656,
not-quite idle connections between subiquity and snapd are piling up and
causing issues when trying to restart subiquity. I don't really
understand why, but using a fresh session for each API access makes the
problem go away.
2021-10-12 22:22:12 +13:00
Michael Hudson-Doyle b144f234ac install packages listed by check-language-support when locale_support == "langpack" 2021-09-30 12:09:57 +13:00
Dan Bungert af8dcfe6c3 pubsub: remove subscribe args, more broadcast args
Remove the subscribe time args, as they weren't used.
With that flexibility we can add many args at broadcast time.
2021-09-24 13:11:55 -06:00
Dan Bungert 350ce11dd9 pubsub: optional argument at broadcast time 2021-09-24 13:10:04 -06:00
Michael Hudson-Doyle 2f9c22961e
Merge pull request #1042 from canonical/wsl_oobe_auto_reconf_mode
DE-98/DE-99 - system_setup: Wsl oobe auto reconf mode
2021-09-24 14:26:23 +12:00
Michael Hudson-Doyle 7f6af23694 set wider permissions on log directory 2021-09-23 21:24:44 +12:00
Patrick Wu 1aac580dfd system_setup: update the detection logic 2021-09-20 21:58:16 +08:00
Michael Hudson-Doyle 1519c49d8e
Merge pull request #1030 from mwhudson/source-selection-3
install source selection
2021-09-14 15:10:58 +12:00
Michael Hudson-Doyle a6270cbaa1 server side implementation of source selection 2021-09-13 13:23:09 +12:00
Dan Bungert a005418cde pubsub: split channels into two classes 2021-09-08 18:33:57 -06:00
Dan Bungert bc8fda47f6 EventCallback: remove 2021-09-08 18:33:57 -06:00
Dan Bungert 3a69683128 geoip: switch to MessageHub 2021-09-08 18:33:57 -06:00
Dan Bungert fc95c72f35 pubsub: Add unit test for MessageHub
Also minor cleanup on the soon-to-be-removed EventCallback test to help
demonostrate that some of this code isn't needed.
2021-09-08 18:33:57 -06:00
Dan Bungert 0ea8139f32 MessageHub: Switch to using enum constants 2021-09-08 18:33:57 -06:00
Michael Hudson-Doyle 7f1beb1d64 add a mode argument to shutdown to allow reboot or power off 2021-08-22 09:36:41 +12:00
Dan Bungert c79aa602dc Proper fix for setting timezone inappropriately in dryrun
Reenable integration test for set of timezone.
Don't set it while in dryrun.
2021-07-15 10:49:32 -06:00
Dan Bungert ada889328d Verify that machine-config arg is a file
If machine-config is pointed to a non-existant file, dryrun can kind of
unhelpfully hang without much indication that anything is happening.
2021-07-14 16:40:22 -06:00
Dan Bungert 40945f1823
TimeZone: autoinstall and API (FR-1184) (#986)
* TimeZone: autoinstall and API

Add support for Get/Set timezone methods.  Get means that we inquire
with GeoIP as to which timezone is suggested.  Non-availability of
GeoIP, or a previous explicit Set, means that we return the system
timezone.  Set of timezone by Post results in set of the live system
timzeone, and queuing a set of the target system by way of cloud-init.

* Add clarifying comment about _request.
2021-07-13 06:25:03 -06:00
Dan Bungert 6a189dd598
Add EventCallback, and move mirror task things to GeoIP (#983)
Move mock_app to common location.
Move run_coro to subiquitycore so that subiquitycore doesn't have to
reference things in subiquity, even for test.
Move task tracking things from mirror to geoip.
Server app owns the geoip instance.
Create EventCallback as an alternative to MessageHub that should
hopefully express clearer intermodule dependencies.
2021-06-14 16:05:27 -06:00
Michael Hudson-Doyle 83d076975d
Merge pull request #979 from mwhudson/install-wpasupplicant-on-demand
install wpasupplicant when a wifi nic is seen
2021-06-10 12:54:09 +12:00
Michael Hudson-Doyle ef008f4aea address review comments 2021-06-10 12:32:29 +12:00
Michael Hudson-Doyle 7b3bb0278b fix some more assorted small wlan problems 2021-06-09 15:28:06 +12:00
Michael Hudson-Doyle fa9628f34c remove support from network model for filtering out wlan devices 2021-06-09 13:00:43 +12:00
Michael Hudson-Doyle 907e7dd7b0 implement UI for tracking wpasupplicant install state
this should perhaps be in the subiquity package vs subiquitycore somehow
but that seems hard.
2021-06-09 13:00:43 +12:00
Michael Hudson-Doyle 47b2836aee pretend virtual wlan (i.e. mac80211_hwsim) devices are real
this allows their use for testing
2021-06-02 12:40:57 +12:00
Michael Hudson-Doyle d14fd35330 move "enabling wifi turns on dhcp4" behaviour to controller from view 2021-06-02 12:40:50 +12:00
Michael Hudson-Doyle 902c57f7f7 move start_scan error handling into controller
report errors via scan_state field
2021-06-02 12:28:44 +12:00
Michael Hudson-Doyle b84fa27752 call apply_config in controller set_wlan method 2021-06-02 12:28:44 +12:00
Michael Hudson-Doyle b046608a78 fix type annotations in network model types 2021-06-02 12:28:44 +12:00
Michael Hudson-Doyle 4850cee5ce NetworkConfigureWLANStretchy.update_link should only care about updates for its nic
this was very confusing to debug!
2021-06-02 12:28:44 +12:00
Michael Hudson-Doyle c325e76e9e fix the wlan view calls to controller methods to pass just the nic name 2021-06-02 12:28:42 +12:00
Dan Bungert 2719c57c1b
locale - let it check interactive-sections again (#937)
* locale - let it check interactive-sections again

* Turn Serial into a whole new screen

When in serial, first offer the rich/basic choice (or SSH button),
and only show the current welcome screen if we choose rich mode.
Add a back button on Welcome if we are on serial.

LP: #1919251
2021-04-21 10:11:27 -06:00
Michael Hudson-Doyle bc2ae6199a asyncify pubsub a bit 2021-04-13 09:41:43 +12:00
Michael Hudson-Doyle dab04bcb3a simple replacement for urwid signals wrapper as used in server
I think this removes all use of urwid from the server code.
2021-04-13 09:41:43 +12:00
Michael Hudson-Doyle b0af11ad02 kill any foreground subprocess before restarting
This fixes a problem where you drop to a shell and refresh subiquity
from that shell -- the client tries to restart but it is running in the
background and so crashes trying to modify the terminal settings. So
this kills the subprocess before restarting. This required the extremely
angry PR I sent before: forcefully killing the subprocess also crashes
the client before restart in a similar way.
2021-04-01 17:24:49 +13:00
Michael Hudson-Doyle 939c81920c do not crash when subshell exits via signal
Here is something you can try with a live server installer today: drop
into a subshell and type "kill -9 $$". The installer will crash with an
'Input/output error' from tcsetattr.

What's going on is some deep unix arcana: when the subshell exits via
signal somehow the shell's process group is still in the foreground
(even though there are no processes in it?) and calling tcsetattr() from
a background process is not allowed. So the fix for this is reasonably
simple (or at least: short): call tcsetpgrp() to put our process group
back into the foreground. A background process doing this gets sent
SIGTTOU, but if we ignore that, all is well.

Frankly this is all very strange and I would like a lie down now.
2021-04-01 16:27:05 +13:00
Michael Hudson-Doyle 26593f4c16
Merge pull request #924 from mwhudson/lp-1921820-2
more reliably restart client when server restarts
2021-03-31 13:30:56 +13:00
Michael Hudson-Doyle 132440451d more reliably restart client when server restarts
Splitting subiquity into server and client means that in general
old versions of the client can still be running when the server is
updated (the client running on tty1 will be restarted by snapd/systemd
when the snap is updated but clients running via e.g. ssh will not). I
implemented a way for the client to detect this and restart itself: the
server sets a header in all responses that indicates if it has been
updated. So far so good. But the way it knows that it has been updated
is to check the presence of a file that is only created when subiquity
itself triggers the refresh, so it's not there in the case of manual
refresh, and as reported in https://bugs.launchpad.net/bugs/1921820 this
can lead to the client crashing because it cannot parse the new server's
response. This simply changes to creating the marker file in the snap
post-refresh hook, which will be executed for manual snap refreshes as
well.

While I'm at it, remove the rest of the post-install hook that restarted
subiquity clients running on the serial line as the generic machinery
will work for these too.
2021-03-31 13:15:06 +13:00
Michael Hudson-Doyle 64ac97aafe make subiquity client use new API for guided disk usage 2021-03-30 14:22:28 +13:00
Michael Hudson-Doyle e3361aa51c do not set installer user password if it has password or authorized keys
dearie me making a nice UI can involve a lot of typing.
2021-03-25 14:26:49 +13:00
Michael Hudson-Doyle 6fa1d9bbd0 fix crash on refresh: change ids are strings in the snapd api
for https://bugs.launchpad.net/subiquity/+bug/1913417
2021-02-10 11:43:58 +13:00
Michael Hudson-Doyle fac0eeed43 fix crash when trying to view nic info
fixes half of https://bugs.launchpad.net/subiquity/+bug/1912955
2021-01-27 09:35:09 +13:00
Michael Hudson-Doyle 53d06961cc append, do not overwrite logs
The log file names have pids in now, but when subiquity re-execs itself
to fake a snap refresh the pid doesn't change. Having the pre "refresh"
logs get overwritten does not help anything and is sometimes very
annoying.
2020-12-18 12:18:40 +13:00
Michael Hudson-Doyle 007dd3e5ef tidy up answers handling a bit and fix a race 2020-12-16 10:21:32 +13:00
Michael Hudson-Doyle aad036d925 split subiquity.core into subiquity.client.client and subiquity.server.server 2020-11-04 10:57:22 +13:00