From 200e8f2ff17d9d92adb132ed4f6974ffece130ae Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Wed, 11 Oct 2023 12:33:17 +1000 Subject: [PATCH 01/23] initial sql tuning and python version comparison --- docs/maintenance/tuning/index.md | 1 + docs/maintenance/tuning/python.md | 633 ++++++++++++++++++++++++++++++ docs/maintenance/tuning/sql.md | 196 +++++++++ 3 files changed, 830 insertions(+) create mode 100644 docs/maintenance/tuning/python.md create mode 100644 docs/maintenance/tuning/sql.md diff --git a/docs/maintenance/tuning/index.md b/docs/maintenance/tuning/index.md index 9acf1909..e01d46cc 100644 --- a/docs/maintenance/tuning/index.md +++ b/docs/maintenance/tuning/index.md @@ -14,4 +14,5 @@ The official installation guide will install a stable version of Alliance Auth t gunicorn celery redis + python ``` diff --git a/docs/maintenance/tuning/python.md b/docs/maintenance/tuning/python.md new file mode 100644 index 00000000..b0777d97 --- /dev/null +++ b/docs/maintenance/tuning/python.md @@ -0,0 +1,633 @@ +# Python + +## Version Update + +Newer versions of python can focus heavily on performance improvements, some more than others. But be aware regressions for stability or security reasons may always be the case. + +As a general rule, Python 3.9 and Python 3.11 both had a strong focus on performance improvements. Python 3.12 is looking promising but has yet to have widespread testing, adoption and deployment. A simple comparison is available at [speed.python.org](https://speed.python.org/comparison/?exe=12%2BL%2B3.11%2C12%2BL%2B3.12%2C12%2BL%2B3.10%2C12%2BL%2B3.9%2C12%2BL%2B3.8&ben=746&env=1&hor=false&bas=none&chart=normal+bars). + +[Djangobench](https://github.com/django/djangobench/tree/master) is source of synthetic benchmarks and a useful tool for running comparisons. Below are some examples to inform your investigations. + +Keep in mind while a 1.2x faster result is significant, it's only one step of the process, Celery, SQL, Redis and many other factors will influence the end result and this _python_ speed improvement will not translate 1:1 into real world performance. + +### Django 4.0.10 + +- Djangobench 0.10.0 +- Django 4.0.10 +- Python 3.8.18 vs Python 3.11.5 + +```bash +joel@METABOX:~/djangobench/django$ djangobench --vcs=none --control=. --experiment=. --control-python=/home/joel/djangobench/py38/bin/python --experiment-python=/home/joel/djangobench/py311/bin/python -r /home/joel/djangobench/results -t 500 +Running all benchmarks +Recording data to '/home/joel/djangobench/results' +Control: Django 4.0.10 (in .) +Experiment: Django 4.0.10 (in .) + +Running 'multi_value_dict' benchmark ... +Min: 0.000014 -> 0.000013: 1.0304x faster +Avg: 0.000183 -> 0.000133: 1.3698x faster +Significant (t=9.325958) +Stddev: 0.00010 -> 0.00007: 1.3791x smaller (N = 500) + +Running 'query_values' benchmark ... +Min: 0.000079 -> 0.000070: 1.1308x faster +Avg: 0.000084 -> 0.000074: 1.1267x faster +Significant (t=19.174361) +Stddev: 0.00001 -> 0.00001: 1.0255x larger (N = 500) + +Running 'query_delete' benchmark ... +Min: 0.000082 -> 0.000074: 1.1145x faster +Avg: 0.000086 -> 0.000078: 1.0987x faster +Significant (t=17.504085) +Stddev: 0.00001 -> 0.00001: 1.1888x smaller (N = 500) + +Running 'query_select_related' benchmark ... +Min: 0.016771 -> 0.013520: 1.2405x faster +Avg: 0.017897 -> 0.014149: 1.2649x faster +Significant (t=40.942990) +Stddev: 0.00190 -> 0.00077: 2.4535x smaller (N = 500) + +Running 'query_aggregate' benchmark ... +Min: 0.000092 -> 0.000083: 1.1105x faster +Avg: 0.000100 -> 0.000090: 1.1107x faster +Significant (t=9.967204) +Stddev: 0.00002 -> 0.00001: 1.5003x smaller (N = 500) + +Running 'query_raw_deferred' benchmark ... +Min: 0.004157 -> 0.003563: 1.1666x faster +Avg: 0.004626 -> 0.003809: 1.2143x faster +Significant (t=12.325104) +Stddev: 0.00121 -> 0.00086: 1.4047x smaller (N = 500) + +Running 'query_get_or_create' benchmark ... +Min: 0.000412 -> 0.000362: 1.1385x faster +Avg: 0.000458 -> 0.000407: 1.1259x faster +Significant (t=14.169322) +Stddev: 0.00006 -> 0.00005: 1.1306x smaller (N = 500) + +Running 'query_values_list' benchmark ... +Min: 0.000080 -> 0.000071: 1.1231x faster +Avg: 0.000089 -> 0.000076: 1.1706x faster +Significant (t=18.298942) +Stddev: 0.00001 -> 0.00001: 1.9398x smaller (N = 500) + +Running 'url_resolve_flat_i18n_off' benchmark ... +Min: 0.055764 -> 0.045370: 1.2291x faster +Avg: 0.057670 -> 0.047020: 1.2265x faster +Significant (t=111.187780) +Stddev: 0.00206 -> 0.00059: 3.4618x smaller (N = 500) + +Running 'qs_filter_chaining' benchmark ... +Min: 0.000236 -> 0.000196: 1.2034x faster +Avg: 0.000248 -> 0.000206: 1.2041x faster +Significant (t=44.893544) +Stddev: 0.00002 -> 0.00001: 1.0833x smaller (N = 500) + +Running 'template_render' benchmark ... +Min: 0.000933 -> 0.000712: 1.3110x faster +Avg: 0.001003 -> 0.000777: 1.2909x faster +Significant (t=8.379095) +Stddev: 0.00043 -> 0.00042: 1.0287x smaller (N = 500) + +Running 'query_get' benchmark ... +Min: 0.000259 -> 0.000230: 1.1259x faster +Avg: 0.000282 -> 0.000238: 1.1829x faster +Significant (t=42.267305) +Stddev: 0.00002 -> 0.00001: 1.7842x smaller (N = 500) + +Running 'query_none' benchmark ... +Min: 0.000053 -> 0.000045: 1.1830x faster +Avg: 0.000056 -> 0.000049: 1.1449x faster +Significant (t=16.426843) +Stddev: 0.00001 -> 0.00001: 1.1267x larger (N = 500) + +Running 'query_complex_filter' benchmark ... +Min: 0.000039 -> 0.000034: 1.1527x faster +Avg: 0.000041 -> 0.000037: 1.1091x faster +Significant (t=13.582718) +Stddev: 0.00000 -> 0.00001: 1.5373x larger (N = 500) + +Running 'query_filter' benchmark ... +Min: 0.000127 -> 0.000112: 1.1288x faster +Avg: 0.000133 -> 0.000119: 1.1228x faster +Significant (t=22.727829) +Stddev: 0.00001 -> 0.00001: 1.1771x smaller (N = 500) + +Running 'template_render_simple' benchmark ... +Min: 0.000030 -> 0.000024: 1.2405x faster +Avg: 0.000035 -> 0.000029: 1.2042x faster +Not significant +Stddev: 0.00007 -> 0.00005: 1.3190x smaller (N = 500) + +Running 'default_middleware' benchmark ... +Min: -0.000047 -> -0.000054: 0.8624x faster +Avg: 0.000017 -> 0.000017: 1.0032x faster +Not significant +Stddev: 0.00037 -> 0.00037: 1.0091x larger (N = 500) + +Running 'query_annotate' benchmark ... +Min: 0.000186 -> 0.000162: 1.1505x faster +Avg: 0.000207 -> 0.000178: 1.1660x faster +Significant (t=16.516089) +Stddev: 0.00003 -> 0.00003: 1.1403x smaller (N = 500) + +Running 'raw_sql' benchmark ... +Min: 0.000015 -> 0.000013: 1.1070x faster +Avg: 0.000017 -> 0.000014: 1.1676x faster +Significant (t=13.598519) +Stddev: 0.00000 -> 0.00000: 2.3503x smaller (N = 500) + +Running 'url_resolve_flat' benchmark ... +Min: 0.056378 -> 0.044772: 1.2592x faster +Avg: 0.058268 -> 0.046656: 1.2489x faster +Significant (t=197.176590) +Stddev: 0.00121 -> 0.00051: 2.3665x smaller (N = 500) + +Running 'l10n_render' benchmark ... +Min: 0.001097 -> 0.000727: 1.5092x faster +Avg: 0.001160 -> 0.000768: 1.5101x faster +Significant (t=36.971179) +Stddev: 0.00019 -> 0.00014: 1.2946x smaller (N = 500) + +Running 'query_count' benchmark ... +Min: 0.000083 -> 0.000073: 1.1302x faster +Avg: 0.000091 -> 0.000079: 1.1640x faster +Significant (t=15.049336) +Stddev: 0.00002 -> 0.00001: 1.6661x smaller (N = 500) + +Running 'model_delete' benchmark ... +Min: 0.000123 -> 0.000105: 1.1701x faster +Avg: 0.000135 -> 0.000119: 1.1396x faster +Significant (t=17.781816) +Stddev: 0.00001 -> 0.00002: 1.1990x larger (N = 500) + +Running 'query_iterator' benchmark ... +Min: 0.000102 -> 0.000088: 1.1605x faster +Avg: 0.000108 -> 0.000093: 1.1598x faster +Significant (t=23.872009) +Stddev: 0.00001 -> 0.00001: 1.1366x smaller (N = 500) + +Running 'template_compilation' benchmark ... +Min: 0.000155 -> 0.000129: 1.2015x faster +Avg: 0.000169 -> 0.000137: 1.2317x faster +Significant (t=6.119618) +Stddev: 0.00009 -> 0.00007: 1.4162x smaller (N = 500) + +Running 'query_all_multifield' benchmark ... +Min: 0.014582 -> 0.012509: 1.1658x faster +Avg: 0.015715 -> 0.013337: 1.1783x faster +Significant (t=19.183517) +Stddev: 0.00207 -> 0.00184: 1.1241x smaller (N = 500) + +Running 'query_prefetch_related' benchmark ... +Min: 0.014293 -> 0.012157: 1.1758x faster +Avg: 0.015467 -> 0.013276: 1.1650x faster +Significant (t=20.607411) +Stddev: 0.00176 -> 0.00160: 1.0952x smaller (N = 500) + +Running 'query_all_converters' benchmark ... +Min: 0.000536 -> 0.000464: 1.1554x faster +Avg: 0.000563 -> 0.000486: 1.1595x faster +Significant (t=38.503433) +Stddev: 0.00004 -> 0.00002: 1.6468x smaller (N = 500) + +Running 'query_distinct' benchmark ... +Min: 0.000106 -> 0.000092: 1.1583x faster +Avg: 0.000127 -> 0.000096: 1.3223x faster +Significant (t=27.798102) +Stddev: 0.00002 -> 0.00001: 3.7187x smaller (N = 500) + +Running 'query_dates' benchmark ... +Min: 0.000249 -> 0.000209: 1.1953x faster +Avg: 0.000275 -> 0.000228: 1.2056x faster +Significant (t=30.785168) +Stddev: 0.00003 -> 0.00002: 1.0854x smaller (N = 500) + +Running 'model_save_existing' benchmark ... +Min: 0.003526 -> 0.003094: 1.1397x faster +Avg: 0.003723 -> 0.003212: 1.1591x faster +Significant (t=47.274918) +Stddev: 0.00018 -> 0.00016: 1.1817x smaller (N = 500) + +Running 'query_delete_related' benchmark ... +Min: 0.000120 -> 0.000103: 1.1655x faster +Avg: 0.000132 -> 0.000111: 1.1815x faster +Significant (t=6.428771) +Stddev: 0.00005 -> 0.00004: 1.2149x smaller (N = 500) + +Running 'url_reverse' benchmark ... +Min: 0.000062 -> 0.000060: 1.0318x faster +Avg: 0.000072 -> 0.000068: 1.0622x faster +Not significant +Stddev: 0.00006 -> 0.00005: 1.0531x smaller (N = 500) + +Running 'query_latest' benchmark ... +Min: 0.000136 -> 0.000118: 1.1454x faster +Avg: 0.000155 -> 0.000129: 1.2008x faster +Significant (t=8.372115) +Stddev: 0.00007 -> 0.00001: 5.1365x smaller (N = 500) + +Running 'form_create' benchmark ... +Min: 0.000015 -> 0.000013: 1.2319x faster +Avg: 0.000019 -> 0.000015: 1.2739x faster +Significant (t=4.158080) +Stddev: 0.00002 -> 0.00001: 1.1449x smaller (N = 500) + +Running 'query_update' benchmark ... +Min: 0.000047 -> 0.000041: 1.1323x faster +Avg: 0.000052 -> 0.000044: 1.1721x faster +Significant (t=18.470635) +Stddev: 0.00001 -> 0.00000: 1.6104x smaller (N = 500) + +Running 'query_in_bulk' benchmark ... +Min: 0.000152 -> 0.000136: 1.1193x faster +Avg: 0.000173 -> 0.000147: 1.1735x faster +Significant (t=16.901845) +Stddev: 0.00003 -> 0.00001: 2.1199x smaller (N = 500) + +Running 'url_resolve_nested' benchmark ... +Min: 0.000043 -> 0.000034: 1.2871x faster +Avg: 0.000075 -> 0.000047: 1.6049x faster +Not significant +Stddev: 0.00066 -> 0.00023: 2.8387x smaller (N = 500) + +Running 'model_creation' benchmark ... +Min: 0.000077 -> 0.000066: 1.1579x faster +Avg: 0.000088 -> 0.000072: 1.2205x faster +Significant (t=10.514202) +Stddev: 0.00003 -> 0.00001: 3.1410x smaller (N = 500) + +Running 'query_order_by' benchmark ... +Min: 0.000135 -> 0.000124: 1.0945x faster +Avg: 0.000145 -> 0.000133: 1.0902x faster +Significant (t=13.574502) +Stddev: 0.00001 -> 0.00001: 1.1586x smaller (N = 500) + +Running 'startup' benchmark ... +Skipped: Django 1.9 and later has changed app loading. This benchmark needs fixing anyway. + +Running 'form_clean' benchmark ... +Min: 0.000005 -> 0.000003: 1.4696x faster +Avg: 0.000006 -> 0.000004: 1.4931x faster +Significant (t=11.263253) +Stddev: 0.00000 -> 0.00000: 2.2571x smaller (N = 500) + +Running 'locale_from_request' benchmark ... +Min: 0.000076 -> 0.000082: 1.0895x slower +Avg: 0.000083 -> 0.000090: 1.0877x slower +Not significant +Stddev: 0.00009 -> 0.00006: 1.6230x smaller (N = 500) + +Running 'query_exists' benchmark ... +Min: 0.000243 -> 0.000214: 1.1399x faster +Avg: 0.000262 -> 0.000227: 1.1571x faster +Significant (t=27.797738) +Stddev: 0.00002 -> 0.00002: 1.2601x smaller (N = 500) + +Running 'query_values_10000' benchmark ... +Min: 0.005755 -> 0.005269: 1.0923x faster +Avg: 0.006184 -> 0.005587: 1.1067x faster +Significant (t=10.895954) +Stddev: 0.00094 -> 0.00079: 1.1902x smaller (N = 500) + +Running 'query_exclude' benchmark ... +Min: 0.000159 -> 0.000141: 1.1256x faster +Avg: 0.000177 -> 0.000151: 1.1741x faster +Significant (t=23.556200) +Stddev: 0.00002 -> 0.00001: 1.8250x smaller (N = 500) + +Running 'query_raw' benchmark ... +Min: 0.005619 -> 0.004860: 1.1562x faster +Avg: 0.006181 -> 0.005041: 1.2263x faster +Significant (t=18.008590) +Stddev: 0.00121 -> 0.00074: 1.6376x smaller (N = 500) + +Running 'url_resolve' benchmark ... +Min: 0.004666 -> 0.004233: 1.1023x faster +Avg: 0.004920 -> 0.004347: 1.1318x faster +Significant (t=24.865249) +Stddev: 0.00049 -> 0.00016: 3.1507x smaller (N = 500) + +Running 'model_save_new' benchmark ... +Min: 0.003420 -> 0.003105: 1.1014x faster +Avg: 0.003610 -> 0.003217: 1.1221x faster +Significant (t=42.956103) +Stddev: 0.00017 -> 0.00011: 1.6304x smaller (N = 500) + +Running 'query_all' benchmark ... +Min: 0.008101 -> 0.007077: 1.1447x faster +Avg: 0.009006 -> 0.007936: 1.1348x faster +Significant (t=9.981534) +Stddev: 0.00171 -> 0.00168: 1.0215x smaller (N = 500) +``` + +### Django 4.2.6 + +- Djangobench 0.10.0 +- Django 4.0.10 +- Python 3.8.18 vs Python 3.11.5 + +```bash +joel@METABOX:~/djangobench/django$ djangobench --vcs=none --control=. --experiment=. --control-python=/home/joel/djangobench/py38/bin/python --experiment-python=/home/joel/djangobench/py311/bin/python -r /home/joel/djangobench/results -t 500 +Running all benchmarks +Recording data to '/home/joel/djangobench/results' +Control: Django 4.2.6 (in .) +Experiment: Django 4.2.6 (in .) + +Running 'multi_value_dict' benchmark ... +Min: -0.000004 -> 0.000013: -3.0336x slower +Avg: 0.000182 -> 0.000133: 1.3680x faster +Significant (t=9.151616) +Stddev: 0.00010 -> 0.00007: 1.3826x smaller (N = 500) + +Running 'query_values' benchmark ... +Min: 0.000082 -> 0.000072: 1.1485x faster +Avg: 0.000086 -> 0.000075: 1.1462x faster +Significant (t=30.114973) +Stddev: 0.00001 -> 0.00001: 1.0258x larger (N = 500) + +Running 'query_delete' benchmark ... +Min: 0.000080 -> 0.000071: 1.1169x faster +Avg: 0.000086 -> 0.000077: 1.1088x faster +Significant (t=13.459411) +Stddev: 0.00001 -> 0.00001: 1.0008x smaller (N = 500) + +Running 'query_select_related' benchmark ... +Min: 0.016889 -> 0.013513: 1.2498x faster +Avg: 0.018370 -> 0.013885: 1.3230x faster +Significant (t=48.921967) +Stddev: 0.00196 -> 0.00061: 3.2174x smaller (N = 500) + +Running 'query_aggregate' benchmark ... +Min: 0.000167 -> 0.000153: 1.0904x faster +Avg: 0.000182 -> 0.000165: 1.1029x faster +Significant (t=12.685517) +Stddev: 0.00002 -> 0.00002: 1.3019x smaller (N = 500) + +Running 'query_raw_deferred' benchmark ... +Min: 0.004160 -> 0.003674: 1.1323x faster +Avg: 0.004596 -> 0.003888: 1.1820x faster +Significant (t=11.504156) +Stddev: 0.00117 -> 0.00073: 1.5957x smaller (N = 500) + +Running 'query_get_or_create' benchmark ... +Min: 0.000421 -> 0.000356: 1.1823x faster +Avg: 0.000470 -> 0.000392: 1.2011x faster +Significant (t=14.613017) +Stddev: 0.00008 -> 0.00009: 1.0954x larger (N = 500) + +Running 'query_values_list' benchmark ... +Min: 0.000080 -> 0.000070: 1.1395x faster +Avg: 0.000085 -> 0.000075: 1.1202x faster +Significant (t=20.300988) +Stddev: 0.00001 -> 0.00001: 1.0537x smaller (N = 500) + +Running 'url_resolve_flat_i18n_off' benchmark ... +Min: 0.056031 -> 0.045854: 1.2219x faster +Avg: 0.057048 -> 0.048370: 1.1794x faster +Significant (t=106.668460) +Stddev: 0.00117 -> 0.00139: 1.1819x larger (N = 500) + +Running 'qs_filter_chaining' benchmark ... +Min: 0.000247 -> 0.000205: 1.2080x faster +Avg: 0.000267 -> 0.000219: 1.2211x faster +Significant (t=38.507950) +Stddev: 0.00002 -> 0.00002: 1.0252x larger (N = 500) + +Running 'template_render' benchmark ... +Min: 0.000956 -> 0.000761: 1.2550x faster +Avg: 0.001061 -> 0.000862: 1.2302x faster +Significant (t=6.128572) +Stddev: 0.00052 -> 0.00051: 1.0109x smaller (N = 500) + +Running 'query_get' benchmark ... +Min: 0.000268 -> 0.000235: 1.1388x faster +Avg: 0.000293 -> 0.000256: 1.1411x faster +Significant (t=24.002331) +Stddev: 0.00002 -> 0.00003: 1.2917x larger (N = 500) + +Running 'query_none' benchmark ... +Min: 0.000055 -> 0.000050: 1.1079x faster +Avg: 0.000061 -> 0.000055: 1.1183x faster +Significant (t=3.149707) +Stddev: 0.00003 -> 0.00004: 1.3162x larger (N = 500) + +Running 'query_complex_filter' benchmark ... +Min: 0.000040 -> 0.000034: 1.1777x faster +Avg: 0.000042 -> 0.000038: 1.1267x faster +Significant (t=15.246074) +Stddev: 0.00000 -> 0.00001: 1.5250x larger (N = 500) + +Running 'query_filter' benchmark ... +Min: 0.000131 -> 0.000116: 1.1288x faster +Avg: 0.000139 -> 0.000127: 1.0907x faster +Significant (t=14.448319) +Stddev: 0.00001 -> 0.00001: 1.2281x larger (N = 500) + +Running 'template_render_simple' benchmark ... +Min: 0.000031 -> 0.000024: 1.2650x faster +Avg: 0.000037 -> 0.000029: 1.2895x faster +Significant (t=2.094800) +Stddev: 0.00007 -> 0.00005: 1.3630x smaller (N = 500) + +Running 'default_middleware' benchmark ... +Min: -0.000037 -> -0.000060: 0.6180x faster +Avg: 0.000001 -> 0.000001: 1.0056x slower +Not significant +Stddev: 0.00002 -> 0.00002: 1.0915x smaller (N = 500) + +Running 'query_annotate' benchmark ... +Min: 0.000192 -> 0.000173: 1.1122x faster +Avg: 0.000206 -> 0.000185: 1.1134x faster +Significant (t=17.849733) +Stddev: 0.00002 -> 0.00002: 1.0456x smaller (N = 500) + +Running 'raw_sql' benchmark ... +Min: 0.000013 -> 0.000012: 1.0839x faster +Avg: 0.000015 -> 0.000014: 1.0882x faster +Significant (t=4.252084) +Stddev: 0.00001 -> 0.00000: 1.5868x smaller (N = 500) + +Running 'url_resolve_flat' benchmark ... +Min: 0.055540 -> 0.046018: 1.2069x faster +Avg: 0.058030 -> 0.048408: 1.1988x faster +Significant (t=98.852976) +Stddev: 0.00157 -> 0.00151: 1.0444x smaller (N = 500) + +Running 'l10n_render' benchmark ... +Min: 0.001604 -> 0.001253: 1.2797x faster +Avg: 0.001684 -> 0.001304: 1.2918x faster +Significant (t=37.535402) +Stddev: 0.00017 -> 0.00015: 1.1476x smaller (N = 500) + +Running 'query_count' benchmark ... +Min: 0.000176 -> 0.000165: 1.0631x faster +Avg: 0.000189 -> 0.000176: 1.0755x faster +Significant (t=12.229046) +Stddev: 0.00002 -> 0.00002: 1.0395x larger (N = 500) + +Running 'model_delete' benchmark ... +Min: 0.000122 -> 0.000104: 1.1743x faster +Avg: 0.000152 -> 0.000115: 1.3227x faster +Significant (t=19.812953) +Stddev: 0.00004 -> 0.00001: 2.6554x smaller (N = 500) + +Running 'query_iterator' benchmark ... +Min: 0.000108 -> 0.000094: 1.1518x faster +Avg: 0.000119 -> 0.000098: 1.2203x faster +Significant (t=21.984884) +Stddev: 0.00002 -> 0.00001: 2.7750x smaller (N = 500) + +Running 'template_compilation' benchmark ... +Min: 0.000164 -> 0.000148: 1.1034x faster +Avg: 0.000184 -> 0.000162: 1.1386x faster +Significant (t=4.665298) +Stddev: 0.00008 -> 0.00007: 1.2952x smaller (N = 500) + +Running 'query_all_multifield' benchmark ... +Min: 0.014802 -> 0.012188: 1.2144x faster +Avg: 0.016029 -> 0.013294: 1.2057x faster +Significant (t=21.516971) +Stddev: 0.00210 -> 0.00191: 1.0984x smaller (N = 500) + +Running 'query_prefetch_related' benchmark ... +Min: 0.013401 -> 0.011583: 1.1569x faster +Avg: 0.014822 -> 0.013366: 1.1090x faster +Significant (t=11.422100) +Stddev: 0.00170 -> 0.00229: 1.3410x larger (N = 500) + +Running 'query_all_converters' benchmark ... +Min: 0.000499 -> 0.000429: 1.1618x faster +Avg: 0.000531 -> 0.000455: 1.1670x faster +Significant (t=42.716720) +Stddev: 0.00002 -> 0.00003: 1.5394x larger (N = 500) + +Running 'query_distinct' benchmark ... +Min: 0.000108 -> 0.000095: 1.1397x faster +Avg: 0.000116 -> 0.000100: 1.1646x faster +Significant (t=25.915629) +Stddev: 0.00001 -> 0.00001: 1.1204x larger (N = 500) + +Running 'query_dates' benchmark ... +Min: 0.000333 -> 0.000290: 1.1490x faster +Avg: 0.000365 -> 0.000326: 1.1207x faster +Significant (t=18.213858) +Stddev: 0.00003 -> 0.00003: 1.0118x larger (N = 500) + +Running 'model_save_existing' benchmark ... +Min: 0.003455 -> 0.003081: 1.1215x faster +Avg: 0.003764 -> 0.003326: 1.1316x faster +Significant (t=32.229651) +Stddev: 0.00023 -> 0.00020: 1.1398x smaller (N = 500) + +Running 'query_delete_related' benchmark ... +Min: 0.000122 -> 0.000102: 1.1946x faster +Avg: 0.000131 -> 0.000113: 1.1564x faster +Significant (t=5.027485) +Stddev: 0.00005 -> 0.00006: 1.4129x larger (N = 500) + +Running 'url_reverse' benchmark ... +Min: 0.000068 -> 0.000067: 1.0193x faster +Avg: 0.000075 -> 0.000074: 1.0157x faster +Not significant +Stddev: 0.00006 -> 0.00005: 1.1543x smaller (N = 500) + +Running 'query_latest' benchmark ... +Min: 0.000147 -> 0.000138: 1.0631x faster +Avg: 0.000167 -> 0.000148: 1.1277x faster +Significant (t=11.353029) +Stddev: 0.00003 -> 0.00002: 1.6091x smaller (N = 500) + +Running 'form_create' benchmark ... +Min: 0.000016 -> 0.000013: 1.2659x faster +Avg: 0.000020 -> 0.000015: 1.2770x faster +Significant (t=3.482649) +Stddev: 0.00002 -> 0.00002: 1.0947x larger (N = 500) + +Running 'query_update' benchmark ... +Min: 0.000047 -> 0.000043: 1.0971x faster +Avg: 0.000050 -> 0.000046: 1.0691x faster +Significant (t=9.363513) +Stddev: 0.00001 -> 0.00000: 1.2636x smaller (N = 500) + +Running 'query_in_bulk' benchmark ... +Min: 0.000157 -> 0.000143: 1.0970x faster +Avg: 0.000178 -> 0.000162: 1.0981x faster +Significant (t=9.031182) +Stddev: 0.00002 -> 0.00003: 1.5173x larger (N = 500) + +Running 'url_resolve_nested' benchmark ... +Min: 0.000046 -> 0.000038: 1.2179x faster +Avg: 0.000075 -> 0.000052: 1.4505x faster +Not significant +Stddev: 0.00059 -> 0.00024: 2.4300x smaller (N = 500) + +Running 'model_creation' benchmark ... +Min: 0.000071 -> 0.000065: 1.1058x faster +Avg: 0.000079 -> 0.000073: 1.0876x faster +Significant (t=2.786580) +Stddev: 0.00003 -> 0.00004: 1.1518x larger (N = 500) + +Running 'query_order_by' benchmark ... +Min: 0.000146 -> 0.000128: 1.1407x faster +Avg: 0.000154 -> 0.000138: 1.1206x faster +Significant (t=14.021341) +Stddev: 0.00002 -> 0.00002: 1.2540x larger (N = 500) + +Running 'startup' benchmark ... +Skipped: Django 1.9 and later has changed app loading. This benchmark needs fixing anyway. + +Running 'form_clean' benchmark ... +Min: 0.000005 -> 0.000004: 1.4613x faster +Avg: 0.000006 -> 0.000004: 1.3654x faster +Significant (t=12.763128) +Stddev: 0.00000 -> 0.00000: 1.1666x larger (N = 500) + +Running 'locale_from_request' benchmark ... +Min: 0.000097 -> 0.000108: 1.1090x slower +Avg: 0.000108 -> 0.000120: 1.1178x slower +Significant (t=-3.057677) +Stddev: 0.00007 -> 0.00006: 1.1186x smaller (N = 500) + +Running 'query_exists' benchmark ... +Min: 0.000273 -> 0.000234: 1.1698x faster +Avg: 0.000290 -> 0.000248: 1.1686x faster +Significant (t=39.518859) +Stddev: 0.00002 -> 0.00002: 1.2025x smaller (N = 500) + +Running 'query_values_10000' benchmark ... +Min: 0.005601 -> 0.005298: 1.0571x faster +Avg: 0.006023 -> 0.005691: 1.0583x faster +Significant (t=6.167352) +Stddev: 0.00082 -> 0.00088: 1.0752x larger (N = 500) + +Running 'query_exclude' benchmark ... +Min: 0.000159 -> 0.000140: 1.1367x faster +Avg: 0.000165 -> 0.000149: 1.1020x faster +Significant (t=19.643154) +Stddev: 0.00001 -> 0.00001: 1.2636x larger (N = 500) + +Running 'query_raw' benchmark ... +Min: 0.005764 -> 0.004630: 1.2450x faster +Avg: 0.006169 -> 0.004881: 1.2638x faster +Significant (t=20.996453) +Stddev: 0.00109 -> 0.00083: 1.3105x smaller (N = 500) + +Running 'url_resolve' benchmark ... +Min: 0.004928 -> 0.004597: 1.0721x faster +Avg: 0.005217 -> 0.004716: 1.1063x faster +Significant (t=46.893945) +Stddev: 0.00022 -> 0.00010: 2.2192x smaller (N = 500) + +Running 'model_save_new' benchmark ... +Min: 0.003404 -> 0.003012: 1.1301x faster +Avg: 0.003494 -> 0.003105: 1.1251x faster +Significant (t=45.888484) +Stddev: 0.00014 -> 0.00013: 1.0298x smaller (N = 500) + +Running 'query_all' benchmark ... +Min: 0.007971 -> 0.007085: 1.1250x faster +Avg: 0.009091 -> 0.008147: 1.1159x faster +Significant (t=7.583074) +Stddev: 0.00183 -> 0.00210: 1.1518x larger (N = 500) +``` diff --git a/docs/maintenance/tuning/sql.md b/docs/maintenance/tuning/sql.md new file mode 100644 index 00000000..6f78ed66 --- /dev/null +++ b/docs/maintenance/tuning/sql.md @@ -0,0 +1,196 @@ +# SQL + +SQL Tuning is usually the realm of experienced Database Admins, as it can be full of missteps leading to worse performance. It is _extremely_ important that you take it slowly, make one change at a time with dedicated research and test before and after. + +Before you start down this path its best to update [MariaDB](https://mariadb.org/download/?t=repo-config) / MySQL. Performance Schemas, some default tuning and other general performance improvements are only available on new versions. You must also allow your server to run for 24 hours at least to gather accurate data. + +## MySQLTuner + +[MySQLTuner](https://github.com/major/MySQLTuner-perl) is a Perl script that will analyze inbuilt metrics and spit out recommendations. + +### [performance_schema](https://mariadb.com/kb/en/performance-schema-system-variables/#performance_schema) + +This should be ON for 24 hours before applying any recommendations, then can be turned _OFF_ to save Memory while its not needed. + +```bash +-------- Performance schema ------------------------------------------------------------------------ +[--] Performance_schema is activated. +[--] Memory used by Performance_schema: 105.7M +[--] Sys schema is installed. +# 105M could be significant depending on your hardware +``` + +## SQL Variables + +### [skip-name-resolve](https://mariadb.com/kb/en/server-system-variables/#skip_name_resolve) + +While on, SQL will perform a dns resolve for all connections, if your database is connected via IP, this will save you a handful of cpu cycles per connection. + +Note you must use 127.0.0.1 for localhost connections, and all entries in GRANT tables (permissions), must use IP addresses. + +### [table_definition_cache](https://mariadb.com/kb/en/server-system-variables/#table_definition_cache) + +Will usually need to be expanded on installs with many extensions + +Most installs should cache all their tables, but if your hit rate is still quite high, you may have a lot of rarely used tables that you don't need to waste memory caching. + +```bash +[OK] Table cache hit rate: 63% (2K hits / 4K requests). +# Only 63% of our queries are using this cache +table_definition_cache (400) > 567 or -1 (autosizing if supported) +# Here We have 567 tables, but a default cache of only 400. +``` + +```bash +[OK] Table cache hit rate: 99% (372M hits / 372M requests) +[OK] table_definition_cache (600) is greater than number of tables (567) +# Much better +``` + +### [innodb_buffer_pool_size](https://mariadb.com/kb/en/innodb-system-variables/#innodb_buffer_pool_size) + +This is in short, the amount of memory assigned to store data for faster reads. If you are memory starved you should not increase this variable regardless of the suggestions of this tool. Pushing SQL cache to pagefile will not result in faster queries. + +If you are not memory starved, you can wind this up to the amount of total data you have to store it all in memory. This would be a significant performance increase for larger installs on dedicated hardware with memory to spare. + +```bash +[!!] InnoDB buffer pool / data size: 128.0M / 651.6M +# I have 651mb of _possible_ data to cache. +# We won't and shouldn't cache it all unless we have excess memory to spare. +... +[!!] InnoDB Read buffer efficiency: 0% (-2019 hits / 0 total) +# A low ratio here would suggest more Memory can be used effectively. +# A high ratio might mean we have most of our regularly used data cached already +``` + +### [innodb_log_buffer_size](https://mariadb.com/kb/en/innodb-system-variables/#innodb_log_buffer_size) / [innodb_log_file_size](https://mariadb.com/kb/en/innodb-system-variables/#innodb_log_file_size) + +[innodb_log_file_size](https://mariadb.com/kb/en/innodb-system-variables/#innodb_log_file_size) This is your _write_ log, used to redo any commits in the event of a crash. MySQLTuner recommends this be 1/4 of your innodb_buffer_pool / read buffer. I would not lower this past the default size. + +[innodb_log_buffer_size](https://mariadb.com/kb/en/innodb-system-variables/#innodb_log_buffer_size) This is the memory buffer for the write log. Larger transactions will benefit from a larger setting. + +```bash +[!!] Ratio InnoDB log file size / InnoDB Buffer pool size (75%): 96.0M \* 1 / 128.0M should be equal to 25% +# Here our write log file is 75% of our read buffer, but 96MB is the default so we probably wont shrink it further +... +[OK] InnoDB Write Log efficiency: 99.11% (23167614 hits / 23375465 total) # Our transactions are typically not large enough to exhaust the write log buffer, +[OK] InnoDB log waits: 0.00% (0 waits / 207851 writes) +``` + +### [innodb_file_per_table](https://mariadb.com/kb/en/innodb-system-variables/#innodb_file_per_table) + +This is not for performance, but for file system utilization and ease of use. While off all tables are stored in a single monolith file, as opposed to individual files. This is deprecated and set to ON in MariaDB 11.x + +```bash +[OK] InnoDB File per table is activated +``` + +### [join_buffer_size](https://mariadb.com/kb/en/server-system-variables/#join_buffer_size) + +It is always better to optimize a table with indexes, if you have valuable performance data and analysis please reach out to either the Alliance Auth or Community dev responsible for the data that could benefit from indexes. MySQLTuner will likely recommend increasing this number for as long as there are any queries that could benefit, regardless of their resulting performance impact. + +Also keep in mind this is _per thread_, if you have a potential 200 connections, 256MB \* 200 = 50MB, scaling this setting out too far can result in more memory use than expected. + +```bash +[!!] Joins performed without indexes: 67646 +``` + +```bash +[OK] No joins without indexes +# An ideal scenario. With well designed apps this is possible with a default join buffer. +``` + +### [tmp_table_size](https://mariadb.com/kb/en/server-system-variables/#tmp_table_size) / [max_heap_table_size](https://mariadb.com/kb/en/server-system-variables/#max_heap_table_size) + +If a temporary table must be created due to a lack of other optimizations or large queries, it may only be stored in memory under this size. Any larger and it is performed on disk reducing performance. + +tmp_table_size and max_heap_table_size should be increased together. + +```bash +[!!] Temporary tables created on disk: 32% (775 on disk / 2K total) +# 32% of my temp tables are performed on disk. If you increase this size, monitor if your performance improves. +# If it does not you may have data of a certain size that is impractical to cache, and you can reclaim this memory. +``` + +```bash +[OK] Temporary tables created on disk: 0% (5K on disk / 4M total) +# Here only a miniscule amount of my temp tables are done on disk. No action required +``` + +### key_buffer_size + +Index buffer for MyISAM tables, If you use no or very little data in MyISAM tables. You may reclaim some memory here + +In this example we still have some MyISAM tables, you may have none + +```bash +[--] General MyIsam metrics: +[--] +-- Total MyISAM Tables : 67 +[--] +-- Total MyISAM indexes : 7.1M +[--] +-- KB Size :8.0M +[--] +-- KB Used Size :1.5M +[--] +-- KB used :18.3% +[--] +-- Read KB hit rate: 0% (0 cached / 0 reads) +[--] +-- Write KB hit rate: 0% (0 cached / 0 writes) +[!!] Key buffer used: 18.3% (1.5M used / 8.0M cache) # We have only filled 1.5M of the 8 assigned +[OK] Key buffer size / total MyISAM indexes: 8.0M/7.1M # This is the max theoretical buffer to cache all my indexes +Variables to adjust: + key_buffer_size (~ 1M) +# Tuner has seen that we barely use this buffer and it can be shrunk, if you care about its impact don't lower this below your total indexes. +``` + +### [aria_pagecache_buffer_size](https://mariadb.com/kb/en/aria-system-variables/#aria_pagecache_buffer_size) + +Index and data buffer for Aria tables, If you use no or very little data in Aria tables. You may reclaim some memory here + +```bash +-------- Aria Metrics ------------------------------------------------------------------------------ +[--] Aria Storage Engine is enabled. +[OK] Aria pagecache size / total Aria indexes: 128.0M/328.0K # i use a fraction of my aria buffer since i have no aria tables. +[OK] Aria pagecache hit rate: 99.9% (112K cached / 75 reads) # Aria is used internally for MariaDB, so you still want an incredily high ratio here. +``` + +## Swappiness + +Swappiness is not an SQL variable but part of your system kernel. Swappiness controls how much free memory a server "likes" to have at any given time, and how frequently it shifts data to swapfile in order to free up memory. Desktop operating systems will have this value set quite high, whereas servers are less aggressive with their swapfile. + +Database workloads especially benefit from having their caches stay in memory and will recommend values under 10 for a dedicated database server. 10 is a good compromise for a mixed use server with adequate memory. + +If your server is memory starved, leave swapfile aggressive to ensure it is moving memory around as needed. + +```bash +joel@METABOX:~/aa_dev$ free -m + total used free shared buff/cache available +Mem: 15998 1903 13372 2 722 13767 +Swap: 4096 1404 2691 +# Here we can see a lot of memory page (1404MB) sitting in swap while there is free memory (13372MB) available + +``` + +```bash +[root@auth ~]# free -m + total used free shared buff/cache available +Mem: 738 611 59 1 68 35 +Swap: 2047 1014 1033 +# Here we can see a memory starved server highly utilizing swap already. I wouldn't mess with it too much. (vm.swappiness is 30) +``` + +```bash +[root@mysql ~]# free -m + total used free shared buff/cache available +Mem: 738 498 95 7 145 120 +Swap: 2047 289 1758 +# Here we can see a dedicated single use Database Server, Swappiness is 10 here because we have been careful not to starve it of memory and there is low potential to impact other applications +``` + +```bash +vm.swappiness <= 10 (echo 10 > /proc/sys/vm/swappiness) or vm.swappiness=10 in /etc/sysctl.conf +``` + +## Max Asyncronous IO + +Unless you are still operating on spinning rust (Hard Disk Drives), or an IO limited VPS, you can likely increase this value. Database workloads appreciate the additional scaling. + +```bash +fs.aio-max-nr > 1M (echo 1048576 > /proc/sys/fs/aio-max-nr) or fs.aio-max-nr=1048576 in /etc/sysctl.conf +``` From ea1887b9ec6d59941ff86e2cb25d8fc2fccaab31 Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Thu, 26 Oct 2023 11:26:39 +1000 Subject: [PATCH 02/23] mild clarifications --- .../aa_core/{code-style => code-style.md} | 0 docs/maintenance/tuning/index.md | 1 + docs/maintenance/tuning/sql.md | 15 +++++++++++---- 3 files changed, 12 insertions(+), 4 deletions(-) rename docs/development/aa_core/{code-style => code-style.md} (100%) diff --git a/docs/development/aa_core/code-style b/docs/development/aa_core/code-style.md similarity index 100% rename from docs/development/aa_core/code-style rename to docs/development/aa_core/code-style.md diff --git a/docs/maintenance/tuning/index.md b/docs/maintenance/tuning/index.md index e01d46cc..44b50c1d 100644 --- a/docs/maintenance/tuning/index.md +++ b/docs/maintenance/tuning/index.md @@ -15,4 +15,5 @@ The official installation guide will install a stable version of Alliance Auth t celery redis python + sql ``` diff --git a/docs/maintenance/tuning/sql.md b/docs/maintenance/tuning/sql.md index 6f78ed66..17253608 100644 --- a/docs/maintenance/tuning/sql.md +++ b/docs/maintenance/tuning/sql.md @@ -89,7 +89,7 @@ This is not for performance, but for file system utilization and ease of use. Wh It is always better to optimize a table with indexes, if you have valuable performance data and analysis please reach out to either the Alliance Auth or Community dev responsible for the data that could benefit from indexes. MySQLTuner will likely recommend increasing this number for as long as there are any queries that could benefit, regardless of their resulting performance impact. -Also keep in mind this is _per thread_, if you have a potential 200 connections, 256MB \* 200 = 50MB, scaling this setting out too far can result in more memory use than expected. +Also keep in mind this is _per thread_, if you have a potential 200 connections, 256KB * 200 = 50MB, scaling this setting out too far can result in more memory use than expected. ```bash [!!] Joins performed without indexes: 67646 @@ -147,7 +147,7 @@ Index and data buffer for Aria tables, If you use no or very little data in Aria -------- Aria Metrics ------------------------------------------------------------------------------ [--] Aria Storage Engine is enabled. [OK] Aria pagecache size / total Aria indexes: 128.0M/328.0K # i use a fraction of my aria buffer since i have no aria tables. -[OK] Aria pagecache hit rate: 99.9% (112K cached / 75 reads) # Aria is used internally for MariaDB, so you still want an incredily high ratio here. +[OK] Aria pagecache hit rate: 99.9% (112K cached / 75 reads) # Aria is used internally for MariaDB, so you still want an incredibly high ratio here. ``` ## Swappiness @@ -164,7 +164,6 @@ joel@METABOX:~/aa_dev$ free -m Mem: 15998 1903 13372 2 722 13767 Swap: 4096 1404 2691 # Here we can see a lot of memory page (1404MB) sitting in swap while there is free memory (13372MB) available - ``` ```bash @@ -184,13 +183,21 @@ Swap: 2047 289 1758 ``` ```bash +[--] Information about kernel tuning: +... +[--] vm.swappiness = 30 +[xx] Swappiness is < 10. +... vm.swappiness <= 10 (echo 10 > /proc/sys/vm/swappiness) or vm.swappiness=10 in /etc/sysctl.conf ``` -## Max Asyncronous IO +## Max Asynchronous IO Unless you are still operating on spinning rust (Hard Disk Drives), or an IO limited VPS, you can likely increase this value. Database workloads appreciate the additional scaling. ```bash +[--] Information about kernel tuning: +[--] fs.aio-max-nr = 65536 +... fs.aio-max-nr > 1M (echo 1048576 > /proc/sys/fs/aio-max-nr) or fs.aio-max-nr=1048576 in /etc/sysctl.conf ``` From 13d866bd0d87451d1f7879ad8e3fb3c5b7e65002 Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Fri, 27 Oct 2023 16:37:09 +1000 Subject: [PATCH 03/23] RST to MyST, pyproject doc dependencies, add sphinx tabs --- .readthedocs.yml | 11 +++-- README.md | 2 +- docs/conf.py | 104 +++++++++++++----------------------------- docs/requirements.txt | 20 -------- pyproject.toml | 10 +++- 5 files changed, 49 insertions(+), 98 deletions(-) delete mode 100644 docs/requirements.txt diff --git a/.readthedocs.yml b/.readthedocs.yml index 936dbfe8..6837aabd 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -7,11 +7,11 @@ version: 2 # Set the version of Python and other tools you might need build: - os: ubuntu-20.04 + os: ubuntu-22.04 apt_packages: - redis tools: - python: "3.8" + python: "3.11" # Build documentation in the docs/ directory with Sphinx sphinx: @@ -20,7 +20,10 @@ sphinx: # Optionally build your docs in additional formats such as PDF and ePub formats: all -# Optionally set the version of Python and requirements required to build your docs +# Python requirements required to build your docs python: install: - - requirements: docs/requirements.txt + - method: pip + path: . + extra_requirements: + - docs diff --git a/README.md b/README.md index 7c6bc43e..5e9f5e94 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ An auth system for EVE Online to help in-game organizations manage online servic - [Documentation](http://allianceauth.rtfd.io) - [Support](#support) - [Release Notes](https://gitlab.com/allianceauth/allianceauth/-/releases) -- [Developer Team](#developer-team) +- [Developer Team](#development-team) - [Contributing](#contributing) ## Overview diff --git a/docs/conf.py b/docs/conf.py index 87502ae6..71a047e9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,15 +1,10 @@ +# Configuration file for the Sphinx documentation builder. # -# Alliance Auth documentation build configuration file, created by -# sphinx-quickstart on Tue Jan 3 12:56:59 2017. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -18,23 +13,23 @@ import os import sys import django +import sphinx_rtd_theme # noqa + sys.path.insert(0, os.path.abspath('..')) os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.settings_all' django.setup() +# -- Project information ----------------------------------------------------- + +project = 'Alliance Auth' +copyright = '2018-2023, Alliance Auth' +author = 'Alliance Auth Team' + +# -- General configuration --------------------------------------------------- + # on_rtd is whether we are on readthedocs.org, this line of code grabbed from docs.readthedocs.org on_rtd = os.environ.get('READTHEDOCS', None) == 'True' -# Support for recommonmark module -import recommonmark -from recommonmark.transform import AutoStructify - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. @@ -42,11 +37,18 @@ from recommonmark.transform import AutoStructify extensions = [ 'sphinx_rtd_theme', 'sphinx.ext.autodoc', + 'sphinx.ext.intersphinx', 'sphinx.ext.napoleon', - 'recommonmark', - 'sphinxcontrib_django2', 'sphinx.ext.viewcode', - 'sphinx_copybutton' + 'myst_parser', + 'sphinxcontrib_django2', + 'sphinx_copybutton', + 'sphinx_tabs.tabs' +] + +myst_enable_extensions = [ + "colon_fence", + "tasklist", ] # Add any paths that contain templates here, relative to this directory. @@ -59,41 +61,16 @@ templates_path = ['_templates'] source_suffix = ['.md', '.rst'] # The master toctree document. -master_doc = 'index' - -# General information about the project. -project = 'Alliance Auth' -copyright = '2018-2022, Alliance Auth' -author = 'Alliance Auth Team' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '3.0' -# The full version, including alpha/beta/rc tags. -# release = u'1.14.0' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = 'en' +root_doc = 'index' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False - # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for @@ -101,15 +78,6 @@ todo_include_todos = False # html_theme = 'sphinx_rtd_theme' -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# - -html_theme_options = { - 'navigation_depth': 4, -} - # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". @@ -147,7 +115,7 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'AllianceAuth.tex', 'Alliance Auth Documentation', 'R4stl1n', 'manual'), + (root_doc, 'AllianceAuth.tex', 'Alliance Auth Documentation', 'Alliance Auth Team', 'manual'), ] @@ -156,7 +124,7 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'allianceauth', 'Alliance Auth Documentation', + (root_doc, 'allianceauth', 'Alliance Auth Documentation', [author], 1) ] @@ -169,15 +137,7 @@ add_module_names = False # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'AllianceAuth', 'Alliance Auth Documentation', - author, 'AllianceAuth', 'An auth system for EVE Online to help in-game organizations manage online service access.', - 'Miscellaneous'), +texinfo_documents = [( + root_doc, 'AllianceAuth', 'Alliance Auth Documentation', author, 'AllianceAuth', + 'An auth system for EVE Online to help in-game organizations manage online service access.', 'Miscellaneous'), ] - - -def setup(app): - app.add_config_value('recommonmark_config', { - 'auto_toc_tree_section': 'Contents', - }, True) - app.add_transform(AutoStructify) diff --git a/docs/requirements.txt b/docs/requirements.txt deleted file mode 100644 index fc8d395c..00000000 --- a/docs/requirements.txt +++ /dev/null @@ -1,20 +0,0 @@ -# Docs Specific Packages -sphinx>=4.4.0,<5.0.0 -sphinx_rtd_theme>=1.0.0,<2.0.0 -recommonmark==0.7.1 -Jinja2<3.1 -docutils==0.16 -sphinxcontrib-django2 -sphinx-copybutton - -# Autodoc dependencies -celery>=5.2.0,<6.0.0 -celery_once>=3.0.1 -django>=4.0.6,<4.1.0 -django-bootstrap-form -django-celery-beat>=2.3.0 -django-esi>=4.0.1 -django-redis>=5.2.0,<6.0.0 -django-sortedm2m -passlib -redis>=4.0.0,<5.0.0 diff --git a/pyproject.toml b/pyproject.toml index 18318565..efa516a5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,7 +60,15 @@ dependencies = [ test = [ "coverage>=4.3.1", "django-webtest", - "requests-mock>=1.2.0", + "requests-mock>=1.2.0" +] +docs = [ + "sphinx", + "sphinx_rtd_theme>=1.0.0,<2.0.0", + "myst-parser", + "sphinxcontrib-django", + "sphinx-copybutton", + "sphinx-tabs", ] [project.scripts] From b9d128259e601ec41a72b163baaed97a191139ab Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Fri, 27 Oct 2023 16:37:30 +1000 Subject: [PATCH 04/23] correct path --- docs/development/aa_core/{code-style => code-style.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename docs/development/aa_core/{code-style => code-style.md} (99%) diff --git a/docs/development/aa_core/code-style b/docs/development/aa_core/code-style.md similarity index 99% rename from docs/development/aa_core/code-style rename to docs/development/aa_core/code-style.md index 4f9d5b60..849d3aa0 100644 --- a/docs/development/aa_core/code-style +++ b/docs/development/aa_core/code-style.md @@ -10,7 +10,7 @@ To get started, `pip install pre-commit`, then `pre-commit install` to add the g Before any code is "git push"-ed, pre-commit will check it for uniformity and correct it if possible -```bash +```shell check python ast.....................................(no files to check)Skipped check yaml...........................................(no files to check)Skipped check json...........................................(no files to check)Skipped From ffb526ab0c6c1e60f30227e726e649ddc99e39a3 Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Fri, 27 Oct 2023 16:37:53 +1000 Subject: [PATCH 05/23] find and replace fixes, will introduce errors --- docs/customizing/index.md | 12 +- docs/development/aa_core/documentation.md | 15 +- docs/development/aa_core/index.md | 9 +- docs/development/custom/index.md | 13 +- .../custom/integrating-services.md | 2 +- docs/development/custom/menu-hooks.md | 2 +- docs/development/custom/url-hooks.md | 5 +- .../dev_setup/aa-dev-setup-wsl-vsc-v2.md | 69 ++- docs/development/dev_setup/index.md | 7 +- docs/development/index.md | 13 +- docs/development/tech_docu/api/index.md | 21 +- docs/development/tech_docu/celery.md | 13 +- docs/development/tech_docu/index.md | 13 +- docs/features/apps/autogroups.md | 7 +- docs/features/apps/corpstats.md | 2 +- docs/features/apps/fleetactivitytracking.md | 2 +- docs/features/apps/hrapplications.md | 2 +- docs/features/apps/index.md | 21 +- docs/features/apps/optimer.md | 2 +- docs/features/apps/permissions_tool.md | 2 +- docs/features/apps/srp.md | 2 +- docs/features/apps/timerboard.md | 2 +- docs/features/core/admin_site.md | 7 +- docs/features/core/analytics.md | 2 +- docs/features/core/dashboard.md | 2 +- docs/features/core/groups.md | 15 +- docs/features/core/index.md | 17 +- docs/features/index.md | 15 +- docs/features/services/discord.md | 22 +- docs/features/services/discourse.md | 16 +- docs/features/services/index.md | 30 +- docs/features/services/mumble.md | 47 +- docs/features/services/nameformats.md | 11 +- docs/features/services/openfire.md | 16 +- docs/features/services/permissions.md | 4 +- docs/features/services/phpbb3.md | 16 +- docs/features/services/smf.md | 10 +- docs/features/services/teamspeak3.md | 18 +- docs/features/services/xenforo.md | 2 +- docs/index.md | 21 +- docs/installation/allianceauth.md | 474 ++++++++++-------- docs/installation/apache.md | 14 +- docs/installation/gunicorn.md | 12 +- docs/installation/index.md | 17 +- docs/installation/nginx.md | 12 +- docs/installation/upgrade_python.md | 93 ++-- docs/maintenance/apps.md | 19 +- docs/maintenance/index.md | 13 +- docs/maintenance/troubleshooting.md | 4 +- docs/maintenance/tuning/celery.md | 24 +- docs/maintenance/tuning/gunicorn.md | 2 +- docs/maintenance/tuning/index.md | 13 +- 52 files changed, 615 insertions(+), 589 deletions(-) diff --git a/docs/customizing/index.md b/docs/customizing/index.md index 3ff85913..2fb9de6e 100644 --- a/docs/customizing/index.md +++ b/docs/customizing/index.md @@ -2,7 +2,7 @@ It is possible to customize your **Alliance Auth** instance. -```eval_rst +```{eval-rst} .. warning:: Keep in mind that you may need to update some of your customizations manually after new Auth releases (e.g. when replacing templates). ``` @@ -82,7 +82,7 @@ First you need to create the folder for the template on your server. For AA to p If you have a default installation you can create the folder like this: -```sh +```shell mkdir -p /home/allianceserver/myauth/myauth/templates/allianceauth ``` @@ -90,7 +90,7 @@ mkdir -p /home/allianceserver/myauth/myauth/templates/allianceauth Next you need to download a copy of the original template file we want to change. For that let's move into the above folder and then download the file into the current folder with: -```sh +```shell cd /home/allianceserver/myauth/myauth/templates/allianceauth wget ``` @@ -99,11 +99,11 @@ wget ` tag: -```sh +```shell nano /home/allianceserver/myauth/myauth/templates/allianceauth/side-menu.html ``` -```jinja +```django
  • Google @@ -111,7 +111,7 @@ nano /home/allianceserver/myauth/myauth/templates/allianceauth/side-menu.html
  • ``` -```eval_rst +```{eval-rst} .. hint:: You can find other icons with a matching style on the `Font Awesome site `_ . AA currently uses Font Awesome version 5. You also want to keep the ``fa-fw`` tag to ensure all icons have the same width. ``` diff --git a/docs/development/aa_core/documentation.md b/docs/development/aa_core/documentation.md index 0d443213..a72f6055 100644 --- a/docs/development/aa_core/documentation.md +++ b/docs/development/aa_core/documentation.md @@ -4,13 +4,13 @@ The documentation for Alliance Auth uses [Sphinx](http://www.sphinx-doc.org/) to to specific branches is made (master, primarily), the repository is automatically pulled, docs built and deployed on [readthedocs.org](https://readthedocs.org/). - Documentation was migrated from the GitHub wiki pages and into the repository to allow documentation changes to be included with pull requests. This means that documentation can be guaranteed to be updated when a pull request is accepted rather than hoping documentation is updated afterwards or relying on maintainers to do the work. It also allows for documentation to be maintained at different versions more easily. ## Building Documentation + If you're developing new documentation, its likely you'll want or need to test build it before committing to your branch. To achieve this you can use Sphinx to build the documentation locally as it appears on Read the Docs. @@ -24,15 +24,16 @@ build in the `/docs/_build/` directory. Occasionally you may need to fully rebuild the documents by running `make clean` first, usually when you add or rearrange toctrees. - ## Documentation Format -CommonMark Markdown is the current preferred format, via [recommonmark](https://github.com/rtfd/recommonmark). -reStructuredText is supported if required, or you can execute snippets of reST inside Markdown by using a code block: +CommonMark-plus Markdown is the current preferred format, via [MyST-Parser](https://github.com/executablebooks/MyST-Parser). +reStructuredText is supported if required, or you can execute snippets of MyST inside Markdown by using a code block: - ```eval_rst - reStructuredText here - ``` +````md +```{eval-rst} +reStructuredText here +``` +```` Markdown is used elsewhere on Github so it provides the most portability of documentation from Issues and Pull Requests as well as providing an easier initial migration path from the Github wiki. diff --git a/docs/development/aa_core/index.md b/docs/development/aa_core/index.md index 836a5a15..1c3a2883 100644 --- a/docs/development/aa_core/index.md +++ b/docs/development/aa_core/index.md @@ -2,10 +2,9 @@ This section contains important information on how to develop Alliance Auth itself. -```eval_rst -.. toctree:: - :maxdepth: 1 +```{toctree} +:maxdepth: 1 - documentation - code-style +documentation +code-style ``` diff --git a/docs/development/custom/index.md b/docs/development/custom/index.md index 72882345..46841730 100644 --- a/docs/development/custom/index.md +++ b/docs/development/custom/index.md @@ -2,12 +2,11 @@ This section describes how to extend **Alliance Auth** with custom apps and services. -```eval_rst -.. toctree:: - :maxdepth: 1 +```{toctree} +:maxdepth: 1 - integrating-services - menu-hooks - url-hooks - logging +integrating-services +menu-hooks +url-hooks +logging ``` diff --git a/docs/development/custom/integrating-services.md b/docs/development/custom/integrating-services.md index 3c28d8e4..f829626f 100644 --- a/docs/development/custom/integrating-services.md +++ b/docs/development/custom/integrating-services.md @@ -46,7 +46,7 @@ In order to integrate with Alliance Auth service modules must provide a `service This would register the ExampleService class which would need to be a subclass of `services.hooks.ServiceHook`. -```eval_rst +```{eval-rst} .. important:: The hook **MUST** be registered in ``yourservice.auth_hooks`` along with any other hooks you are registering for Alliance Auth. ``` diff --git a/docs/development/custom/menu-hooks.md b/docs/development/custom/menu-hooks.md index 04efc38a..2284a2ff 100644 --- a/docs/development/custom/menu-hooks.md +++ b/docs/development/custom/menu-hooks.md @@ -40,7 +40,7 @@ A list of views or namespaces the link should be highlighted on. See [django-nav This is a great feature to signal the user, that he has some open issues to take care of within an app. For example Auth uses this feature to show the specific number of open group request to the current user. -```eval_rst +```{eval-rst} .. hint:: Here is how to stay consistent with the Auth design philosophy for using this feature: 1. Use it to display open items that the current user can close by himself only. Do not use it for items, that the user has no control over. diff --git a/docs/development/custom/url-hooks.md b/docs/development/custom/url-hooks.md index 1c43544a..ffe8fdf3 100644 --- a/docs/development/custom/url-hooks.md +++ b/docs/development/custom/url-hooks.md @@ -18,8 +18,7 @@ In addition is it possible to make views public. Normally, all views are automat An app can opt-out of this feature by adding a list of views to be excluded when registering the URLs. See the `excluded_views` parameter for details. -```eval_rst -.. note:: +:::{note} Note that for a public view to work, administrators need to also explicitly allow apps to have public views in their AA installation, by adding the apps label to ``APPS_WITH_PUBLIC_VIEWS`` setting. ``` @@ -59,7 +58,7 @@ When this app is included in the project's `settings.INSTALLED_APPS` users would ## API -```eval_rst +```{eval-rst} .. autoclass:: allianceauth.services.hooks.UrlHook :members: ``` diff --git a/docs/development/dev_setup/aa-dev-setup-wsl-vsc-v2.md b/docs/development/dev_setup/aa-dev-setup-wsl-vsc-v2.md index ab3b8217..14429e9f 100644 --- a/docs/development/dev_setup/aa-dev-setup-wsl-vsc-v2.md +++ b/docs/development/dev_setup/aa-dev-setup-wsl-vsc-v2.md @@ -6,7 +6,7 @@ The main benefit of this setup is that it runs all services and code in the nati In addition all tools described in this guide are open source or free software. -```eval_rst +```{eval-rst} .. hint:: This guide is meant for development purposes only and not for installing AA in a production environment. For production installation please see chapter **Installation**. ``` @@ -25,8 +25,7 @@ The development environment consists of the following components: We will use the build-in Django development web server, so we don't need to setup a WSGI server or a web server. -```eval_rst -.. note:: +:::{note} This setup works with both WSL 1 and WSL 2. However, due to the significantly better performance we recommend WSL 2. ``` @@ -58,13 +57,13 @@ The only requirement is a PC with Windows 10 and Internet connection in order to Open a WSL bash and update all software packets: -```bash +```shell sudo apt update && sudo apt upgrade -y ``` ### Install Tools -```bash +```shell sudo apt-get install build-essential sudo apt-get install gettext ``` @@ -73,13 +72,12 @@ sudo apt-get install gettext Next we need to install Python and related development tools. -```eval_rst +```{eval-rst} .. hint:: To check your system's Python 3 version you can enter: ``python3 --version`` ``` -```eval_rst -.. note:: +:::{note} Should your Ubuntu come with a newer version of Python we recommend to still setup your dev environment with the oldest Python 3 version currently supported by AA (e.g Python 3.8 at this time of writing) to ensure your apps are compatible with all current AA installations You an check out this `page `_ on how to install additional Python versions on Ubuntu. @@ -90,19 +88,19 @@ Next we need to install Python and related development tools. Use the following command to install Python 3 with all required libraries with the default version: -```bash +```shell sudo apt-get install python3 python3-dev python3-venv python3-setuptools python3-pip python-pip ``` ### Install redis and other tools -```bash +```shell sudo apt-get install unzip git redis-server curl libssl-dev libbz2-dev libffi-dev pkg-config ``` Start redis -```bash +```shell sudo redis-server --daemonize yes ``` @@ -110,30 +108,29 @@ sudo redis-server --daemonize yes Install MySQL and required libraries with the following command: -```bash +```shell sudo apt-get install mysql-server mysql-client libmysqlclient-dev ``` -```eval_rst -.. note:: +:::{note} We chose to use MySQL instead of MariaDB, because the standard version of MariaDB that comes with this Ubuntu distribution will not work with AA. ``` We need to apply a permission fix to mysql or you will get a warning with every startup: -```bash +```shell sudo usermod -d /var/lib/mysql/ mysql ``` Start the mysql server -```bash +```shell sudo service mysql start ``` Create database and user for AA -```bash +```shell sudo mysql -u root ``` @@ -147,12 +144,11 @@ exit; Add timezone info to mysql: -```bash +```shell sudo mysql_tzinfo_to_sql /usr/share/zoneinfo | sudo mysql -u root mysql ``` -```eval_rst -.. note:: +:::{note} If your WSL does not have an init.d service, it will not automatically start your services such as MySQL and Redis when you boot your Windows machine and you have to manually start them. For convenience we recommend putting these commands in a bash script. Here is an example: :: @@ -183,7 +179,7 @@ Following this approach you can also setup additional AA projects, e.g. aa-dev-2 Create the root folder `aa-dev`. -```eval_rst +```{eval-rst} .. hint:: The folders `venv` and `myauth` will be created automatically in later steps. Please do not create them manually as this would lead to errors. ``` @@ -192,19 +188,19 @@ Create the root folder `aa-dev`. Create the virtual environment. Run this in your aa-dev folder: -```bash +```shell python3 -m venv venv ``` And activate your venv: -```bash +```shell source venv/bin/activate ``` ### Install and update basic Python packages -```bash +```shell pip install -U pip setuptools wheel ``` @@ -212,19 +208,19 @@ pip install -U pip setuptools wheel ### Install and create AA instance -```bash +```shell pip install allianceauth ``` Now we are ready to setup our AA instance. Make sure to run this command in your aa-dev folder: -```bash +```shell allianceauth start myauth ``` Next we will setup our VSC project for aa-dev by starting it directly from the WSL bash: -```bash +```shell code . ``` @@ -244,7 +240,7 @@ For the Eve Online related setup you need to create a SSO app on the developer s Open your local Django settings with VSC. The file is under `myauth/myauth/settings/local.py` -```eval_rst +```{eval-rst} .. hint:: There are two Django settings files: ``base.py`` and ``local.py``. The base settings file is controlled by the AA project and may change at any time. It is therefore recommended to only change the local settings file. ``` @@ -293,14 +289,14 @@ REGISTRATION_VERIFY_EMAIL = False Before we can start AA we need to run migrations: -```bash +```shell cd myauth python manage.py migrate ``` We also need to create a superuser for our AA installation: -```bash +```shell python manage.py createsuperuser ``` @@ -310,19 +306,18 @@ python manage.py createsuperuser We are now ready to run out AA instance with the following command: -```bash +```shell python manage.py runserver ``` Once running you can access your auth site on the browser under `http://localhost:8000`. Or the admin site under `http://localhost:8000/admin` -```eval_rst +```{eval-rst} .. hint:: You can start your AA server directly from a terminal window in VSC or with a VSC debug config (see chapter about debugging for details). ``` -```eval_rst -.. note:: +:::{note} **Debug vs. Non-Debug mode** Usually it is best to run your dev AA instance in debug mode, so you get all the detailed error messages that helps a lot for finding errors. But there might be cases where you want to test features that do not exist in debug mode (e.g. error pages) or just want to see how your app behaves in non-debug / production mode. @@ -335,7 +330,7 @@ In addition you can start a celery worker instance for myauth. For development p This can be done from the command line with the following command in the myauth folder (where manage.py is located): -```bash +```shell celery -A myauth worker -l info -P solo ``` @@ -499,7 +494,7 @@ Open a WSL bash and navigate to the aa-dev folder. Make sure you have activate y Run these commands: -```bash +```shell git clone https://gitlab.com/ErikKalkoken/allianceauth-example-plugin.git pip install -e allianceauth-example-plugin ``` @@ -508,7 +503,7 @@ Add `'example'` to INSTALLED_APPS in your `local.py` settings. Run migrations and restart your AA server, e.g.: -```bash +```shell cd myauth python manage.py migrate ``` diff --git a/docs/development/dev_setup/index.md b/docs/development/dev_setup/index.md index 0b9be3be..cda0fb7c 100644 --- a/docs/development/dev_setup/index.md +++ b/docs/development/dev_setup/index.md @@ -2,9 +2,8 @@ Here you find guides on how to setup your development environment for AA. -```eval_rst -.. toctree:: - :maxdepth: 1 +```{toctree} +:maxdepth: 1 - aa-dev-setup-wsl-vsc-v2 +aa-dev-setup-wsl-vsc-v2 ``` diff --git a/docs/development/index.md b/docs/development/index.md index 05636730..40ce9551 100644 --- a/docs/development/index.md +++ b/docs/development/index.md @@ -2,12 +2,11 @@ **Alliance Auth** is designed to be extended easily. Learn how to develop your own apps and services for AA or to develop for AA core in the development chapter. -```eval_rst -.. toctree:: - :maxdepth: 1 +```{toctree} +:maxdepth: 1 - custom/index - aa_core/index - dev_setup/index - tech_docu/index +custom/index +aa_core/index +dev_setup/index +tech_docu/index ``` diff --git a/docs/development/tech_docu/api/index.md b/docs/development/tech_docu/api/index.md index 23e3018c..87c6994a 100644 --- a/docs/development/tech_docu/api/index.md +++ b/docs/development/tech_docu/api/index.md @@ -2,16 +2,15 @@ To reduce redundancy and help speed up development we encourage developers to utilize the following packages when developing apps for Alliance Auth. -```eval_rst -.. toctree:: - :maxdepth: 1 +```{toctree} +:maxdepth: 1 - discord_client - discord_service - esi - evelinks - eveonline - notifications - testutils - utils +discord_client +discord_service +esi +evelinks +eveonline +notifications +testutils +utils ``` diff --git a/docs/development/tech_docu/celery.md b/docs/development/tech_docu/celery.md index e406c867..53c4b781 100644 --- a/docs/development/tech_docu/celery.md +++ b/docs/development/tech_docu/celery.md @@ -14,8 +14,7 @@ Alliance Auth is an online web application and as such the user expects fast and As a rule of thumb we therefore recommend to use celery tasks for every process that can take longer than 1 sec to complete (also think about how long your process might take with large amounts of data). -```eval_rst -.. note:: +:::{note} Another solution for dealing with long response time in particular when loading pages is to load parts of a page asynchronously, for example with AJAX. ``` @@ -106,7 +105,7 @@ In this example we fist add 10 example tasks that need to run one after the othe The list of task signatures is then converted to a chain and started asynchronously. -```eval_rst +```{eval-rst} .. hint:: In our example we use ``si()``, which is a shortcut for "immutable signatures" and prevents us from having to deal with result sharing between tasks. @@ -137,7 +136,7 @@ CELERYBEAT_SCHEDULE['structures_update_all_structures'] = { In Alliance Auth we have defined task priorities from 0 - 9 as follows: -```eval_rst +```{eval-rst} ====== ========= =========== Number Priority Description ====== ========= =========== @@ -150,14 +149,14 @@ In Alliance Auth we have defined task priorities from 0 - 9 as follows: ====== ========= =========== ``` -```eval_rst +```{eval-rst} .. warning:: Please make sure to use task priorities with care and especially do not use higher priorities without a good reason. All apps including Alliance Auth share the same task queues, so using higher task priorities excessively can potentially prevent more important tasks (of other apps) from completing on time. You also want to make sure to run use lower priorities if you have a large amount of tasks or long running tasks, which are not super urgent. (e.g. the regular update of all Eve characters from ESI runs with priority 7) ``` -```eval_rst +```{eval-rst} .. hint:: If no priority is specified all tasks will be started with the default priority, which is 5. ``` @@ -170,7 +169,7 @@ Example for starting a task with priority 3: example.apply_async(priority=3) ``` -```eval_rst +```{eval-rst} .. hint:: For defining a priority to tasks you can not use the convenient shortcut ``delay()``, but instead need to start a task with ``apply_async()``, which also requires you to pass parameters to your task function differently. Please check out the `official docs `_ for details. ``` diff --git a/docs/development/tech_docu/index.md b/docs/development/tech_docu/index.md index 578df28d..e544eead 100644 --- a/docs/development/tech_docu/index.md +++ b/docs/development/tech_docu/index.md @@ -2,12 +2,11 @@ In this section you find topics useful for app developers. -```eval_rst -.. toctree:: - :maxdepth: 1 +```{toctree} +:maxdepth: 1 - api/index - celery - core_models - templatetags +api/index +celery +core_models +templatetags ``` diff --git a/docs/features/apps/autogroups.md b/docs/features/apps/autogroups.md index 4dd4ce5a..b6db021b 100644 --- a/docs/features/apps/autogroups.md +++ b/docs/features/apps/autogroups.md @@ -1,7 +1,6 @@ # Auto Groups -```eval_rst -.. note:: +:::{note} New in 2.0 ``` @@ -19,7 +18,7 @@ When you create an autogroup config you will be given the following options: ![Create Autogroup page](/_static/images/features/apps/autogroups/group-creation.png) -```eval_rst +```{eval-rst} .. warning:: After creating a group you wont be able to change the Corp and Alliance group prefixes, name source and the replace spaces settings. Make sure you configure these the way you want before creating the config. If you need to change these you will have to create a new autogroup config. ``` @@ -38,7 +37,7 @@ When you create an autogroup config you will be given the following options: Auto Groups are configured via models in the Admin Interface, a user will require the `Staff` Flag in addition to the following permissions. -```eval_rst +```{eval-rst} +-------------------------------------------+------------------+----------------+ | Permission | Admin Site | Auth Site | +===========================================+==================+================+ diff --git a/docs/features/apps/corpstats.md b/docs/features/apps/corpstats.md index b25f1f3c..215abaeb 100644 --- a/docs/features/apps/corpstats.md +++ b/docs/features/apps/corpstats.md @@ -90,7 +90,7 @@ Characters from all Corp Stats to which the user has view access will be display To use this feature, users will require some of the following: -```eval_rst +```{eval-rst} +---------------------------------------+------------------+----------------------------------------------------+ | Permission | Admin Site | Auth Site | +=======================================+==================+====================================================+ diff --git a/docs/features/apps/fleetactivitytracking.md b/docs/features/apps/fleetactivitytracking.md index f0556105..c7e69810 100644 --- a/docs/features/apps/fleetactivitytracking.md +++ b/docs/features/apps/fleetactivitytracking.md @@ -16,7 +16,7 @@ To administer this feature, users will require some of the following. Users do not require any permissions to interact with FAT Links created. -```eval_rst +```{eval-rst} +---------------------------------------+------------------+--------------------------------------------------------------------------+ | Permission | Admin Site | Auth Site | +=======================================+==================+==========================================================================+ diff --git a/docs/features/apps/hrapplications.md b/docs/features/apps/hrapplications.md index 517803d3..6f01c6ff 100644 --- a/docs/features/apps/hrapplications.md +++ b/docs/features/apps/hrapplications.md @@ -44,7 +44,7 @@ To administer this feature, users will require some of the following. Users do not require any permission to apply to a corporation and fill out the form. -```eval_rst +```{eval-rst} +---------------------------------------+------------------+----------------------------------------------------+ | Permission | Admin Site | Auth Site | +=======================================+==================+====================================================+ diff --git a/docs/features/apps/index.md b/docs/features/apps/index.md index 21f77d4c..084b4efb 100644 --- a/docs/features/apps/index.md +++ b/docs/features/apps/index.md @@ -2,16 +2,15 @@ **Alliance Auth** comes with a set of apps (also called plugin-apps) which provide basic functions useful to many organizations in Eve Online like a fleet schedule and a timerboard. This section describes which apps are available and how to install and use them. Please note that any app need to be installed before it can be used. -```eval_rst -.. toctree:: - :maxdepth: 1 +```{toctree} +:maxdepth: 1 - autogroups - corpstats - fleetactivitytracking - hrapplications - optimer - permissions_tool - srp - timerboard +autogroups +corpstats +fleetactivitytracking +hrapplications +optimer +permissions_tool +srp +timerboard ``` diff --git a/docs/features/apps/optimer.md b/docs/features/apps/optimer.md index d2c7020e..91bbb3e2 100644 --- a/docs/features/apps/optimer.md +++ b/docs/features/apps/optimer.md @@ -12,7 +12,7 @@ Add `'allianceauth.optimer',` to your `INSTALLED_APPS` list in your auth project To use and administer this feature, users will require some of the following. -```eval_rst +```{eval-rst} +---------------------------------------+------------------+--------------------------------------------------------------------------+ | Permission | Admin Site | Auth Site | +=======================================+==================+==========================================================================+ diff --git a/docs/features/apps/permissions_tool.md b/docs/features/apps/permissions_tool.md index b262a5eb..e25a914f 100644 --- a/docs/features/apps/permissions_tool.md +++ b/docs/features/apps/permissions_tool.md @@ -42,7 +42,7 @@ Please note that users may appear multiple times if this permission is granted v To use this feature, users will require some of the following. -```eval_rst +```{eval-rst} +---------------------------------------+------------------+--------------------------------------------------------------------------+ | Permission | Admin Site | Auth Site | +=======================================+==================+==========================================================================+ diff --git a/docs/features/apps/srp.md b/docs/features/apps/srp.md index cf2a8ce7..7663bb04 100644 --- a/docs/features/apps/srp.md +++ b/docs/features/apps/srp.md @@ -12,7 +12,7 @@ Add `'allianceauth.srp',` to your `INSTALLED_APPS` list in your auth project's s To use and administer this feature, users will require some of the following. -```eval_rst +```{eval-rst} +----------------------+------------------+------------------------------------------------------------+ | Permission | Admin Site | Auth Site | +======================+==================+============================================================+ diff --git a/docs/features/apps/timerboard.md b/docs/features/apps/timerboard.md index 24cc1df1..6a134b2c 100644 --- a/docs/features/apps/timerboard.md +++ b/docs/features/apps/timerboard.md @@ -12,7 +12,7 @@ Add `'allianceauth.timerboard',` to your `INSTALLED_APPS` list in your auth proj To use and administer this feature, users will require some of the following. -```eval_rst +```{eval-rst} +---------------------------------------+------------------+--------------------------------------------------------------------------+ | Permission | Admin Site | Auth Site | +=======================================+==================+==========================================================================+ diff --git a/docs/features/core/admin_site.md b/docs/features/core/admin_site.md index 2ab8d1ff..d7adce80 100644 --- a/docs/features/core/admin_site.md +++ b/docs/features/core/admin_site.md @@ -10,7 +10,7 @@ You can open the admin site by clicking on "Admin" in the drop down menu for a u For small to medium size alliances it is often sufficient to have no more then two superuser admins (admins that also are superusers). Having two admins usually makes sense, so you can have one primary and one backup. -```eval_rst +```{eval-rst} .. warning:: Superusers have read & write access to everything on your AA installation. Superusers also automatically have all permissions and therefore access to all features of your apps. Therefore we recommend to be very careful to whom you give superuser privileges. ``` @@ -26,8 +26,7 @@ To create a staff admin you need to do two things: 1. Enable the `is_staff` property for a user 1. Give the user permissions for admin tasks -```eval_rst -.. note:: +:::{note} Note that staff admins have the following limitations: - Can not promote users to staff @@ -42,7 +41,7 @@ To create a staff admin you need to do two things: Access to the admin site is restricted. Users needs to have the `is_staff` property to be able to open the site at all. The superuser that is created during the installation process will automatically have access to the admin site. -```eval_rst +```{eval-rst} .. hint:: Without any permissions a "staff user" can open the admin site, but can neither view nor edit anything except for viewing the list of permissions. ``` diff --git a/docs/features/core/analytics.md b/docs/features/core/analytics.md index 0ee03f8a..78761cdd 100644 --- a/docs/features/core/analytics.md +++ b/docs/features/core/analytics.md @@ -64,7 +64,7 @@ This data is stored in a Team Google Analytics Dashboard. The Maintainers all ha ### Analytics Event -```eval_rst +```{eval-rst} .. automodule:: allianceauth.analytics.tasks :members: analytics_event :undoc-members: diff --git a/docs/features/core/dashboard.md b/docs/features/core/dashboard.md index 57a6d536..037fc547 100644 --- a/docs/features/core/dashboard.md +++ b/docs/features/core/dashboard.md @@ -13,7 +13,7 @@ For admin users the dashboard shows additional technical information about the Here is a list of available settings for the dashboard. They can be configured by adding them to your AA settings file (``local.py``). Note that all settings are optional and the app will use the documented default settings if they are not used. -```eval_rst +```{eval-rst} +-----------------------------------------------------+-------------------------------------------------------------------------+-----------+ | Name | Description | Default | +=====================================================+=========================================================================+===========+ diff --git a/docs/features/core/groups.md b/docs/features/core/groups.md index 2868ca4d..2de54a61 100644 --- a/docs/features/core/groups.md +++ b/docs/features/core/groups.md @@ -42,7 +42,7 @@ Most people won't have a use for public groups, though it can be useful if you w When a group is restricted only superuser admins can directly add or remove them to/from users. The purpose of this property is prevent staff admins from assigning themselves to groups that are security sensitive. The "restricted" property can be combined with all the other properties. -```eval_rst +```{eval-rst} .. _ref-reserved-group-names: ``` @@ -50,8 +50,7 @@ When a group is restricted only superuser admins can directly add or remove them When using Alliance Auth to manage external services like Discord, Auth will automatically duplicate groups on those services. E.g. on Discord Auth will create roles of the same name as groups. However, there may be cases where you want to manage groups on external services by yourself or by another bot. For those cases you can define a list of reserved group names. Auth will ensure that you can not create groups with a reserved name. You will find this list on the admin site under groupmanagement. -```eval_rst -.. note:: +:::{note} While this feature can help to avoid naming conflicts with groups on external services, the respective service component in Alliance Auth also needs to be build in such a way that it knows how to prevent these conflicts. Currently only the Discord and Teamspeak3 services have this ability. ``` @@ -101,8 +100,7 @@ By default, in AA both requests and leaves for non-open groups must be approved GROUPMANAGEMENT_AUTO_LEAVE = True ``` -```eval_rst -.. note:: +:::{note} Before you set `GROUPMANAGEMENT_AUTO_LEAVE = True`, make sure there are no pending leave requests, as this option will hide the "Leave Requests" tab. ``` @@ -111,7 +109,7 @@ GROUPMANAGEMENT_AUTO_LEAVE = True Here is a list of available settings for Group Management. They can be configured by adding them to your AA settings file (``local.py``). Note that all settings are optional and the app will use the documented default settings if they are not used. -```eval_rst +```{eval-rst} +---------------------------------------------+---------------------------------------------------------------------------+------------+ | Name | Description | Default | +=============================================+===========================================================================+============+ @@ -127,14 +125,13 @@ In order to join a group other than a public group, the permission `groupmanagem When a user loses this permission, they will be removed from all groups _except_ Public groups. -```eval_rst -.. note:: +:::{note} By default, the ``groupmanagement.request_groups`` permission is applied to the ``Member`` group. In most instances this, and perhaps adding it to the ``Blue`` group, should be all that is ever needed. It is unsupported and NOT advisable to apply this permission to a public group. See #697 for more information. ``` Group Management should be mostly done using group leaders, a series of permissions are included below for thoroughness: -```eval_rst +```{eval-rst} +--------------------------------+-------------------+------------------------------------------------------------------------------------+ | Permission | Admin Site | Auth Site | +================================+===================+====================================================================================+ diff --git a/docs/features/core/index.md b/docs/features/core/index.md index 02007bd6..06428136 100644 --- a/docs/features/core/index.md +++ b/docs/features/core/index.md @@ -2,14 +2,13 @@ Managing access to applications and services is one of the core functions of **Alliance Auth**. The related key concepts and functionalities are describes in this section. -```eval_rst -.. toctree:: - :maxdepth: 1 +```{toctree} +:maxdepth: 1 - dashboard - states - groups - analytics - notifications - admin_site +dashboard +states +groups +analytics +notifications +admin_site ``` diff --git a/docs/features/index.md b/docs/features/index.md index b2eee634..2fd59d78 100644 --- a/docs/features/index.md +++ b/docs/features/index.md @@ -2,13 +2,12 @@ Learn about the features of **Alliance Auth** and how to install and use them. -```eval_rst -.. toctree:: - :maxdepth: 1 +```{toctree} +:maxdepth: 1 - overview - core/index - services/index - apps/index - community/index +overview +core/index +services/index +apps/index +community/index ``` diff --git a/docs/features/services/discord.md b/docs/features/services/discord.md index 72159c56..0ffed134 100644 --- a/docs/features/services/discord.md +++ b/docs/features/services/discord.md @@ -33,8 +33,7 @@ CELERYBEAT_SCHEDULE['discord.update_all_usernames'] = { } ``` -```eval_rst -.. note:: +:::{note} You will have to add most the values for these settings, e.g. your Discord server ID (aka guild ID), later in the setup process. ``` @@ -48,8 +47,7 @@ Now retrieve the server ID [following this procedure.](https://support.discord.c Update your auth project's settings file, inputting the server ID as `DISCORD_GUILD_ID` -```eval_rst -.. note:: +:::{note} If you already have a Discord server skip the creation step, but be sure to retrieve the server ID ``` @@ -107,12 +105,11 @@ Second, it is possible to exclude Discord roles from being managed by Auth at al To exclude roles from being managed by Auth you only have to add them to the list of reserved group names in Group Management. -```eval_rst -.. note:: +:::{note} Role names on Discord are case sensitive, while reserved group names on Auth are not. Therefore reserved group names will cover all roles regardless of their case. For example if you have reserved the group name "alpha", then the Discord roles "alpha" and "Alpha" will both be persisted. ``` -```eval_rst +```{eval-rst} .. seealso:: For more information see :ref:`ref-reserved-group-names`. ``` @@ -123,11 +120,11 @@ The Discord service contains a number of tasks that can be run to manually perfo You can run any of these tasks from the command line. Please make sure that you are in your venv and then you can run this command from the same folder that your manage.py is located: -```bash +```shell celery -A myauth call discord.update_all_groups ``` -```eval_rst +```{eval-rst} ======================== ==================================================== Name Description ======================== ==================================================== @@ -138,8 +135,7 @@ Name Description ======================== ==================================================== ``` -```eval_rst -.. note:: +:::{note} Depending on how many users you have, running these tasks can take considerable time to finish. You can calculate roughly 1 sec per user for all tasks, except update_all, which needs roughly 3 secs per user. ``` @@ -147,7 +143,7 @@ Name Description You can configure your Discord services with the following settings: -```eval_rst +```{eval-rst} =================================== ============================================================================================= ======= Name Description Default =================================== ============================================================================================= ======= @@ -168,7 +164,7 @@ Name Description To use this service, users will require some of the following. -```eval_rst +```{eval-rst} +---------------------------------------+------------------+--------------------------------------------------------------------------+ | Permission | Admin Site | Auth Site | +=======================================+==================+==========================================================================+ diff --git a/docs/features/services/discourse.md b/docs/features/services/discourse.md index f451282b..e66a112f 100644 --- a/docs/features/services/discourse.md +++ b/docs/features/services/discourse.md @@ -17,7 +17,7 @@ DISCOURSE_SSO_SECRET = '' ## Install Docker -```bash +```shell wget -qO- https://get.docker.io/ | sh ``` @@ -25,14 +25,14 @@ wget -qO- https://get.docker.io/ | sh ### Download Discourse -```bash +```shell mkdir /var/discourse git clone https://github.com/discourse/discourse_docker.git /var/discourse ``` ### Configure -```bash +```shell cd /var/discourse cp samples/standalone.yml containers/app.yml nano containers/app.yml @@ -68,7 +68,7 @@ Or any other port will do, if taken. Remember this number. ### Build and launch -```bash +```shell nano /etc/default/docker ``` @@ -80,13 +80,13 @@ Uncomment this line: Restart Docker: -```bash +```shell service docker restart ``` Now build: -```bash +```shell ./launcher bootstrap app ./launcher start app ``` @@ -124,7 +124,7 @@ server { From the `/var/discourse` directory, -```bash +```shell ./launcher enter app rake admin:create ``` @@ -157,7 +157,7 @@ Finally run migrations and restart Gunicorn and Celery. To use this service, users will require some of the following. -```eval_rst +```{eval-rst} +---------------------------------------+------------------+--------------------------------------------------------------------------+ | Permission | Admin Site | Auth Site | +=======================================+==================+==========================================================================+ diff --git a/docs/features/services/index.md b/docs/features/services/index.md index 3c64f848..af29780d 100644 --- a/docs/features/services/index.md +++ b/docs/features/services/index.md @@ -4,26 +4,24 @@ ## Supported Services -```eval_rst -.. toctree:: - :maxdepth: 1 +```{toctree} +:maxdepth: 1 - discord - discourse - mumble - openfire - phpbb3 - smf - teamspeak3 - xenforo +discord +discourse +mumble +openfire +phpbb3 +smf +teamspeak3 +xenforo ``` ## Tools -```eval_rst -.. toctree:: - :maxdepth: 1 +```{toctree} +:maxdepth: 1 - nameformats - permissions +nameformats +permissions ``` diff --git a/docs/features/services/mumble.md b/docs/features/services/mumble.md index d0c754b7..ffc4c8f7 100644 --- a/docs/features/services/mumble.md +++ b/docs/features/services/mumble.md @@ -2,12 +2,11 @@ Mumble is a free voice chat server. While not as flashy as TeamSpeak, it has all the functionality and is easier to customize. And is better. I may be slightly biased. -```eval_rst -.. note:: +:::{note} Note that this guide assumes that you have installed Auth with the official :doc:`/installation/allianceauth` guide under ``/home/allianceserver`` and that it is called ``myauth``. Accordingly it assumes that you have a service user called ``allianceserver`` that is used to run all Auth services under supervisor. ``` -```eval_rst +```{eval-rst} .. warning:: This guide is currently for Ubuntu only. ``` @@ -18,17 +17,17 @@ Mumble is a free voice chat server. While not as flashy as TeamSpeak, it has all The mumble server package can be retrieved from a repository, which we need to add: -```bash +```shell sudo apt-add-repository ppa:mumble/release ``` -```bash +```shell sudo apt-get update ``` Now three packages need to be installed: -```bash +```shell sudo apt-get install python-software-properties mumble-server libqt5sql5-mysql ``` @@ -36,19 +35,19 @@ sudo apt-get install python-software-properties mumble-server libqt5sql5-mysql Next, we need to download the latest authenticator release from the [authenticator repository](https://gitlab.com/allianceauth/mumble-authenticator). -```bash +```shell git clone https://gitlab.com/allianceauth/mumble-authenticator /home/allianceserver/mumble-authenticator ``` We will now install the authenticator into your Auth virtual environment. Please make sure to activate it first: -```bash +```shell source /home/allianceserver/venv/auth/bin/activate ``` Install the python dependencies for the mumble authenticator. Note that this process can take 2-10 minutes to complete. -```bash +```shell pip install -r requirements.txt ``` @@ -66,7 +65,7 @@ GRANT ALL PRIVILEGES ON alliance_mumble . * TO 'allianceserver'@'localhost'; Mumble ships with a configuration file that needs customization. By default it’s located at `/etc/mumble-server.ini`. Open it with your favorite text editor: -```bash +```shell sudo nano /etc/mumble-server.ini ``` @@ -90,7 +89,7 @@ Save and close the file. To get Mumble superuser account credentials, run the following: -```bash +```shell sudo dpkg-reconfigure mumble-server ``` @@ -98,7 +97,7 @@ Set the password to something you’ll remember and write it down. This is your Now restart the server to see the changes reflected. -```bash +```shell sudo service mumble-server restart ``` @@ -110,7 +109,7 @@ The ICE authenticator lives in the mumble-authenticator repository, cd to the di Make a copy of the default config: -```bash +```shell cp authenticator.ini.example authenticator.ini ``` @@ -124,19 +123,19 @@ Edit `authenticator.ini` and change these values: Test your configuration by starting it: -```bash +```shell python /home/allianceserver/mumble-authenticator/authenticator.py ``` And finally ensure the allianceserver user has read/write permissions to the mumble authenticator files before proceeding: -```bash +```shell sudo chown -R allianceserver:allianceserver /home/allianceserver/mumble-authenticator ``` The authenticator needs to be running 24/7 to validate users on Mumble. This can be achieved by adding a section to your auth project's supervisor config file like the following example: -```text +```ini [program:authenticator] command=/home/allianceserver/venv/auth/bin/python authenticator.py directory=/home/allianceserver/mumble-authenticator @@ -151,7 +150,7 @@ priority=996 In addition we'd recommend to add the authenticator to Auth's restart group in your supervisor conf. For that you need to add it to the group line as shown in the following example: -```text +```ini [group:myauth] programs=beat,worker,gunicorn,authenticator priority=999 @@ -159,7 +158,7 @@ priority=999 To enable the changes in your supervisor configuration you need to restart the supervisor process itself. And before we do that we are shutting down the current Auth supervisors gracefully: -```bash +```shell sudo supervisor stop myauth: sudo systemctl restart supervisor ``` @@ -187,11 +186,11 @@ MUMBLE_URL = "mumble.example.com" Finally, run migrations and restart your supervisor to complete the setup: -```bash +```shell python /home/allianceserver/myauth/manage.py migrate ``` -```bash +```shell supervisorctl restart myauth: ``` @@ -199,7 +198,7 @@ supervisorctl restart myauth: To use this service, users will require some of the following. -```eval_rst +```{eval-rst} +---------------------------------------+------------------+--------------------------------------------------------------------------+ | Permission | Admin Site | Auth Site | +=======================================+==================+==========================================================================+ @@ -262,19 +261,19 @@ If Push to Talk is to your tastes, configure the suggestion as follows With the default configuration your mumble server is public. Meaning that everyone who has the address can at least connect to it and might also be able join all channels that don't have any permissions set (Depending on your ACL configured for the root channel). If you want only registered member being able to join your mumble, you have to set a server password. To do so open your mumble server configuration which is by default located at `/etc/mumble-server.ini`. -```bash +```shell sudo nano /etc/mumble-server.ini ``` Now search for `serverpassword=` and set your password here. If there is no such line, simply add it. -```text +```ini serverpassword=YourSuperSecretServerPassword ``` Save the file and restart your mumble server afterwards. -```bash +```shell sudo service mumble-server restart ``` diff --git a/docs/features/services/nameformats.md b/docs/features/services/nameformats.md index 82f3c95f..549939ae 100644 --- a/docs/features/services/nameformats.md +++ b/docs/features/services/nameformats.md @@ -6,7 +6,7 @@ Each service's username or nickname, depending on which the service supports, ca Currently the following services support custom name formats: -```eval_rst +```{eval-rst} +-------------+-----------+-------------------------------------+ | Service | Used with | Default Formatter | +=============+===========+=====================================+ @@ -30,8 +30,7 @@ Currently the following services support custom name formats: +-------------+-----------+-------------------------------------+ ``` -```eval_rst -.. note:: +:::{note} It's important to note here, before we get into what you can do with a name formatter, that before the generated name is passed off to the service to create an account it will be sanitized to remove characters (the letters and numbers etc.) that the service cannot support. This means that, despite what you configured, the service may display something different. It is up to you to test your formatter and understand how your format may be disrupted by a certain services sanitization function. ``` @@ -59,7 +58,7 @@ A more digestible documentation of string formatting in Python is available on t Some examples of strings you could use: -```eval_rst +```{eval-rst} +------------------------------------------+---------------------------+ | Formatter | Result | +==========================================+===========================+ @@ -71,12 +70,12 @@ Some examples of strings you could use: +------------------------------------------+---------------------------+ ``` -```eval_rst +```{eval-rst} .. important:: For most services, name formats only take effect when a user creates an account. This means if you create or update a name formatter it wont retroactively alter the format of users names. There are some exceptions to this where the service updates nicknames on a periodic basis. Check the service's documentation to see which of these apply. ``` -```eval_rst +```{eval-rst} .. important:: You must only create one formatter per service per state. E.g. don't create two formatters for Mumble for the Member state. In this case one of the formatters will be used and it may not be the formatter you are expecting. ``` diff --git a/docs/features/services/openfire.md b/docs/features/services/openfire.md index 27f10a28..6fb345cd 100644 --- a/docs/features/services/openfire.md +++ b/docs/features/services/openfire.md @@ -25,18 +25,18 @@ Openfire require a Java 8 runtime environment. Ubuntu 1804, 2004, 2204: -```bash +```shell sudo apt-get install openjdk-11-jre ``` Centos 7: -```bash +```shell sudo yum install java-11-openjdk java-11-openjdk-devel ``` Centos Stream 8, Stream 9: -```bash +```shell sudo dnf install java-11-openjdk java-11-openjdk-devel ``` @@ -51,7 +51,7 @@ On your PC, navigate to the [Ignite Realtime downloads section](https://www.igni Retrieve the file location by copying the URL from the “click here” link, depending on your browser you may have a Copy Link or similar option in your right click menu. In the console, ensure you’re in your user’s home directory: -```bash +```shell cd ~ ``` @@ -59,14 +59,14 @@ Download and install the package, replacing the URL with the latest you got from Ubuntu 1804, 2004, 2204: -```bash +```shell wget https://www.igniterealtime.org/downloadServlet?filename=openfire/openfire_4.7.2_all.deb dpkg -i openfire_4.7.2_all.deb ``` Centos 7, Stream 8, Stream 9: -```bash +```shell wget https://www.igniterealtime.org/downloadServlet?filename=openfire/openfire-4.7.2-1.noarch.rpm yum install -y openfire-4.7.2-1.noarch.rpm ``` @@ -74,7 +74,7 @@ yum install -y openfire-4.7.2-1.noarch.rpm Performance is best when working from a SQL database. If you installed MySQL or MariaDB alongside your auth project, go ahead and create a database for Openfire: -```bash +```shell mysql -u root -p create database alliance_jabber; grant all privileges on alliance_jabber . * to 'allianceserver'@'localhost'; @@ -165,7 +165,7 @@ ACL is achieved by assigning groups to each of the three tiers: `Owners`, `Admin To use this service, users will require some of the following. -```eval_rst +```{eval-rst} +---------------------------------------+------------------+--------------------------------------------------------------------------+ | Permission | Admin Site | Auth Site | +=======================================+==================+==========================================================================+ diff --git a/docs/features/services/permissions.md b/docs/features/services/permissions.md index 847bc364..ff4b702c 100644 --- a/docs/features/services/permissions.md +++ b/docs/features/services/permissions.md @@ -6,7 +6,7 @@ In the past, access to services was dictated by a list of settings in `settings. Instead of granting access to services by the previous rigid structure, access to services is now granted by the built in Django permissions system. This means that service access can be more granular, allowing only certain states, certain groups, for instance Corp CEOs, or even individual user access to each enabled service. -```eval_rst +```{eval-rst} .. important:: If you grant access to an individual user, they will have access to that service regardless of whether or not they are a member. ``` @@ -19,7 +19,7 @@ A user can be granted the same permission from multiple sources. e.g. they may h ## Removing access -```eval_rst +```{eval-rst} .. danger:: Access removal is processed immediately after removing a permission from a user or group. If you remove access from a large group, such as Member, it will immediately remove all users from that service. ``` diff --git a/docs/features/services/phpbb3.md b/docs/features/services/phpbb3.md index e244949e..aea7e2f5 100644 --- a/docs/features/services/phpbb3.md +++ b/docs/features/services/phpbb3.md @@ -34,7 +34,7 @@ DATABASES['phpbb3'] = { Create a database to install phpBB3 in. -```bash +```shell mysql -u root -p create database alliance_forum; grant all privileges on alliance_forum . * to 'allianceserver'@'localhost'; @@ -51,19 +51,19 @@ In the console, navigate to your user’s home directory: `cd ~` Now download using wget, replacing the URL with the URL for the package you just retrieved -```bash +```shell wget https://download.phpbb.com/pub/release/3.3/3.3.8/phpBB-3.3.8.zip ``` This needs to be unpackaged. Unzip it, replacing the file name with that of the file you just downloaded -```bash +```shell unzip phpBB-3.3.8.zip ``` Now we need to move this to our web directory. Usually `/var/www/forums`. -```bash +```shell mv phpBB3 /var/www/forums ``` @@ -72,7 +72,7 @@ The web server needs read/write permission to this folder Apache: `chown -R www-data:www-data /var/www/forums` Nginx: `chown -R nginx:nginx /var/www/forums` -```eval_rst +```{eval-rst} .. tip:: Nginx: Some distributions use the ``www-data:www-data`` user:group instead of ``nginx:nginx``. If you run into problems with permissions try it instead. .. @@ -157,7 +157,7 @@ phpBB will then write its own config file. Before users can see the forums, we need to remove the install directory -```bash +```shell rm -rf /var/www/forums/install ``` @@ -171,7 +171,7 @@ You can allow members to overwrite the portrait with a custom image if desired. Users generated via Alliance Auth do not have a default theme set. You will need to set this on the phpbb_users table in SQL -```bash +```shell mysql -u root -p use alliance_forum; alter table phpbb_users change user_style user_style int not null default 1 @@ -187,7 +187,7 @@ Once settings have been configured, run migrations and restart Gunicorn and Cele To use this service, users will require some of the following. -```eval_rst +```{eval-rst} +---------------------------------------+------------------+--------------------------------------------------------------------------+ | Permission | Admin Site | Auth Site | +=======================================+==================+==========================================================================+ diff --git a/docs/features/services/smf.md b/docs/features/services/smf.md index b0d3dffd..f55a3b19 100644 --- a/docs/features/services/smf.md +++ b/docs/features/services/smf.md @@ -36,17 +36,17 @@ Using your browser, you can download the latest version of SMF to your desktop c Download using wget, replacing the URL with the URL for the package you just retrieved -```bash +```shell wget https://download.simplemachines.org/index.php?thanks;filename=smf_2-1-2_install.tar.gz ``` This needs to be unpackaged. Unzip it, replacing the file name with that of the file you just downloaded -```bash +```shell unzip smf_2-1-2_install.zip ``` Now we need to move this to our web directory. Usually `/var/www/forums`. -```bash +```shell mv smf /var/www/forums ```` @@ -55,7 +55,7 @@ The web server needs read/write permission to this folder Apache: `chown -R www-data:www-data /var/www/forums` Nginx: `chown -R nginx:nginx /var/www/forums` -```eval_rst +```{eval-rst} .. tip:: Nginx: Some distributions use the ``www-data:www-data`` user:group instead of ``nginx:nginx``. If you run into problems with permissions try it instead. .. @@ -139,7 +139,7 @@ Once settings are entered, apply migrations and restart Gunicorn and Celery. To use this service, users will require some of the following. -```eval_rst +```{eval-rst} +---------------------------------------+------------------+--------------------------------------------------------------------------+ | Permission | Admin Site | Auth Site | +=======================================+==================+==========================================================================+ diff --git a/docs/features/services/teamspeak3.md b/docs/features/services/teamspeak3.md index 3394d284..fed2b60e 100644 --- a/docs/features/services/teamspeak3.md +++ b/docs/features/services/teamspeak3.md @@ -38,14 +38,14 @@ To install we need a copy of the server. You can find the latest version from th Download the server, replacing the link with the link you got earlier. -``` bash +```bash cd ~ wget https://files.teamspeak-services.com/releases/server/3.13.7/teamspeak3-server_linux_amd64-3.13.7.tar.bz2 ``` Now we need to extract the file. -```bash +```shell tar -xf teamspeak3-server_linux_amd64-3.13.7.tar.bz2 ``` @@ -53,7 +53,7 @@ tar -xf teamspeak3-server_linux_amd64-3.13.7.tar.bz2 TeamSpeak needs its own user. -```bash +```shell adduser --disabled-login teamspeak ``` @@ -61,7 +61,7 @@ adduser --disabled-login teamspeak Now we move the server binary somewhere more accessible and change its ownership to the new user. -```bash +```shell mv teamspeak3-server_linux_amd64 /usr/local/teamspeak chown -R teamspeak:teamspeak /usr/local/teamspeak ``` @@ -70,14 +70,14 @@ chown -R teamspeak:teamspeak /usr/local/teamspeak Now we generate a startup script so TeamSpeak comes up with the server. -```bash +```shell ln -s /usr/local/teamspeak/ts3server_startscript.sh /etc/init.d/teamspeak update-rc.d teamspeak defaults ``` Finally we start the server. -```bash +```shell service teamspeak start ``` @@ -85,7 +85,7 @@ service teamspeak start Set your Teamspeak Serveradmin password to a random string -```bash +```shell ./ts3server_minimal_runscript.sh inifile=ts3server.ini serveradmin_password=pleasegeneratearandomstring ``` @@ -139,7 +139,7 @@ Then, in the top-right corner click, click on `Update TS3 Groups` to start the p Start a django shell with: -```bash +```shell python manage.py shell ``` @@ -180,7 +180,7 @@ This usually occurs if you've created a separate serverquery user to use with au To use and configure this service, users will require some of the following. -```eval_rst +```{eval-rst} +---------------------------------------+------------------+--------------------------------------------------------------------------+ | Permission | Admin Site | Auth Site | +=======================================+==================+==========================================================================+ diff --git a/docs/features/services/xenforo.md b/docs/features/services/xenforo.md index b17f38db..0412e2c2 100644 --- a/docs/features/services/xenforo.md +++ b/docs/features/services/xenforo.md @@ -47,7 +47,7 @@ Once these are entered, run migrations and restart Gunicorn and Celery. To use this service, users will require some of the following. -```eval_rst +```{eval-rst} +---------------------------------------+------------------+--------------------------------------------------------------------------+ | Permission | Admin Site | Auth Site | +=======================================+==================+==========================================================================+ diff --git a/docs/index.md b/docs/index.md index 2ddb046b..f3e9d490 100644 --- a/docs/index.md +++ b/docs/index.md @@ -7,16 +7,15 @@ Welcome to the official documentation for **Alliance Auth**! **Alliance Auth** is a web site that helps Eve Online organizations efficiently manage access to applications and external services. -```eval_rst -.. toctree:: - :maxdepth: 2 - :caption: Contents +```{toctree} +:maxdepth: 2 +:caption: Contents - installation/index - features/index - maintenance/index - support/index - customizing/index - development/index - contributing/index +installation/index +features/index +maintenance/index +support/index +customizing/index +development/index +contributing/index ``` diff --git a/docs/installation/allianceauth.md b/docs/installation/allianceauth.md index 018650a9..81d65b28 100644 --- a/docs/installation/allianceauth.md +++ b/docs/installation/allianceauth.md @@ -2,10 +2,9 @@ This document describes how to install **Alliance Auth** from scratch. -```eval_rst -.. note:: - There are additional installation steps for activating services and apps that come with **Alliance Auth**. Please see the page for the respective service or apps in chapter :doc:`/features/index` for details. -``` +:::{note} +There are additional installation steps for activating services and apps that come with **Alliance Auth**. Please see the page for the respective service or apps in chapter :doc:`/features/index` for details. +::: ## Dependencies @@ -28,234 +27,243 @@ To install on your favorite flavour of Linux, identify and install equivalent pa It is recommended to ensure your OS is fully up to date before proceeding. We may also add Package Repositories here, used later in the documentation. -Ubuntu 1804, 2004, 2204: +::::{tabs} -```bash +:::{group-tab} Ubuntu 2004, 2204 + +```shell sudo apt-get update ``` -```bash +```shell sudo apt-get upgrade ``` -```bash +```shell sudo do-dist-upgrade ``` -CentOS 7: +::: +:::{group-tab} CentOS 7 -```bash +```shell yum install epel-release ``` -```bash +```shell sudo yum upgrade ``` -CentOS Stream 8: +::: +:::{group-tab} CentOS Stream 8 -```bash +```shell sudo dnf config-manager --set-enabled powertools ``` -```bash +```shell sudo dnf install epel-release epel-next-release ``` -```bash +```shell sudo yum upgrade ``` -CentOS Stream 9: +::: +:::{group-tab} CentOS Stream 9 -```bash +```shell sudo dnf config-manager --set-enabled crb ``` -```bash -dnf install epel-release epel-next-release +```shell +sudo dnf install epel-release epel-next-release ``` -```bash +```shell sudo yum upgrade ``` +::: +:::: + ### Python -Install Python 3.10 and related tools on your system. +Install Python 3.11 and related tools on your system. -Ubuntu 1804, 2004: +::::{tabs} -```bash +:::{group-tab} Ubuntu 2004, 2204 + +```shell sudo add-apt-repository ppa:deadsnakes/ppa ``` -```bash +```shell sudo apt-get update ``` -```bash -sudo apt-get install python3.10 python3.10-dev python3.10-venv +```shell +sudo apt-get install python3.11 python3.11-dev python3.11-venv ``` -Ubuntu 2204: - -```eval_rst -.. note:: - Ubuntu 2204 ships with Python 3.10 already, but some important tools are missing in the default installation. -``` - -```bash -sudo apt-get install python3.10-dev python3.10-venv -``` - -CentOS 7: +::: +:::{group-tab} CentOS 7, Stream 8, Stream 9 We need to build Python from source -Centos Stream 8/9: - -```eval_rst -.. note:: - A Python 3.9 Package is available for Stream 8 and 9. You _may_ use this instead of building your own package. But our documentation will assume Python3.10 and you may need to substitute as necessary - sudo dnf install python39 python39-devel -``` - -```bash +```shell cd ~ ``` -```bash +```shell sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget ``` -```bash -wget https://www.python.org/ftp/python/3.10.5/Python-3.10.5.tgz +```shell +wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz ``` -```bash -tar xvf Python-3.10.5.tgz +```shell +tar xvf Python-3.11.5.tgz ``` -```bash -cd Python-3.10.5/ +```shell +cd Python-3.11.5/ ``` -```bash +```shell ./configure --enable-optimizations --enable-shared ``` -```bash +```shell sudo make altinstall ``` +::: +:::: + ### Database -It's recommended to use a database service instead of SQLite. Many options are available, but this guide will use MariaDB. +It's recommended to use a database service instead of SQLite. Many options are available, but this guide will use MariaDB 10.11 -```eval_rst -.. note:: - Ubuntu distributions prior to 20.04 come with an older version of Maria DB, which is not compatible with **Alliance Auth**. You need Maria DB 10.3 or higher! - For 20.04 we still recommend to install Maria DB from the link below in order to get the newest stable version. - For 22.04 we recommend installing from the default Ubuntu distro, since it comes with the newest stable version. -``` +::::{tabs} -Ubuntu 1804, 2004: +:::{group-tab} Ubuntu 2004, 2204 +Follow the instructions at to add the MariaDB repository to your host. -```eval_rst -.. warning:: - Please follow these steps to update MariaDB - https://mariadb.org/download/?t=repo-config&d=20.04+%22focal%22&v=10.6&r_m=osuosl -``` - -Ubuntu 1804, 2004, 2204 - -```bash +```shell sudo apt-get install mariadb-server mariadb-client libmysqlclient-dev ``` -CentOS 7: +::: +:::{group-tab} CentOS 7 +Follow the instructions at to add the MariaDB repository to your host. -```eval_rst -.. warning:: - Please follow these steps to update MariaDB - https://mariadb.org/download/?t=repo-config&d=CentOS+7+%28x86_64%29&v=10.6&r_m=osuosl -``` - -```bash +```shell sudo yum install MariaDB-server MariaDB-client MariaDB-devel MariaDB-shared ``` -CentOS Stream 8/9: +::: +:::{group-tab} CentOS Stream 8 +Follow the instructions at to add the MariaDB repository to your host. -```eval_rst -.. note:: - We recommend using the built in AppStream, as they are maintained by CentOS. Currently an AppStream is not available for 10.6 -``` - -```bash -sudo dnf module enable mariadb:10.5 -``` - -```bash +```shell sudo dnf install mariadb mariadb-server mariadb-devel ``` -```bash -sudo systemctl enable mariadb +::: +:::{group-tab} CentOS Stream 9 +Follow the instructions at to add the MariaDB repository to your host. + +```shell +sudo dnf install mariadb mariadb-server mariadb-devel ``` -```bash -sudo systemctl start mariadb -``` +::: +:::: -```eval_rst -.. important:: - If you don't plan on running the database on the same server as auth you still need to install the ``libmysqlclient-dev`` package on Ubuntu or ``mariadb-devel`` package on CentOS. -``` +:::::{important} +::::{tabs} +:::{group-tab} Ubuntu 2004, 2204 +If you don't plan on running the database on the same server as auth you still need to install the `libmysqlclient-dev` package +::: +:::{group-tab} CentOS 7 +If you don't plan on running the database on the same server as auth you still need to install the `mariadb-devel` package +::: +:::{group-tab} CentOS Stream 8 +If you don't plan on running the database on the same server as auth you still need to install the `mariadb-devel` package +::: +:::{group-tab} CentOS Stream 9 +If you don't plan on running the database on the same server as auth you still need to install the `mariadb-devel` package +::: +:::: +::::: ### Redis and Other Tools A few extra utilities are also required for installation of packages. -Ubuntu 1804, 2004, 2204: +::::{tabs} -```bash +:::{group-tab} Ubuntu 2004, 2204 + +```shell sudo apt-get install unzip git redis-server curl libssl-dev libbz2-dev libffi-dev build-essential pkg-config ``` -CentOS 7: +::: +:::{group-tab} CentOS 7 -```bash +```shell sudo yum install gcc gcc-c++ unzip git redis curl bzip2-devel openssl-devel libffi-devel wget pkg-config ``` -```bash +```shell sudo systemctl enable redis.service ``` -```bash +```shell sudo systemctl start redis.service ``` -CentOS Stream 8, Stream 9: +::: +:::{group-tab} CentOS Stream 8 -```bash +```shell sudo dnf install gcc gcc-c++ unzip git redis curl bzip2-devel openssl-devel libffi-devel wget ``` -```bash +```shell sudo systemctl enable redis.service ``` -```bash +```shell sudo systemctl start redis.service ``` +::: +:::{group-tab} CentOS Stream 9 + +```shell +sudo dnf install gcc gcc-c++ unzip git redis curl bzip2-devel openssl-devel libffi-devel wget +``` + +```shell +sudo systemctl enable redis.service +``` + +```shell +sudo systemctl start redis.service +``` + +::: +:::: + ## Database Setup Alliance Auth needs a MySQL user account and database. Open an SQL shell with -```bash +```shell sudo mysql -u root ``` @@ -271,22 +279,24 @@ Once your database is set up, you can leave the SQL shell with `exit`. Add timezone tables to your mysql installation: -```bash +```shell mysql_tzinfo_to_sql /usr/share/zoneinfo | sudo mysql -u root mysql ``` -```eval_rst -.. note:: - You may see errors when you add the timezone tables. To make sure that they were correctly added run the following commands and check for the ``time_zone`` tables:: +:::{note} +You may see errors when you add the timezone tables. To make sure that they were correctly added run the following commands and check for the ``time_zone`` tables - mysql -u root -p - use mysql; - show tables; +```bash +mysql -u root -p +use mysql; +show tables; ``` +::: + Close the SQL shell and secure your database server with this command: -```bash +```shell mysql_secure_installation ``` @@ -295,86 +305,96 @@ mysql_secure_installation ### User Account For security and permissions, it’s highly recommended you create a separate user to install auth under. Do not log in as this account. +::::{tabs} -Ubuntu 1804, 2004, 2204: +:::{group-tab} Ubuntu 2004, 2204 -```bash -sudo adduser --disabled-login allianceserver -``` - -CentOS 7, Stream 8, Stream 9: - -```bash +```shell sudo useradd -s /bin/bash allianceserver ``` -```bash +::: +:::{group-tab} CentOS 7 + +```shell sudo passwd -l allianceserver ``` +::: +:::{group-tab} CentOS Stream 8 + +```shell +sudo passwd -l allianceserver +``` + +::: +:::{group-tab} CentOS Stream 9 + +```shell +sudo passwd -l allianceserver +``` + +::: +:::: + ### Prepare Directories -```bash +```shell sudo mkdir -p /var/www/myauth/static ``` -```bash +```shell sudo chown -R allianceserver:allianceserver /var/www/myauth/static/ ``` -```eval_rst -.. note:: - When installing and performing maintenance on Alliance Auth, using the allianceserver user will greatly simplify permission management:: +:::{warning} +When installing and performing maintenance on Alliance Auth, virtual environments and python packages, _sudo_ means _superuser_ _do_, this will not use your venv or your allianceserver user and will routinely break your permission structure. - sudo su allianceserver +Only use sudo for _system_ management or if you are unsure, when explicitly instructed to do so. + +```shell +sudo su allianceserver ``` +::: + ### Virtual Environment Switch to the allianceserver user. -```bash +```shell sudo su allianceserver ``` And switch to it's home directory: -```bash -cd -``` - -```eval_rst -.. note:: - In general using the allianceserver user will greatly simplify permission management, when installing and performing maintenance on Alliance Auth. +```shell +cd ~ ``` Create a Python virtual environment and put it somewhere convenient (e.g. `/home/allianceserver/venv/auth/`) -```eval_rst -.. note:: - Your python3.x command/version may vary depending on your installed python version. +:::{note} +Your python3.x command/version may vary depending on your installed python version. +::: + +```shell +python3.11 -m venv /home/allianceserver/venv/auth/ ``` -```bash -python3.10 -m venv /home/allianceserver/venv/auth/ -``` - -```eval_rst -.. tip:: - A virtual environment provides support for creating a lightweight "copy" of Python with their own site directories. Each virtual environment has its own Python binary (allowing creation of environments with various Python versions) and can have its own independent set of installed Python packages in its site directories. You can read more about virtual environments on the Python_ docs. -.. _Python: https://docs.python.org/3/library/venv.html -``` +:::{tip} +A virtual environment provides support for creating a lightweight "copy" of Python with their own site directories. Each virtual environment has its own Python binary (allowing creation of environments with various Python versions) and can have its own independent set of installed Python packages in its site directories. You can read more about virtual environments on the Python_ docs. +::: Activate the virtual environment with (Note the `/bin/activate` on the end of the path): -```bash +```shell source /home/allianceserver/venv/auth/bin/activate ``` -```eval_rst -.. hint:: - Each time you come to do maintenance on your Alliance Auth installation, you should activate your virtual environment first. When finished, deactivate it with the ``deactivate`` command. -``` +:::{hint} +Each time you come to do maintenance on your Alliance Auth installation, you should activate your virtual environment first. When finished, deactivate it with the ``deactivate`` command. +::: ### Eve Online SSO @@ -386,22 +406,21 @@ As **callback URL** you want to define the URL of your Alliance Auth site plus t ### Alliance Auth Project -```eval_rst -.. warning:: - Before installing any Python packages please double-check that you have activated in the virtual environment. This is usually indicated by your command line in the terminal starting with: `(auth)`. -``` +:::{warning} +Before installing any Python packages please double-check that you have activated in the virtual environment. This is usually indicated by your command line in the terminal starting with: `(auth)`. +::: #### Install Python packages Update & install basic tools before installing further Python packages: -```bash +```shell pip install -U pip setuptools wheel ``` You can install **Alliance Auth** with the following command. This will install AA, AA's Python dependencies, superlance for memory monitoring and gunicorn as a wsgi server -```bash +```shell pip install allianceauth superlance gunicorn ``` @@ -409,13 +428,13 @@ pip install allianceauth superlance gunicorn Now you need to create the Django project that will run **Alliance Auth**. Ensure you are in the allianceserver home directory by issuing: -```bash +```shell cd /home/allianceserver ``` The following command bootstraps a Django project which will run your **Alliance Auth** instance. You can rename it from `myauth` to anything you'd like. Note that this name is shown by default as the site name but that can be changed later. -```bash +```shell allianceauth start myauth ``` @@ -423,7 +442,7 @@ allianceauth start myauth Your settings file needs configuring: -```bash +```shell nano myauth/myauth/settings/local.py ``` @@ -439,34 +458,36 @@ nano myauth/myauth/settings/local.py Django needs to setup the database before it can start. -```bash +```shell python /home/allianceserver/myauth/manage.py migrate ``` Now we need to round up all the static files required to render templates. Make a directory to serve them from and populate it. -```bash +```shell python /home/allianceserver/myauth/manage.py collectstatic --noinput ``` Check to ensure your settings are valid. -```bash +```shell python /home/allianceserver/myauth/manage.py check ``` -```eval_rst -.. hint:: - If you are using root, ensure the allianceserver user has read/write permissions to this directory before proceeding:: +:::{hint} +If you are using root, ensure the allianceserver user has read/write permissions to this directory before proceeding:: - chown -R allianceserver:allianceserver /home/allianceserver/myauth ``` +chown -R allianceserver:allianceserver /home/allianceserver/myauth +``` + +::: #### Setup superuser Before using your auth site, it is essential to create a superuser account. This account will have all permissions in Alliance Auth. It's OK to use this as your personal auth account. -```bash +```shell python /home/allianceserver/myauth/manage.py createsuperuser ``` @@ -488,72 +509,117 @@ The default configuration is good enough for most installations. Additional info [Supervisor](http://supervisord.org/) is a process watchdog service: it makes sure other processes are started automatically and kept running. It can be used to automatically start the WSGI server and Celery workers for background tasks. -```eval_rst -.. note:: +:::{note} You will need to exit the allianceserver user back to a user with sudo capabilities to install supervisor:: +```bash exit ``` -Ubuntu 1804, 2004, 2204: +::: -```bash +::::{tabs} + +:::{group-tab} Ubuntu 2004, 2204 + +```shell sudo apt-get install supervisor ``` -CentOS 7: +::: +:::{group-tab} CentOS 7 -```bash +```shell sudo dnf install supervisor ``` -```bash +```shell sudo systemctl enable supervisord.service ``` -```bash +```shell sudo systemctl start supervisord.service ``` -CentOS Stream 8, Stream 9: +::: +:::{group-tab} CentOS Stream 8 -```bash +```shell sudo dnf install supervisor ``` -```bash +```shell sudo systemctl enable supervisord.service ``` -```bash +```shell sudo systemctl start supervisord.service ``` +::: +:::{group-tab} CentOS Stream 9 + +```shell +sudo dnf install supervisor +``` + +```shell +sudo systemctl enable supervisord.service +``` + +```shell +sudo systemctl start supervisord.service +``` + +::: +:::: + Once installed, it needs a configuration file to know which processes to watch. Your Alliance Auth project comes with a ready-to-use template which will ensure the Celery workers, Celery task scheduler and Gunicorn are all running. +::::{tabs} -Ubuntu 1804, 2004: +:::{group-tab} Ubuntu 2004, 2204 -```bash +```shell ln -s /home/allianceserver/myauth/supervisor.conf /etc/supervisor/conf.d/myauth.conf ``` -CentOS: +::: +:::{group-tab} CentOS 7 -```bash +```shell sudo ln -s /home/allianceserver/myauth/supervisor.conf /etc/supervisord.d/myauth.ini ``` +::: +:::{group-tab} CentOS Stream 8 + +```shell +sudo ln -s /home/allianceserver/myauth/supervisor.conf /etc/supervisord.d/myauth.ini +``` + +::: +:::{group-tab} CentOS Stream 9 + +```shell +sudo ln -s /home/allianceserver/myauth/supervisor.conf /etc/supervisord.d/myauth.ini +``` + +::: +:::: + Activate it with `sudo supervisorctl reload`. You can check the status of the processes with `sudo supervisorctl status`. Logs from these processes are available in `/home/allianceserver/myauth/log` named by process. -```eval_rst -.. note:: - Any time the code or your settings change you'll need to restart Gunicorn and Celery. :: +:::{note} +Any time the code or your settings change you'll need to restart Gunicorn and Celery. :: - sudo supervisorctl restart myauth: +```shell +sudo supervisorctl restart myauth: ``` +::: + ## Web server Once installed, decide on whether you're going to use [NGINX](nginx.md) or [Apache](apache.md) and follow the respective guide. @@ -566,42 +632,42 @@ Periodically [new releases](https://gitlab.com/allianceauth/allianceauth/tags) a To update your install, swap to your allianceserver user -```bash +```shell sudo su allianceserver ``` Activate your virtual environment -```bash +```shell source /home/allianceserver/venv/auth/bin/activate ``` and update with: -```bash +```shell pip install -U allianceauth ``` Some releases come with changes to the base settings. Update your project's settings with: -```bash +```shell allianceauth update /home/allianceserver/myauth ``` Some releases come with new or changed models. Update your database to reflect this with: -```bash +```shell python /home/allianceserver/myauth/manage.py migrate ``` Finally, some releases come with new or changed static files. Run the following command to update your static files folder: -```bash +```shell python /home/allianceserver/myauth/manage.py collectstatic --noinput ``` Always restart AA, Celery and Gunicorn after updating: -```bash +```shell supervisorctl restart myauth: ``` diff --git a/docs/installation/apache.md b/docs/installation/apache.md index 79f8c615..36ee6953 100644 --- a/docs/installation/apache.md +++ b/docs/installation/apache.md @@ -9,25 +9,25 @@ If you're using a small VPS to host services with very limited memory, consider ## Installation Ubuntu 1804, 2004: -```bash +```shell apt-get install apache2 ``` CentOS 7: -```bash +```shell yum install httpd ``` Centos Stream 8, Stream 9 -```bash +```shell dnf install httpd ``` CentOS 7, Stream 8, Stream 9 -```bash +```shell systemctl enable httpd ``` -```bash +```shell systemctl start httpd ``` ## Configuration @@ -49,7 +49,7 @@ A virtual host for auth need only proxy requests to your WSGI server (Gunicorn i ### Ubuntu To proxy and modify headers a few mods need to be enabled. -```bash +```shell a2enmod proxy a2enmod proxy_http a2enmod headers @@ -57,7 +57,7 @@ a2enmod headers Create a new config file for auth e.g. `/etc/apache2/sites-available/myauth.conf` and fill out the virtual host configuration. To enable your config use `a2ensite myauth.conf` and then reload apache with `service apache2 reload`. -```eval_rst +```{eval-rst} .. warning:: In some scenarios, the Apache default page is still enabled. To disable it use:: a2dissite 000-default.conf diff --git a/docs/installation/gunicorn.md b/docs/installation/gunicorn.md index 2267945f..a2697164 100644 --- a/docs/installation/gunicorn.md +++ b/docs/installation/gunicorn.md @@ -6,15 +6,13 @@ If you find Apache's `mod_wsgi` to be a headache or want to use NGINX (or some o Check out the full [Gunicorn docs](http://docs.gunicorn.org/en/latest/index.html). -```eval_rst -.. note:: +:::{note} The page contains additional steps on how to setup and configure Gunicorn that are not required for users who decide to stick with the default Gunicorn configuration as described in the main installation guide for AA. ``` ## Setting up Gunicorn -```eval_rst -.. note:: +:::{note} If you're using a virtual environment, activate it now:: sudo su allianceserver source /home/allianceserver/venv/auth/bin/activate @@ -22,7 +20,7 @@ Check out the full [Gunicorn docs](http://docs.gunicorn.org/en/latest/index.html Install Gunicorn using pip -```bash +```shell pip install gunicorn ``` @@ -38,7 +36,7 @@ If you are following this guide, we already use [Supervisor](allianceauth.md#sup You'll want to edit `/etc/supervisor/conf.d/myauth.conf` (or whatever you want to call the config file) -```text +```ini [program:gunicorn] user = allianceserver directory=/home/allianceserver/myauth/ @@ -97,6 +95,6 @@ Any web server capable of proxy passing should be able to sit in front of Gunico In the past when you made changes you restarted the entire Apache server. This is no longer required. When you update or make configuration changes that ask you to restart Apache, instead you can just restart Gunicorn: -```bash +```shell supervisorctl restart myauth:gunicorn ``` diff --git a/docs/installation/index.md b/docs/installation/index.md index f9b43ecb..41e25b2e 100644 --- a/docs/installation/index.md +++ b/docs/installation/index.md @@ -4,14 +4,13 @@ This chapter contains the main installation guides for **Alliance Auth**. In addition to main guide for installation Alliance Auth you also find guides for configuring web servers (Apache, NGINX) and the recommended WSGI server (Gunicorn). -```eval_rst -.. toctree:: - :maxdepth: 1 +```{toctree} +:maxdepth: 1 - allianceauth - nginx - apache - gunicorn - upgrade_python - switch_to_non_root +allianceauth +nginx +apache +gunicorn +upgrade_python +switch_to_non_root ``` diff --git a/docs/installation/nginx.md b/docs/installation/nginx.md index c47af9d1..3c8f5b2a 100644 --- a/docs/installation/nginx.md +++ b/docs/installation/nginx.md @@ -14,7 +14,7 @@ If you're converting from Apache, here are some things to consider. Nginx is lightweight for a reason. It doesn't try to do everything internally and instead concentrates on just being a good HTTP server. This means that, unlike Apache, it won't automatically run PHP scripts via mod_php and doesn't have an internal WSGI server like mod_wsgi. That doesn't mean that it can't, just that it relies on external processes to run these instead. This might be good or bad depending on your outlook. It's good because it allows you to segment your applications, restarting Alliance Auth wont impact your PHP applications. On the other hand it means more config and more management of services. For some people it will be worth it, for others losing the centralised nature of Apache may not be worth it. -```eval_rst +```{eval-rst} +-----------+----------------------------------------+ | Apache | Nginx Replacement | +===========+========================================+ @@ -33,7 +33,7 @@ Install Nginx via your preferred package manager or other method. If you need he Nginx needs to be able to read the folder containing your auth project's static files. `chown -R nginx:nginx /var/www/myauth/static`. -```eval_rst +```{eval-rst} .. tip:: Some specific distros may use ``www-data:www-data`` instead of ``nginx:nginx``, causing static files (images, stylesheets etc) not to appear. You can confirm what user Nginx will run under by checking either its base config file ``/etc/nginx/nginx.conf`` for the "user" setting, or once Nginx has started ``ps aux | grep nginx``. Adjust your chown commands to the correct user if needed. @@ -45,24 +45,24 @@ You will need to have [Gunicorn](gunicorn.md) or some other WSGI server setup fo ## Install Ubuntu 1804, 2004, 2204: -```bash +```shell sudo apt-get install nginx ``` CentOS 7 -```bash +```shell sudo yum install nginx ``` CentOS Stream 8, Stream 9: -```bash +```shell sudo dnf install nginx ``` Create a config file in `/etc/nginx/sites-available` (`/etc/nginx/conf.d` on CentOS) and call it `alliance-auth.conf` or whatever your preferred name is. Create a symbolic link to enable the site (not needed on CentOS): -```bash +```shell ln -s /etc/nginx/sites-available/alliance-auth.conf /etc/nginx/sites-enabled/ ``` diff --git a/docs/installation/upgrade_python.md b/docs/installation/upgrade_python.md index 2853f736..ac0f4f0c 100644 --- a/docs/installation/upgrade_python.md +++ b/docs/installation/upgrade_python.md @@ -4,8 +4,7 @@ This guide describes how to upgrade an existing Alliance Auth (AA) installation This guide shares many similarities with the Alliance Auth install guide, but it is targeted towards existing installs needing to update. -```eval_rst -.. note:: +:::{note} This guide will upgrade the software components only but not change any data or configuration. ``` @@ -16,20 +15,19 @@ To run AA with a newer Python 3 version than your system's default you need to i To install other Python versions than those included with your distribution, you need to add a new installation repository. Then you can install the specific Python 3 to your system. Ubuntu 1804, 2004: -```eval_rst -.. note:: +:::{note} Ubuntu 2204 ships with Python 3.10 already ``` -```bash +```shell sudo add-apt-repository ppa:deadsnakes/ppa ``` -```bash +```shell sudo apt-get update ``` -```bash +```shell sudo apt-get install python3.10 python3.10-dev python3.10-venv ``` @@ -37,37 +35,36 @@ CentOS 7: We need to build Python from source Centos Stream 8/9: -```eval_rst -.. note:: +:::{note} A Python 3.9 Package is available for Stream 8 and 9. You _may_ use this instead of building your own package. But our documentation will assume Python3.10 and you may need to substitute as neccessary sudo dnf install python39 python39-devel ``` -```bash +```shell cd ~ ``` -```bash +```shell sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget ``` -```bash +```shell wget https://www.python.org/ftp/python/3.10.5/Python-3.10.5.tgz ``` -```bash +```shell tar xvf Python-3.10.5.tgz ``` -```bash +```shell cd Python-3.10.5/ ``` -```bash +```shell ./configure --enable-optimizations --enable-shared ``` -```bash +```shell sudo make altinstall ``` ## Preparing your venv @@ -76,8 +73,7 @@ Before updating your venv it is important to make sure that your current install Start by navigating to your main project folder (the one that has `manage.py` in it). If you followed the default installation the path is: `/home/allianceserver/myauth` -```eval_rst -.. note:: +:::{note} If you installed Alliance Auth under the allianceserver user, as reccommended. Remember to switch users for easier permission management:: sudo su allianceserver @@ -85,7 +81,7 @@ Start by navigating to your main project folder (the one that has `manage.py` in Activate your venv: -```bash +```shell source /home/allianceserver/venv/auth/bin/activate ``` @@ -93,23 +89,23 @@ source /home/allianceserver/venv/auth/bin/activate Make sure to upgrade AA to the newest version: -```bash +```shell pip install -U allianceauth ``` Run migrations and collectstatic. -```bash +```shell python manage.py migrate ``` -```bash +```shell python manage.py collectstatic ``` Restart your AA supervisor: -```bash +```shell supervisorctl restart myauth: ``` @@ -119,23 +115,23 @@ You also need to upgrade all additional apps to their newest version that you ha If you unsure which apps you have installed from repos check `INSTALLED_APPS` in your settings. Alternatively run this command to get a list all apps in your venv. -```bash +```shell pip list ``` Repeat as needed for your apps -```bash +```shell pip install -U APP_NAME ``` Make sure to run migrations and collect static files for all upgraded apps. -```bash +```shell python manage.py migrate ``` -```bash +```shell python manage.py collectstatic ``` ### Restart and final check @@ -144,13 +140,13 @@ Do a final restart of your AA supervisors and make sure your installation is sti For a final check that they are no issues - e.g. any outstanding migrations - run this command: -```bash +```shell python manage.py check ``` If you get the following result you are good to go. Otherwise make sure to fix any issues first before proceeding. -```bash +```shell System check identified no issues (0 silenced). ``` @@ -160,7 +156,7 @@ Make sure you are in your venv! First we create a list of all installed packages in your venv. You can use this list later as reference to see what packages should be installed. -```bash +```shell pip freeze > requirements.txt ``` @@ -169,29 +165,28 @@ At this point we recommend creating a list of the additional packages that you n - Community AA apps (e.g. aa-structures) - Additional tools you are using (e.g. flower, django-extensions) -```eval_rst +```{eval-rst} .. hint:: While `requirements.txt` will contain a complete list of your packages, it will also contain many packages that are automatically installed as dependencies and don't need be manually reinstalled. ``` -```eval_rst -.. note:: +:::{note} Some guide on the Internet will suggest to use use the requirements.txt file to recreate a venv. This is indeed possible, but only works if all packages can be installed from PyPI. Since most community apps are installed directly from repos this guide will not follow that approach. ``` Leave the venv and shutdown all AA services: -```bash +```shell deactivate ``` -```bash +```shell supervisorctl stop myauth: ``` Rename and keep your old venv so we have a fallback in case of some unforeseeable issues: -```bash +```shell mv /home/allianceserver/venv/auth /home/allianceserver/venv/auth_old ``` @@ -199,11 +194,11 @@ mv /home/allianceserver/venv/auth /home/allianceserver/venv/auth_old Now let's create our new venv with Python 3.10 and activate it: -```bash +```shell python3.10 -m venv /home/allianceserver/venv/auth ``` -```bash +```shell source /home/allianceserver/venv/auth/bin/activate ``` @@ -213,17 +208,17 @@ Now we need to reinstall all packages into your new venv. ### Install basic packages -```bash +```shell pip install -U pip setuptools wheel ``` ### Installing AA & Gunicorn -```bash +```shell pip install allianceauth ``` -```bash +```shell pip install gunicorn ``` @@ -235,13 +230,13 @@ Use the list of packages you created earlier as a checklist. Alternatively you u To check whether you are missing any apps you can also run the check command: -```bash +```shell python manage.py check ``` Note: In case you forget to install an app you will get this error -```bash +```shell ModuleNotFoundError: No module named 'xyz' ``` @@ -251,7 +246,7 @@ Note that you should not need to run any migrations unless you forgot to upgrade After you have completed installing all packages just start your AA supervisor again. -```bash +```shell supervisorctl start myauth: ``` @@ -263,7 +258,7 @@ In case you run into any major issue you can always switch back to your initial Before you start double-check that you still have your old venv for auth: -```bash +```shell ls /home/allianceserver/venv/auth /home/allianceserver/venv ``` @@ -274,18 +269,18 @@ If the output shows these two folders you should be safe to proceed: Run these commands to remove your current venv and switch back to the old venv for auth: -```bash +```shell supervisorctl stop myauth: ``` -```bash +```shell rm -rf /home/allianceserver/venv/auth ``` -```bash +```shell mv /home/allianceserver/venv/auth_old /home/allianceserver/venv/auth ``` -```bash +```shell supervisorctl start myauth: ``` diff --git a/docs/maintenance/apps.md b/docs/maintenance/apps.md index 59fafcf1..a9ce6101 100644 --- a/docs/maintenance/apps.md +++ b/docs/maintenance/apps.md @@ -13,8 +13,7 @@ Your auth project is just a regular Django project - you can add in [other Djang The following instructions will explain how you can remove an app properly fom your Alliance Auth installation. -```eval_rst -.. note:: +:::{note} We recommend following these instructions to avoid dangling foreign keys or orphaned Python packages on your system, which might cause conflicts with other apps down the road. ``` @@ -27,7 +26,7 @@ First, we want to remove the app related tables from the database. Let's first try the automatic approach by running the following command: -```sh +```shell python manage.py migrate appname zero ``` @@ -39,32 +38,32 @@ If that did not work and you got error messages, you will need to remove the tab First, tell Django that these migrations are no longer in effect (note the additional `--fake`): -```sh +```shell python manage.py migrate appname zero --fake ``` Then, open the mysql tool and connect to your Alliance Auth database: -```sh +```shell sudo mysql -u root use alliance_auth; ``` Next disable foreign key check. This makes it much easier to drop tables in any order. -```sh +```shell SET FOREIGN_KEY_CHECKS=0; ``` Then get a list of all tables. All tables belonging to the app in question will start with `appname_`. -```sh +```shell show tables; ``` Now, drop the tables from the app one by one like so: -```sh +```shell drop table appname_model_1; drop table appname_model_2; ... @@ -72,7 +71,7 @@ drop table appname_model_2; And finally, but very importantly, re-enable foreign key checks again and then exit: -```sh +```shell SET FOREIGN_KEY_CHECKS=1; exit; ``` @@ -85,7 +84,7 @@ Once the tables have been removed, you you can remove the app from Alliance Auth Finally, we want to remove the app's Python package. For that run the following command: -```sh +```shell pip uninstall app-package-name ``` diff --git a/docs/maintenance/index.md b/docs/maintenance/index.md index 7b99b061..8d8b6cf5 100644 --- a/docs/maintenance/index.md +++ b/docs/maintenance/index.md @@ -2,12 +2,11 @@ In the maintenance chapter you find details about where important log files are found, how you can customize your AA installation and how to solve common issues. -```eval_rst -.. toctree:: - :maxdepth: 1 +```{toctree} +:maxdepth: 1 - apps - project - troubleshooting - tuning/index +apps +project +troubleshooting +tuning/index ``` diff --git a/docs/maintenance/troubleshooting.md b/docs/maintenance/troubleshooting.md index c64b10bf..c81ae285 100644 --- a/docs/maintenance/troubleshooting.md +++ b/docs/maintenance/troubleshooting.md @@ -24,7 +24,7 @@ Make sure the background processes are running: `supervisorctl status myauth:`. Stop celery workers with `supervisorctl stop myauth:worker` then clear the queue: -```bash +```shell redis-cli FLUSHALL celery -A myauth worker --purge ``` @@ -49,7 +49,7 @@ Gunicorn needs to have context for its running location, `/home/alllianceserver/ Migrations may about with the following error message: -```bash +```shell Specified key was too long; max key length is 767 bytes ``` diff --git a/docs/maintenance/tuning/celery.md b/docs/maintenance/tuning/celery.md index 8735c177..83159c76 100644 --- a/docs/maintenance/tuning/celery.md +++ b/docs/maintenance/tuning/celery.md @@ -1,6 +1,6 @@ # Celery -```eval_rst +```{eval-rst} .. hint:: Most tunings will require a change to your supervisor configuration in your `supervisor.conf` file. Note that you need to restart the supervisor daemon in order for any changes to take effect. And before restarting the daemon you may want to make sure your supervisors stop gracefully:(Ubuntu): @@ -14,13 +14,13 @@ By default task logging is deactivated. Enabling task logging allows you to monitor what tasks are doing in addition to getting all warnings and error messages. To enable info logging for tasks add the following to the command configuration of your worker in the `supervisor.conf` file: -```text +```ini -l info ``` Full example: -```text +```ini command=/home/allianceserver/venv/auth/bin/celery -A myauth worker -l info ``` @@ -28,7 +28,7 @@ command=/home/allianceserver/venv/auth/bin/celery -A myauth worker -l info Celery workers often have memory leaks and will therefore grow in size over time. While the Alliance Auth team is working hard to ensure Auth is free of memory leaks some may still be cause by bugs in different versions of libraries or community apps. It is therefore good practice to enable features that protect against potential memory leaks. -```eval_rst +```{eval-rst} .. hint:: The 256 MB limit is just an example and should be adjusted to your system configuration. We would suggest to not go below 128MB though, since new workers start with around 80 MB already. Also take into consideration that this value is per worker and that you may have more than one worker running in your system. ``` @@ -42,13 +42,13 @@ This is not a built in feature and requires the 3rd party extension [superlance] To setup install superlance into your venv with: -```bash +```shell pip install superlance ``` You can then add `memmon` to your `supervisor.conf`: -```text +```ini [eventlistener:memmon] command=/home/allianceserver/venv/auth/bin/memmon -p worker=256MB directory=/home/allianceserver/myauth @@ -67,7 +67,7 @@ Celery tasks are designed to run concurrently, so one obvious way to increase ta The easiest way to increate throughput can be achieved by increasing the `numprocs` parameter of the suprvisor process. For example: -```text +```ini [program:worker] ... numprocs=2 @@ -83,14 +83,14 @@ numprocs * concurency = workers increasing this number will require a modification to the memmon settings as each `numproc` worker will get a unique name for example with `numproc=3` -```text +```ini [eventlistener:memmon] ... command=... -p worker_00=256MB -p worker_01=256MB -p worker_02=256MB ... ``` -```eval_rst +```{eval-rst} .. hint:: You will want to experiment with different settings to find the optimal. One way to generate task load and verify your configuration is to run a model update with the following command: @@ -104,11 +104,11 @@ command=... -p worker_00=256MB -p worker_01=256MB -p worker_02=256MB This can be achieved by the setting the concurrency parameter of the celery worker to a higher number. For example: -```text +```ini --concurrency=10 ``` -```eval_rst +```{eval-rst} .. hint:: The optimal number will hugely depend on your individual system configuration and you may want to experiment with different settings to find the optimal. One way to generate task load and verify your configuration is to run a model update with the following command: @@ -118,7 +118,7 @@ This can be achieved by the setting the concurrency parameter of the celery work ``` -```eval_rst +```{eval-rst} .. hint:: The optimal number of concurrent workers will be different for every system and we recommend experimenting with different figures to find the optimal for your system. Note, that the example of 10 threads is conservative and should work even with smaller systems. ``` diff --git a/docs/maintenance/tuning/gunicorn.md b/docs/maintenance/tuning/gunicorn.md index 8cdef965..5c856c34 100644 --- a/docs/maintenance/tuning/gunicorn.md +++ b/docs/maintenance/tuning/gunicorn.md @@ -8,6 +8,6 @@ The number you set this to will depend on your own server environment, how many For example to get 5 workers change the setting `--workers=5` in your `supervisor.conf` file and then reload the supervisor with the following command to activate the change (Ubuntu): -```bash +```shell systemctl restart supervisor ``` diff --git a/docs/maintenance/tuning/index.md b/docs/maintenance/tuning/index.md index 9acf1909..f2a53b53 100644 --- a/docs/maintenance/tuning/index.md +++ b/docs/maintenance/tuning/index.md @@ -2,16 +2,15 @@ The official installation guide will install a stable version of Alliance Auth that will work fine for most cases. However, there are a lot of levels that can be used to optimize a system. For example some installations may we short on RAM and want to reduce the total memory footprint, even though that may reduce system performance. Others are fine with further increasing the memory footprint to get better system performance. -```eval_rst +```{eval-rst} .. warning:: Tuning usually has benefits and costs and should only be performed by experienced Linux administrators who understand the impact of tuning decisions on to their system. ``` -```eval_rst -.. toctree:: - :maxdepth: 1 +```{toctree} +:maxdepth: 1 - gunicorn - celery - redis +gunicorn +celery +redis ``` From 906c589f14b1fa1ad316d98b4fc6d9c66077f0a4 Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Fri, 27 Oct 2023 22:19:28 +1000 Subject: [PATCH 06/23] more automated upgrades --- docs/customizing/index.md | 10 +++---- docs/development/aa_core/index.md | 4 +-- docs/development/custom/index.md | 4 +-- .../custom/integrating-services.md | 5 ++-- docs/development/custom/menu-hooks.md | 6 ++--- .../dev_setup/aa-dev-setup-wsl-vsc-v2.md | 26 +++++++------------ docs/development/dev_setup/index.md | 4 +-- docs/development/index.md | 4 +-- docs/development/tech_docu/api/index.md | 4 +-- docs/development/tech_docu/celery.md | 22 ++++++---------- docs/development/tech_docu/index.md | 4 +-- docs/features/apps/autogroups.md | 6 ++--- docs/features/apps/index.md | 4 +-- docs/features/core/admin_site.md | 11 +++----- docs/features/core/index.md | 4 +-- docs/features/index.md | 4 +-- docs/features/services/index.md | 8 +++--- docs/features/services/mumble.md | 6 ++--- docs/features/services/nameformats.md | 10 +++---- docs/features/services/permissions.md | 10 +++---- docs/features/services/smf.md | 8 +++--- docs/index.md | 4 +-- docs/installation/index.md | 4 +-- docs/installation/nginx.md | 11 ++++---- docs/installation/upgrade_python.md | 8 +++--- docs/maintenance/index.md | 4 +-- docs/maintenance/tuning/celery.md | 25 +++++++----------- docs/maintenance/tuning/index.md | 9 +++---- 28 files changed, 96 insertions(+), 133 deletions(-) diff --git a/docs/customizing/index.md b/docs/customizing/index.md index 2fb9de6e..0fe4be54 100644 --- a/docs/customizing/index.md +++ b/docs/customizing/index.md @@ -2,10 +2,9 @@ It is possible to customize your **Alliance Auth** instance. -```{eval-rst} -.. warning:: +:::{warning} Keep in mind that you may need to update some of your customizations manually after new Auth releases (e.g. when replacing templates). -``` +::: ## Site name @@ -111,10 +110,9 @@ nano /home/allianceserver/myauth/myauth/templates/allianceauth/side-menu.html ``` -```{eval-rst} -.. hint:: +:::{hint} You can find other icons with a matching style on the `Font Awesome site `_ . AA currently uses Font Awesome version 5. You also want to keep the ``fa-fw`` tag to ensure all icons have the same width. -``` +::: ### Step 4 - Restart your AA services diff --git a/docs/development/aa_core/index.md b/docs/development/aa_core/index.md index 1c3a2883..d7c9d67e 100644 --- a/docs/development/aa_core/index.md +++ b/docs/development/aa_core/index.md @@ -2,9 +2,9 @@ This section contains important information on how to develop Alliance Auth itself. -```{toctree} +:::{toctree} :maxdepth: 1 documentation code-style -``` +::: diff --git a/docs/development/custom/index.md b/docs/development/custom/index.md index 46841730..e068f920 100644 --- a/docs/development/custom/index.md +++ b/docs/development/custom/index.md @@ -2,11 +2,11 @@ This section describes how to extend **Alliance Auth** with custom apps and services. -```{toctree} +:::{toctree} :maxdepth: 1 integrating-services menu-hooks url-hooks logging -``` +::: diff --git a/docs/development/custom/integrating-services.md b/docs/development/custom/integrating-services.md index f829626f..39645bac 100644 --- a/docs/development/custom/integrating-services.md +++ b/docs/development/custom/integrating-services.md @@ -46,10 +46,9 @@ In order to integrate with Alliance Auth service modules must provide a `service This would register the ExampleService class which would need to be a subclass of `services.hooks.ServiceHook`. -```{eval-rst} -.. important:: +:::{important} The hook **MUST** be registered in ``yourservice.auth_hooks`` along with any other hooks you are registering for Alliance Auth. -``` +::: A subclassed `ServiceHook` might look like this: diff --git a/docs/development/custom/menu-hooks.md b/docs/development/custom/menu-hooks.md index 2284a2ff..2bae5ebc 100644 --- a/docs/development/custom/menu-hooks.md +++ b/docs/development/custom/menu-hooks.md @@ -40,13 +40,11 @@ A list of views or namespaces the link should be highlighted on. See [django-nav This is a great feature to signal the user, that he has some open issues to take care of within an app. For example Auth uses this feature to show the specific number of open group request to the current user. -```{eval-rst} -.. hint:: +:::{hint} Here is how to stay consistent with the Auth design philosophy for using this feature: 1. Use it to display open items that the current user can close by himself only. Do not use it for items, that the user has no control over. 2. If there are currently no open items, do not show a badge at all. -``` - +::: To use it set count the `render()` function of your subclass in accordance to the current user. Here is an example: ```Python diff --git a/docs/development/dev_setup/aa-dev-setup-wsl-vsc-v2.md b/docs/development/dev_setup/aa-dev-setup-wsl-vsc-v2.md index 14429e9f..0396a6e6 100644 --- a/docs/development/dev_setup/aa-dev-setup-wsl-vsc-v2.md +++ b/docs/development/dev_setup/aa-dev-setup-wsl-vsc-v2.md @@ -6,10 +6,9 @@ The main benefit of this setup is that it runs all services and code in the nati In addition all tools described in this guide are open source or free software. -```{eval-rst} -.. hint:: +:::{hint} This guide is meant for development purposes only and not for installing AA in a production environment. For production installation please see chapter **Installation**. -``` +::: ## Overview @@ -72,10 +71,8 @@ sudo apt-get install gettext Next we need to install Python and related development tools. -```{eval-rst} -.. hint:: - To check your system's Python 3 version you can enter: ``python3 --version`` -``` +:::{hint} +::: :::{note} Should your Ubuntu come with a newer version of Python we recommend to still setup your dev environment with the oldest Python 3 version currently supported by AA (e.g Python 3.8 at this time of writing) to ensure your apps are compatible with all current AA installations @@ -179,10 +176,9 @@ Following this approach you can also setup additional AA projects, e.g. aa-dev-2 Create the root folder `aa-dev`. -```{eval-rst} -.. hint:: +:::{hint} The folders `venv` and `myauth` will be created automatically in later steps. Please do not create them manually as this would lead to errors. -``` +::: ### Setup virtual Python environment for aa-dev @@ -240,10 +236,9 @@ For the Eve Online related setup you need to create a SSO app on the developer s Open your local Django settings with VSC. The file is under `myauth/myauth/settings/local.py` -```{eval-rst} -.. hint:: +:::{hint} There are two Django settings files: ``base.py`` and ``local.py``. The base settings file is controlled by the AA project and may change at any time. It is therefore recommended to only change the local settings file. -``` +::: ```python DEBUG = True @@ -312,10 +307,9 @@ python manage.py runserver Once running you can access your auth site on the browser under `http://localhost:8000`. Or the admin site under `http://localhost:8000/admin` -```{eval-rst} -.. hint:: +:::{hint} You can start your AA server directly from a terminal window in VSC or with a VSC debug config (see chapter about debugging for details). -``` +::: :::{note} **Debug vs. Non-Debug mode** diff --git a/docs/development/dev_setup/index.md b/docs/development/dev_setup/index.md index cda0fb7c..fe8e4090 100644 --- a/docs/development/dev_setup/index.md +++ b/docs/development/dev_setup/index.md @@ -2,8 +2,8 @@ Here you find guides on how to setup your development environment for AA. -```{toctree} +:::{toctree} :maxdepth: 1 aa-dev-setup-wsl-vsc-v2 -``` +::: diff --git a/docs/development/index.md b/docs/development/index.md index 40ce9551..3e8999f9 100644 --- a/docs/development/index.md +++ b/docs/development/index.md @@ -2,11 +2,11 @@ **Alliance Auth** is designed to be extended easily. Learn how to develop your own apps and services for AA or to develop for AA core in the development chapter. -```{toctree} +:::{toctree} :maxdepth: 1 custom/index aa_core/index dev_setup/index tech_docu/index -``` +::: diff --git a/docs/development/tech_docu/api/index.md b/docs/development/tech_docu/api/index.md index 87c6994a..daa45209 100644 --- a/docs/development/tech_docu/api/index.md +++ b/docs/development/tech_docu/api/index.md @@ -2,7 +2,7 @@ To reduce redundancy and help speed up development we encourage developers to utilize the following packages when developing apps for Alliance Auth. -```{toctree} +:::{toctree} :maxdepth: 1 discord_client @@ -13,4 +13,4 @@ eveonline notifications testutils utils -``` +::: diff --git a/docs/development/tech_docu/celery.md b/docs/development/tech_docu/celery.md index 53c4b781..18a2bcd9 100644 --- a/docs/development/tech_docu/celery.md +++ b/docs/development/tech_docu/celery.md @@ -105,14 +105,13 @@ In this example we fist add 10 example tasks that need to run one after the othe The list of task signatures is then converted to a chain and started asynchronously. -```{eval-rst} -.. hint:: +:::{hint} In our example we use ``si()``, which is a shortcut for "immutable signatures" and prevents us from having to deal with result sharing between tasks. For more information on signature and work flows see the official documentation on `Canvas `_. In this context please note that Alliance Auth currently only supports chaining, because all other variants require a so called results back, which Alliance Auth does not have. -``` +::: ## How can I define periodic tasks for my app? @@ -149,18 +148,14 @@ In Alliance Auth we have defined task priorities from 0 - 9 as follows: ====== ========= =========== ``` -```{eval-rst} -.. warning:: +:::{warning} Please make sure to use task priorities with care and especially do not use higher priorities without a good reason. All apps including Alliance Auth share the same task queues, so using higher task priorities excessively can potentially prevent more important tasks (of other apps) from completing on time. You also want to make sure to run use lower priorities if you have a large amount of tasks or long running tasks, which are not super urgent. (e.g. the regular update of all Eve characters from ESI runs with priority 7) -``` - -```{eval-rst} -.. hint:: +::: +:::{hint} If no priority is specified all tasks will be started with the default priority, which is 5. -``` - +::: To run a task with a different priority you need to specify it when starting it. Example for starting a task with priority 3: @@ -169,10 +164,9 @@ Example for starting a task with priority 3: example.apply_async(priority=3) ``` -```{eval-rst} -.. hint:: +:::{hint} For defining a priority to tasks you can not use the convenient shortcut ``delay()``, but instead need to start a task with ``apply_async()``, which also requires you to pass parameters to your task function differently. Please check out the `official docs `_ for details. -``` +::: ## What special features should I be aware of? diff --git a/docs/development/tech_docu/index.md b/docs/development/tech_docu/index.md index e544eead..0cc0b51b 100644 --- a/docs/development/tech_docu/index.md +++ b/docs/development/tech_docu/index.md @@ -2,11 +2,11 @@ In this section you find topics useful for app developers. -```{toctree} +:::{toctree} :maxdepth: 1 api/index celery core_models templatetags -``` +::: diff --git a/docs/features/apps/autogroups.md b/docs/features/apps/autogroups.md index b6db021b..387feaff 100644 --- a/docs/features/apps/autogroups.md +++ b/docs/features/apps/autogroups.md @@ -18,11 +18,9 @@ When you create an autogroup config you will be given the following options: ![Create Autogroup page](/_static/images/features/apps/autogroups/group-creation.png) -```{eval-rst} -.. warning:: +:::{warning} After creating a group you wont be able to change the Corp and Alliance group prefixes, name source and the replace spaces settings. Make sure you configure these the way you want before creating the config. If you need to change these you will have to create a new autogroup config. -``` - +::: - States selects which states will be added to automatic Corp/Alliance groups - Corp/Alliance groups checkbox toggles Corp/Alliance autogroups on or off for this config. diff --git a/docs/features/apps/index.md b/docs/features/apps/index.md index 084b4efb..63b04f63 100644 --- a/docs/features/apps/index.md +++ b/docs/features/apps/index.md @@ -2,7 +2,7 @@ **Alliance Auth** comes with a set of apps (also called plugin-apps) which provide basic functions useful to many organizations in Eve Online like a fleet schedule and a timerboard. This section describes which apps are available and how to install and use them. Please note that any app need to be installed before it can be used. -```{toctree} +:::{toctree} :maxdepth: 1 autogroups @@ -13,4 +13,4 @@ optimer permissions_tool srp timerboard -``` +::: diff --git a/docs/features/core/admin_site.md b/docs/features/core/admin_site.md index d7adce80..f28ef28f 100644 --- a/docs/features/core/admin_site.md +++ b/docs/features/core/admin_site.md @@ -10,11 +10,9 @@ You can open the admin site by clicking on "Admin" in the drop down menu for a u For small to medium size alliances it is often sufficient to have no more then two superuser admins (admins that also are superusers). Having two admins usually makes sense, so you can have one primary and one backup. -```{eval-rst} -.. warning:: +:::{warning} Superusers have read & write access to everything on your AA installation. Superusers also automatically have all permissions and therefore access to all features of your apps. Therefore we recommend to be very careful to whom you give superuser privileges. -``` - +::: ## Setup for large installations For large alliances and coalitions you may want to have a couple of administrators to be able to distribute and handle the work load. However, having a larger number of superusers may be a security concern. @@ -41,10 +39,9 @@ To create a staff admin you need to do two things: Access to the admin site is restricted. Users needs to have the `is_staff` property to be able to open the site at all. The superuser that is created during the installation process will automatically have access to the admin site. -```{eval-rst} -.. hint:: +:::{hint} Without any permissions a "staff user" can open the admin site, but can neither view nor edit anything except for viewing the list of permissions. -``` +::: ### Permissions for common admin tasks diff --git a/docs/features/core/index.md b/docs/features/core/index.md index 06428136..92b10a84 100644 --- a/docs/features/core/index.md +++ b/docs/features/core/index.md @@ -2,7 +2,7 @@ Managing access to applications and services is one of the core functions of **Alliance Auth**. The related key concepts and functionalities are describes in this section. -```{toctree} +:::{toctree} :maxdepth: 1 dashboard @@ -11,4 +11,4 @@ groups analytics notifications admin_site -``` +::: diff --git a/docs/features/index.md b/docs/features/index.md index 2fd59d78..2f96c4b2 100644 --- a/docs/features/index.md +++ b/docs/features/index.md @@ -2,7 +2,7 @@ Learn about the features of **Alliance Auth** and how to install and use them. -```{toctree} +:::{toctree} :maxdepth: 1 overview @@ -10,4 +10,4 @@ core/index services/index apps/index community/index -``` +::: diff --git a/docs/features/services/index.md b/docs/features/services/index.md index af29780d..bef4d8a2 100644 --- a/docs/features/services/index.md +++ b/docs/features/services/index.md @@ -4,7 +4,7 @@ ## Supported Services -```{toctree} +:::{toctree} :maxdepth: 1 discord @@ -15,13 +15,13 @@ phpbb3 smf teamspeak3 xenforo -``` +::: ## Tools -```{toctree} +:::{toctree} :maxdepth: 1 nameformats permissions -``` +::: diff --git a/docs/features/services/mumble.md b/docs/features/services/mumble.md index ffc4c8f7..d38503f4 100644 --- a/docs/features/services/mumble.md +++ b/docs/features/services/mumble.md @@ -6,11 +6,9 @@ Mumble is a free voice chat server. While not as flashy as TeamSpeak, it has all Note that this guide assumes that you have installed Auth with the official :doc:`/installation/allianceauth` guide under ``/home/allianceserver`` and that it is called ``myauth``. Accordingly it assumes that you have a service user called ``allianceserver`` that is used to run all Auth services under supervisor. ``` -```{eval-rst} -.. warning:: +:::{warning} This guide is currently for Ubuntu only. -``` - +::: ## Installations ### Installing Mumble Server diff --git a/docs/features/services/nameformats.md b/docs/features/services/nameformats.md index 549939ae..e995b8e2 100644 --- a/docs/features/services/nameformats.md +++ b/docs/features/services/nameformats.md @@ -70,12 +70,10 @@ Some examples of strings you could use: +------------------------------------------+---------------------------+ ``` -```{eval-rst} -.. important:: +:::{important} For most services, name formats only take effect when a user creates an account. This means if you create or update a name formatter it wont retroactively alter the format of users names. There are some exceptions to this where the service updates nicknames on a periodic basis. Check the service's documentation to see which of these apply. -``` +::: -```{eval-rst} -.. important:: +:::{important} You must only create one formatter per service per state. E.g. don't create two formatters for Mumble for the Member state. In this case one of the formatters will be used and it may not be the formatter you are expecting. -``` +::: diff --git a/docs/features/services/permissions.md b/docs/features/services/permissions.md index ff4b702c..c4ad73e7 100644 --- a/docs/features/services/permissions.md +++ b/docs/features/services/permissions.md @@ -6,10 +6,9 @@ In the past, access to services was dictated by a list of settings in `settings. Instead of granting access to services by the previous rigid structure, access to services is now granted by the built in Django permissions system. This means that service access can be more granular, allowing only certain states, certain groups, for instance Corp CEOs, or even individual user access to each enabled service. -```{eval-rst} -.. important:: +:::{important} If you grant access to an individual user, they will have access to that service regardless of whether or not they are a member. -``` +::: Each service has an access permission defined, named like `Can access the service`. @@ -19,10 +18,9 @@ A user can be granted the same permission from multiple sources. e.g. they may h ## Removing access -```{eval-rst} -.. danger:: +:::{danger} Access removal is processed immediately after removing a permission from a user or group. If you remove access from a large group, such as Member, it will immediately remove all users from that service. -``` +::: When you remove a service permission from a user, a signal is triggered which will activate an immediate permission check. For users this will trigger an access check for all services. For groups, due to the potential extra load, only the services whose permissions have changed will be verified, and only the users in that group. diff --git a/docs/features/services/smf.md b/docs/features/services/smf.md index f55a3b19..1999dc80 100644 --- a/docs/features/services/smf.md +++ b/docs/features/services/smf.md @@ -48,18 +48,18 @@ unzip smf_2-1-2_install.zip Now we need to move this to our web directory. Usually `/var/www/forums`. ```shell mv smf /var/www/forums -```` +``` The web server needs read/write permission to this folder Apache: `chown -R www-data:www-data /var/www/forums` Nginx: `chown -R nginx:nginx /var/www/forums` -```{eval-rst} -.. tip:: +:::{tip} + Nginx: Some distributions use the ``www-data:www-data`` user:group instead of ``nginx:nginx``. If you run into problems with permissions try it instead. .. -``` +::: ### Database Preparation diff --git a/docs/index.md b/docs/index.md index f3e9d490..6a0d6b2b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -7,7 +7,7 @@ Welcome to the official documentation for **Alliance Auth**! **Alliance Auth** is a web site that helps Eve Online organizations efficiently manage access to applications and external services. -```{toctree} +:::{toctree} :maxdepth: 2 :caption: Contents @@ -18,4 +18,4 @@ support/index customizing/index development/index contributing/index -``` +::: diff --git a/docs/installation/index.md b/docs/installation/index.md index 41e25b2e..d52391b0 100644 --- a/docs/installation/index.md +++ b/docs/installation/index.md @@ -4,7 +4,7 @@ This chapter contains the main installation guides for **Alliance Auth**. In addition to main guide for installation Alliance Auth you also find guides for configuring web servers (Apache, NGINX) and the recommended WSGI server (Gunicorn). -```{toctree} +:::{toctree} :maxdepth: 1 allianceauth @@ -13,4 +13,4 @@ apache gunicorn upgrade_python switch_to_non_root -``` +::: diff --git a/docs/installation/nginx.md b/docs/installation/nginx.md index 3c8f5b2a..ee31c250 100644 --- a/docs/installation/nginx.md +++ b/docs/installation/nginx.md @@ -33,12 +33,11 @@ Install Nginx via your preferred package manager or other method. If you need he Nginx needs to be able to read the folder containing your auth project's static files. `chown -R nginx:nginx /var/www/myauth/static`. -```{eval-rst} -.. tip:: - Some specific distros may use ``www-data:www-data`` instead of ``nginx:nginx``, causing static files (images, stylesheets etc) not to appear. You can confirm what user Nginx will run under by checking either its base config file ``/etc/nginx/nginx.conf`` for the "user" setting, or once Nginx has started ``ps aux | grep nginx``. - Adjust your chown commands to the correct user if needed. -.. -``` +:::{tip} + +Some specific distros may use ``www-data:www-data`` instead of ``nginx:nginx``, causing static files (images, stylesheets etc) not to appear. You can confirm what user Nginx will run under by checking either its base config file ``/etc/nginx/nginx.conf`` for the "user" setting, or once Nginx has started ``ps aux | grep nginx``. +Adjust your chown commands to the correct user if needed. +::: You will need to have [Gunicorn](gunicorn.md) or some other WSGI server setup for hosting Alliance Auth. diff --git a/docs/installation/upgrade_python.md b/docs/installation/upgrade_python.md index ac0f4f0c..919d80f6 100644 --- a/docs/installation/upgrade_python.md +++ b/docs/installation/upgrade_python.md @@ -165,14 +165,12 @@ At this point we recommend creating a list of the additional packages that you n - Community AA apps (e.g. aa-structures) - Additional tools you are using (e.g. flower, django-extensions) -```{eval-rst} -.. hint:: +:::{hint} While `requirements.txt` will contain a complete list of your packages, it will also contain many packages that are automatically installed as dependencies and don't need be manually reinstalled. -``` - +::: :::{note} Some guide on the Internet will suggest to use use the requirements.txt file to recreate a venv. This is indeed possible, but only works if all packages can be installed from PyPI. Since most community apps are installed directly from repos this guide will not follow that approach. -``` +::: Leave the venv and shutdown all AA services: diff --git a/docs/maintenance/index.md b/docs/maintenance/index.md index 8d8b6cf5..1e44b218 100644 --- a/docs/maintenance/index.md +++ b/docs/maintenance/index.md @@ -2,11 +2,11 @@ In the maintenance chapter you find details about where important log files are found, how you can customize your AA installation and how to solve common issues. -```{toctree} +:::{toctree} :maxdepth: 1 apps project troubleshooting tuning/index -``` +::: diff --git a/docs/maintenance/tuning/celery.md b/docs/maintenance/tuning/celery.md index 83159c76..759e163f 100644 --- a/docs/maintenance/tuning/celery.md +++ b/docs/maintenance/tuning/celery.md @@ -1,14 +1,13 @@ # Celery -```{eval-rst} -.. hint:: +:::{hint} Most tunings will require a change to your supervisor configuration in your `supervisor.conf` file. Note that you need to restart the supervisor daemon in order for any changes to take effect. And before restarting the daemon you may want to make sure your supervisors stop gracefully:(Ubuntu): :: supervisor stop myauth: systemctl supervisor restart -``` +::: ## Task Logging @@ -28,10 +27,9 @@ command=/home/allianceserver/venv/auth/bin/celery -A myauth worker -l info Celery workers often have memory leaks and will therefore grow in size over time. While the Alliance Auth team is working hard to ensure Auth is free of memory leaks some may still be cause by bugs in different versions of libraries or community apps. It is therefore good practice to enable features that protect against potential memory leaks. -```{eval-rst} -.. hint:: +:::{hint} The 256 MB limit is just an example and should be adjusted to your system configuration. We would suggest to not go below 128MB though, since new workers start with around 80 MB already. Also take into consideration that this value is per worker and that you may have more than one worker running in your system. -``` +::: ### Supervisor @@ -90,15 +88,14 @@ command=... -p worker_00=256MB -p worker_01=256MB -p worker_02=256MB ... ``` -```{eval-rst} -.. hint:: +:::{hint} You will want to experiment with different settings to find the optimal. One way to generate task load and verify your configuration is to run a model update with the following command: :: celery -A myauth call allianceauth.eveonline.tasks.run_model_update -``` +::: ### Concurrency @@ -108,17 +105,15 @@ This can be achieved by the setting the concurrency parameter of the celery work --concurrency=10 ``` -```{eval-rst} -.. hint:: +:::{hint} The optimal number will hugely depend on your individual system configuration and you may want to experiment with different settings to find the optimal. One way to generate task load and verify your configuration is to run a model update with the following command: :: celery -A myauth call allianceauth.eveonline.tasks.run_model_update -``` +::: -```{eval-rst} -.. hint:: +:::{hint} The optimal number of concurrent workers will be different for every system and we recommend experimenting with different figures to find the optimal for your system. Note, that the example of 10 threads is conservative and should work even with smaller systems. -``` +::: diff --git a/docs/maintenance/tuning/index.md b/docs/maintenance/tuning/index.md index f2a53b53..7b0d2fb8 100644 --- a/docs/maintenance/tuning/index.md +++ b/docs/maintenance/tuning/index.md @@ -2,15 +2,14 @@ The official installation guide will install a stable version of Alliance Auth that will work fine for most cases. However, there are a lot of levels that can be used to optimize a system. For example some installations may we short on RAM and want to reduce the total memory footprint, even though that may reduce system performance. Others are fine with further increasing the memory footprint to get better system performance. -```{eval-rst} -.. warning:: +:::{warning} Tuning usually has benefits and costs and should only be performed by experienced Linux administrators who understand the impact of tuning decisions on to their system. -``` +::: -```{toctree} +:::{toctree} :maxdepth: 1 gunicorn celery redis -``` +::: From a0719e4b86289943d5264c13deabf1dc7e5a2ab8 Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Fri, 27 Oct 2023 22:20:11 +1000 Subject: [PATCH 07/23] tabify --- docs/installation/apache.md | 89 +++++++++++++++++++++++++++++++------ 1 file changed, 75 insertions(+), 14 deletions(-) diff --git a/docs/installation/apache.md b/docs/installation/apache.md index 36ee6953..d94503c3 100644 --- a/docs/installation/apache.md +++ b/docs/installation/apache.md @@ -8,21 +8,41 @@ If you're using a small VPS to host services with very limited memory, consider ## Installation +::::{tabs} + +:::{group-tab} Ubuntu 2004, 2204 + +::: +:::{group-tab} CentOS 7 + +::: +:::{group-tab} CentOS Stream 8 + +::: +:::{group-tab} CentOS Stream 9 + +::: +:::: Ubuntu 1804, 2004: + ```shell apt-get install apache2 ``` CentOS 7: + ```shell yum install httpd ``` + Centos Stream 8, Stream 9 + ```shell dnf install httpd ``` CentOS 7, Stream 8, Stream 9 + ```shell systemctl enable httpd ``` @@ -30,25 +50,54 @@ systemctl enable httpd ```shell systemctl start httpd ``` + ## Configuration +### Permissions + Apache needs to be able to read the folder containing your auth project's static files. -Ubuntu 1804, 2004: -``` + +::::{tabs} +:::{group-tab} Ubuntu 2004, 2204 + +```shell chown -R www-data:www-data /var/www/myauth/static ``` -CentOS 7, Stream 8, Stream 9 -``` + +::: +:::{group-tab} CentOS 7 + +```shell chown -R apache:apache /var/www/myauth/static ``` +::: +:::{group-tab} CentOS Stream 8 + +```shell +chown -R apache:apache /var/www/myauth/static +``` + +::: +:::{group-tab} CentOS Stream 9 + +```shell +chown -R apache:apache /var/www/myauth/static +``` + +::: +:::: + +### Further Configuration + Apache serves sites through defined virtual hosts. These are located in `/etc/apache2/sites-available/` on Ubuntu and `/etc/httpd/conf.d/httpd.conf` on CentOS. A virtual host for auth need only proxy requests to your WSGI server (Gunicorn if you followed the install guide) and serve static files. Examples can be found below. Create your config in its own file e.g. `myauth.conf` -### Ubuntu - +::::{tabs} +:::{group-tab} Ubuntu 2004, 2204 To proxy and modify headers a few mods need to be enabled. + ```shell a2enmod proxy a2enmod proxy_http @@ -56,20 +105,32 @@ a2enmod headers ``` Create a new config file for auth e.g. `/etc/apache2/sites-available/myauth.conf` and fill out the virtual host configuration. To enable your config use `a2ensite myauth.conf` and then reload apache with `service apache2 reload`. +::: +:::{group-tab} CentOS 7 +Place your virtual host configuration in the appropriate section within `/etc/httpd/conf.d/httpd.conf` and restart the httpd service with `systemctl restart httpd`. +::: +:::{group-tab} CentOS Stream 8 +Place your virtual host configuration in the appropriate section within `/etc/httpd/conf.d/httpd.conf` and restart the httpd service with `systemctl restart httpd`. +::: +:::{group-tab} CentOS Stream 9 +Place your virtual host configuration in the appropriate section within `/etc/httpd/conf.d/httpd.conf` and restart the httpd service with `systemctl restart httpd`. +::: +:::: -```{eval-rst} -.. warning:: - In some scenarios, the Apache default page is still enabled. To disable it use:: - a2dissite 000-default.conf +:::{warning} +In some scenarios, the Apache default page is still enabled. To disable it use + +```shell +a2dissite 000-default.conf ``` +::: + ### CentOS -Place your virtual host configuration in the appropriate section within `/etc/httpd/conf.d/httpd.conf` and restart the httpd service with `systemctl restart httpd`. - ## Sample Config File -``` +```conf ServerName auth.example.com @@ -107,7 +168,7 @@ It's 2018 - there's no reason to run a site without SSL. The EFF provides free, After acquiring SSL the config file needs to be adjusted. Add the following lines inside the `` block: -``` +```conf RequestHeader set X-FORWARDED-PROTOCOL https RequestHeader set X-FORWARDED-SSL On ``` From 7024552c4e71b2f6b748adf2112e610b615d9ef0 Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Fri, 27 Oct 2023 22:20:27 +1000 Subject: [PATCH 08/23] remove ubuntu 1804 --- docs/installation/allianceauth.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/installation/allianceauth.md b/docs/installation/allianceauth.md index 81d65b28..e672f356 100644 --- a/docs/installation/allianceauth.md +++ b/docs/installation/allianceauth.md @@ -14,7 +14,6 @@ Alliance Auth can be installed on any in-support *nix operating system. Our install documentation targets the following operating systems. -- Ubuntu 18.04 - Ubuntu 20.04 - Ubuntu 22.04 - Centos 7 From 98e91fe207c406197aa9bc2cd1c24cee656af98e Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Tue, 31 Oct 2023 23:31:41 +1000 Subject: [PATCH 09/23] MyST conversion --- .../custom/integrating-services.md | 136 ++++++++++-------- docs/development/custom/logging.md | 11 ++ docs/development/custom/menu-hooks.md | 13 +- docs/development/custom/url-hooks.md | 4 +- .../dev_setup/aa-dev-setup-wsl-vsc-v2.md | 59 ++++---- docs/development/tech_docu/celery.md | 34 ++--- docs/features/apps/autogroups.md | 11 +- docs/features/apps/fleetactivitytracking.md | 3 +- docs/features/core/admin_site.md | 18 +-- docs/features/core/groups.md | 11 +- docs/features/services/discord.md | 19 +-- docs/features/services/mumble.md | 13 +- docs/features/services/nameformats.md | 9 +- docs/features/services/openfire.md | 51 +++++-- docs/features/services/permissions.md | 4 +- docs/features/services/smf.md | 23 +-- docs/features/services/teamspeak3.md | 2 +- docs/installation/allianceauth.md | 62 +------- docs/installation/apache.md | 4 +- docs/installation/gunicorn.md | 14 +- docs/installation/nginx.md | 32 +++-- docs/installation/upgrade_python.md | 108 +++++++------- docs/maintenance/apps.md | 5 +- docs/maintenance/tuning/celery.md | 32 ++--- docs/maintenance/tuning/redis.md | 2 +- 25 files changed, 348 insertions(+), 332 deletions(-) diff --git a/docs/development/custom/integrating-services.md b/docs/development/custom/integrating-services.md index 39645bac..29ad0832 100644 --- a/docs/development/custom/integrating-services.md +++ b/docs/development/custom/integrating-services.md @@ -20,19 +20,21 @@ Typically a service will contain 5 key components: The architecture looks something like this: - urls -------▶ Views - ▲ | - | | - | ▼ - ServiceHook ----▶ Tasks ----▶ Manager - ▲ - | - | - AllianceAuth +```none + urls -------▶ Views + ▲ | + | | + | ▼ + ServiceHook ----▶ Tasks ----▶ Manager + ▲ + | + | + AllianceAuth - Where: - Module --▶ Dependency/Import + Where: + Module --▶ Dependency/Import +``` While this is the typical structure of the existing services modules, there is no enforcement of this structure and you are, effectively, free to create whatever architecture may be necessary. A service module need not even communicate with an external service, for example, if similar triggers such as validate_user, delete_user are required for a module it may be convenient to masquerade as a service. Ideally though, using the common structure improves the maintainability for other developers. @@ -40,27 +42,31 @@ While this is the typical structure of the existing services modules, there is n In order to integrate with Alliance Auth service modules must provide a `services_hook`. This hook will be a function that returns an instance of the `services.hooks.ServiceHook` class and decorated with the `@hooks.registerhook` decorator. For example: - @hooks.register('services_hook') - def register_service(): - return ExampleService() +```python +@hooks.register('services_hook') +def register_service(): + return ExampleService() +``` This would register the ExampleService class which would need to be a subclass of `services.hooks.ServiceHook`. :::{important} - The hook **MUST** be registered in ``yourservice.auth_hooks`` along with any other hooks you are registering for Alliance Auth. +The hook **MUST** be registered in ``yourservice.auth_hooks`` along with any other hooks you are registering for Alliance Auth. ::: A subclassed `ServiceHook` might look like this: - class ExampleService(ServicesHook): - def __init__(self): - ServicesHook.__init__(self) - self.urlpatterns = urlpatterns - self.service_url = 'http://exampleservice.example.com' +```python +class ExampleService(ServicesHook): + def __init__(self): + ServicesHook.__init__(self) + self.urlpatterns = urlpatterns + self.service_url = 'http://exampleservice.example.com' - """ - Overload base methods here to implement functionality - """ + """ + Overload base methods here to implement functionality + """ +``` ### The ServiceHook class @@ -70,9 +76,9 @@ You will need to subclass `services.hooks.ServiceHook` in order to provide imple Instance Variables: -- [self.name](#self-name) -- [self.urlpatterns](#self-url-patterns) -- [self.service_ctrl_template](#self-service-ctrl-template) +- [self.name](#selfname) +- [self.urlpatterns](#selfurlpatterns) +- [self.service_ctrl_template](#selfservice_ctrl_template) Properties: @@ -87,8 +93,6 @@ Functions: - [update_groups](#update_groups) - [update_groups_bulk](#update_groups_bulk) - [update_all_groups](#update_all_groups) -- [service_enabled_members](#service_enabled_members) -- [service_enabled_blues](#service_enabled_blues) - [service_active_for_user](#service_active_for_user) - [show_service_ctrl](#show_service_ctrl) - [render_service_ctrl](#render_service_ctrl) @@ -101,18 +105,20 @@ Internal name of the module, should be unique amongst modules. You should define all of your service URLs internally, usually in `urls.py`. Then you can import them and set `self.urlpatterns` to your defined urlpatterns. - from . import urls - ... - class MyService(ServiceHook): - def __init__(self): - ... - self.urlpatterns = urls.urlpatterns +```python +from . import urls +... +class MyService(ServiceHook): + def __init__(self): + ... + self.urlpatterns = urls.urlpatterns +``` All of your apps defined urlpatterns will then be included in the `URLconf` when the core application starts. #### self.service_ctrl_template -This is provided as a courtesy and defines the default template to be used with [render_service_ctrl](#render-service-ctrl). You are free to redefine or not use this variable at all. +This is provided as a courtesy and defines the default template to be used with [render_service_ctrl](#render_service_ctrl). You are free to redefine or not use this variable at all. #### title @@ -134,10 +140,12 @@ Validate the users service account, deleting it if they should no longer have ac An implementation will probably look like the following: - def validate_user(self, user): - logger.debug('Validating user %s %s account' % (user, self.name)) - if ExampleTasks.has_account(user) and not self.service_active_for_user(user): - self.delete_user(user, notify_user=True) +```python +def validate_user(self, user): +logger.debug('Validating user %s %s account' % (user, self.name)) +if ExampleTasks.has_account(user) and not self.service_active_for_user(user): + self.delete_user(user, notify_user=True) +``` No return value is expected. @@ -206,37 +214,39 @@ Should the service be shown for the given `user` with the given `state`? The `us Usually you wont need to override this function. -For more information see the [render_service_ctrl](#render-service-ctrl) section. +For more information see the [render_service_ctrl](#render_service_ctrl) section. #### render_service_ctrl `def render_services_ctrl(self, request):` -Render the services control row. This will be called for all active services when a user visits the `/services/` page and [show_service_ctrl](#show-service-ctrl) returns `True` for the given user. +Render the services control row. This will be called for all active services when a user visits the `/services/` page and [show_service_ctrl](#show_service_ctrl) returns `True` for the given user. It should return a string (usually from `render_to_string`) of a table row (``) with 4 columns (``). Column #1 is the service name, column #2 is the users username for this service, column #3 is the services URL, and column #4 is the action buttons. You may either define your own service template or use the default one provided. The default can be used like this example: - def render_services_ctrl(self, request): - """ - Example for rendering the service control panel row - You can override the default template and create a - custom one if you wish. - :param request: - :return: - """ - urls = self.Urls() - urls.auth_activate = 'auth_example_activate' - urls.auth_deactivate = 'auth_example_deactivate' - urls.auth_reset_password = 'auth_example_reset_password' - urls.auth_set_password = 'auth_example_set_password' - return render_to_string(self.service_ctrl_template, { - 'service_name': self.title, - 'urls': urls, - 'service_url': self.service_url, - 'username': 'example username' - }, request=request) +```python +def render_services_ctrl(self, request): + """ + Example for rendering the service control panel row + You can override the default template and create a + custom one if you wish. + :param request: + :return: + """ + urls = self.Urls() + urls.auth_activate = 'auth_example_activate' + urls.auth_deactivate = 'auth_example_deactivate' + urls.auth_reset_password = 'auth_example_reset_password' + urls.auth_set_password = 'auth_example_set_password' + return render_to_string(self.service_ctrl_template, { + 'service_name': self.title, + 'urls': urls, + 'service_url': self.service_url, + 'username': 'example username' + }, request=request) +``` the `Urls` class defines the available URL names for the 4 actions available in the default template: @@ -293,3 +303,9 @@ You should have a look through some of the other service modules before you get ## Testing You will need to add unit tests for all aspects of your service module before it is accepted. Be mindful that you don't actually want to make external calls to the service so you should mock the appropriate components to prevent this behavior. + +```{eval-rst} +.. autoclass:: allianceauth.services.hooks.ServicesHook + :members: + :undoc-members: +``` diff --git a/docs/development/custom/logging.md b/docs/development/custom/logging.md index bd6d8a81..b2526c17 100644 --- a/docs/development/custom/logging.md +++ b/docs/development/custom/logging.md @@ -1,7 +1,9 @@ # Logging from Custom Apps + Alliance Auth provides a logger for use with custom apps to make everyone's life a little easier. ## Using the Extensions Logger + AllianceAuth provides a helper function to get the logger for the current module to reduce the amount of code you need to write. @@ -15,19 +17,28 @@ This works by creating a child logger of the extension logger which propagates a to the parent (extensions) logger. ## Changing the Logging Level + By default, the extension logger's level is set to `DEBUG`. To change this, uncomment (or add) the following line in `local.py`. ```python LOGGING['handlers']['extension_file']['level'] = 'INFO' ``` + *(Remember to restart your supervisor workers after changes to `local.py`)* This will change the logger's level to the level you define. Options are: *(all options accept entries of levels listed below them)* + * `DEBUG` * `INFO` * `WARNING` * `ERROR` * `CRITICAL` + +```{eval-rst} +.. automodule:: allianceauth.services.hooks.get_extension_logger + :members: + :undoc-members: +``` diff --git a/docs/development/custom/menu-hooks.md b/docs/development/custom/menu-hooks.md index 2bae5ebc..08515888 100644 --- a/docs/development/custom/menu-hooks.md +++ b/docs/development/custom/menu-hooks.md @@ -4,10 +4,10 @@ The menu hooks allow you to dynamically specify menu items from your plugin app To register a MenuItemHook class you would do the following: -```Python +```python @hooks.register('menu_item_hook') def register_menu(): - return MenuItemHook('Example Item', 'glyphicon glyphicon-heart', 'example_url_name',150) + return MenuItemHook('Example Item', 'fas fa-users fa-fw', 'example_url_name',150) ``` The `MenuItemHook` class specifies some parameters/instance variables required for menu item display. @@ -41,13 +41,14 @@ A list of views or namespaces the link should be highlighted on. See [django-nav This is a great feature to signal the user, that he has some open issues to take care of within an app. For example Auth uses this feature to show the specific number of open group request to the current user. :::{hint} - Here is how to stay consistent with the Auth design philosophy for using this feature: - 1. Use it to display open items that the current user can close by himself only. Do not use it for items, that the user has no control over. - 2. If there are currently no open items, do not show a badge at all. +Here is how to stay consistent with the Auth design philosophy for using this feature: + +1. Use it to display open items that the current user can close by himself only. Do not use it for items, that the user has no control over. +2. If there are currently no open items, do not show a badge at all. ::: To use it set count the `render()` function of your subclass in accordance to the current user. Here is an example: -```Python +```python def render(self, request): # ... self.count = calculate_count_for_user(request.user) diff --git a/docs/development/custom/url-hooks.md b/docs/development/custom/url-hooks.md index ffe8fdf3..907f0c73 100644 --- a/docs/development/custom/url-hooks.md +++ b/docs/development/custom/url-hooks.md @@ -19,8 +19,8 @@ In addition is it possible to make views public. Normally, all views are automat An app can opt-out of this feature by adding a list of views to be excluded when registering the URLs. See the `excluded_views` parameter for details. :::{note} - Note that for a public view to work, administrators need to also explicitly allow apps to have public views in their AA installation, by adding the apps label to ``APPS_WITH_PUBLIC_VIEWS`` setting. -``` +Note that for a public view to work, administrators need to also explicitly allow apps to have public views in their AA installation, by adding the apps label to ``APPS_WITH_PUBLIC_VIEWS`` setting. +::: ## Examples diff --git a/docs/development/dev_setup/aa-dev-setup-wsl-vsc-v2.md b/docs/development/dev_setup/aa-dev-setup-wsl-vsc-v2.md index 0396a6e6..c5f91a73 100644 --- a/docs/development/dev_setup/aa-dev-setup-wsl-vsc-v2.md +++ b/docs/development/dev_setup/aa-dev-setup-wsl-vsc-v2.md @@ -7,7 +7,7 @@ The main benefit of this setup is that it runs all services and code in the nati In addition all tools described in this guide are open source or free software. :::{hint} - This guide is meant for development purposes only and not for installing AA in a production environment. For production installation please see chapter **Installation**. +This guide is meant for development purposes only and not for installing AA in a production environment. For production installation please see chapter **Installation**. ::: ## Overview @@ -25,8 +25,8 @@ The development environment consists of the following components: We will use the build-in Django development web server, so we don't need to setup a WSGI server or a web server. :::{note} - This setup works with both WSL 1 and WSL 2. However, due to the significantly better performance we recommend WSL 2. -``` +This setup works with both WSL 1 and WSL 2. However, due to the significantly better performance we recommend WSL 2. +::: ## Requirement @@ -37,19 +37,14 @@ The only requirement is a PC with Windows 10 and Internet connection in order to ### Windows Subsystem for Linux - Install from here: [Microsoft docs](https://docs.microsoft.com/en-us/windows/wsl/install-win10) - - Choose Ubuntu 18.04. LTS or higher ### Visual Studio Code - Install from here: [VSC Download](https://code.visualstudio.com/Download) - - Open the app and install the following VSC extensions: - - Remote WSL - - Connect to WSL. This will automatically install the VSC server on the VSC server for WSL - - Once connected to WSL install the Python extension on the WSL side ## Setting up WSL / Linux @@ -71,18 +66,18 @@ sudo apt-get install gettext Next we need to install Python and related development tools. -:::{hint} -::: - :::{note} - Should your Ubuntu come with a newer version of Python we recommend to still setup your dev environment with the oldest Python 3 version currently supported by AA (e.g Python 3.8 at this time of writing) to ensure your apps are compatible with all current AA installations - You an check out this `page `_ on how to install additional Python versions on Ubuntu. +Should your Ubuntu come with a newer version of Python we recommend to still setup your dev environment with the oldest Python 3 version currently supported by AA (e.g Python 3.8 at this time of writing) to ensure your apps are compatible with all current AA installations +You an check out this `page `_ on how to install additional Python versions on Ubuntu. - If you install a different python version from the default you need to adjust some of the commands below to install appopriate versions of those packages for example using Python 3.8 you might need to run the following after using the setup steps for the repository mentioned in the AskUbuntu post above: +If you install a different python version from the default you need to adjust some of the commands below to install appopriate versions of those packages for example using Python 3.8 you might need to run the following after using the setup steps for the repository mentioned in the AskUbuntu post above: - `sudo apt-get install python3.8 python3.8-dev python3.8-venv python3-setuptools python3-pip python-pip` +```shell +sudo apt-get install python3.8 python3.8-dev python3.8-venv python3-setuptools python3-pip python-pip ``` +::: + Use the following command to install Python 3 with all required libraries with the default version: ```shell @@ -110,8 +105,8 @@ sudo apt-get install mysql-server mysql-client libmysqlclient-dev ``` :::{note} - We chose to use MySQL instead of MariaDB, because the standard version of MariaDB that comes with this Ubuntu distribution will not work with AA. -``` +We chose to use MySQL instead of MariaDB, because the standard version of MariaDB that comes with this Ubuntu distribution will not work with AA. +::: We need to apply a permission fix to mysql or you will get a warning with every startup: @@ -146,17 +141,17 @@ sudo mysql_tzinfo_to_sql /usr/share/zoneinfo | sudo mysql -u root mysql ``` :::{note} - If your WSL does not have an init.d service, it will not automatically start your services such as MySQL and Redis when you boot your Windows machine and you have to manually start them. For convenience we recommend putting these commands in a bash script. Here is an example: - - :: - - #/bin/bash - # start services for AA dev - sudo service mysql start - sudo redis-server --daemonize yes +If your WSL does not have an init.d service, it will not automatically start your services such as MySQL and Redis when you boot your Windows machine and you have to manually start them. For convenience we recommend putting these commands in a bash script. Here is an example: +```shell +#/bin/bash +# start services for AA dev +sudo service mysql start +sudo redis-server --daemonize yes ``` +::: + ### Setup dev folder on WSL Setup your folders on WSL bash for your dev project. Our approach will setup one AA project with one venv and multiple apps running under the same AA project, but each in their own folder and git. @@ -177,7 +172,7 @@ Following this approach you can also setup additional AA projects, e.g. aa-dev-2 Create the root folder `aa-dev`. :::{hint} - The folders `venv` and `myauth` will be created automatically in later steps. Please do not create them manually as this would lead to errors. +The folders `venv` and `myauth` will be created automatically in later steps. Please do not create them manually as this would lead to errors. ::: ### Setup virtual Python environment for aa-dev @@ -237,7 +232,7 @@ For the Eve Online related setup you need to create a SSO app on the developer s Open your local Django settings with VSC. The file is under `myauth/myauth/settings/local.py` :::{hint} - There are two Django settings files: ``base.py`` and ``local.py``. The base settings file is controlled by the AA project and may change at any time. It is therefore recommended to only change the local settings file. +There are two Django settings files: ``base.py`` and ``local.py``. The base settings file is controlled by the AA project and may change at any time. It is therefore recommended to only change the local settings file. ::: ```python @@ -308,15 +303,15 @@ python manage.py runserver Once running you can access your auth site on the browser under `http://localhost:8000`. Or the admin site under `http://localhost:8000/admin` :::{hint} - You can start your AA server directly from a terminal window in VSC or with a VSC debug config (see chapter about debugging for details). +You can start your AA server directly from a terminal window in VSC or with a VSC debug config (see chapter about debugging for details). ::: :::{note} - **Debug vs. Non-Debug mode** - Usually it is best to run your dev AA instance in debug mode, so you get all the detailed error messages that helps a lot for finding errors. But there might be cases where you want to test features that do not exist in debug mode (e.g. error pages) or just want to see how your app behaves in non-debug / production mode. +**Debug vs. Non-Debug mode** +Usually it is best to run your dev AA instance in debug mode, so you get all the detailed error messages that helps a lot for finding errors. But there might be cases where you want to test features that do not exist in debug mode (e.g. error pages) or just want to see how your app behaves in non-debug / production mode. - When you turn off debug mode you will see a problem though: Your pages will not render correctly. The reason is that Django will stop serving your static files in production mode and expect you to serve them from a real web server. Luckily, there is an option that forces Django to continue serving your static files directly even when not in debug mode. Just start your server with the following option: ``python manage.py runserver --insecure`` -``` +When you turn off debug mode you will see a problem though: Your pages will not render correctly. The reason is that Django will stop serving your static files in production mode and expect you to serve them from a real web server. Luckily, there is an option that forces Django to continue serving your static files directly even when not in debug mode. Just start your server with the following option: ``python manage.py runserver --insecure`` +::: ### Celery diff --git a/docs/development/tech_docu/celery.md b/docs/development/tech_docu/celery.md index 18a2bcd9..42b27cc2 100644 --- a/docs/development/tech_docu/celery.md +++ b/docs/development/tech_docu/celery.md @@ -15,8 +15,8 @@ Alliance Auth is an online web application and as such the user expects fast and As a rule of thumb we therefore recommend to use celery tasks for every process that can take longer than 1 sec to complete (also think about how long your process might take with large amounts of data). :::{note} - Another solution for dealing with long response time in particular when loading pages is to load parts of a page asynchronously, for example with AJAX. -``` +Another solution for dealing with long response time in particular when loading pages is to load parts of a page asynchronously, for example with AJAX. +::: ### Recurrence @@ -39,7 +39,7 @@ Please use the following approach to ensure your tasks are working properly with Here is an example implementation of a task: -```Python +```python import logging from celery import shared_task @@ -53,7 +53,7 @@ def example(): This task can then be started from any another Python module like so: -```Python +```python from .tasks import example example.delay() @@ -79,7 +79,7 @@ However, many long running tasks consist of several smaller processes that need Example implementation for a celery chain: -```Python +```python import logging from celery import shared_task, chain @@ -106,11 +106,11 @@ In this example we fist add 10 example tasks that need to run one after the othe The list of task signatures is then converted to a chain and started asynchronously. :::{hint} - In our example we use ``si()``, which is a shortcut for "immutable signatures" and prevents us from having to deal with result sharing between tasks. +In our example we use ``si()``, which is a shortcut for "immutable signatures" and prevents us from having to deal with result sharing between tasks. - For more information on signature and work flows see the official documentation on `Canvas `_. +For more information on signature and work flows see the official documentation on `Canvas `_. - In this context please note that Alliance Auth currently only supports chaining, because all other variants require a so called results back, which Alliance Auth does not have. +In this context please note that Alliance Auth currently only supports chaining, because all other variants require a so called results back, which Alliance Auth does not have. ::: ## How can I define periodic tasks for my app? @@ -119,7 +119,7 @@ Periodic tasks are normal celery tasks which are added the scheduler for periodi Example setting: -```Python +```python CELERYBEAT_SCHEDULE['structures_update_all_structures'] = { 'task': 'structures.tasks.update_all_structures', 'schedule': crontab(minute='*/30'), @@ -149,23 +149,23 @@ In Alliance Auth we have defined task priorities from 0 - 9 as follows: ``` :::{warning} - Please make sure to use task priorities with care and especially do not use higher priorities without a good reason. All apps including Alliance Auth share the same task queues, so using higher task priorities excessively can potentially prevent more important tasks (of other apps) from completing on time. +Please make sure to use task priorities with care and especially do not use higher priorities without a good reason. All apps including Alliance Auth share the same task queues, so using higher task priorities excessively can potentially prevent more important tasks (of other apps) from completing on time. - You also want to make sure to run use lower priorities if you have a large amount of tasks or long running tasks, which are not super urgent. (e.g. the regular update of all Eve characters from ESI runs with priority 7) +You also want to make sure to run use lower priorities if you have a large amount of tasks or long running tasks, which are not super urgent. (e.g. the regular update of all Eve characters from ESI runs with priority 7) ::: :::{hint} - If no priority is specified all tasks will be started with the default priority, which is 5. +If no priority is specified all tasks will be started with the default priority, which is 5. ::: To run a task with a different priority you need to specify it when starting it. Example for starting a task with priority 3: -```Python +```python example.apply_async(priority=3) ``` :::{hint} - For defining a priority to tasks you can not use the convenient shortcut ``delay()``, but instead need to start a task with ``apply_async()``, which also requires you to pass parameters to your task function differently. Please check out the `official docs `_ for details. +For defining a priority to tasks you can not use the convenient shortcut ``delay()``, but instead need to start a task with ``apply_async()``, which also requires you to pass parameters to your task function differently. Please check out the `official docs `_ for details. ::: ## What special features should I be aware of? @@ -179,18 +179,18 @@ Celery-once is a celery extension "that allows you to prevent multiple execution We use a custom backend for celery_once in Alliance Auth defined [here](https://gitlab.com/allianceauth/allianceauth/-/blob/master/allianceauth/services/tasks.py#L14) You can import it for use like so: -```Python +```python from allianceauth.services.tasks import QueueOnce ``` An example of AllianceAuth's use within the `@sharedtask` decorator, can be seen [here](https://gitlab.com/allianceauth/allianceauth/-/blob/master/allianceauth/services/modules/discord/tasks.py#L62) in the discord module You can use it like so: -```Python +```python @shared_task(bind=True, name='your_modules.update_task', base=QueueOnce) ``` -Please see the [official documentation](hhttps://pypi.org/project/celery_once/) of celery-once for details. +Please see the [official documentation](https://pypi.org/project/celery_once/) of celery-once for details. ### task priorities diff --git a/docs/features/apps/autogroups.md b/docs/features/apps/autogroups.md index 387feaff..5bcb335f 100644 --- a/docs/features/apps/autogroups.md +++ b/docs/features/apps/autogroups.md @@ -1,9 +1,5 @@ # Auto Groups -:::{note} - New in 2.0 -``` - Auto groups allows you to automatically place users of certain states into Corp or Alliance based groups. These groups are created when the first user is added to them and removed when the configuration is deleted. ## Installation @@ -19,16 +15,13 @@ When you create an autogroup config you will be given the following options: ![Create Autogroup page](/_static/images/features/apps/autogroups/group-creation.png) :::{warning} - After creating a group you wont be able to change the Corp and Alliance group prefixes, name source and the replace spaces settings. Make sure you configure these the way you want before creating the config. If you need to change these you will have to create a new autogroup config. +After creating a group you wont be able to change the Corp and Alliance group prefixes, name source and the replace spaces settings. Make sure you configure these the way you want before creating the config. If you need to change these you will have to create a new autogroup config. ::: + - States selects which states will be added to automatic Corp/Alliance groups - - Corp/Alliance groups checkbox toggles Corp/Alliance autogroups on or off for this config. - - Corp/Alliance group prefix sets the prefix for the group name, e.g. if your Corp was called `MyCorp` and your prefix was `Corp`, your autogroup name would be created as `Corp MyCorp`. This field accepts leading/trailing spaces. - - Corp/Alliance name source sets the source of the Corp/Alliance name used in creating the group name. Currently the options are Full name and Ticker. - - Replace spaces allows you to replace spaces in the autogroup name with the value in the Replace spaces with field. This can be blank. ## Permissions diff --git a/docs/features/apps/fleetactivitytracking.md b/docs/features/apps/fleetactivitytracking.md index c7e69810..d34c3794 100644 --- a/docs/features/apps/fleetactivitytracking.md +++ b/docs/features/apps/fleetactivitytracking.md @@ -22,7 +22,6 @@ Users do not require any permissions to interact with FAT Links created. +=======================================+==================+==========================================================================+ | auth.fleetactivitytracking | None | Create and Modify FATLinks | +---------------------------------------+------------------+--------------------------------------------------------------------------+ -| auth.fleetactivitytracking_statistics | None | Can view detailed statistics for corp models and other characters. | +| auth.fleetactivitytracking_statistics | None | Can view detailed statistics for corp models and other characters. | +---------------------------------------+------------------+--------------------------------------------------------------------------+ - ``` diff --git a/docs/features/core/admin_site.md b/docs/features/core/admin_site.md index f28ef28f..bf5756e9 100644 --- a/docs/features/core/admin_site.md +++ b/docs/features/core/admin_site.md @@ -11,8 +11,9 @@ You can open the admin site by clicking on "Admin" in the drop down menu for a u For small to medium size alliances it is often sufficient to have no more then two superuser admins (admins that also are superusers). Having two admins usually makes sense, so you can have one primary and one backup. :::{warning} - Superusers have read & write access to everything on your AA installation. Superusers also automatically have all permissions and therefore access to all features of your apps. Therefore we recommend to be very careful to whom you give superuser privileges. +Superusers have read & write access to everything on your AA installation. Superusers also automatically have all permissions and therefore access to all features of your apps. Therefore we recommend to be very careful to whom you give superuser privileges. ::: + ## Setup for large installations For large alliances and coalitions you may want to have a couple of administrators to be able to distribute and handle the work load. However, having a larger number of superusers may be a security concern. @@ -25,14 +26,15 @@ To create a staff admin you need to do two things: 1. Give the user permissions for admin tasks :::{note} - Note that staff admins have the following limitations: +Note that staff admins have the following limitations: - - Can not promote users to staff - - Can not promote users to superuser - - Can not add/remove permissions for users, groups and states +- Can not promote users to staff +- Can not promote users to superuser +- Can not add/remove permissions for users, groups and states - These limitations exist to prevent staff admins to promote themselves to quasi superusers. Only superusers can perform these actions. -``` +These limitations exist to prevent staff admins to promote themselves to quasi superusers. Only superusers can perform these actions. + +::: ### Staff property @@ -40,7 +42,7 @@ Access to the admin site is restricted. Users needs to have the `is_staff` prope process will automatically have access to the admin site. :::{hint} - Without any permissions a "staff user" can open the admin site, but can neither view nor edit anything except for viewing the list of permissions. +Without any permissions a "staff user" can open the admin site, but can neither view nor edit anything except for viewing the list of permissions. ::: ### Permissions for common admin tasks diff --git a/docs/features/core/groups.md b/docs/features/core/groups.md index 2de54a61..ced1f32c 100644 --- a/docs/features/core/groups.md +++ b/docs/features/core/groups.md @@ -45,14 +45,13 @@ When a group is restricted only superuser admins can directly add or remove them ```{eval-rst} .. _ref-reserved-group-names: ``` - ## Reserved group names When using Alliance Auth to manage external services like Discord, Auth will automatically duplicate groups on those services. E.g. on Discord Auth will create roles of the same name as groups. However, there may be cases where you want to manage groups on external services by yourself or by another bot. For those cases you can define a list of reserved group names. Auth will ensure that you can not create groups with a reserved name. You will find this list on the admin site under groupmanagement. :::{note} - While this feature can help to avoid naming conflicts with groups on external services, the respective service component in Alliance Auth also needs to be build in such a way that it knows how to prevent these conflicts. Currently only the Discord and Teamspeak3 services have this ability. -``` +While this feature can help to avoid naming conflicts with groups on external services, the respective service component in Alliance Auth also needs to be build in such a way that it knows how to prevent these conflicts. Currently only the Discord and Teamspeak3 services have this ability. +::: ## Managing groups @@ -102,7 +101,7 @@ GROUPMANAGEMENT_AUTO_LEAVE = True :::{note} Before you set `GROUPMANAGEMENT_AUTO_LEAVE = True`, make sure there are no pending leave requests, as this option will hide the "Leave Requests" tab. -``` +::: ## Settings @@ -126,8 +125,8 @@ In order to join a group other than a public group, the permission `groupmanagem When a user loses this permission, they will be removed from all groups _except_ Public groups. :::{note} - By default, the ``groupmanagement.request_groups`` permission is applied to the ``Member`` group. In most instances this, and perhaps adding it to the ``Blue`` group, should be all that is ever needed. It is unsupported and NOT advisable to apply this permission to a public group. See #697 for more information. -``` +By default, the ``groupmanagement.request_groups`` permission is applied to the ``Member`` group. In most instances this, and perhaps adding it to the ``Blue`` group, should be all that is ever needed. It is unsupported and NOT advisable to apply this permission to a public group. See #697 for more information. +::: Group Management should be mostly done using group leaders, a series of permissions are included below for thoroughness: diff --git a/docs/features/services/discord.md b/docs/features/services/discord.md index 0ffed134..04db3374 100644 --- a/docs/features/services/discord.md +++ b/docs/features/services/discord.md @@ -35,7 +35,7 @@ CELERYBEAT_SCHEDULE['discord.update_all_usernames'] = { :::{note} You will have to add most the values for these settings, e.g. your Discord server ID (aka guild ID), later in the setup process. -``` +::: ### Creating a Server @@ -48,9 +48,8 @@ Now retrieve the server ID [following this procedure.](https://support.discord.c Update your auth project's settings file, inputting the server ID as `DISCORD_GUILD_ID` :::{note} - If you already have a Discord server skip the creation step, but be sure to retrieve the server ID -``` - +If you already have a Discord server skip the creation step, but be sure to retrieve the server ID +::: ### Registering an Application Navigate to the [Discord Developers site.](https://discord.com/developers/applications/me) Press the plus sign to create a new application. @@ -106,14 +105,13 @@ Second, it is possible to exclude Discord roles from being managed by Auth at al To exclude roles from being managed by Auth you only have to add them to the list of reserved group names in Group Management. :::{note} - Role names on Discord are case sensitive, while reserved group names on Auth are not. Therefore reserved group names will cover all roles regardless of their case. For example if you have reserved the group name "alpha", then the Discord roles "alpha" and "Alpha" will both be persisted. -``` +Role names on Discord are case sensitive, while reserved group names on Auth are not. Therefore reserved group names will cover all roles regardless of their case. For example if you have reserved the group name "alpha", then the Discord roles "alpha" and "Alpha" will both be persisted. +::: ```{eval-rst} .. seealso:: For more information see :ref:`ref-reserved-group-names`. ``` - ## Tasks The Discord service contains a number of tasks that can be run to manually perform updates to all users. @@ -134,10 +132,9 @@ Name Description `update_all` Update groups, nicknames, usernames of all users ======================== ==================================================== ``` - :::{note} - Depending on how many users you have, running these tasks can take considerable time to finish. You can calculate roughly 1 sec per user for all tasks, except update_all, which needs roughly 3 secs per user. -``` +Depending on how many users you have, running these tasks can take considerable time to finish. You can calculate roughly 1 sec per user for all tasks, except update_all, which needs roughly 3 secs per user. +::: ## Settings @@ -159,7 +156,6 @@ Name Description `DISCORD_TASKS_MAX_RETRIES` max retries of tasks after an error occurred `3` =================================== ============================================================================================= ======= ``` - ## Permissions To use this service, users will require some of the following. @@ -171,7 +167,6 @@ To use this service, users will require some of the following. | discord.access_discord | None | Can Access the Discord Service | +---------------------------------------+------------------+--------------------------------------------------------------------------+ ``` - ## Troubleshooting ### "Unknown Error" on Discord site when activating service diff --git a/docs/features/services/mumble.md b/docs/features/services/mumble.md index d38503f4..30ca32e0 100644 --- a/docs/features/services/mumble.md +++ b/docs/features/services/mumble.md @@ -3,16 +3,19 @@ Mumble is a free voice chat server. While not as flashy as TeamSpeak, it has all the functionality and is easier to customize. And is better. I may be slightly biased. :::{note} - Note that this guide assumes that you have installed Auth with the official :doc:`/installation/allianceauth` guide under ``/home/allianceserver`` and that it is called ``myauth``. Accordingly it assumes that you have a service user called ``allianceserver`` that is used to run all Auth services under supervisor. -``` +Note that this guide assumes that you have installed Auth with the official :doc:`/installation/allianceauth` guide under ``/home/allianceserver`` and that it is called ``myauth``. Accordingly it assumes that you have a service user called ``allianceserver`` that is used to run all Auth services under supervisor. +::: :::{warning} - This guide is currently for Ubuntu only. +This guide is currently for Ubuntu only. ::: ## Installations ### Installing Mumble Server +::::{tabs} +:::{group-tab} Ubuntu 2004, 2204 + The mumble server package can be retrieved from a repository, which we need to add: ```shell @@ -29,6 +32,10 @@ Now three packages need to be installed: sudo apt-get install python-software-properties mumble-server libqt5sql5-mysql ``` +::: +:::: + + ### Installing Mumble Authenticator Next, we need to download the latest authenticator release from the [authenticator repository](https://gitlab.com/allianceauth/mumble-authenticator). diff --git a/docs/features/services/nameformats.md b/docs/features/services/nameformats.md index e995b8e2..3a007137 100644 --- a/docs/features/services/nameformats.md +++ b/docs/features/services/nameformats.md @@ -29,10 +29,9 @@ Currently the following services support custom name formats: | Xenforo | Username | ``{character_name}`` | +-------------+-----------+-------------------------------------+ ``` - :::{note} - It's important to note here, before we get into what you can do with a name formatter, that before the generated name is passed off to the service to create an account it will be sanitized to remove characters (the letters and numbers etc.) that the service cannot support. This means that, despite what you configured, the service may display something different. It is up to you to test your formatter and understand how your format may be disrupted by a certain services sanitization function. -``` +It's important to note here, before we get into what you can do with a name formatter, that before the generated name is passed off to the service to create an account it will be sanitized to remove characters (the letters and numbers etc.) that the service cannot support. This means that, despite what you configured, the service may display something different. It is up to you to test your formatter and understand how your format may be disrupted by a certain services sanitization function. +::: ## Available format data @@ -71,9 +70,9 @@ Some examples of strings you could use: ``` :::{important} - For most services, name formats only take effect when a user creates an account. This means if you create or update a name formatter it wont retroactively alter the format of users names. There are some exceptions to this where the service updates nicknames on a periodic basis. Check the service's documentation to see which of these apply. +For most services, name formats only take effect when a user creates an account. This means if you create or update a name formatter it wont retroactively alter the format of users names. There are some exceptions to this where the service updates nicknames on a periodic basis. Check the service's documentation to see which of these apply. ::: :::{important} - You must only create one formatter per service per state. E.g. don't create two formatters for Mumble for the Member state. In this case one of the formatters will be used and it may not be the formatter you are expecting. +You must only create one formatter per service per state. E.g. don't create two formatters for Mumble for the Member state. In this case one of the formatters will be used and it may not be the formatter you are expecting: ::: diff --git a/docs/features/services/openfire.md b/docs/features/services/openfire.md index 6fb345cd..7477bffb 100644 --- a/docs/features/services/openfire.md +++ b/docs/features/services/openfire.md @@ -23,23 +23,37 @@ BROADCAST_SERVICE_NAME = "broadcast" Openfire require a Java 8 runtime environment. -Ubuntu 1804, 2004, 2204: +::::{tabs} +:::{group-tab} Ubuntu 2004, 2204 ```shell sudo apt-get install openjdk-11-jre ``` -Centos 7: +::: +:::{group-tab} CentOS 7 ```shell sudo yum install java-11-openjdk java-11-openjdk-devel ``` -Centos Stream 8, Stream 9: +::: +:::{group-tab} CentOS Stream 8 + ```shell sudo dnf install java-11-openjdk java-11-openjdk-devel ``` +::: +:::{group-tab} CentOS Stream 9 + +```shell +sudo dnf install java-11-openjdk java-11-openjdk-devel +``` + +::: +:::: + ## Setup ### Download Installer @@ -51,31 +65,40 @@ On your PC, navigate to the [Ignite Realtime downloads section](https://www.igni Retrieve the file location by copying the URL from the “click here” link, depending on your browser you may have a Copy Link or similar option in your right click menu. In the console, ensure you’re in your user’s home directory: + ```shell cd ~ ``` Download and install the package, replacing the URL with the latest you got from the Openfire download page earlier -Ubuntu 1804, 2004, 2204: +::::{tabs} +:::{group-tab} Ubuntu 2004, 2204 -```shell -wget https://www.igniterealtime.org/downloadServlet?filename=openfire/openfire_4.7.2_all.deb +::: +:::{group-tab} CentOS 7 +wget dpkg -i openfire_4.7.2_all.deb -``` - -Centos 7, Stream 8, Stream 9: - -```shell -wget https://www.igniterealtime.org/downloadServlet?filename=openfire/openfire-4.7.2-1.noarch.rpm +::: +:::{group-tab} CentOS Stream 8 +wget yum install -y openfire-4.7.2-1.noarch.rpm -``` +::: +:::{group-tab} CentOS Stream 9 +wget +yum install -y openfire-4.7.2-1.noarch.rpm +::: +:::: + ### Create Database Performance is best when working from a SQL database. If you installed MySQL or MariaDB alongside your auth project, go ahead and create a database for Openfire: ```shell mysql -u root -p +``` + +```sql create database alliance_jabber; grant all privileges on alliance_jabber . * to 'allianceserver'@'localhost'; exit; @@ -83,7 +106,7 @@ exit; ### Web Configuration -The remainder of the setup occurs through Openfire’s web interface. Navigate to http://example.com:9090, or if you’re behind CloudFlare, go straight to your server’s IP:9090. +The remainder of the setup occurs through Openfire’s web interface. Navigate to , or if you’re behind CloudFlare, go straight to your server’s IP:9090. Select your language. I sure hope it’s English if you’re reading this guide. diff --git a/docs/features/services/permissions.md b/docs/features/services/permissions.md index c4ad73e7..2f809e70 100644 --- a/docs/features/services/permissions.md +++ b/docs/features/services/permissions.md @@ -7,7 +7,7 @@ In the past, access to services was dictated by a list of settings in `settings. Instead of granting access to services by the previous rigid structure, access to services is now granted by the built in Django permissions system. This means that service access can be more granular, allowing only certain states, certain groups, for instance Corp CEOs, or even individual user access to each enabled service. :::{important} - If you grant access to an individual user, they will have access to that service regardless of whether or not they are a member. +If you grant access to an individual user, they will have access to that service regardless of whether or not they are a member. ::: Each service has an access permission defined, named like `Can access the service`. @@ -19,7 +19,7 @@ A user can be granted the same permission from multiple sources. e.g. they may h ## Removing access :::{danger} - Access removal is processed immediately after removing a permission from a user or group. If you remove access from a large group, such as Member, it will immediately remove all users from that service. +Access removal is processed immediately after removing a permission from a user or group. If you remove access from a large group, such as Member, it will immediately remove all users from that service. ::: When you remove a service permission from a user, a signal is triggered which will activate an immediate permission check. For users this will trigger an access check for all services. For groups, due to the potential extra load, only the services whose permissions have changed will be verified, and only the users in that group. diff --git a/docs/features/services/smf.md b/docs/features/services/smf.md index 1999dc80..96ce7c42 100644 --- a/docs/features/services/smf.md +++ b/docs/features/services/smf.md @@ -11,6 +11,7 @@ SMF requires PHP installed in your web server. Apache has `mod_php`, NGINX requi ## Prepare Your Settings In your auth project's settings file, do the following: + - Add `'allianceauth.services.modules.smf',` to your `INSTALLED_APPS` list - Append the following to the bottom of the settings file: @@ -31,8 +32,7 @@ DATABASES['smf'] = { ### Download SMF -Using your browser, you can download the latest version of SMF to your desktop computer. All SMF downloads can be found at SMF Downloads. The latest recommended version will always be available at http://www.simplemachines.org/download/index.php/latest/install/. Retrieve the file location from the hyperlinked box icon for the zip full install, depending on your browser you may have a Copy Link or similar option in your right click menu. - +Using your browser, you can download the latest version of SMF to your desktop computer. All SMF downloads can be found at SMF Downloads. The latest recommended version will always be available at . Retrieve the file location from the hyperlinked box icon for the zip full install, depending on your browser you may have a Copy Link or similar option in your right click menu. Download using wget, replacing the URL with the URL for the package you just retrieved @@ -41,11 +41,13 @@ wget https://download.simplemachines.org/index.php?thanks;filename=smf_2-1-2_ins ``` This needs to be unpackaged. Unzip it, replacing the file name with that of the file you just downloaded + ```shell unzip smf_2-1-2_install.zip ``` Now we need to move this to our web directory. Usually `/var/www/forums`. + ```shell mv smf /var/www/forums ``` @@ -56,19 +58,18 @@ Apache: `chown -R www-data:www-data /var/www/forums` Nginx: `chown -R nginx:nginx /var/www/forums` :::{tip} - - Nginx: Some distributions use the ``www-data:www-data`` user:group instead of ``nginx:nginx``. If you run into problems with permissions try it instead. -.. +Nginx: Some distributions use the ``www-data:www-data`` user:group instead of ``nginx:nginx``. If you run into problems with permissions try it instead. ::: ### Database Preparation SMF needs a database. Create one: + ```shell mysql -u root -p ``` -```mysql +```sql create database alliance_smf; grant all privileges on alliance_smf . * to 'allianceserver'@'localhost'; exit; @@ -81,7 +82,8 @@ Enter the database information into the `DATABASES['smf']` section of your auth Your web server needs to be configured to serve SMF. A minimal Apache config might look like: -```apache + +```ini ServerName forums.example.com DocumentRoot /var/www/forums @@ -92,7 +94,8 @@ A minimal Apache config might look like: ```` A minimal Nginx config might look like: -```nginx + +```ini server { listen 80; server_name forums.example.com; @@ -108,7 +111,8 @@ server { include fastcgi_params; } } -```` +``` + Enter the web address to your forums into the `SMF_URL` setting in your auth project's settings file. ### Web Install @@ -120,6 +124,7 @@ Click on the `Install` tab. All the requirements should be met. Press `Start Install`. Under Database Settings, set the following: + - Database Type is `MySQL` - Database Server Hostname is `127.0.0.1` - Database Server Port is left blank diff --git a/docs/features/services/teamspeak3.md b/docs/features/services/teamspeak3.md index fed2b60e..559301bc 100644 --- a/docs/features/services/teamspeak3.md +++ b/docs/features/services/teamspeak3.md @@ -38,7 +38,7 @@ To install we need a copy of the server. You can find the latest version from th Download the server, replacing the link with the link you got earlier. -```bash +```shell cd ~ wget https://files.teamspeak-services.com/releases/server/3.13.7/teamspeak3-server_linux_amd64-3.13.7.tar.bz2 ``` diff --git a/docs/installation/allianceauth.md b/docs/installation/allianceauth.md index e672f356..62bd523d 100644 --- a/docs/installation/allianceauth.md +++ b/docs/installation/allianceauth.md @@ -32,13 +32,7 @@ It is recommended to ensure your OS is fully up to date before proceeding. We ma ```shell sudo apt-get update -``` - -```shell sudo apt-get upgrade -``` - -```shell sudo do-dist-upgrade ``` @@ -47,9 +41,6 @@ sudo do-dist-upgrade ```shell yum install epel-release -``` - -```shell sudo yum upgrade ``` @@ -58,13 +49,7 @@ sudo yum upgrade ```shell sudo dnf config-manager --set-enabled powertools -``` - -```shell sudo dnf install epel-release epel-next-release -``` - -```shell sudo yum upgrade ``` @@ -73,13 +58,7 @@ sudo yum upgrade ```shell sudo dnf config-manager --set-enabled crb -``` - -```shell sudo dnf install epel-release epel-next-release -``` - -```shell sudo yum upgrade ``` @@ -96,13 +75,7 @@ Install Python 3.11 and related tools on your system. ```shell sudo add-apt-repository ppa:deadsnakes/ppa -``` - -```shell sudo apt-get update -``` - -```shell sudo apt-get install python3.11 python3.11-dev python3.11-venv ``` @@ -110,31 +83,13 @@ sudo apt-get install python3.11 python3.11-dev python3.11-venv :::{group-tab} CentOS 7, Stream 8, Stream 9 We need to build Python from source -```shell +```bash cd ~ -``` - -```shell sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget -``` - -```shell wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz -``` - -```shell tar xvf Python-3.11.5.tgz -``` - -```shell cd Python-3.11.5/ -``` - -```shell ./configure --enable-optimizations --enable-shared -``` - -```shell sudo make altinstall ``` @@ -219,9 +174,6 @@ sudo yum install gcc gcc-c++ unzip git redis curl bzip2-devel openssl-devel libf ```shell sudo systemctl enable redis.service -``` - -```shell sudo systemctl start redis.service ``` @@ -234,9 +186,6 @@ sudo dnf install gcc gcc-c++ unzip git redis curl bzip2-devel openssl-devel libf ```shell sudo systemctl enable redis.service -``` - -```shell sudo systemctl start redis.service ``` @@ -249,9 +198,6 @@ sudo dnf install gcc gcc-c++ unzip git redis curl bzip2-devel openssl-devel libf ```shell sudo systemctl enable redis.service -``` - -```shell sudo systemctl start redis.service ``` @@ -285,7 +231,7 @@ mysql_tzinfo_to_sql /usr/share/zoneinfo | sudo mysql -u root mysql :::{note} You may see errors when you add the timezone tables. To make sure that they were correctly added run the following commands and check for the ``time_zone`` tables -```bash +```shell mysql -u root -p use mysql; show tables; @@ -476,7 +422,7 @@ python /home/allianceserver/myauth/manage.py check :::{hint} If you are using root, ensure the allianceserver user has read/write permissions to this directory before proceeding:: -``` +```shell chown -R allianceserver:allianceserver /home/allianceserver/myauth ``` @@ -511,7 +457,7 @@ The default configuration is good enough for most installations. Additional info :::{note} You will need to exit the allianceserver user back to a user with sudo capabilities to install supervisor:: -```bash +```shell exit ``` diff --git a/docs/installation/apache.md b/docs/installation/apache.md index d94503c3..e590980f 100644 --- a/docs/installation/apache.md +++ b/docs/installation/apache.md @@ -130,7 +130,7 @@ a2dissite 000-default.conf ## Sample Config File -```conf +```ini ServerName auth.example.com @@ -168,7 +168,7 @@ It's 2018 - there's no reason to run a site without SSL. The EFF provides free, After acquiring SSL the config file needs to be adjusted. Add the following lines inside the `` block: -```conf +```ini RequestHeader set X-FORWARDED-PROTOCOL https RequestHeader set X-FORWARDED-SSL On ``` diff --git a/docs/installation/gunicorn.md b/docs/installation/gunicorn.md index a2697164..524d3bf7 100644 --- a/docs/installation/gunicorn.md +++ b/docs/installation/gunicorn.md @@ -7,16 +7,16 @@ If you find Apache's `mod_wsgi` to be a headache or want to use NGINX (or some o Check out the full [Gunicorn docs](http://docs.gunicorn.org/en/latest/index.html). :::{note} - The page contains additional steps on how to setup and configure Gunicorn that are not required for users who decide to stick with the default Gunicorn configuration as described in the main installation guide for AA. -``` +The page contains additional steps on how to setup and configure Gunicorn that are not required for users who decide to stick with the default Gunicorn configuration as described in the main installation guide for AA. +::: ## Setting up Gunicorn :::{note} - If you're using a virtual environment, activate it now:: - sudo su allianceserver - source /home/allianceserver/venv/auth/bin/activate -``` +If you're using a virtual environment, activate it now:: + sudo su allianceserver + source /home/allianceserver/venv/auth/bin/activate +::: Install Gunicorn using pip @@ -47,6 +47,7 @@ autostart=true autorestart=true stopsignal=INT ``` + - `[program:gunicorn]` - Change `gunicorn` to whatever you wish to call your process in Supervisor. - `user = allianceserver` - Change to whatever user you wish Gunicorn to run as. You could even set this as allianceserver if you wished. I'll leave the question security of that up to you. - `directory=/home/allianceserver/myauth/` - Needs to be the path to your Alliance Auth project. @@ -79,6 +80,7 @@ Following this guide, you are running with a virtual environment. Therefore you' e.g. `command=/path/to/venv/bin/gunicorn myauth.wsgi` The example config is using the myauth venv from the main installation guide: + ```ini command=/home/allianceserver/venv/auth/bin/gunicorn myauth.wsgi ``` diff --git a/docs/installation/nginx.md b/docs/installation/nginx.md index ee31c250..2c5a52b4 100644 --- a/docs/installation/nginx.md +++ b/docs/installation/nginx.md @@ -22,7 +22,6 @@ Nginx is lightweight for a reason. It doesn't try to do everything internally an +-----------+----------------------------------------+ | mod_wsgi | Gunicorn or other external WSGI server | +-----------+----------------------------------------+ - ``` Your .htaccess files won't work. Nginx has a separate way of managing access to folders via the server config. Everything you can do with htaccess files you can do with Nginx config. [Read more on the Nginx wiki](https://www.nginx.com/resources/wiki/start/topics/examples/likeapache-htaccess/) @@ -34,7 +33,6 @@ Install Nginx via your preferred package manager or other method. If you need he Nginx needs to be able to read the folder containing your auth project's static files. `chown -R nginx:nginx /var/www/myauth/static`. :::{tip} - Some specific distros may use ``www-data:www-data`` instead of ``nginx:nginx``, causing static files (images, stylesheets etc) not to appear. You can confirm what user Nginx will run under by checking either its base config file ``/etc/nginx/nginx.conf`` for the "user" setting, or once Nginx has started ``ps aux | grep nginx``. Adjust your chown commands to the correct user if needed. ::: @@ -43,24 +41,41 @@ You will need to have [Gunicorn](gunicorn.md) or some other WSGI server setup fo ## Install -Ubuntu 1804, 2004, 2204: +::::{tabs} +:::{group-tab} Ubuntu 2004, 2204 + ```shell sudo apt-get install nginx ``` -CentOS 7 +::: +:::{group-tab} CentOS 7 + ```shell sudo yum install nginx ``` -CentOS Stream 8, Stream 9: +::: +:::{group-tab} CentOS Stream 8 + ```shell sudo dnf install nginx ``` +::: +:::{group-tab} CentOS Stream 9 + +```shell +sudo dnf install nginx +``` + +::: +:::: + Create a config file in `/etc/nginx/sites-available` (`/etc/nginx/conf.d` on CentOS) and call it `alliance-auth.conf` or whatever your preferred name is. Create a symbolic link to enable the site (not needed on CentOS): + ```shell ln -s /etc/nginx/sites-available/alliance-auth.conf /etc/nginx/sites-enabled/ ``` @@ -69,8 +84,7 @@ ln -s /etc/nginx/sites-available/alliance-auth.conf /etc/nginx/sites-enabled/ Copy this basic config into your config file. Make whatever changes you feel are necessary. - -``` +```ini server { listen 80; listen [::]:80; @@ -106,7 +120,7 @@ With [Let's Encrypt](https://letsencrypt.org/) offering free SSL certificates, t Your config will need a few additions once you've got your certificate. -``` +```ini listen 443 ssl http2; # Replace listen 80; with this listen [::]:443 ssl http2; # Replace listen [::]:80; with this @@ -122,7 +136,7 @@ Your config will need a few additions once you've got your certificate. If you want to redirect all your non-SSL visitors to your secure site, below your main configs `server` block, add the following: -``` +```ini server { listen 80; listen [::]:80; diff --git a/docs/installation/upgrade_python.md b/docs/installation/upgrade_python.md index 919d80f6..c88112c5 100644 --- a/docs/installation/upgrade_python.md +++ b/docs/installation/upgrade_python.md @@ -5,8 +5,8 @@ This guide describes how to upgrade an existing Alliance Auth (AA) installation This guide shares many similarities with the Alliance Auth install guide, but it is targeted towards existing installs needing to update. :::{note} - This guide will upgrade the software components only but not change any data or configuration. -``` +This guide will upgrade the software components only but not change any data or configuration. +::: ## Install a new Python version @@ -14,59 +14,67 @@ To run AA with a newer Python 3 version than your system's default you need to i To install other Python versions than those included with your distribution, you need to add a new installation repository. Then you can install the specific Python 3 to your system. -Ubuntu 1804, 2004: :::{note} Ubuntu 2204 ships with Python 3.10 already -``` - -```shell -sudo add-apt-repository ppa:deadsnakes/ppa -``` - -```shell -sudo apt-get update -``` - -```shell -sudo apt-get install python3.10 python3.10-dev python3.10-venv -``` - -CentOS 7: -We need to build Python from source +::: Centos Stream 8/9: :::{note} - A Python 3.9 Package is available for Stream 8 and 9. You _may_ use this instead of building your own package. But our documentation will assume Python3.10 and you may need to substitute as neccessary - sudo dnf install python39 python39-devel -``` +A Python 3.9 Package is available for Stream 8 and 9. You _may_ use this instead of building your own package. But our documentation will assume Python3.11 and you may need to substitute as neccessary +sudo dnf install python39 python39-devel +::: + +::::{tabs} +:::{group-tab} Ubuntu 2004, 2204 ```shell +sudo add-apt-repository ppa:deadsnakes/ppa +sudo apt-get update +sudo apt-get install python3.11 python3.11-dev python3.11-venv +``` + +::: +:::{group-tab} CentOS 7 + +```bash cd ~ -``` - -```shell sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget -``` - -```shell -wget https://www.python.org/ftp/python/3.10.5/Python-3.10.5.tgz -``` - -```shell -tar xvf Python-3.10.5.tgz -``` - -```shell -cd Python-3.10.5/ -``` - -```shell +wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz +tar xvf Python-3.11.5.tgz +cd Python-3.11.5/ ./configure --enable-optimizations --enable-shared -``` - -```shell sudo make altinstall ``` + +::: +:::{group-tab} CentOS Stream 8 + +```bash +cd ~ +sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget +wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz +tar xvf Python-3.11.5.tgz +cd Python-3.11.5/ +./configure --enable-optimizations --enable-shared +sudo make altinstall +``` + +::: +:::{group-tab} CentOS Stream 9 + +```bash +cd ~ +sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget +wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz +tar xvf Python-3.11.5.tgz +cd Python-3.11.5/ +./configure --enable-optimizations --enable-shared +sudo make altinstall +``` + +::: +:::: + ## Preparing your venv Before updating your venv it is important to make sure that your current installation is stable. Otherwise your new venv might not be consistent with your data, which might create problems. @@ -74,9 +82,10 @@ Before updating your venv it is important to make sure that your current install Start by navigating to your main project folder (the one that has `manage.py` in it). If you followed the default installation the path is: `/home/allianceserver/myauth` :::{note} - If you installed Alliance Auth under the allianceserver user, as reccommended. Remember to switch users for easier permission management:: +If you installed Alliance Auth under the allianceserver user, as reccommended. Remember to switch users for easier permission management:: - sudo su allianceserver +```bash +sudo su allianceserver ``` Activate your venv: @@ -134,6 +143,7 @@ python manage.py migrate ```shell python manage.py collectstatic ``` + ### Restart and final check Do a final restart of your AA supervisors and make sure your installation is still running normally. @@ -166,10 +176,10 @@ At this point we recommend creating a list of the additional packages that you n - Additional tools you are using (e.g. flower, django-extensions) :::{hint} - While `requirements.txt` will contain a complete list of your packages, it will also contain many packages that are automatically installed as dependencies and don't need be manually reinstalled. +While `requirements.txt` will contain a complete list of your packages, it will also contain many packages that are automatically installed as dependencies and don't need be manually reinstalled. ::: :::{note} - Some guide on the Internet will suggest to use use the requirements.txt file to recreate a venv. This is indeed possible, but only works if all packages can be installed from PyPI. Since most community apps are installed directly from repos this guide will not follow that approach. +Some guide on the Internet will suggest to use use the requirements.txt file to recreate a venv. This is indeed possible, but only works if all packages can be installed from PyPI. Since most community apps are installed directly from repos this guide will not follow that approach. ::: Leave the venv and shutdown all AA services: @@ -190,10 +200,10 @@ mv /home/allianceserver/venv/auth /home/allianceserver/venv/auth_old ## Create your new venv -Now let's create our new venv with Python 3.10 and activate it: +Now let's create our new venv with Python 3.11 and activate it: ```shell -python3.10 -m venv /home/allianceserver/venv/auth +python3.11 -m venv /home/allianceserver/venv/auth ``` ```shell diff --git a/docs/maintenance/apps.md b/docs/maintenance/apps.md index a9ce6101..99f4bc5a 100644 --- a/docs/maintenance/apps.md +++ b/docs/maintenance/apps.md @@ -14,9 +14,8 @@ Your auth project is just a regular Django project - you can add in [other Djang The following instructions will explain how you can remove an app properly fom your Alliance Auth installation. :::{note} - We recommend following these instructions to avoid dangling foreign keys or orphaned Python packages on your system, which might cause conflicts with other apps down the road. - -``` +We recommend following these instructions to avoid dangling foreign keys or orphaned Python packages on your system, which might cause conflicts with other apps down the road. +::: ### Step 1 - Removing database tables diff --git a/docs/maintenance/tuning/celery.md b/docs/maintenance/tuning/celery.md index 759e163f..0d8b2cd4 100644 --- a/docs/maintenance/tuning/celery.md +++ b/docs/maintenance/tuning/celery.md @@ -1,12 +1,13 @@ # Celery :::{hint} - Most tunings will require a change to your supervisor configuration in your `supervisor.conf` file. Note that you need to restart the supervisor daemon in order for any changes to take effect. And before restarting the daemon you may want to make sure your supervisors stop gracefully:(Ubuntu): +Most tunings will require a change to your supervisor configuration in your `supervisor.conf` file. Note that you need to restart the supervisor daemon in order for any changes to take effect. And before restarting the daemon you may want to make sure your supervisors stop gracefully:(Ubuntu): - :: +```bash +supervisor stop myauth: +systemctl supervisor restart +``` - supervisor stop myauth: - systemctl supervisor restart ::: ## Task Logging @@ -28,10 +29,9 @@ command=/home/allianceserver/venv/auth/bin/celery -A myauth worker -l info Celery workers often have memory leaks and will therefore grow in size over time. While the Alliance Auth team is working hard to ensure Auth is free of memory leaks some may still be cause by bugs in different versions of libraries or community apps. It is therefore good practice to enable features that protect against potential memory leaks. :::{hint} - The 256 MB limit is just an example and should be adjusted to your system configuration. We would suggest to not go below 128MB though, since new workers start with around 80 MB already. Also take into consideration that this value is per worker and that you may have more than one worker running in your system. +The 256 MB limit is just an example and should be adjusted to your system configuration. We would suggest to not go below 128MB though, since new workers start with around 80 MB already. Also take into consideration that this value is per worker and that you may have more than one worker running in your system. ::: - ### Supervisor It is also possible to configure your supervisor to monitor and automatically restart programs that exceed a memory threshold. @@ -75,7 +75,7 @@ process_name=%(program_name)s_%(process_num)02d This number will be multiplied by your concurrency setting, -``` +```math numprocs * concurency = workers ``` @@ -89,11 +89,11 @@ command=... -p worker_00=256MB -p worker_01=256MB -p worker_02=256MB ``` :::{hint} - You will want to experiment with different settings to find the optimal. One way to generate task load and verify your configuration is to run a model update with the following command: +You will want to experiment with different settings to find the optimal. One way to generate task load and verify your configuration is to run a model update with the following command: - :: - - celery -A myauth call allianceauth.eveonline.tasks.run_model_update +```bash +celery -A myauth call allianceauth.eveonline.tasks.run_model_update +``` ::: @@ -106,14 +106,14 @@ This can be achieved by the setting the concurrency parameter of the celery work ``` :::{hint} - The optimal number will hugely depend on your individual system configuration and you may want to experiment with different settings to find the optimal. One way to generate task load and verify your configuration is to run a model update with the following command: +The optimal number will hugely depend on your individual system configuration and you may want to experiment with different settings to find the optimal. One way to generate task load and verify your configuration is to run a model update with the following command: - :: - - celery -A myauth call allianceauth.eveonline.tasks.run_model_update +```bash +celery -A myauth call allianceauth.eveonline.tasks.run_model_update +``` ::: :::{hint} - The optimal number of concurrent workers will be different for every system and we recommend experimenting with different figures to find the optimal for your system. Note, that the example of 10 threads is conservative and should work even with smaller systems. +The optimal number of concurrent workers will be different for every system and we recommend experimenting with different figures to find the optimal for your system. Note, that the example of 10 threads is conservative and should work even with smaller systems. ::: diff --git a/docs/maintenance/tuning/redis.md b/docs/maintenance/tuning/redis.md index 2c912cfd..abd21434 100644 --- a/docs/maintenance/tuning/redis.md +++ b/docs/maintenance/tuning/redis.md @@ -2,7 +2,7 @@ ## Compression -Cache compression can help tame the memory usage of specialised installation configurations and Community Apps that heavily utilize Redis. +Cache compression can help tame the memory usage of specialised installation configurations and Community Apps that heavily utilize Redis, in exchange for increased CPU utilization. Various compression algorithms are supported, with various strengths. Our testing has shown that lzma works best with our use cases. You can read more at [Django-Redis Compression Support](https://github.com/jazzband/django-redis#compression-support) From bf14e9c7c3bff543d29756546711aebbff723548 Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Tue, 31 Oct 2023 23:36:42 +1000 Subject: [PATCH 10/23] merged back into sphinxcontrib-django --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 71a047e9..fc97d52a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -41,7 +41,7 @@ extensions = [ 'sphinx.ext.napoleon', 'sphinx.ext.viewcode', 'myst_parser', - 'sphinxcontrib_django2', + 'sphinxcontrib_django', 'sphinx_copybutton', 'sphinx_tabs.tabs' ] From e16c68e25540d035a4c139a54849832869b8a6d1 Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Tue, 31 Oct 2023 23:43:45 +1000 Subject: [PATCH 11/23] increase anchor generation --- docs/conf.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index fc97d52a..90e05262 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -141,3 +141,8 @@ texinfo_documents = [( root_doc, 'AllianceAuth', 'Alliance Auth Documentation', author, 'AllianceAuth', 'An auth system for EVE Online to help in-game organizations manage online service access.', 'Miscellaneous'), ] + + +# -- https://myst-parser.readthedocs.io/en/latest/configuration.html + +myst_heading_anchors = 4 From 60084de3db8b3b7632a78d53df0391c581c727b8 Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Tue, 31 Oct 2023 23:43:52 +1000 Subject: [PATCH 12/23] Pygments lexer name 'math' is not known --- docs/maintenance/tuning/celery.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/maintenance/tuning/celery.md b/docs/maintenance/tuning/celery.md index 0d8b2cd4..5e5590f9 100644 --- a/docs/maintenance/tuning/celery.md +++ b/docs/maintenance/tuning/celery.md @@ -75,7 +75,7 @@ process_name=%(program_name)s_%(process_num)02d This number will be multiplied by your concurrency setting, -```math +```text numprocs * concurency = workers ``` From ce25deeca13733dda6520e98fc9795ece46dfba5 Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Tue, 31 Oct 2023 23:52:34 +1000 Subject: [PATCH 13/23] minor formatting --- docs/features/services/discourse.md | 8 +++--- docs/installation/allianceauth.md | 3 +-- docs/installation/apache.md | 40 ++++++++++------------------- docs/installation/upgrade_python.md | 1 + docs/maintenance/troubleshooting.md | 4 +-- docs/maintenance/tuning/index.md | 2 +- 6 files changed, 22 insertions(+), 36 deletions(-) diff --git a/docs/features/services/discourse.md b/docs/features/services/discourse.md index e66a112f..a0ee6150 100644 --- a/docs/features/services/discourse.md +++ b/docs/features/services/discourse.md @@ -75,20 +75,20 @@ nano /etc/default/docker Uncomment this line: ```ini - DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4" +DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4" ``` Restart Docker: ```shell - service docker restart +service docker restart ``` Now build: ```shell - ./launcher bootstrap app - ./launcher start app +./launcher bootstrap app +./launcher start app ``` ## Web Server Configuration diff --git a/docs/installation/allianceauth.md b/docs/installation/allianceauth.md index 62bd523d..94936785 100644 --- a/docs/installation/allianceauth.md +++ b/docs/installation/allianceauth.md @@ -27,7 +27,6 @@ To install on your favorite flavour of Linux, identify and install equivalent pa It is recommended to ensure your OS is fully up to date before proceeding. We may also add Package Repositories here, used later in the documentation. ::::{tabs} - :::{group-tab} Ubuntu 2004, 2204 ```shell @@ -458,7 +457,7 @@ The default configuration is good enough for most installations. Additional info You will need to exit the allianceserver user back to a user with sudo capabilities to install supervisor:: ```shell - exit +exit ``` ::: diff --git a/docs/installation/apache.md b/docs/installation/apache.md index e590980f..1c173329 100644 --- a/docs/installation/apache.md +++ b/docs/installation/apache.md @@ -11,45 +11,31 @@ If you're using a small VPS to host services with very limited memory, consider ::::{tabs} :::{group-tab} Ubuntu 2004, 2204 - -::: -:::{group-tab} CentOS 7 - -::: -:::{group-tab} CentOS Stream 8 - -::: -:::{group-tab} CentOS Stream 9 - -::: -:::: -Ubuntu 1804, 2004: - ```shell apt-get install apache2 ``` - -CentOS 7: - +::: +:::{group-tab} CentOS 7 ```shell yum install httpd ``` - -Centos Stream 8, Stream 9 - +::: +:::{group-tab} CentOS Stream 8 ```shell dnf install httpd ``` +::: +:::{group-tab} CentOS Stream 9 +```shell +systemctl enable httpd +systemctl start httpd +``` + +::: +:::: CentOS 7, Stream 8, Stream 9 -```shell -systemctl enable httpd -``` - -```shell -systemctl start httpd -``` ## Configuration diff --git a/docs/installation/upgrade_python.md b/docs/installation/upgrade_python.md index c88112c5..50e7bb29 100644 --- a/docs/installation/upgrade_python.md +++ b/docs/installation/upgrade_python.md @@ -83,6 +83,7 @@ Start by navigating to your main project folder (the one that has `manage.py` in :::{note} If you installed Alliance Auth under the allianceserver user, as reccommended. Remember to switch users for easier permission management:: +::: ```bash sudo su allianceserver diff --git a/docs/maintenance/troubleshooting.md b/docs/maintenance/troubleshooting.md index c81ae285..33f1f530 100644 --- a/docs/maintenance/troubleshooting.md +++ b/docs/maintenance/troubleshooting.md @@ -25,8 +25,8 @@ Make sure the background processes are running: `supervisorctl status myauth:`. Stop celery workers with `supervisorctl stop myauth:worker` then clear the queue: ```shell - redis-cli FLUSHALL - celery -A myauth worker --purge +redis-cli FLUSHALL +celery -A myauth worker --purge ``` Press Control+C once. diff --git a/docs/maintenance/tuning/index.md b/docs/maintenance/tuning/index.md index 7b0d2fb8..005a6a9f 100644 --- a/docs/maintenance/tuning/index.md +++ b/docs/maintenance/tuning/index.md @@ -3,7 +3,7 @@ The official installation guide will install a stable version of Alliance Auth that will work fine for most cases. However, there are a lot of levels that can be used to optimize a system. For example some installations may we short on RAM and want to reduce the total memory footprint, even though that may reduce system performance. Others are fine with further increasing the memory footprint to get better system performance. :::{warning} - Tuning usually has benefits and costs and should only be performed by experienced Linux administrators who understand the impact of tuning decisions on to their system. +Tuning usually has benefits and costs and should only be performed by experienced Linux administrators who understand the impact of tuning decisions on to their system. ::: :::{toctree} From 6118c0ddec856249c75e4fe3ac4f7349b7e4d511 Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Wed, 1 Nov 2023 01:10:39 +1000 Subject: [PATCH 14/23] override non compatible dark mode check css --- docs/_static/css/tabs.css | 72 +++++++++++++++++++++++++++++++++++++++ docs/conf.py | 2 +- 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 docs/_static/css/tabs.css diff --git a/docs/_static/css/tabs.css b/docs/_static/css/tabs.css new file mode 100644 index 00000000..72573c81 --- /dev/null +++ b/docs/_static/css/tabs.css @@ -0,0 +1,72 @@ +.sphinx-tabs { + margin-bottom: 1rem; +} + +[role="tablist"] { + border-bottom: 1px solid #a0b3bf; +} + +.sphinx-tabs-tab { + position: relative; + font-family: Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif; + color: #1D5C87; + line-height: 24px; + margin: 0; + font-size: 16px; + font-weight: 400; + background-color: rgba(255, 255, 255, 0); + border-radius: 5px 5px 0 0; + border: 0; + padding: 1rem 1.5rem; + margin-bottom: 0; +} + +.sphinx-tabs-tab[aria-selected="true"] { + font-weight: 700; + border: 1px solid #a0b3bf; + border-bottom: 1px solid white; + margin: -1px; + background-color: white; +} + +.sphinx-tabs-tab:focus { + z-index: 1; + outline-offset: 1px; +} + +.sphinx-tabs-panel { + position: relative; + padding: 1rem; + border: 1px solid #a0b3bf; + margin: 0px -1px -1px -1px; + border-radius: 0 0 5px 5px; + border-top: 0; + background: white; +} + +.sphinx-tabs-panel.code-tab { + padding: 0.4rem; +} + +.sphinx-tab img { + margin-bottom: 24 px; +} + +/* Dark theme preference styling */ + +@media (prefers-color-scheme: dark) { + .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); + } + + .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); + } + + .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 1px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); + } +} diff --git a/docs/conf.py b/docs/conf.py index 90e05262..78f8c63b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -82,7 +82,7 @@ html_theme = 'sphinx_rtd_theme' # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] -html_css_files = ["css/rtd_dark.css"] +html_css_files = ["css/rtd_dark.css", "css/tabs.css"] # -- Options for HTMLHelp output ------------------------------------------ From 77e5747a2351b77c1a265ab66bb53c8dbda14ba4 Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Wed, 1 Nov 2023 13:15:18 +1000 Subject: [PATCH 15/23] move tox tests to new dependency format --- tox.ini | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tox.ini b/tox.ini index ccb213e7..7ea2153f 100644 --- a/tox.ini +++ b/tox.ini @@ -25,9 +25,7 @@ commands = [testenv:docs] description = invoke sphinx-build to build the HTML docs -basepython = python3.9 -skip_install = True -deps = -r{toxinidir}/docs/requirements.txt -install_command = python -I -m pip install {opts} {packages} +basepython = python3.11 +install_command = pip install -e ".[docs]" -U {opts} {packages} commands = sphinx-build -T -E -b html -d "{toxworkdir}/docs_doctree" -D language=en docs "{toxworkdir}/docs_out" {posargs} From 4d66b7d45695b11712cd11cadaa7d06301655a7a Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Wed, 1 Nov 2023 13:28:32 +1000 Subject: [PATCH 16/23] and gitlab ci update for new docs --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e5a2d353..9eeeeaaf 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -195,7 +195,7 @@ build-test: test-docs: <<: *only-default - image: python:3.10-bullseye + image: python:3.11-bullseye script: - tox -e docs From 004c48b8ade6e959c0825c5fad6f32b0767f7efc Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Wed, 8 Nov 2023 13:45:43 +1000 Subject: [PATCH 17/23] mild formatting changes --- docs/customizing/index.md | 12 ++++++------ docs/development/custom/logging.md | 2 ++ docs/features/core/groups.md | 3 ++- docs/installation/allianceauth.md | 29 +++++++++++++++++++++++++++-- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/docs/customizing/index.md b/docs/customizing/index.md index 0fe4be54..d7cc4e01 100644 --- a/docs/customizing/index.md +++ b/docs/customizing/index.md @@ -3,7 +3,7 @@ It is possible to customize your **Alliance Auth** instance. :::{warning} - Keep in mind that you may need to update some of your customizations manually after new Auth releases (e.g. when replacing templates). +Keep in mind that you may need to update some of your customizations manually after new Auth releases (e.g. when replacing templates). ::: ## Site name @@ -103,11 +103,11 @@ nano /home/allianceserver/myauth/myauth/templates/allianceauth/side-menu.html ``` ```django -
  • - - Google - -
  • +
  • + + Google + +
  • ``` :::{hint} diff --git a/docs/development/custom/logging.md b/docs/development/custom/logging.md index b2526c17..a9c53d70 100644 --- a/docs/development/custom/logging.md +++ b/docs/development/custom/logging.md @@ -37,6 +37,8 @@ Options are: *(all options accept entries of levels listed below them)* * `ERROR` * `CRITICAL` +## allianceauth.services.hooks.get_extension_logger + ```{eval-rst} .. automodule:: allianceauth.services.hooks.get_extension_logger :members: diff --git a/docs/features/core/groups.md b/docs/features/core/groups.md index ced1f32c..ee59264f 100644 --- a/docs/features/core/groups.md +++ b/docs/features/core/groups.md @@ -45,6 +45,7 @@ When a group is restricted only superuser admins can directly add or remove them ```{eval-rst} .. _ref-reserved-group-names: ``` + ## Reserved group names When using Alliance Auth to manage external services like Discord, Auth will automatically duplicate groups on those services. E.g. on Discord Auth will create roles of the same name as groups. However, there may be cases where you want to manage groups on external services by yourself or by another bot. For those cases you can define a list of reserved group names. Auth will ensure that you can not create groups with a reserved name. You will find this list on the admin site under groupmanagement. @@ -100,7 +101,7 @@ GROUPMANAGEMENT_AUTO_LEAVE = True ``` :::{note} - Before you set `GROUPMANAGEMENT_AUTO_LEAVE = True`, make sure there are no pending leave requests, as this option will hide the "Leave Requests" tab. +Before you set `GROUPMANAGEMENT_AUTO_LEAVE = True`, make sure there are no pending leave requests, as this option will hide the "Leave Requests" tab. ::: ## Settings diff --git a/docs/installation/allianceauth.md b/docs/installation/allianceauth.md index 94936785..9f7b622b 100644 --- a/docs/installation/allianceauth.md +++ b/docs/installation/allianceauth.md @@ -79,7 +79,7 @@ sudo apt-get install python3.11 python3.11-dev python3.11-venv ``` ::: -:::{group-tab} CentOS 7, Stream 8, Stream 9 +:::{group-tab} CentOS 7 We need to build Python from source ```bash @@ -93,7 +93,32 @@ sudo make altinstall ``` ::: -:::: +:::{group-tab} CentOS Stream 8 +We need to build Python from source + +```bash +cd ~ +sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget +wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz +tar xvf Python-3.11.5.tgz +cd Python-3.11.5/ +./configure --enable-optimizations --enable-shared +sudo make altinstall +``` + +::: +:::{group-tab} CentOS Stream 9 +We need to build Python from source + +```bash +cd ~ +sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget +wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz +tar xvf Python-3.11.5.tgz +cd Python-3.11.5/ +./configure --enable-optimizations --enable-shared +sudo make altinstall +``` ### Database From 2a9981cdb943efee200948fc513a4e8824ed3ef4 Mon Sep 17 00:00:00 2001 From: Dusty Meg Date: Wed, 8 Nov 2023 13:04:11 +0000 Subject: [PATCH 18/23] Stop renaming discord nick when setting has it disabled --- .../services/modules/discord/auth_hooks.py | 26 +++++++++++-------- .../modules/discord/tests/test_auth_hooks.py | 7 +++++ .../modules/discord/tests/test_integration.py | 2 ++ 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/allianceauth/services/modules/discord/auth_hooks.py b/allianceauth/services/modules/discord/auth_hooks.py index 2d6bd204..4f3af11f 100644 --- a/allianceauth/services/modules/discord/auth_hooks.py +++ b/allianceauth/services/modules/discord/auth_hooks.py @@ -11,6 +11,9 @@ from .models import DiscordUser from .urls import urlpatterns from .utils import LoggerAddTag from . import tasks, __title__ +from .app_settings import ( + DISCORD_SYNC_NAMES +) logger = LoggerAddTag(logging.getLogger(__name__), __title__) @@ -99,17 +102,18 @@ class DiscordService(ServicesHook): return has_perms def sync_nickname(self, user): - logger.debug('Syncing %s nickname for user %s', self.name, user) - if self.user_has_account(user): - tasks.update_nickname.apply_async( - kwargs={ - 'user_pk': user.pk, - # since the new nickname is not yet in the DB we need to - # provide it manually to the task - 'nickname': user_formatted_nick(user) - }, - priority=SINGLE_TASK_PRIORITY - ) + if DISCORD_SYNC_NAMES: + logger.debug('Syncing %s nickname for user %s', self.name, user) + if self.user_has_account(user): + tasks.update_nickname.apply_async( + kwargs={ + 'user_pk': user.pk, + # since the new nickname is not yet in the DB we need to + # provide it manually to the task + 'nickname': user_formatted_nick(user) + }, + priority=SINGLE_TASK_PRIORITY + ) def sync_nicknames_bulk(self, users: list): """Sync nickname for a list of users in bulk. diff --git a/allianceauth/services/modules/discord/tests/test_auth_hooks.py b/allianceauth/services/modules/discord/tests/test_auth_hooks.py index 61c07cbf..0ca60ce5 100644 --- a/allianceauth/services/modules/discord/tests/test_auth_hooks.py +++ b/allianceauth/services/modules/discord/tests/test_auth_hooks.py @@ -81,11 +81,18 @@ class TestDiscordService(NoSocketsTestCase): self.assertFalse(DiscordUser.objects.filter(user=self.none_member).exists()) @patch(MODULE_PATH + '.tasks.update_nickname') + @patch(MODULE_PATH + '.auth_hooks.DISCORD_SYNC_NAMES', True) def test_sync_nickname(self, mock_update_nickname): service = self.service() service.sync_nickname(self.member) self.assertTrue(mock_update_nickname.apply_async.called) + @patch(MODULE_PATH + '.tasks.update_nickname') + def test_sync_nickname_no_setting(self, mock_update_nickname): + service = self.service() + service.sync_nickname(self.member) + self.assertFalse(mock_update_nickname.apply_async.called) + @patch(MODULE_PATH + '.tasks.update_nicknames_bulk') def test_sync_nicknames_bulk(self, mock_update_nicknames_bulk): service = self.service() diff --git a/allianceauth/services/modules/discord/tests/test_integration.py b/allianceauth/services/modules/discord/tests/test_integration.py index 2d50db5e..aae213e9 100644 --- a/allianceauth/services/modules/discord/tests/test_integration.py +++ b/allianceauth/services/modules/discord/tests/test_integration.py @@ -164,6 +164,7 @@ class TestServiceFeatures(TransactionTestCase): self.discord_user = DiscordUser.objects.create(user=self.user, uid=TEST_USER_ID) self.assertTrue(DiscordUser.objects.user_has_account(self.user)) + @patch(MODULE_PATH + '.auth_hooks.DISCORD_SYNC_NAMES', True) def test_when_name_of_main_changes_then_discord_nick_is_updated( self, requests_mocker ): @@ -185,6 +186,7 @@ class TestServiceFeatures(TransactionTestCase): self.assertTrue(nick_updated) self.assertTrue(DiscordUser.objects.user_has_account(self.user)) + @patch(MODULE_PATH + '.auth_hooks.DISCORD_SYNC_NAMES', True) def test_when_name_of_main_changes_and_user_deleted_then_account_is_deleted( self, requests_mocker ): From 2477c31656e2372c08b395ca00f0ffabdd3bf8a8 Mon Sep 17 00:00:00 2001 From: Erik Kalkoken Date: Wed, 8 Nov 2023 13:04:26 +0000 Subject: [PATCH 19/23] Fix leave tab for autoleave --- allianceauth/groupmanagement/models.py | 7 +++---- .../templates/groupmanagement/index.html | 4 ++-- .../groupmanagement/tests/test_views.py | 18 ++++++++++++++++++ allianceauth/groupmanagement/views.py | 13 ++++++++----- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/allianceauth/groupmanagement/models.py b/allianceauth/groupmanagement/models.py index 3ca6b8c6..8491f08f 100644 --- a/allianceauth/groupmanagement/models.py +++ b/allianceauth/groupmanagement/models.py @@ -1,8 +1,7 @@ from typing import Set from django.conf import settings -from django.contrib.auth.models import Group -from django.contrib.auth.models import User +from django.contrib.auth.models import Group, User from django.db import models from django.utils.timezone import now from django.utils.translation import gettext_lazy as _ @@ -14,7 +13,7 @@ from allianceauth.notifications import notify class GroupRequest(models.Model): """Request from a user for joining or leaving a group.""" - leave_request = models.BooleanField(default=0) + leave_request = models.BooleanField(default=False) user = models.ForeignKey(User, on_delete=models.CASCADE) group = models.ForeignKey(Group, on_delete=models.CASCADE) @@ -49,7 +48,7 @@ class RequestLog(models.Model): request_type = models.BooleanField(null=True) group = models.ForeignKey(Group, on_delete=models.CASCADE) request_info = models.CharField(max_length=254) - action = models.BooleanField(default=0) + action = models.BooleanField(default=False) request_actor = models.ForeignKey(User, on_delete=models.CASCADE) date = models.DateTimeField(auto_now_add=True) diff --git a/allianceauth/groupmanagement/templates/groupmanagement/index.html b/allianceauth/groupmanagement/templates/groupmanagement/index.html index 5a383501..c8e7c298 100644 --- a/allianceauth/groupmanagement/templates/groupmanagement/index.html +++ b/allianceauth/groupmanagement/templates/groupmanagement/index.html @@ -29,7 +29,7 @@ - {% if not auto_leave %} + {% if not show_leave_tab %}
  • {% translate "Leave Requests" %} @@ -102,7 +102,7 @@ {% endif %} - {% if not auto_leave %} + {% if not show_leave_tab %}
    {% if leaverequests %}
    diff --git a/allianceauth/groupmanagement/tests/test_views.py b/allianceauth/groupmanagement/tests/test_views.py index e0c9245b..a8bcfe58 100644 --- a/allianceauth/groupmanagement/tests/test_views.py +++ b/allianceauth/groupmanagement/tests/test_views.py @@ -1,6 +1,7 @@ from django.test import RequestFactory, TestCase, override_settings from django.urls import reverse +from allianceauth.groupmanagement.models import Group, GroupRequest from allianceauth.tests.auth_utils import AuthUtils from .. import views @@ -16,6 +17,7 @@ class TestViews(TestCase): self.factory = RequestFactory() self.user = AuthUtils.create_user('Peter Parker') self.user_with_manage_permission = AuthUtils.create_user('Bruce Wayne') + self.group = Group.objects.create(name="Example group") # set permissions AuthUtils.add_permission_to_user_by_name( @@ -83,3 +85,19 @@ class TestViews(TestCase): self.assertEqual(response.status_code, 200) self.assertNotIn('', content) self.assertNotIn('
    ', content) + + @override_settings(GROUPMANAGEMENT_AUTO_LEAVE=True) + def test_should_not_hide_leave_requests_tab_when_there_are_open_requests(self): + # given + request = self.factory.get(reverse('groupmanagement:management')) + request.user = self.user_with_manage_permission + GroupRequest.objects.create(user=self.user, group=self.group, leave_request=True) + + # when + response = views.group_management(request) + + # then + content = response_content_to_str(response) + self.assertEqual(response.status_code, 200) + self.assertIn('', content) + self.assertIn('
    ', content) diff --git a/allianceauth/groupmanagement/views.py b/allianceauth/groupmanagement/views.py index 8ab1af22..13fe33bc 100644 --- a/allianceauth/groupmanagement/views.py +++ b/allianceauth/groupmanagement/views.py @@ -2,13 +2,12 @@ import logging from django.conf import settings from django.contrib import messages -from django.contrib.auth.decorators import login_required -from django.contrib.auth.decorators import user_passes_test +from django.contrib.auth.decorators import login_required, user_passes_test from django.contrib.auth.models import Group from django.core.exceptions import ObjectDoesNotExist, PermissionDenied from django.db.models import Count from django.http import Http404 -from django.shortcuts import render, redirect, get_object_or_404 +from django.shortcuts import get_object_or_404, redirect, render from django.utils.translation import gettext_lazy as _ from allianceauth.notifications import notify @@ -16,7 +15,6 @@ from allianceauth.notifications import notify from .managers import GroupManager from .models import GroupRequest, RequestLog - logger = logging.getLogger(__name__) @@ -45,10 +43,15 @@ def group_management(request): logger.debug("Providing user {} with {} acceptrequests and {} leaverequests.".format( request.user, len(acceptrequests), len(leaverequests))) + show_leave_tab = ( + getattr(settings, 'GROUPMANAGEMENT_AUTO_LEAVE', False) + and not GroupRequest.objects.filter(leave_request=True).exists() + ) + render_items = { 'acceptrequests': acceptrequests, 'leaverequests': leaverequests, - 'auto_leave': getattr(settings, 'GROUPMANAGEMENT_AUTO_LEAVE', False), + 'show_leave_tab': show_leave_tab, } return render(request, 'groupmanagement/index.html', context=render_items) From 3480c4e0e81dcc30e951e2f657429a15cdb60ffe Mon Sep 17 00:00:00 2001 From: Erik Kalkoken Date: Wed, 8 Nov 2023 13:05:24 +0000 Subject: [PATCH 20/23] New Feature: Assign/remove users on group form --- allianceauth/groupmanagement/forms.py | 39 ++++++- .../groupmanagement/tests/test_admin.py | 110 +++++++++++++++--- 2 files changed, 130 insertions(+), 19 deletions(-) diff --git a/allianceauth/groupmanagement/forms.py b/allianceauth/groupmanagement/forms.py index 1214a7c2..73230c4e 100644 --- a/allianceauth/groupmanagement/forms.py +++ b/allianceauth/groupmanagement/forms.py @@ -1,6 +1,10 @@ +import functools + from django import forms -from django.contrib.auth.models import Group +from django.contrib.admin.widgets import FilteredSelectMultiple +from django.contrib.auth.models import Group, User from django.core.exceptions import ValidationError +from django.db.models.functions import Lower from django.utils.timezone import now from django.utils.translation import gettext_lazy as _ @@ -8,6 +12,39 @@ from .models import ReservedGroupName class GroupAdminForm(forms.ModelForm): + users = forms.ModelMultipleChoiceField( + queryset=User.objects.order_by(Lower('username')), + required=False, + widget=FilteredSelectMultiple(verbose_name=_("Users"), is_stacked=False), + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + if self.instance and self.instance.pk: + self.fields["users"].initial = self.instance.user_set.all() + + def save(self, commit=True): + group: Group = super().save(commit=False) + + if commit: + group.save() + + users = self.cleaned_data["users"] + if group.pk: + self._save_m2m_and_users(group, users) + else: + self.save_m2m = functools.partial( + self._save_m2m_and_users, group=group, users=users + ) + + return group + + def _save_m2m_and_users(self, group, users): + """Save m2m relations incl. users.""" + group.user_set.set(users) + self._save_m2m() + def clean_name(self): my_name = self.cleaned_data['name'] if ReservedGroupName.objects.filter(name__iexact=my_name).exists(): diff --git a/allianceauth/groupmanagement/tests/test_admin.py b/allianceauth/groupmanagement/tests/test_admin.py index 3873fe4c..3b9605a1 100644 --- a/allianceauth/groupmanagement/tests/test_admin.py +++ b/allianceauth/groupmanagement/tests/test_admin.py @@ -6,22 +6,22 @@ from django.conf import settings from django.contrib import admin from django.contrib.admin.sites import AdminSite from django.contrib.auth.models import User -from django.test import TestCase, RequestFactory, Client, override_settings +from django.test import Client, RequestFactory, TestCase, override_settings from allianceauth.authentication.models import CharacterOwnership, State from allianceauth.eveonline.models import ( - EveCharacter, EveCorporationInfo, EveAllianceInfo + EveAllianceInfo, EveCharacter, EveCorporationInfo, ) from allianceauth.tests.auth_utils import AuthUtils -from . import get_admin_change_view_url -from ..admin import HasLeaderFilter, GroupAdmin, Group +from ..admin import Group, GroupAdmin, HasLeaderFilter from ..models import ReservedGroupName - +from . import get_admin_change_view_url if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS: _has_auto_groups = True from allianceauth.eveonline.autogroups.models import AutogroupsConfig + from ..admin import IsAutoGroupFilter else: _has_auto_groups = False @@ -621,21 +621,16 @@ class TestGroupAdmin2(TestCase): response = self.client.post( f"/admin/groupmanagement/group/{group.pk}/change/", data={ - "name": f"{group.name}", - "authgroup-TOTAL_FORMS": "1", - "authgroup-INITIAL_FORMS": "1", - "authgroup-MIN_NUM_FORMS": "0", - "authgroup-MAX_NUM_FORMS": "1", - "authgroup-0-description": "", - "authgroup-0-states": f"{member_state.pk}", + "name": group.name, + "users": [user_member.pk, user_guest.pk], + "authgroup-TOTAL_FORMS": 1, + "authgroup-INITIAL_FORMS": 1, + "authgroup-MIN_NUM_FORMS": 0, + "authgroup-MAX_NUM_FORMS": 1, + "authgroup-0-states": member_state.pk, "authgroup-0-internal": "on", "authgroup-0-hidden": "on", - "authgroup-0-group": f"{group.pk}", - "authgroup-__prefix__-description": "", - "authgroup-__prefix__-internal": "on", - "authgroup-__prefix__-hidden": "on", - "authgroup-__prefix__-group": f"{group.pk}", - "_save": "Save" + "authgroup-0-group": group.pk, } ) # then @@ -644,6 +639,85 @@ class TestGroupAdmin2(TestCase): self.assertIn(group, user_member.groups.all()) self.assertNotIn(group, user_guest.groups.all()) + def test_should_add_user_to_existing_group(self): + # given + user_bruce = AuthUtils.create_user("Bruce Wayne") + user_lex = AuthUtils.create_user("Lex Luthor") + group = Group.objects.create(name="dummy") + user_bruce.groups.add(group) + self.client.force_login(self.superuser) + # when + response = self.client.post( + f"/admin/groupmanagement/group/{group.pk}/change/", + data={ + "name": group.name, + "users": [user_bruce.pk, user_lex.pk], + "authgroup-TOTAL_FORMS": 1, + "authgroup-INITIAL_FORMS": 1, + "authgroup-MIN_NUM_FORMS": 0, + "authgroup-MAX_NUM_FORMS": 1, + "authgroup-0-internal": "on", + "authgroup-0-hidden": "on", + "authgroup-0-group": group.pk, + } + ) + # then + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, "/admin/groupmanagement/group/") + self.assertIn(group, user_bruce.groups.all()) + self.assertIn(group, user_lex.groups.all()) + + def test_should_remove_user_from_existing_group(self): + # given + user_bruce = AuthUtils.create_user("Bruce Wayne") + user_lex = AuthUtils.create_user("Lex Luthor") + group = Group.objects.create(name="dummy") + user_bruce.groups.add(group) + user_lex.groups.add(group) + self.client.force_login(self.superuser) + # when + response = self.client.post( + f"/admin/groupmanagement/group/{group.pk}/change/", + data={ + "name": group.name, + "users": user_bruce.pk, + "authgroup-TOTAL_FORMS": 1, + "authgroup-INITIAL_FORMS": 1, + "authgroup-MIN_NUM_FORMS": 0, + "authgroup-MAX_NUM_FORMS": 1, + "authgroup-0-internal": "on", + "authgroup-0-hidden": "on", + "authgroup-0-group": group.pk, + } + ) + # then + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, "/admin/groupmanagement/group/") + self.assertIn(group, user_bruce.groups.all()) + self.assertNotIn(group, user_lex.groups.all()) + + def test_should_include_user_when_creating_group(self): + # given + user_bruce = AuthUtils.create_user("Bruce Wayne") + self.client.force_login(self.superuser) + # when + response = self.client.post( + "/admin/groupmanagement/group/add/", + data={ + "name": "new group", + "users": user_bruce.pk, + "authgroup-TOTAL_FORMS": 1, + "authgroup-INITIAL_FORMS": 0, + "authgroup-MIN_NUM_FORMS": 0, + "authgroup-MAX_NUM_FORMS": 1, + } + ) + # then + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, "/admin/groupmanagement/group/") + group = Group.objects.get(name="new group") + self.assertIn(group, user_bruce.groups.all()) + class TestReservedGroupNameAdmin(TestCase): @classmethod From e5d29629a5763ce08dfb97fe5648566b2a197814 Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Wed, 8 Nov 2023 13:48:26 +0000 Subject: [PATCH 21/23] Update from Transifex --- .tx/config | 2 +- .tx/config_20230406134150.bak | 10 - .tx/transifex.yml | 10 + allianceauth/locale/de/LC_MESSAGES/django.po | 171 ++--- allianceauth/locale/es/LC_MESSAGES/django.po | 10 +- .../locale/fr_FR/LC_MESSAGES/django.po | 18 +- .../locale/it_IT/LC_MESSAGES/django.po | 583 ++++++++++-------- allianceauth/locale/ja/LC_MESSAGES/django.po | 7 +- .../locale/ko_KR/LC_MESSAGES/django.po | 18 +- allianceauth/locale/ru/LC_MESSAGES/django.po | 8 +- allianceauth/locale/uk/LC_MESSAGES/django.po | 60 +- .../locale/zh_Hans/LC_MESSAGES/django.po | 55 +- 12 files changed, 500 insertions(+), 452 deletions(-) delete mode 100644 .tx/config_20230406134150.bak create mode 100644 .tx/transifex.yml diff --git a/.tx/config b/.tx/config index 102c800f..6a041df7 100644 --- a/.tx/config +++ b/.tx/config @@ -1,5 +1,5 @@ [main] -host = https://www.transifex.com +host = https://app.transifex.com lang_map = zh-Hans: zh_Hans [o:alliance-auth:p:alliance-auth:r:django-po] diff --git a/.tx/config_20230406134150.bak b/.tx/config_20230406134150.bak deleted file mode 100644 index b3c32185..00000000 --- a/.tx/config_20230406134150.bak +++ /dev/null @@ -1,10 +0,0 @@ -[main] -host = https://www.transifex.com -lang_map = zh-Hans:zh_Hans - -[alliance-auth.django-po] -file_filter = allianceauth/locale//LC_MESSAGES/django.po -minimum_perc = 0 -source_file = allianceauth/locale/en/LC_MESSAGES/django.po -source_lang = en -type = PO diff --git a/.tx/transifex.yml b/.tx/transifex.yml new file mode 100644 index 00000000..26a515d5 --- /dev/null +++ b/.tx/transifex.yml @@ -0,0 +1,10 @@ +filters: + - filter_type: file + file_format: PO + source_file: allianceauth/locale/en/LC_MESSAGES/django.po + source_language: en + translation_files_expression: allianceauth/locale//LC_MESSAGES/django.po + +settings: + language_mapping: + zh-Hans: zh_Hans diff --git a/allianceauth/locale/de/LC_MESSAGES/django.po b/allianceauth/locale/de/LC_MESSAGES/django.po index 9dfe0130..edf00a0b 100644 --- a/allianceauth/locale/de/LC_MESSAGES/django.po +++ b/allianceauth/locale/de/LC_MESSAGES/django.po @@ -4,9 +4,9 @@ # FIRST AUTHOR , YEAR. # # Translators: -# Erik Kalkoken , 2020 -# Joel Falknau , 2021 -# Peter Pfeufer, 2022 +# Erik Kalkoken , 2023 +# Joel Falknau , 2023 +# Peter Pfeufer, 2023 # #, fuzzy msgid "" @@ -14,8 +14,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-10-09 18:20+1000\n" -"PO-Revision-Date: 2020-02-18 03:14+0000\n" -"Last-Translator: Peter Pfeufer, 2022\n" +"PO-Revision-Date: 2023-10-08 09:23+0000\n" +"Last-Translator: Peter Pfeufer, 2023\n" "Language-Team: German (https://app.transifex.com/alliance-auth/teams/107430/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -34,7 +34,8 @@ msgstr "Google Analytics V4" #: allianceauth/authentication/decorators.py:37 msgid "A main character is required to perform that action. Add one below." msgstr "" -"Für diese Aktion wird ein Hauptcharacter benötigt. Bitte füge einen hinzu." +"Zur Ausführung dieser Aktion ist ein Hauptcharakter erforderlich. Füge unten" +" einen hinzu." #: allianceauth/authentication/forms.py:12 msgid "Email" @@ -131,7 +132,7 @@ msgstr "Hauptcharakter ändern" #: allianceauth/authentication/templates/authentication/dashboard.html:125 msgid "Group Memberships" -msgstr "Gruppen" +msgstr "Gruppenmitgliedschaften" #: allianceauth/authentication/templates/authentication/dashboard.html:145 #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticscorpview.html:21 @@ -206,7 +207,7 @@ msgstr "" #: allianceauth/authentication/views.py:83 #, python-format msgid "Changed main character to %(char)s" -msgstr "Haupcharakter geändert zu %(char)s" +msgstr "Haupcharakter zu %(char)s geändert" #: allianceauth/authentication/views.py:92 #, python-format @@ -233,13 +234,12 @@ msgid "" "Sent confirmation email. Please follow the link to confirm your email " "address." msgstr "" -"Bestätigungsmail gesendet. Bitte folge dem Link in der E-Mail zur " -"Bestätigung." +"Bestätigungs-E-Mail gesendet. Bitte folge dem Link, um Deine E-Mail-Adresse " +"zu bestätigen." #: allianceauth/authentication/views.py:257 msgid "Confirmed your email address. Please login to continue." -msgstr "" -"Deine E-Mail Adresse wurde bestätigt. Bitte log Dich ein um fortzufahren." +msgstr "Deine E-Mail Adresse wurde bestätigt. Bitte einloggen zum Fortfahren." #: allianceauth/authentication/views.py:262 msgid "Registration of new accounts is not allowed at this time." @@ -274,7 +274,7 @@ msgstr "Hauptcharaktere" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:22 #: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:14 msgid "Members" -msgstr "Mitgliederzahl" +msgstr "Mitglieder" #: allianceauth/corputils/templates/corputils/corpstats.html:35 msgid "Unregistered" @@ -282,7 +282,7 @@ msgstr "Nicht registriert" #: allianceauth/corputils/templates/corputils/corpstats.html:38 msgid "Last update:" -msgstr "Letzes Update:" +msgstr "Letzte Aktualisierung:" #: allianceauth/corputils/templates/corputils/corpstats.html:74 #: allianceauth/corputils/templates/corputils/corpstats.html:112 @@ -382,11 +382,11 @@ msgstr "Charakter nicht registriert!" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html:19 msgid "This character is not associated with an auth account." -msgstr "Dieser Charakter ist mit keinen Auth Konto verbunden." +msgstr "Dieser Charakter ist keinem Auth Konto zugeordnet." #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html:19 msgid "Add it here" -msgstr "Füge es hier hinzu" +msgstr "Füge ihn hier hinzu" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html:19 msgid "before attempting to click fleet attendance links." @@ -394,7 +394,7 @@ msgstr "bevor Du versuchst auf FAT-Links zu klicken." #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html:5 msgid "Create Fatlink" -msgstr "Erstelle FAT-Link" +msgstr "FAT-Link erstellen" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html:9 #: allianceauth/optimer/templates/optimer/add.html:13 @@ -409,20 +409,20 @@ msgstr "Fehlerhafte Anfrage!" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html:24 #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:63 msgid "Create fatlink" -msgstr "Erstelle FAT-Link" +msgstr "FAT-Link erstellen" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:3 #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:4 msgid "Fatlink view" -msgstr "FAT-Link sehen" +msgstr "FAT-Link ansehen" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:7 msgid "Edit fatlink" -msgstr "Editiere FAT-Link" +msgstr "FAT-Link bearbeiten" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:11 msgid "Delete fat" -msgstr "Lösche FAT" +msgstr "FAT löschen" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:17 msgid "Registered characters" @@ -497,7 +497,7 @@ msgstr[1] "%(user)s hat diesen Monat %(links)s FAT-Links eingesammelt." #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html:26 msgid "Times used" -msgstr "male genutzt" +msgstr "Wie oft genutzt" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html:37 #, python-format @@ -570,7 +570,7 @@ msgstr "FAT-Link Statistik" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:20 msgid "Ticker" -msgstr "Ticker: " +msgstr "Ticker" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:8 msgid "Participation data" @@ -594,7 +594,7 @@ msgstr "Letzter FAT-Link" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:58 msgid "View statistics" -msgstr "Statistik" +msgstr "Statistiken ansehen" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:95 msgid "No created fatlinks on record." @@ -713,8 +713,8 @@ msgid "" "States listed here will have the ability to join this group provided they " "have the proper permissions.
    " msgstr "" -"Hier gelistete Ränge können dieser Gruppe beitreten, vorausgesetzt sie haben" -" die entsprechenden Berechtigungen.
    " +"Die hier aufgeführten Status können dieser Gruppe beitreten, sofern sie über" +" die entsprechenden Berechtigungen verfügen.
    " #: allianceauth/groupmanagement/models.py:171 msgid "" @@ -814,7 +814,7 @@ msgstr "Gruppenmitglieder" #: allianceauth/groupmanagement/templates/groupmanagement/index.html:113 #: allianceauth/permissions_tool/templates/permissions_tool/audit.html:21 msgid "Organization" -msgstr "Organization" +msgstr "Organisation" #: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:49 #: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:75 @@ -933,18 +933,18 @@ msgstr "Gruppenverwaltung" #: allianceauth/groupmanagement/templates/groupmanagement/index.html:24 msgid "Join Requests" -msgstr "Beitrittsgesuche" +msgstr "Beitrittsanfragen" #: allianceauth/groupmanagement/templates/groupmanagement/index.html:35 msgid "Leave Requests" -msgstr "Austrittsgesuche" +msgstr "Austrittsanfragen" #: allianceauth/groupmanagement/templates/groupmanagement/index.html:57 #: allianceauth/groupmanagement/templates/groupmanagement/index.html:114 #: allianceauth/permissions_tool/templates/permissions_tool/audit.html:18 #: allianceauth/services/modules/openfire/forms.py:6 msgid "Group" -msgstr "Gruppen" +msgstr "Gruppe" #: allianceauth/groupmanagement/templates/groupmanagement/index.html:88 #: allianceauth/groupmanagement/templates/groupmanagement/index.html:145 @@ -968,7 +968,7 @@ msgstr "Keine Gruppenaustrittsanfragen" #: allianceauth/groupmanagement/templates/groupmanagement/menu.html:8 #: allianceauth/templates/allianceauth/top-menu.html:8 msgid "Toggle navigation" -msgstr "Toggle Navigation" +msgstr "Navigation umschalten" #: allianceauth/groupmanagement/templates/groupmanagement/menu.html:19 msgid "Group Requests" @@ -994,7 +994,7 @@ msgstr "Gruppe existiert nicht" #: allianceauth/groupmanagement/views.py:195 #, python-format msgid "Accepted application from %(mainchar)s to %(group)s." -msgstr "Beitrittsgesuch von %(mainchar)s zur Gruppe %(group)s zugestimmt." +msgstr "Beitrittsanfrage von %(mainchar)s zur Gruppe %(group)s akzeptiert." #: allianceauth/groupmanagement/views.py:201 #: allianceauth/groupmanagement/views.py:232 @@ -1003,18 +1003,18 @@ msgid "" "An unhandled error occurred while processing the application from " "%(mainchar)s to %(group)s." msgstr "" -"Bei der Bearbeitung des Beitrittsgesuchs von %(mainchar)s zur Gruppe " +"Bei der Bearbeitung des Beitrittsanfrage von %(mainchar)s zur Gruppe " "%(group)s ist ein unbehandelter Fehler aufgetreten." #: allianceauth/groupmanagement/views.py:226 #, python-format msgid "Rejected application from %(mainchar)s to %(group)s." -msgstr "Beitrittsgesuch von %(mainchar)s zur Gruppe %(group)s abgelehnt." +msgstr "Beitrittsanfrage von %(mainchar)s zur Gruppe %(group)s abgelehnt." #: allianceauth/groupmanagement/views.py:261 #, python-format msgid "Accepted application from %(mainchar)s to leave %(group)s." -msgstr "Austrittsgesuch von %(mainchar)s für Gruppe %(group)s akzeptiert." +msgstr "Austrittsanfrage von %(mainchar)s für Gruppe %(group)s akzeptiert." #: allianceauth/groupmanagement/views.py:266 #: allianceauth/groupmanagement/views.py:298 @@ -1023,13 +1023,13 @@ msgid "" "An unhandled error occurred while processing the application from " "%(mainchar)s to leave %(group)s." msgstr "" -"Bei der Bearbeitung des Austrittsgesuchs von %(mainchar)s für Gruppe " +"Bei der Bearbeitung des Austrittsanfrage von %(mainchar)s für Gruppe " "%(group)s ist ein unbehandelter Fehler aufgetreten." #: allianceauth/groupmanagement/views.py:292 #, python-format msgid "Rejected application from %(mainchar)s to leave %(group)s." -msgstr "Austrittsgesuch von %(mainchar)s für Gruppe %(group)s abgelehnt." +msgstr "Austrittsanfrage von %(mainchar)s für Gruppe %(group)s abgelehnt." #: allianceauth/groupmanagement/views.py:336 #: allianceauth/groupmanagement/views.py:346 @@ -1042,7 +1042,7 @@ msgstr "Du bist bereits Mitglied dieser Gruppe." #: allianceauth/groupmanagement/views.py:358 msgid "You already have a pending application for that group." -msgstr "Du hast Dich bereits für diese Gruppe beworben." +msgstr "Du hast bereits für diese Gruppe angefragt." #: allianceauth/groupmanagement/views.py:367 #, python-format @@ -1059,12 +1059,12 @@ msgstr "Du bist kein Mitglied dieser Gruppe" #: allianceauth/groupmanagement/views.py:393 msgid "You already have a pending leave request for that group." -msgstr "Du hast bereits ein ausstehendes Austrittsgesuch für diese Gruppe." +msgstr "Du hast bereits eine ausstehendes Austrittsanfrage für diese Gruppe." #: allianceauth/groupmanagement/views.py:409 #, python-format msgid "Applied to leave group %(group)s." -msgstr "Austrittsgesuch für Gruppe %(group)s gesendet." +msgstr "Austrittsanfrage für Gruppe %(group)s gesendet." #: allianceauth/hrapplications/auth_hooks.py:14 msgid "Applications" @@ -1086,11 +1086,11 @@ msgstr "Wähle eine Corporation" #: allianceauth/hrapplications/templates/hrapplications/corpchoice.html:10 msgid "Available Corps" -msgstr "Zur Auswahl stehende Corporations" +msgstr "Verfügbare Corporationen" #: allianceauth/hrapplications/templates/hrapplications/corpchoice.html:22 msgid "No corps are accepting applications at this time." -msgstr "Zur Zeit nimmt keine Corp Bewerbungen entgegen." +msgstr "Zur Zeit nimmt keine Corp Bewerbungen an." #: allianceauth/hrapplications/templates/hrapplications/create.html:4 #: allianceauth/hrapplications/templates/hrapplications/create.html:7 @@ -1186,7 +1186,7 @@ msgstr "Keine angesehenen Bewerbungen" #: allianceauth/hrapplications/templates/hrapplications/searchview.html:62 #: allianceauth/hrapplications/templates/hrapplications/view.html:134 msgid "Close" -msgstr "Geschlossen" +msgstr "Schließen" #: allianceauth/hrapplications/templates/hrapplications/management.html:177 #: allianceauth/hrapplications/templates/hrapplications/searchview.html:63 @@ -1200,7 +1200,7 @@ msgstr "Suche" #: allianceauth/hrapplications/templates/hrapplications/searchview.html:11 msgid "Application Search Results" -msgstr "Bewerbungen Suchergebnisse" +msgstr "Ergebnisse der Bewerbungssuche" #: allianceauth/hrapplications/templates/hrapplications/searchview.html:22 msgid "Application ID" @@ -1342,12 +1342,12 @@ msgstr "Operationsart" #: allianceauth/optimer/form.py:17 #: allianceauth/srp/templates/srp/management.html:38 msgid "Fleet Commander" -msgstr "Flottenkommandeur" +msgstr "Flottenkommandant" #: allianceauth/optimer/form.py:22 allianceauth/srp/form.py:14 #: allianceauth/srp/templates/srp/data.html:91 msgid "Additional Info" -msgstr "Zusätzliche Info" +msgstr "Zusätzliche Informationen" #: allianceauth/optimer/form.py:23 msgid "(Optional) Describe the operation with a couple of short words." @@ -1360,7 +1360,7 @@ msgstr "Operation erstellen" #: allianceauth/optimer/templates/optimer/fleetoptable.html:12 msgid "Form Up System" -msgstr "Form Up System" +msgstr "Startsystem" #: allianceauth/optimer/templates/optimer/fleetoptable.html:14 #: allianceauth/timerboard/templates/timerboard/view.html:36 @@ -1384,20 +1384,20 @@ msgstr "Flottenoperationen Zeiten" #: allianceauth/optimer/templates/optimer/management.html:20 #: allianceauth/timerboard/templates/timerboard/view.html:22 msgid "Current Eve Time:" -msgstr "Momentane Eve Zeit" +msgstr "Aktuelle Eve Zeit" #: allianceauth/optimer/templates/optimer/management.html:26 msgid "Next Fleet Operations" -msgstr "Anstehende Flottenoperationen" +msgstr "Anstehende Flotten" #: allianceauth/optimer/templates/optimer/management.html:30 #: allianceauth/timerboard/templates/timerboard/view.html:362 msgid "No upcoming timers." -msgstr "Keine kommenden Timer." +msgstr "Keine bevorstehenden Timer." #: allianceauth/optimer/templates/optimer/management.html:33 msgid "Past Fleet Operations" -msgstr "Vergangene Flottenoperationen" +msgstr "Vergangene Flotten" #: allianceauth/optimer/templates/optimer/management.html:37 #: allianceauth/timerboard/templates/timerboard/view.html:535 @@ -1408,7 +1408,7 @@ msgstr "Keine vergangenen Timer." #: allianceauth/optimer/templates/optimer/update.html:15 #: allianceauth/optimer/templates/optimer/update.html:27 msgid "Update Fleet Operation" -msgstr "Aktualisiere Flottenoperationen" +msgstr "Aktualisiere Flottenoperation" #: allianceauth/optimer/templates/optimer/update.html:21 msgid "Fleet Operation Does Not Exist" @@ -1432,7 +1432,7 @@ msgstr "Änderungen für Operation timer %(opname)s gespeichert." #: allianceauth/permissions_tool/templates/permissions_tool/audit.html:4 #: allianceauth/permissions_tool/templates/permissions_tool/audit.html:8 msgid "Permissions Audit" -msgstr "Berechtigungsübersicht" +msgstr "Berechtigungsprüfung" #: allianceauth/permissions_tool/templates/permissions_tool/audit.html:20 msgid "User / Character" @@ -1494,11 +1494,11 @@ msgstr "Dienste" #: allianceauth/services/forms.py:6 msgid "Name of Fleet:" -msgstr "SRP Flotte erstellen:" +msgstr "Name der Flotte:" #: allianceauth/services/forms.py:7 msgid "Fleet Commander:" -msgstr "Flottenkommandeur:" +msgstr "Flottenkommandant:" #: allianceauth/services/forms.py:8 msgid "Fleet Comms:" @@ -1514,11 +1514,11 @@ msgstr "Schiffspriorität:" #: allianceauth/services/forms.py:11 msgid "Formup Location:" -msgstr "Formup Location:" +msgstr "Startsystem:" #: allianceauth/services/forms.py:12 msgid "Formup Time:" -msgstr "Formup Zeit:" +msgstr "Startzeit:" #: allianceauth/services/forms.py:13 msgid "Expected Duration:" @@ -1530,7 +1530,7 @@ msgstr "Grund:" #: allianceauth/services/forms.py:15 msgid "Reimbursable?*" -msgstr "Erstattungsfähig?" +msgstr "Erstattungsfähig?*" #: allianceauth/services/forms.py:15 allianceauth/services/forms.py:16 msgid "Yes" @@ -1542,7 +1542,7 @@ msgstr "Nein" #: allianceauth/services/forms.py:16 msgid "Important?*" -msgstr "Wichtig?" +msgstr "Wichtig?*" #: allianceauth/services/forms.py:21 allianceauth/services/forms.py:31 msgid "Password" @@ -1550,7 +1550,7 @@ msgstr "Passwort" #: allianceauth/services/forms.py:26 allianceauth/services/forms.py:36 msgid "Password must be at least 8 characters long." -msgstr "Passwort muss mindestens 8 Zeichen lang sein" +msgstr "Das Passwort muss mindestens 8 Zeichen lang sein" #: allianceauth/services/modules/discord/models.py:187 msgid "Discord Account Disabled" @@ -1591,7 +1591,7 @@ msgstr "Discord Konto deaktiviert." #: allianceauth/services/modules/discord/views.py:36 #: allianceauth/services/modules/discord/views.py:59 msgid "An error occurred while processing your Discord account." -msgstr "Es gab einen Fehler bei der Verarbeitung Deines Discord Kontos." +msgstr "Es gab einen Fehler während der Verarbeitung Deines Discord Kontos." #: allianceauth/services/modules/discord/views.py:102 msgid "Your Discord account has been successfully activated." @@ -1607,7 +1607,7 @@ msgstr "" #: allianceauth/services/modules/discourse/views.py:29 msgid "You are not authorized to access Discourse." -msgstr "Du bist nicht autorisiert auf Discorse zuzugreifen." +msgstr "Du bist nicht autorisiert auf Discourse zuzugreifen." #: allianceauth/services/modules/discourse/views.py:34 msgid "You must have a main character set to access Discourse." @@ -1619,14 +1619,14 @@ msgid "" "No SSO payload or signature. Please contact support if this problem " "persists." msgstr "" -"Keine SSO-Nutzdaten oder Signaturen. Bitte wenden Sie sich an den Support, " -"wenn das Problem weiterhin besteht." +"Keine SSO-Nutzdaten oder Signaturen. Bitte wende Dich an den Support, wenn " +"das Problem weiterhin besteht." #: allianceauth/services/modules/discourse/views.py:54 #: allianceauth/services/modules/discourse/views.py:62 msgid "Invalid payload. Please contact support if this problem persists." msgstr "" -"Ungültige Nutzdaten. Bitte wenden Sie sich an den Support, wenn das Problem " +"Ungültige Nutzdaten. Bitte wenden Dich an den Support, wenn das Problem " "weiterhin besteht." #: allianceauth/services/modules/ips4/views.py:31 @@ -1638,7 +1638,7 @@ msgstr "IP4Suite Konto aktiviert." #: allianceauth/services/modules/ips4/views.py:81 #: allianceauth/services/modules/ips4/views.py:101 msgid "An error occurred while processing your IPSuite4 account." -msgstr "Es gab einen Fehler bei der Verarbeitung Deines IPSuite4 Kontos." +msgstr "Es gab einen Fehler während der Verarbeitung Deines IPSuite4 Kontos." #: allianceauth/services/modules/ips4/views.py:52 msgid "Reset IPSuite4 password." @@ -1660,7 +1660,7 @@ msgstr "Jabber" #: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:5 #: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:10 msgid "Jabber Broadcast" -msgstr "Jabber Übertragung" +msgstr "Jabber Ankündigung" #: allianceauth/services/modules/openfire/auth_hooks.py:94 msgid "Fleet Broadcast Formatter" @@ -1672,11 +1672,11 @@ msgstr "Nachricht" #: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:16 msgid "Broadcast Sent!!" -msgstr "Übertragung gesendet!!" +msgstr "Ankündigung gesendet!!" #: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:22 msgid "Broadcast" -msgstr "Übertragungen" +msgstr "Ankündigung" #: allianceauth/services/modules/openfire/views.py:35 msgid "Activated jabber account." @@ -1687,7 +1687,7 @@ msgstr "Jabber Konto aktiviert." #: allianceauth/services/modules/openfire/views.py:76 #: allianceauth/services/modules/openfire/views.py:147 msgid "An error occurred while processing your jabber account." -msgstr "Es gab einen Fehler bei der Verarbeitung Deines Jabber Kontos." +msgstr "Es gab einen Fehler während der Verarbeitung Deines Jabber Kontos." #: allianceauth/services/modules/openfire/views.py:69 msgid "Reset jabber password." @@ -1696,7 +1696,7 @@ msgstr "Jabber Passwort zurücksetzen." #: allianceauth/services/modules/openfire/views.py:115 #, python-format msgid "Sent jabber broadcast to %s" -msgstr "Sende Jabber Durchsage an %s" +msgstr "Sende Jabber Ankündigung an %s" #: allianceauth/services/modules/openfire/views.py:144 msgid "Set jabber password." @@ -1711,7 +1711,7 @@ msgstr "Forum Konto aktiviert." #: allianceauth/services/modules/phpbb3/views.py:78 #: allianceauth/services/modules/phpbb3/views.py:101 msgid "An error occurred while processing your forum account." -msgstr "Es gab einen Fehler bei der Verarbeitung Deines Forum Kontos." +msgstr "Es gab einen Fehler während der Verarbeitung Deines Forum Kontos." #: allianceauth/services/modules/phpbb3/views.py:53 msgid "Deactivated forum account." @@ -1734,7 +1734,7 @@ msgstr "SMF Konto aktiviert." #: allianceauth/services/modules/smf/views.py:102 #: allianceauth/services/modules/smf/views.py:124 msgid "An error occurred while processing your SMF account." -msgstr "Es gab einen Fehler bei der Verarbeitung Deines SMF Kontos." +msgstr "Es gab einen Fehler während der Verarbeitung Deines SMF Kontos." #: allianceauth/services/modules/smf/views.py:78 msgid "Deactivated SMF account." @@ -1751,7 +1751,7 @@ msgstr "Setze SMF Passwort." #: allianceauth/services/modules/teamspeak3/forms.py:14 #, python-format msgid "Unable to locate user %s on server" -msgstr "Kann den Benutzer %s auf dem Server nicht finden" +msgstr "Der Benutzer %s konnte auf dem Server nicht gefunden werden" #: allianceauth/services/modules/teamspeak3/templates/admin/teamspeak3/authts/change_list.html:8 msgid "Update TS3 groups" @@ -1783,7 +1783,8 @@ msgstr "TeamSpeak3 Konto aktiviert." #: allianceauth/services/modules/teamspeak3/views.py:74 #: allianceauth/services/modules/teamspeak3/views.py:100 msgid "An error occurred while processing your TeamSpeak3 account." -msgstr "Es gab einen Fehler bei der Verarbeitung Deines TeamSpeak3 Kontos." +msgstr "" +"Es gab einen Fehler während der Verarbeitung Deines TeamSpeak3 Kontos." #: allianceauth/services/modules/teamspeak3/views.py:71 msgid "Deactivated TeamSpeak3 account." @@ -1802,7 +1803,7 @@ msgstr "XenForo Konto aktiviert." #: allianceauth/services/modules/xenforo/views.py:73 #: allianceauth/services/modules/xenforo/views.py:94 msgid "An error occurred while processing your XenForo account." -msgstr "Es gab einen Fehler bei der Verarbeitung Deines XenForo Kontos." +msgstr "Es gab einen Fehler während der Verarbeitung Deines XenForo Kontos." #: allianceauth/services/modules/xenforo/views.py:50 msgid "Deactivated XenForo account." @@ -1832,7 +1833,7 @@ msgstr "Formatieren" #: allianceauth/services/templates/services/service_confirm_delete.html:12 #, python-format msgid "Delete %(service_name)s Account?" -msgstr "Konto %(service_name)s löschen?" +msgstr " %(service_name)s Konto löschen?" #: allianceauth/services/templates/services/service_confirm_delete.html:20 #, python-format @@ -1856,7 +1857,7 @@ msgstr "%(service_name)s Passwort ändern" #: allianceauth/services/templates/services/service_password.html:9 #, python-format msgid "Set %(service_name)s Password" -msgstr "%(service_name)s Passwort" +msgstr "%(service_name)s Passwort setzen" #: allianceauth/services/templates/services/service_password.html:17 msgid "Set Password" @@ -1927,7 +1928,7 @@ msgstr "SRP Flotten Daten" #: allianceauth/srp/templates/srp/data.html:50 msgid "SRP Fleet Data" -msgstr "SRP-Flotte Daten" +msgstr "SRP Flotte Daten" #: allianceauth/srp/templates/srp/data.html:55 msgid "Mark Incomplete" @@ -2005,7 +2006,7 @@ msgstr "Füge SRP Flotte hinzu" #: allianceauth/srp/templates/srp/management.html:39 msgid "Fleet AAR" -msgstr "Flotten AAR" +msgstr "Flottenbericht" #: allianceauth/srp/templates/srp/management.html:40 msgid "Fleet SRP Code" @@ -2033,7 +2034,7 @@ msgstr "Deaktiviert" #: allianceauth/srp/templates/srp/management.html:83 msgid "Completed" -msgstr "Fertig" +msgstr "Abgeschlossen" #: allianceauth/srp/templates/srp/management.html:101 msgid "Are you sure you want to delete this SRP code and its contents?" @@ -2086,7 +2087,7 @@ msgstr "SRP Link für %(fleetname)s aktiviert." #: allianceauth/srp/views.py:140 #, python-format msgid "Marked SRP fleet %(fleetname)s as completed." -msgstr "SRP Flotte %(fleetname)s als vollständig markiert." +msgstr "SRP Flotte %(fleetname)s als abgeschlossen markiert." #: allianceauth/srp/views.py:153 #, python-format @@ -2204,7 +2205,7 @@ msgstr "Testversion verfügbar" #: allianceauth/templates/allianceauth/admin-status/overview.html:78 msgid "Task Queue" -msgstr "Warteschlange" +msgstr "Task-Warteschlange" #: allianceauth/templates/allianceauth/admin-status/overview.html:81 #, python-format @@ -2249,7 +2250,7 @@ msgstr "Ausloggen" #: allianceauth/timerboard/form.py:53 msgid "Other" -msgstr "anderes" +msgstr "Anderes" #: allianceauth/timerboard/form.py:54 #: allianceauth/timerboard/templates/timerboard/view.html:62 @@ -2353,7 +2354,7 @@ msgstr "Timer löschen" #: allianceauth/timerboard/templates/timerboard/timer_confirm_delete.html:19 #, python-format msgid "Are you sure you want to delete timer \"%(object)s\"?" -msgstr "Bist Du sicher das Du Timer \"%(object)s\" löschen möchtest?" +msgstr "Bist Du sicher das Du Timer „%(object)s“ löschen möchtest?" #: allianceauth/timerboard/templates/timerboard/timer_create_form.html:5 #: allianceauth/timerboard/templates/timerboard/timer_create_form.html:13 diff --git a/allianceauth/locale/es/LC_MESSAGES/django.po b/allianceauth/locale/es/LC_MESSAGES/django.po index 27a35480..1facc81a 100644 --- a/allianceauth/locale/es/LC_MESSAGES/django.po +++ b/allianceauth/locale/es/LC_MESSAGES/django.po @@ -4,11 +4,11 @@ # FIRST AUTHOR , YEAR. # # Translators: -# frank1210 , 2021 -# Joel Falknau , 2021 -# Young Anexo, 2023 # Fegpawn Kaundur, 2023 +# frank1210 , 2023 # trenus, 2023 +# Joel Falknau , 2023 +# Young Anexo, 2023 # #, fuzzy msgid "" @@ -16,8 +16,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-10-09 18:20+1000\n" -"PO-Revision-Date: 2020-02-18 03:14+0000\n" -"Last-Translator: trenus, 2023\n" +"PO-Revision-Date: 2023-10-08 09:23+0000\n" +"Last-Translator: Young Anexo, 2023\n" "Language-Team: Spanish (https://app.transifex.com/alliance-auth/teams/107430/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/allianceauth/locale/fr_FR/LC_MESSAGES/django.po b/allianceauth/locale/fr_FR/LC_MESSAGES/django.po index 6867b96a..7e5156ec 100644 --- a/allianceauth/locale/fr_FR/LC_MESSAGES/django.po +++ b/allianceauth/locale/fr_FR/LC_MESSAGES/django.po @@ -4,14 +4,14 @@ # FIRST AUTHOR , YEAR. # # Translators: -# François LACROIX-DURANT , 2020 -# Philippe Querin-Laporte , 2020 -# Keven D. , 2020 -# Idea ., 2021 -# Mickael PATTE, 2021 -# Geoffrey Fabbro, 2021 +# Keven D. , 2023 +# rockclodbuster, 2023 +# Geoffrey Fabbro, 2023 # Mohssine Daghghar, 2023 -# Ludovick Fortin, 2023 +# François LACROIX-DURANT , 2023 +# Mickael PATTE, 2023 +# Philippe Querin-Laporte , 2023 +# Idea ., 2023 # #, fuzzy msgid "" @@ -19,8 +19,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-10-09 18:20+1000\n" -"PO-Revision-Date: 2020-02-18 03:14+0000\n" -"Last-Translator: Ludovick Fortin, 2023\n" +"PO-Revision-Date: 2023-10-08 09:23+0000\n" +"Last-Translator: Idea ., 2023\n" "Language-Team: French (France) (https://app.transifex.com/alliance-auth/teams/107430/fr_FR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/allianceauth/locale/it_IT/LC_MESSAGES/django.po b/allianceauth/locale/it_IT/LC_MESSAGES/django.po index c8eb9841..f12e7cb6 100644 --- a/allianceauth/locale/it_IT/LC_MESSAGES/django.po +++ b/allianceauth/locale/it_IT/LC_MESSAGES/django.po @@ -4,7 +4,7 @@ # FIRST AUTHOR , YEAR. # # Translators: -# Alessandro Cresti, 2021 +# Alessandro Cresti, 2023 # Linus Hope, 2023 # #, fuzzy @@ -13,7 +13,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-10-09 18:20+1000\n" -"PO-Revision-Date: 2020-02-18 03:14+0000\n" +"PO-Revision-Date: 2023-10-08 09:23+0000\n" "Last-Translator: Linus Hope, 2023\n" "Language-Team: Italian (Italy) (https://app.transifex.com/alliance-auth/teams/107430/it_IT/)\n" "MIME-Version: 1.0\n" @@ -119,7 +119,7 @@ msgstr "" #: allianceauth/authentication/templates/authentication/dashboard.html:101 msgid "No main character set." -msgstr "Nessun personaggio principale impostato" +msgstr "Nessun personaggio principale impostato." #: allianceauth/authentication/templates/authentication/dashboard.html:109 msgid "Add Character" @@ -185,7 +185,7 @@ msgstr "Gestisci applicazioni ESI" #: allianceauth/authentication/templates/public/register.html:6 msgid "Registration" -msgstr "Iscriviti" +msgstr "Registrazione" #: allianceauth/authentication/templates/public/register.html:21 msgid "Register" @@ -223,18 +223,18 @@ msgstr "" #: allianceauth/authentication/views.py:133 msgid "Unable to authenticate as the selected character." -msgstr "Impossibile autenticarsi con il personaggio selezioanto." +msgstr "Impossibile autenticarsi con il personaggio selezionato." #: allianceauth/authentication/views.py:197 msgid "Registration token has expired." -msgstr "L'invito per registrarsi è scaduto." +msgstr "Il token di registrazione è scaduto." #: allianceauth/authentication/views.py:252 msgid "" "Sent confirmation email. Please follow the link to confirm your email " "address." msgstr "" -"Un messaggio di conferma è stato inviato. Per favore, utilizza il link per " +"Una e-mail di conferma è stata inviata. Per favore, utilizza il link per " "confermare il tuo indirizzo di posta elettronica." #: allianceauth/authentication/views.py:257 @@ -352,7 +352,8 @@ msgstr "La corporazione selezionata dispone già di un modulo statistiche." #: allianceauth/corputils/views.py:56 msgid "Failed to gather corporation statistics with selected token." msgstr "" -"Impossibile raccogliere informazioni sulla corporazione con questo codice." +"Raccolta di statistiche della corpoazione non riuscita con il token " +"selezionato." #: allianceauth/fleetactivitytracking/auth_hooks.py:9 msgid "Fleet Activity Tracking" @@ -403,7 +404,7 @@ msgstr "Crea Fatlink" #: allianceauth/optimer/templates/optimer/add.html:13 #: allianceauth/optimer/templates/optimer/add.html:22 msgid "Create Fleet Operation" -msgstr "Crea Fleet Operation" +msgstr "Crea operazione di flotta" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html:13 msgid "Bad request!" @@ -575,7 +576,7 @@ msgstr "Statistiche fatlink" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:20 msgid "Ticker" -msgstr "" +msgstr "Ticker" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:8 msgid "Participation data" @@ -583,7 +584,9 @@ msgstr "Statistiche di partecipazione" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:12 msgid "Most recent clicked fatlinks" -msgstr "Fatlink più recentemente selezionati" +msgstr "" +"Fatlink selezionati più di recente\n" +" " #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:17 msgid "Personal statistics" @@ -654,8 +657,8 @@ msgid "" "etc.
    Overrides Hidden and Open options when selected." msgstr "" "Gruppo interno, gli utenti non possono vedere, unirsi o fare richiesta di " -"adesione a questo gruppo.
    Utilizzato per gruppi come Membri, Corpazioni," -" Alleanze, etc.
    Sovrascrive opzioni nascoste e aperte quando " +"adesione a questo.
    Utilizzato per gruppi come Membri, Corpazioni, " +"Alleanze, etc.
    Sovrascrive opzioni nascoste e aperte quando " "seleazionato." #: allianceauth/groupmanagement/models.py:113 @@ -670,7 +673,7 @@ msgid "" "group is not open users will need their request manually approved." msgstr "" "Il gruppo è aperto e gli utenti saranno automaticamente aggiunti a seguito " -"richiesta.
    Se il gruppo non è aperto gli utenti dovranno necessitare di " +"di richiesta.
    Se il gruppo non è aperto gli utenti necessiteranno di " "approvazione manuale." #: allianceauth/groupmanagement/models.py:126 @@ -680,12 +683,18 @@ msgid "" "remove users from this group automatically when they are no longer " "authenticated." msgstr "" +"Il gruppo è pubblico. Qualsiasi utente registrato può unirsi a questo " +"gruppo, con visibilità basata sulle altre opzioni impostate per questo " +"gruppo.
    Auth non rimuoverà automaticamente gli utenti da questo gruppo " +"quando non sono più autenticati." #: allianceauth/groupmanagement/models.py:135 msgid "" "Group is restricted. This means that adding or removing users for this group" " requires a superuser admin." msgstr "" +"Il gruppo è limitato. Ciò significa che l'aggiunta o la rimozione di utenti " +"per questo gruppo richiede un amministratore." #: allianceauth/groupmanagement/models.py:144 msgid "" @@ -693,6 +702,9 @@ msgid "" "auth.group_management permission to allow a user to manage all " "groups.
    " msgstr "" +"I leader del gruppo possono elaborare le richieste per questo gruppo. Usa " +"l'autorizzazione auth.group_management per consentire ad un " +"utente di gestire tutti i gruppi.
    " #: allianceauth/groupmanagement/models.py:154 msgid "" @@ -700,54 +712,61 @@ msgid "" "auth.group_management permission to allow a user to manage all " "groups.
    " msgstr "" +"I membri dei gruppi leader possono elaborare le richieste per questo gruppo." +" Usa l'autorizzazione auth.group_management per consentire ad " +"un utente di gestire tutti i gruppi.
    " #: allianceauth/groupmanagement/models.py:163 msgid "" "States listed here will have the ability to join this group provided they " "have the proper permissions.
    " msgstr "" +"Gli stati qui elencati avranno la possibilità di aderire a questo gruppo a " +"condizione che dispongano delle opportune autorizzazioni.
    " #: allianceauth/groupmanagement/models.py:171 msgid "" "Short description (max. 512 characters) of the group shown to users." msgstr "" +"Breve descrizione (max. 512 caratteri) del gruppo da mostrare agli " +"utenti." #: allianceauth/groupmanagement/models.py:178 msgid "Can request non-public groups" -msgstr "" +msgstr "Può fare richiesta a gruppi non pubblici" #: allianceauth/groupmanagement/models.py:209 msgid "name" -msgstr "" +msgstr "nome" #: allianceauth/groupmanagement/models.py:212 msgid "Name that can not be used for groups." -msgstr "" +msgstr "Il nome scelto non può essere utilizzato per gruppi." #: allianceauth/groupmanagement/models.py:215 msgid "reason" -msgstr "" +msgstr "ragione" #: allianceauth/groupmanagement/models.py:215 msgid "Reason why this name is reserved." -msgstr "" +msgstr "Ragione per la quale questo nome è riservato." #: allianceauth/groupmanagement/models.py:218 msgid "created by" -msgstr "" +msgstr "creato da" #: allianceauth/groupmanagement/models.py:223 msgid "created at" -msgstr "" +msgstr "creato il" #: allianceauth/groupmanagement/models.py:223 msgid "Date when this entry was created" -msgstr "" +msgstr "Data in cui è stata creata questa voce." #: allianceauth/groupmanagement/templates/groupmanagement/audit.html:4 #: allianceauth/groupmanagement/templates/groupmanagement/audit.html:13 msgid "Audit Log" -msgstr "" +msgstr "Registro di controllo" #: allianceauth/groupmanagement/templates/groupmanagement/audit.html:19 #: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:20 @@ -788,7 +807,7 @@ msgstr "Rimosso" #: allianceauth/groupmanagement/templates/groupmanagement/audit.html:60 msgid "All times displayed are EVE/UTC." -msgstr "Tutti gli orari visualizzati sono in riferimento al EVE/UTC" +msgstr "Tutti gli orari visualizzati sono riferiti a EVE/UTC" #: allianceauth/groupmanagement/templates/groupmanagement/audit.html:67 msgid "No entries found for this group." @@ -808,13 +827,13 @@ msgstr "Organizzazione" #: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:49 #: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:75 msgid "Group leader" -msgstr "" +msgstr "Responsabile del gruppo" #: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:60 #: allianceauth/groupmanagement/templates/groupmanagement/index.html:82 #: allianceauth/groupmanagement/templates/groupmanagement/index.html:139 msgid "(unknown)" -msgstr "" +msgstr "(sconosciuto)" #: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:65 msgid "Remove from group" @@ -860,7 +879,7 @@ msgstr "Nascosto" #: allianceauth/groupmanagement/templates/groupmanagement/groupmembership.html:44 #: allianceauth/templates/allianceauth/admin-status/overview.html:14 msgid "Open" -msgstr "Libero" +msgstr "Aperto" #: allianceauth/groupmanagement/templates/groupmanagement/groupmembership.html:46 msgid "Requestable" @@ -902,7 +921,7 @@ msgstr "Abbandona" #: allianceauth/srp/templates/srp/data.html:135 #: allianceauth/srp/templates/srp/management.html:79 msgid "Pending" -msgstr "" +msgstr "In attesa" #: allianceauth/groupmanagement/templates/groupmanagement/groups.html:39 msgid "Join" @@ -914,7 +933,7 @@ msgstr "Richiedi" #: allianceauth/groupmanagement/templates/groupmanagement/groups.html:58 msgid "No groups available." -msgstr "Nessun gruppo disponibile" +msgstr "Nessun gruppo disponibile." #: allianceauth/groupmanagement/templates/groupmanagement/index.html:5 msgid "Groups Management" @@ -965,12 +984,12 @@ msgstr "Richieste" #: allianceauth/groupmanagement/templates/groupmanagement/menu.html:22 msgid "Group Membership" -msgstr "" +msgstr "Membri del gruppo" #: allianceauth/groupmanagement/views.py:163 #, python-format msgid "Removed user %(user)s from group %(group)s." -msgstr "Rimosso il membro %(user)s da %(group)s." +msgstr "Rimosso il membro %(user)s dal gruppo %(group)s." #: allianceauth/groupmanagement/views.py:165 msgid "User does not exist in that group" @@ -1014,7 +1033,7 @@ msgid "" "An unhandled error occurred while processing the application from " "%(mainchar)s to leave %(group)s." msgstr "" -"Si è verificato un’errore durante l’elaborazione della domanda di comgedo da" +"Si è verificato un’errore durante l’elaborazione della domanda di congedo da" " parte di %(mainchar)s per %(group)s." #: allianceauth/groupmanagement/views.py:292 @@ -1027,15 +1046,16 @@ msgstr "" #: allianceauth/groupmanagement/views.py:336 #: allianceauth/groupmanagement/views.py:346 msgid "You cannot join that group" -msgstr "Non puoi aderire a questo gruppo" +msgstr "Non puoi unirti a questo gruppo" #: allianceauth/groupmanagement/views.py:341 msgid "You are already a member of that group." -msgstr "Sei già parte del gruppo selezionato." +msgstr "Fai già parte del gruppo selezionato." #: allianceauth/groupmanagement/views.py:358 msgid "You already have a pending application for that group." -msgstr "La tua domanda per questo gruppo non è ancora stata valutata." +msgstr "" +"Hai già una candidatura in attesa di essere elaborata per questo gruppo" #: allianceauth/groupmanagement/views.py:367 #, python-format @@ -1052,7 +1072,7 @@ msgstr "Non sei un membro di questo gruppo." #: allianceauth/groupmanagement/views.py:393 msgid "You already have a pending leave request for that group." -msgstr "La tua domanda di congedo non è ancora stata valutata." +msgstr "Hai già una richiesta di congedo in sospeso per quel gruppo." #: allianceauth/groupmanagement/views.py:409 #, python-format @@ -1083,7 +1103,7 @@ msgstr "Corporazioni disponibili" #: allianceauth/hrapplications/templates/hrapplications/corpchoice.html:22 msgid "No corps are accepting applications at this time." -msgstr "Nessuna corporazione accetta domanda al momento." +msgstr "Nessuna corporazione accetta domande al momento." #: allianceauth/hrapplications/templates/hrapplications/create.html:4 #: allianceauth/hrapplications/templates/hrapplications/create.html:7 @@ -1097,7 +1117,7 @@ msgstr "Invia" #: allianceauth/hrapplications/templates/hrapplications/management.html:5 #: allianceauth/hrapplications/templates/hrapplications/searchview.html:5 msgid "HR Application Management" -msgstr "HR Risorse umane" +msgstr "Gestione delle applicazioni HR" #: allianceauth/hrapplications/templates/hrapplications/management.html:10 msgid "Personal Applications" @@ -1165,7 +1185,7 @@ msgstr "Data" #: allianceauth/hrapplications/templates/hrapplications/management.html:138 #: allianceauth/hrapplications/templates/hrapplications/view.html:22 msgid "Reviewer:" -msgstr "" +msgstr "Revisore:" #: allianceauth/hrapplications/templates/hrapplications/management.html:113 msgid "No pending applications." @@ -1173,7 +1193,7 @@ msgstr "Nessuna domanda in sospeso." #: allianceauth/hrapplications/templates/hrapplications/management.html:162 msgid "No reviewed applications." -msgstr "Nessuna domanda revisionata." +msgstr "Nessuna candidatura esaminata." #: allianceauth/hrapplications/templates/hrapplications/management.html:176 #: allianceauth/hrapplications/templates/hrapplications/searchview.html:62 @@ -1266,11 +1286,11 @@ msgstr "Letto" #: allianceauth/notifications/templates/notifications/list.html:17 msgid "Mark All Read" -msgstr "Seleziona tutto visionato" +msgstr "Segna tutto come letto" #: allianceauth/notifications/templates/notifications/list.html:18 msgid "Delete All Read" -msgstr "Cancella tutti i visionati" +msgstr "Elimina tutti i letti" #: allianceauth/notifications/templates/notifications/list_partial.html:7 msgid "Timestamp" @@ -1282,340 +1302,347 @@ msgstr "Titolo" #: allianceauth/notifications/templates/notifications/list_partial.html:28 msgid "No notifications." -msgstr "" +msgstr "Nessuna notifica." #: allianceauth/notifications/templates/notifications/view.html:4 #: allianceauth/notifications/templates/notifications/view.html:8 msgid "View Notification" -msgstr "" +msgstr "Vedi notifiche" #: allianceauth/notifications/views.py:52 msgid "You are not authorized to view that notification." -msgstr "" +msgstr "Non sei autorizzato a visualizzare questa notifica." #: allianceauth/notifications/views.py:68 msgid "Deleted notification." -msgstr "" +msgstr "Elimina notifiche." #: allianceauth/notifications/views.py:75 msgid "Failed to locate notification." -msgstr "" +msgstr "Impossibile trovare la notifica." #: allianceauth/notifications/views.py:83 msgid "Marked all notifications as read." -msgstr "" +msgstr "Contrassegna tutte le notifiche come lette." #: allianceauth/notifications/views.py:91 msgid "Deleted all read notifications." -msgstr "" +msgstr "Elimina tutte le notifiche lette." #: allianceauth/optimer/auth_hooks.py:10 msgid "Fleet Operations" -msgstr "" +msgstr "Operazioni di flotta" #: allianceauth/optimer/form.py:12 #: allianceauth/optimer/templates/optimer/fleetoptable.html:11 msgid "Doctrine" -msgstr "" +msgstr "Dottrina" #: allianceauth/optimer/form.py:14 #: allianceauth/optimer/templates/optimer/fleetoptable.html:13 msgid "Start Time" -msgstr "" +msgstr "Ora di inizio" #: allianceauth/optimer/form.py:15 #: allianceauth/optimer/templates/optimer/fleetoptable.html:9 msgid "Operation Name" -msgstr "" +msgstr "Nome dell'operazione" #: allianceauth/optimer/form.py:16 msgid "Operation Type" -msgstr "" +msgstr "Tipo di operazione" #: allianceauth/optimer/form.py:17 #: allianceauth/srp/templates/srp/management.html:38 msgid "Fleet Commander" -msgstr "" +msgstr "Comandante della flotta" #: allianceauth/optimer/form.py:22 allianceauth/srp/form.py:14 #: allianceauth/srp/templates/srp/data.html:91 msgid "Additional Info" -msgstr "" +msgstr "Informazioni aggiuntive" #: allianceauth/optimer/form.py:23 msgid "(Optional) Describe the operation with a couple of short words." -msgstr "" +msgstr "(Facoltativo) Breve descrizione del tipo di operazione." #: allianceauth/optimer/templates/optimer/add.html:6 #: allianceauth/optimer/templates/optimer/management.html:13 msgid "Create Operation" -msgstr "" +msgstr "Crea operazione" #: allianceauth/optimer/templates/optimer/fleetoptable.html:12 msgid "Form Up System" -msgstr "" +msgstr "Sistema di partenza" #: allianceauth/optimer/templates/optimer/fleetoptable.html:14 #: allianceauth/timerboard/templates/timerboard/view.html:36 #: allianceauth/timerboard/templates/timerboard/view.html:203 #: allianceauth/timerboard/templates/timerboard/view.html:376 msgid "Local Time" -msgstr "" +msgstr "Ora locale" #: allianceauth/optimer/templates/optimer/fleetoptable.html:16 msgid "FC" -msgstr "" +msgstr "Comandante della flotta" #: allianceauth/optimer/templates/optimer/management.html:5 msgid "Fleet Operation Management" -msgstr "" +msgstr "Gestione delle operazioni di flotta" #: allianceauth/optimer/templates/optimer/management.html:10 msgid "Fleet Operation Timers" -msgstr "" +msgstr "Timer delle operazioni di flotta" #: allianceauth/optimer/templates/optimer/management.html:20 #: allianceauth/timerboard/templates/timerboard/view.html:22 msgid "Current Eve Time:" -msgstr "" +msgstr "Ora EVE attuale:" #: allianceauth/optimer/templates/optimer/management.html:26 msgid "Next Fleet Operations" -msgstr "" +msgstr "Prossime operazioni di flotta" #: allianceauth/optimer/templates/optimer/management.html:30 #: allianceauth/timerboard/templates/timerboard/view.html:362 msgid "No upcoming timers." -msgstr "" +msgstr "Nessun timer prossimo." #: allianceauth/optimer/templates/optimer/management.html:33 msgid "Past Fleet Operations" -msgstr "" +msgstr "Operazioni di flotta passate" #: allianceauth/optimer/templates/optimer/management.html:37 #: allianceauth/timerboard/templates/timerboard/view.html:535 msgid "No past timers." -msgstr "" +msgstr "Nessun timer passato." #: allianceauth/optimer/templates/optimer/update.html:6 #: allianceauth/optimer/templates/optimer/update.html:15 #: allianceauth/optimer/templates/optimer/update.html:27 msgid "Update Fleet Operation" -msgstr "" +msgstr "Aggiorna operazioni di flotta" #: allianceauth/optimer/templates/optimer/update.html:21 msgid "Fleet Operation Does Not Exist" -msgstr "" +msgstr "L'operazione di flotta non esiste" #: allianceauth/optimer/views.py:69 #, python-format msgid "Created operation timer for %(opname)s." -msgstr "" +msgstr "Creato il timer per l'operazione %(opname)s." #: allianceauth/optimer/views.py:87 #, python-format msgid "Removed operation timer for %(opname)s." -msgstr "" +msgstr "Rimosso il timer per l'operazione %(opname)s." #: allianceauth/optimer/views.py:125 #, python-format msgid "Saved changes to operation timer for %(opname)s." -msgstr "" +msgstr "Salvati i cambiamenti per l'operazione %(opname)s." #: allianceauth/permissions_tool/templates/permissions_tool/audit.html:4 #: allianceauth/permissions_tool/templates/permissions_tool/audit.html:8 msgid "Permissions Audit" -msgstr "" +msgstr "Verifica dei permessi" #: allianceauth/permissions_tool/templates/permissions_tool/audit.html:20 msgid "User / Character" -msgstr "" +msgstr "Utente / Personaggio" #: allianceauth/permissions_tool/templates/permissions_tool/overview.html:4 #: allianceauth/permissions_tool/templates/permissions_tool/overview.html:8 msgid "Permissions Overview" -msgstr "" +msgstr "Panoramica dei permessi" #: allianceauth/permissions_tool/templates/permissions_tool/overview.html:11 msgid "Showing only applied permissions" -msgstr "" +msgstr "Mostrando solo i permessi applicati" #: allianceauth/permissions_tool/templates/permissions_tool/overview.html:12 msgid "Show All" -msgstr "" +msgstr "Mostra tutto" #: allianceauth/permissions_tool/templates/permissions_tool/overview.html:14 msgid "Showing all permissions" -msgstr "" +msgstr "Mostrando tutti i permessi" #: allianceauth/permissions_tool/templates/permissions_tool/overview.html:15 msgid "Show Applied" -msgstr "" +msgstr "Mostra applicati" #: allianceauth/permissions_tool/templates/permissions_tool/overview.html:23 msgid "App" -msgstr "" +msgstr "App" #: allianceauth/permissions_tool/templates/permissions_tool/overview.html:26 msgid "Model" -msgstr "" +msgstr "Modello" #: allianceauth/permissions_tool/templates/permissions_tool/overview.html:29 msgid "Code Name" -msgstr "" +msgstr "Nome del codice" #: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35 msgid "Users" -msgstr "" +msgstr "Utenti" #: allianceauth/permissions_tool/templates/permissions_tool/overview.html:41 msgid "States" -msgstr "" +msgstr "Stati" #: allianceauth/services/abstract.py:72 msgid "That service account already exists" -msgstr "" +msgstr "Un account per questo servizio già esiste" #: allianceauth/services/abstract.py:103 #, python-brace-format msgid "Successfully set your {self.service_name} password" -msgstr "" +msgstr "La password del {self.service_name} è stata impostata con sucesso" #: allianceauth/services/auth_hooks.py:12 msgid "Services" -msgstr "" +msgstr "Servizi" #: allianceauth/services/forms.py:6 msgid "Name of Fleet:" -msgstr "" +msgstr "Nome della flotta:" #: allianceauth/services/forms.py:7 msgid "Fleet Commander:" -msgstr "" +msgstr "Comandante della flotta:" #: allianceauth/services/forms.py:8 msgid "Fleet Comms:" -msgstr "" +msgstr "Canale voce della flotta:" #: allianceauth/services/forms.py:9 msgid "Fleet Type:" -msgstr "" +msgstr "Tipo di flotta:" #: allianceauth/services/forms.py:10 msgid "Ship Priorities:" -msgstr "" +msgstr "Navi prioritarie:" #: allianceauth/services/forms.py:11 msgid "Formup Location:" -msgstr "" +msgstr "Sistema di partenza:" #: allianceauth/services/forms.py:12 msgid "Formup Time:" -msgstr "" +msgstr "Ora di partenza:" #: allianceauth/services/forms.py:13 msgid "Expected Duration:" -msgstr "" +msgstr "Durata stimata:" #: allianceauth/services/forms.py:14 msgid "Purpose:" -msgstr "" +msgstr "Obiettivo:" #: allianceauth/services/forms.py:15 msgid "Reimbursable?*" -msgstr "" +msgstr "SRP?*" #: allianceauth/services/forms.py:15 allianceauth/services/forms.py:16 msgid "Yes" -msgstr "" +msgstr "Si" #: allianceauth/services/forms.py:15 allianceauth/services/forms.py:16 msgid "No" -msgstr "" +msgstr "No" #: allianceauth/services/forms.py:16 msgid "Important?*" -msgstr "" +msgstr "Importante?*" #: allianceauth/services/forms.py:21 allianceauth/services/forms.py:31 msgid "Password" -msgstr "" +msgstr "Password" #: allianceauth/services/forms.py:26 allianceauth/services/forms.py:36 msgid "Password must be at least 8 characters long." -msgstr "" +msgstr "La password deve contenere almeno 8 caratteri." #: allianceauth/services/modules/discord/models.py:187 msgid "Discord Account Disabled" -msgstr "" +msgstr "Account discord disabilitato" #: allianceauth/services/modules/discord/models.py:189 msgid "" "Your Discord account was disabled automatically by Auth. If you think this " "was a mistake, please contact an admin." msgstr "" +"Il tuo account discord è stato disabilitato automaticamente dall'Auth. Se " +"pensi questo sia un errore per favore contatta un ammistratore." #: allianceauth/services/modules/discord/templates/services/discord/discord_service_ctrl.html:5 msgid "Discord" -msgstr "" +msgstr "Discord" #: allianceauth/services/modules/discord/templates/services/discord/discord_service_ctrl.html:18 msgid "Join the Discord server" -msgstr "" +msgstr "Unisciti al server discord" #: allianceauth/services/modules/discord/templates/services/discord/discord_service_ctrl.html:22 msgid "Leave- and rejoin the Discord Server (Reset)" -msgstr "" +msgstr "Abbandona e unisciti nuovamente al server discord (ripristino)" #: allianceauth/services/modules/discord/templates/services/discord/discord_service_ctrl.html:25 msgid "Leave the Discord server" -msgstr "" +msgstr "Lascia il server discord" #: allianceauth/services/modules/discord/templates/services/discord/discord_service_ctrl.html:32 msgid "Link Discord Server" -msgstr "" +msgstr "Collega server discord" #: allianceauth/services/modules/discord/views.py:30 msgid "Deactivated Discord account." -msgstr "" +msgstr "Disabilita l'account discord" #: allianceauth/services/modules/discord/views.py:36 #: allianceauth/services/modules/discord/views.py:59 msgid "An error occurred while processing your Discord account." msgstr "" +"Si è verificato un errore durante l'elaborazione del tuo account discord." #: allianceauth/services/modules/discord/views.py:102 msgid "Your Discord account has been successfully activated." -msgstr "" +msgstr "Il tuo account discord è stato attivato con successo." #: allianceauth/services/modules/discord/views.py:108 msgid "" "An error occurred while trying to activate your Discord account. Please try " "again." msgstr "" +"Si è verificato un errore durante l'attivazione del tuo account discord. Per" +" favore ritenta." #: allianceauth/services/modules/discourse/views.py:29 msgid "You are not authorized to access Discourse." -msgstr "" +msgstr "Non sei autorizzato ad accedere Discourse." #: allianceauth/services/modules/discourse/views.py:34 msgid "You must have a main character set to access Discourse." msgstr "" +"Devi avere impostato un personaggio principale per poter accedere Discourse." #: allianceauth/services/modules/discourse/views.py:44 msgid "" "No SSO payload or signature. Please contact support if this problem " "persists." msgstr "" +"Nessun payload o firma SSO. Contatta l'assistenza se il problema persiste." #: allianceauth/services/modules/discourse/views.py:54 #: allianceauth/services/modules/discourse/views.py:62 msgid "Invalid payload. Please contact support if this problem persists." -msgstr "" +msgstr "Payload non valido. Contatta l'assistenza se il problema persiste." #: allianceauth/services/modules/ips4/views.py:31 msgid "Activated IPSuite4 account." -msgstr "" +msgstr "Attiva account IPSuite4." #: allianceauth/services/modules/ips4/views.py:39 #: allianceauth/services/modules/ips4/views.py:60 @@ -1623,32 +1650,33 @@ msgstr "" #: allianceauth/services/modules/ips4/views.py:101 msgid "An error occurred while processing your IPSuite4 account." msgstr "" +"Si è verificato un errore durante l'elaborazione del tuo account IPSuite4." #: allianceauth/services/modules/ips4/views.py:52 msgid "Reset IPSuite4 password." -msgstr "" +msgstr "Reimposta password IPSuite4." #: allianceauth/services/modules/ips4/views.py:78 msgid "Set IPSuite4 password." -msgstr "" +msgstr "Imposta password IPSuite4." #: allianceauth/services/modules/ips4/views.py:98 msgid "Deactivated IPSuite4 account." -msgstr "" +msgstr "Disattiva account IPSuite4." #: allianceauth/services/modules/openfire/auth_hooks.py:26 msgid "Jabber" -msgstr "" +msgstr "Jabber" #: allianceauth/services/modules/openfire/auth_hooks.py:79 #: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:5 #: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:10 msgid "Jabber Broadcast" -msgstr "" +msgstr "Jabber broadcast" #: allianceauth/services/modules/openfire/auth_hooks.py:94 msgid "Fleet Broadcast Formatter" -msgstr "" +msgstr "Strumento formattazione broadcast" #: allianceauth/services/modules/openfire/forms.py:7 msgid "Message" @@ -1656,15 +1684,15 @@ msgstr "Messaggio" #: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:16 msgid "Broadcast Sent!!" -msgstr "" +msgstr "Broadcast inviato!" #: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:22 msgid "Broadcast" -msgstr "" +msgstr "Broadcast" #: allianceauth/services/modules/openfire/views.py:35 msgid "Activated jabber account." -msgstr "" +msgstr "Attivato account jabber." #: allianceauth/services/modules/openfire/views.py:43 #: allianceauth/services/modules/openfire/views.py:56 @@ -1672,23 +1700,24 @@ msgstr "" #: allianceauth/services/modules/openfire/views.py:147 msgid "An error occurred while processing your jabber account." msgstr "" +"Si è verificato un errore durante l'elaborazione del tuo account jabber." #: allianceauth/services/modules/openfire/views.py:69 msgid "Reset jabber password." -msgstr "" +msgstr "Reimposta password jabber." #: allianceauth/services/modules/openfire/views.py:115 #, python-format msgid "Sent jabber broadcast to %s" -msgstr "" +msgstr "Broadcast jabber inviato a %s" #: allianceauth/services/modules/openfire/views.py:144 msgid "Set jabber password." -msgstr "" +msgstr "Imposta password jabber." #: allianceauth/services/modules/phpbb3/views.py:34 msgid "Activated forum account." -msgstr "" +msgstr "Account forum attivato." #: allianceauth/services/modules/phpbb3/views.py:42 #: allianceauth/services/modules/phpbb3/views.py:56 @@ -1696,90 +1725,92 @@ msgstr "" #: allianceauth/services/modules/phpbb3/views.py:101 msgid "An error occurred while processing your forum account." msgstr "" +"Si è verificato un errore durante l'elaborazione del tuo account forum." #: allianceauth/services/modules/phpbb3/views.py:53 msgid "Deactivated forum account." -msgstr "" +msgstr "Disattivato account forum." #: allianceauth/services/modules/phpbb3/views.py:70 msgid "Reset forum password." -msgstr "" +msgstr "Reimposta password forum." #: allianceauth/services/modules/phpbb3/views.py:98 msgid "Set forum password." -msgstr "" +msgstr "Imposta password forum." #: allianceauth/services/modules/smf/views.py:52 msgid "Activated SMF account." -msgstr "" +msgstr "Attivato account SMF." #: allianceauth/services/modules/smf/views.py:65 #: allianceauth/services/modules/smf/views.py:81 #: allianceauth/services/modules/smf/views.py:102 #: allianceauth/services/modules/smf/views.py:124 msgid "An error occurred while processing your SMF account." -msgstr "" +msgstr "Si è verificato un errore durante l'elaborazione del tuo account SMF." #: allianceauth/services/modules/smf/views.py:78 msgid "Deactivated SMF account." -msgstr "" +msgstr "Disattivato account SMF." #: allianceauth/services/modules/smf/views.py:95 msgid "Reset SMF password." -msgstr "" +msgstr "Reimposta password SMF." #: allianceauth/services/modules/smf/views.py:121 msgid "Set SMF password." -msgstr "" +msgstr "Imposta password SMF." #: allianceauth/services/modules/teamspeak3/forms.py:14 #, python-format msgid "Unable to locate user %s on server" -msgstr "" +msgstr "Impossibile trovare utente %s nel server" #: allianceauth/services/modules/teamspeak3/templates/admin/teamspeak3/authts/change_list.html:8 msgid "Update TS3 groups" -msgstr "" +msgstr "Aggiorna gruppi TS3" #: allianceauth/services/modules/teamspeak3/templates/services/teamspeak3/teamspeakjoin.html:5 msgid "Verify Teamspeak" -msgstr "" +msgstr "Verifica Teamspeak" #: allianceauth/services/modules/teamspeak3/templates/services/teamspeak3/teamspeakjoin.html:10 msgid "Verify Teamspeak Identity" -msgstr "" +msgstr "Verifica identità teamspeak" #: allianceauth/services/modules/teamspeak3/templates/services/teamspeak3/teamspeakjoin.html:13 msgid "Join Server" -msgstr "" +msgstr "Unisciti al server" #: allianceauth/services/modules/teamspeak3/templates/services/teamspeak3/teamspeakjoin.html:19 #: allianceauth/services/templates/services/service_credentials.html:19 #: allianceauth/srp/templates/srp/add.html:31 msgid "Continue" -msgstr "" +msgstr "Continua" #: allianceauth/services/modules/teamspeak3/views.py:35 msgid "Activated TeamSpeak3 account." -msgstr "" +msgstr "Account Teamspeak3 attivato." #: allianceauth/services/modules/teamspeak3/views.py:38 #: allianceauth/services/modules/teamspeak3/views.py:74 #: allianceauth/services/modules/teamspeak3/views.py:100 msgid "An error occurred while processing your TeamSpeak3 account." msgstr "" +"Si è verificato un errore durante l'elaborazione del tuo account Teamspeak3." #: allianceauth/services/modules/teamspeak3/views.py:71 msgid "Deactivated TeamSpeak3 account." -msgstr "" +msgstr "Disattivato account TeamSpeak3." #: allianceauth/services/modules/teamspeak3/views.py:97 msgid "Reset TeamSpeak3 permission key." -msgstr "" +msgstr "Reimposta la chiave di autorizzazione TeamSpeak3." #: allianceauth/services/modules/xenforo/views.py:30 msgid "Activated XenForo account." -msgstr "" +msgstr "Attivato account XenForo." #: allianceauth/services/modules/xenforo/views.py:40 #: allianceauth/services/modules/xenforo/views.py:52 @@ -1787,310 +1818,317 @@ msgstr "" #: allianceauth/services/modules/xenforo/views.py:94 msgid "An error occurred while processing your XenForo account." msgstr "" +"Si è verificato un errore durante l'elaborazione del tuo account XenForo." #: allianceauth/services/modules/xenforo/views.py:50 msgid "Deactivated XenForo account." -msgstr "" +msgstr "Disattivato account XenForo." #: allianceauth/services/modules/xenforo/views.py:65 msgid "Reset XenForo account password." -msgstr "" +msgstr "Reimposta password dell'account XenForo." #: allianceauth/services/modules/xenforo/views.py:91 msgid "Changed XenForo password." -msgstr "" +msgstr "Password XenForo modificata." #: allianceauth/services/templates/services/fleetformattertool.html:5 msgid "Fleet Formatter Tool" -msgstr "" +msgstr "Strumento formattazione della flotta" #: allianceauth/services/templates/services/fleetformattertool.html:10 msgid "Fleet Broadcast Formatter Tool" -msgstr "" +msgstr "Strumento formattazione brocast della flotta" #: allianceauth/services/templates/services/fleetformattertool.html:23 msgid "Format" -msgstr "" +msgstr "Formato" #: allianceauth/services/templates/services/service_confirm_delete.html:6 #: allianceauth/services/templates/services/service_confirm_delete.html:12 #, python-format msgid "Delete %(service_name)s Account?" -msgstr "" +msgstr "Eliminare l'account %(service_name)s?" #: allianceauth/services/templates/services/service_confirm_delete.html:20 #, python-format msgid "" "Are you sure you want to delete your %(service_name)s account %(object)s?" -msgstr "" +msgstr "Sei sicuro di voler eliminare l'account %(service_name)s %(object)s?" #: allianceauth/services/templates/services/service_credentials.html:4 #: allianceauth/services/templates/services/service_credentials.html:8 #, python-format msgid "%(service_name)s Credentials" -msgstr "" +msgstr "%(service_name)s Credenziali" #: allianceauth/services/templates/services/service_password.html:5 #, python-format msgid "%(service_name)s Password Change" -msgstr "" +msgstr "%(service_name)s Modifica password" #: allianceauth/services/templates/services/service_password.html:9 #, python-format msgid "Set %(service_name)s Password" -msgstr "" +msgstr "Imposta password %(service_name)s " #: allianceauth/services/templates/services/service_password.html:17 msgid "Set Password" -msgstr "" +msgstr "Imposta password" #: allianceauth/services/templates/services/services.html:4 msgid "Services Management" -msgstr "" +msgstr "Gestione dei servizi" #: allianceauth/services/templates/services/services.html:9 msgid "Available Services" -msgstr "" +msgstr "Servizi disponibili" #: allianceauth/services/templates/services/services.html:14 msgid "Service" -msgstr "" +msgstr "Servizio" #: allianceauth/services/templates/services/services.html:16 msgid "Domain" -msgstr "" +msgstr "Dominio" #: allianceauth/srp/auth_hooks.py:13 msgid "Ship Replacement" -msgstr "" +msgstr "Sostituzione della nave" #: allianceauth/srp/form.py:9 #: allianceauth/srp/templates/srp/management.html:36 msgid "Fleet Time" -msgstr "" +msgstr "Orario della flotta" #: allianceauth/srp/form.py:10 #: allianceauth/srp/templates/srp/management.html:37 msgid "Fleet Doctrine" -msgstr "" +msgstr "Dottrina della flotta" #: allianceauth/srp/form.py:16 msgid "Killboard Link (zkillboard.com or kb.evetools.org)" -msgstr "" +msgstr "Killboard link (zkillboard.com o kb.evetools.org) " #: allianceauth/srp/form.py:34 msgid "Invalid Link. Please use zkillboard.com or kb.evetools.org" -msgstr "" +msgstr "Link non valido. Per favore utilizza zkillboard.com o kb.evetools.org" #: allianceauth/srp/form.py:46 msgid "Invalid Link. Please post a direct link to a killmail." msgstr "" +"Link non valido. Per favore utilizza un link direttamente collegato alla " +"killmail." #: allianceauth/srp/form.py:53 msgid "After Action Report Link" -msgstr "" +msgstr "Link di resoconto della flotta" #: allianceauth/srp/templates/srp/add.html:5 msgid "SRP Fleet Create" -msgstr "" +msgstr "Crea SRP della flotta" #: allianceauth/srp/templates/srp/add.html:13 #: allianceauth/srp/templates/srp/add.html:23 msgid "Create SRP Fleet" -msgstr "" +msgstr "Crea SRP della flotta" #: allianceauth/srp/templates/srp/add.html:26 msgid "Give this link to the line members" -msgstr "" +msgstr "Fornisci questo link ai membri" #: allianceauth/srp/templates/srp/data.html:5 msgid "Srp Fleet Data" -msgstr "" +msgstr "Dati del SRP della flotta" #: allianceauth/srp/templates/srp/data.html:50 msgid "SRP Fleet Data" -msgstr "" +msgstr "Dati del SRP della flotta" #: allianceauth/srp/templates/srp/data.html:55 msgid "Mark Incomplete" -msgstr "" +msgstr "Contrassegna incompleto" #: allianceauth/srp/templates/srp/data.html:59 msgid "Mark Completed" -msgstr "" +msgstr "Contrassegna completo" #: allianceauth/srp/templates/srp/data.html:71 #: allianceauth/srp/templates/srp/data.html:157 msgid "Total Losses:" -msgstr "" +msgstr "Perdite totali:" #: allianceauth/srp/templates/srp/data.html:72 #: allianceauth/srp/templates/srp/data.html:158 #: allianceauth/srp/templates/srp/management.html:28 msgid "Total ISK Cost:" -msgstr "" +msgstr "Costo totale in ISK:" #: allianceauth/srp/templates/srp/data.html:80 #: allianceauth/srp/templates/srp/data.html:166 msgid "Are you sure you want to delete SRP requests?" -msgstr "" +msgstr "Sei sicuro di voler eliminare la richiesta di SRP?" #: allianceauth/srp/templates/srp/data.html:89 msgid "Pilot Name" -msgstr "" +msgstr "Nome del pilota" #: allianceauth/srp/templates/srp/data.html:90 msgid "Killboard Link" -msgstr "" +msgstr "Link killboard" #: allianceauth/srp/templates/srp/data.html:92 msgid "Ship Type" -msgstr "" +msgstr "Tipologia nave" #: allianceauth/srp/templates/srp/data.html:93 msgid "Killboard Loss Amt" -msgstr "" +msgstr "Valore delle perdite Killboard" #: allianceauth/srp/templates/srp/data.html:94 msgid "SRP ISK Cost" -msgstr "" +msgstr "Costo in ISK del SRP" #: allianceauth/srp/templates/srp/data.html:95 msgid "Click value to edit Enter to save & next ESC to cancel" msgstr "" +"Fai clic sul valore per modificare, Invio per salvare e proseguire, ESC per " +"annullare" #: allianceauth/srp/templates/srp/data.html:98 msgid "Post Time" -msgstr "" +msgstr "Ora di pubblicazione" #: allianceauth/srp/templates/srp/data.html:175 msgid "No SRP requests for this fleet." -msgstr "" +msgstr "Nessuna richiesta di SRP per questa flotta." #: allianceauth/srp/templates/srp/management.html:6 msgid "Srp Management" -msgstr "" +msgstr "Gestione SRP" #: allianceauth/srp/templates/srp/management.html:12 msgid "SRP Management" -msgstr "" +msgstr "Gestione SRP" #: allianceauth/srp/templates/srp/management.html:16 msgid "View All" -msgstr "" +msgstr "Vedi tutti" #: allianceauth/srp/templates/srp/management.html:21 msgid "Add SRP Fleet" -msgstr "" +msgstr "Aggiungi SRP alla flotta" #: allianceauth/srp/templates/srp/management.html:39 msgid "Fleet AAR" -msgstr "" +msgstr "Resoconto della flotta" #: allianceauth/srp/templates/srp/management.html:40 msgid "Fleet SRP Code" -msgstr "" +msgstr "Codice SRP della flotta" #: allianceauth/srp/templates/srp/management.html:41 msgid "Fleet ISK Cost" -msgstr "" +msgstr "Costo in ISK della flotta" #: allianceauth/srp/templates/srp/management.html:42 msgid "SRP Status" -msgstr "" +msgstr "Status del SRP" #: allianceauth/srp/templates/srp/management.html:43 msgid "Pending Requests" -msgstr "" +msgstr "Richieste in sospeso" #: allianceauth/srp/templates/srp/management.html:62 msgid "Link" -msgstr "" +msgstr "Link" #: allianceauth/srp/templates/srp/management.html:70 msgid "Disabled" -msgstr "" +msgstr "Disabilitato" #: allianceauth/srp/templates/srp/management.html:83 msgid "Completed" -msgstr "" +msgstr "Completato" #: allianceauth/srp/templates/srp/management.html:101 msgid "Are you sure you want to delete this SRP code and its contents?" -msgstr "" +msgstr "Sei sicuro di voler eliminare questo codice SRP e i suoi contenuti?" #: allianceauth/srp/templates/srp/management.html:122 msgid "No SRP fleets created." -msgstr "" +msgstr "Nessun SRP delle flotte creato." #: allianceauth/srp/templates/srp/request.html:5 msgid "SRP Request" -msgstr "" +msgstr "Richieste SRP" #: allianceauth/srp/templates/srp/request.html:10 #: allianceauth/srp/templates/srp/request.html:19 msgid "Create SRP Request" -msgstr "" +msgstr "Crea richiesta SRP" #: allianceauth/srp/templates/srp/update.html:5 #: allianceauth/srp/templates/srp/update.html:10 #: allianceauth/srp/templates/srp/update.html:22 msgid "Update AAR Link" -msgstr "" +msgstr "Aggiorna resoconto della flotta" #: allianceauth/srp/templates/srp/update.html:16 msgid "SRP Fleet Does Not Exist" -msgstr "" +msgstr "SRP della flotta non esiste" #: allianceauth/srp/views.py:85 #, python-format msgid "Created SRP fleet %(fleetname)s." -msgstr "" +msgstr "Creato SRP della flotta %(fleetname)s." #: allianceauth/srp/views.py:103 #, python-format msgid "Removed SRP fleet %(fleetname)s." -msgstr "" +msgstr "Rimosso SRP della flotta %(fleetname)s." #: allianceauth/srp/views.py:115 #, python-format msgid "Disabled SRP fleet %(fleetname)s." -msgstr "" +msgstr "Disabilitato SRP della flotta %(fleetname)s." #: allianceauth/srp/views.py:127 #, python-format msgid "Enabled SRP fleet %(fleetname)s." -msgstr "" +msgstr "Abilitato SRP della flotta %(fleetname)s." #: allianceauth/srp/views.py:140 #, python-format msgid "Marked SRP fleet %(fleetname)s as completed." -msgstr "" +msgstr "SRP della flotta %(fleetname)s è stato contrassegnato completato." #: allianceauth/srp/views.py:153 #, python-format msgid "Marked SRP fleet %(fleetname)s as incomplete." -msgstr "" +msgstr "L'SRP della flotta %(fleetname)s è stato contrassegnato incompleto." #: allianceauth/srp/views.py:165 #, python-format msgid "Unable to locate SRP code with ID %(srpfleetid)s" -msgstr "" +msgstr "Impossibile trovare il codice di SRP con ID %(srpfleetid)s" #: allianceauth/srp/views.py:179 msgid "This kill mail has already been posted." -msgstr "" +msgstr "Questa killmail è già stata pubblicata." #: allianceauth/srp/views.py:200 msgid "" "Your SRP request Killmail link is invalid. Please make sure you are using " "zKillboard." msgstr "" +"La tua richiesta di SRP contiente un link killmail non valido. Per favore " +"assicurarti di utilizzare zKillboard." #: allianceauth/srp/views.py:212 #, python-format msgid "Submitted SRP request for your %(ship)s." -msgstr "" +msgstr "Richiesta di SRP inviata per la tua nave %(ship)s." #: allianceauth/srp/views.py:216 #, python-format @@ -2098,88 +2136,90 @@ msgid "" "Character %(charid)s does not belong to your Auth account. Please add the " "API key for this character and try again" msgstr "" +"Il personaggio %(charid)s non è collegato al tuo profilo Auth. Per favore " +"aggiungi le API key di questo personaggio e ritenta." #: allianceauth/srp/views.py:236 allianceauth/srp/views.py:262 #: allianceauth/srp/views.py:300 msgid "No SRP requests selected" -msgstr "" +msgstr "Nessuna richiesta di SRP selezionata" #: allianceauth/srp/views.py:247 allianceauth/srp/views.py:285 msgid "Unable to locate selected SRP request." -msgstr "" +msgstr "Impossible trovare la richiesta di SRP selezionata." #: allianceauth/srp/views.py:250 #, python-format msgid "Deleted %(numrequests)s SRP requests" -msgstr "" +msgstr "Eliminata/e %(numrequests)s richiesta/e di SRP" #: allianceauth/srp/views.py:288 #, python-format msgid "Approved %(numrequests)s SRP requests" -msgstr "" +msgstr "Approvata/e %(numrequests)srichiesta/e di SRP" #: allianceauth/srp/views.py:320 msgid "Unable to locate selected SRP request" -msgstr "" +msgstr "Impossible trovare la richiesta di SRP selezionata" #: allianceauth/srp/views.py:323 #, python-format msgid "Rejected %(numrequests)s SRP requests." -msgstr "" +msgstr "Rifiutata/e %(numrequests)s richiesta/e di SRP." #: allianceauth/srp/views.py:336 #, python-format msgid "Unable to locate SRP request with ID %(requestid)s" -msgstr "" +msgstr "Impossibile trovare la richiesta di SRP con ID %(requestid)s" #: allianceauth/srp/views.py:360 #, python-format msgid "Saved changes to SRP fleet %(fleetname)s" -msgstr "" +msgstr "Salvati i cambiamenti al SRP della flotta %(fleetname)s" #: allianceauth/templates/allianceauth/admin-status/overview.html:8 msgid "Alliance Auth Notifications" -msgstr "" +msgstr "Notifiche Auth Alleanza" #: allianceauth/templates/allianceauth/admin-status/overview.html:16 msgid "Closed" -msgstr "" +msgstr "Chiuso" #: allianceauth/templates/allianceauth/admin-status/overview.html:28 msgid "Powered by GitLab" -msgstr "" +msgstr "Powered by GitLab" #: allianceauth/templates/allianceauth/admin-status/overview.html:35 msgid "Support Discord" -msgstr "" +msgstr "Discord di supporto" #: allianceauth/templates/allianceauth/admin-status/overview.html:43 msgid "Software Version" -msgstr "" +msgstr "Versione del software" #: allianceauth/templates/allianceauth/admin-status/overview.html:47 msgid "Current" -msgstr "" +msgstr "Attuale" #: allianceauth/templates/allianceauth/admin-status/overview.html:53 msgid "Latest Stable" -msgstr "" +msgstr "Ultima versione stabile" #: allianceauth/templates/allianceauth/admin-status/overview.html:59 msgid "Update available" -msgstr "" +msgstr "Aggiornamento disponibile" #: allianceauth/templates/allianceauth/admin-status/overview.html:64 msgid "Latest Pre-Release" -msgstr "" +msgstr "Ultima versione preliminare" #: allianceauth/templates/allianceauth/admin-status/overview.html:70 msgid "Pre-Release available" -msgstr "" +msgstr "Versione preliminare disponibile" #: allianceauth/templates/allianceauth/admin-status/overview.html:78 msgid "Task Queue" -msgstr "" +msgstr "Coda delle attività" #: allianceauth/templates/allianceauth/admin-status/overview.html:81 #, python-format @@ -2188,6 +2228,9 @@ msgid "" " Status of %(total)s processed tasks • last %(latest)s\n" " " msgstr "" +"\n" +" Stato di %(total)s attività elaborate • ultimo %(latest)s\n" +" " #: allianceauth/templates/allianceauth/admin-status/overview.html:95 #, python-format @@ -2196,183 +2239,185 @@ msgid "" " %(queue_length)s queued tasks\n" " " msgstr "" +"\n" +"%(queue_length)scompiti in coda" #: allianceauth/templates/allianceauth/top-menu-admin.html:9 msgid "Admin" -msgstr "" +msgstr "Amministratore" #: allianceauth/templates/allianceauth/top-menu-admin.html:19 msgid "AA Documentation" -msgstr "" +msgstr "Documentazione AA" #: allianceauth/templates/allianceauth/top-menu-admin.html:26 msgid "AA Support Discord" -msgstr "" +msgstr "AA Discord di supporto" #: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:10 #: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:14 msgid "User Menu" -msgstr "" +msgstr "Menu utente" #: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:56 msgid "Logout" -msgstr "" +msgstr "Disconnettersi" #: allianceauth/timerboard/form.py:53 msgid "Other" -msgstr "" +msgstr "Altro" #: allianceauth/timerboard/form.py:54 #: allianceauth/timerboard/templates/timerboard/view.html:62 #: allianceauth/timerboard/templates/timerboard/view.html:229 #: allianceauth/timerboard/templates/timerboard/view.html:402 msgid "Friendly" -msgstr "" +msgstr "Amichevole" #: allianceauth/timerboard/form.py:55 #: allianceauth/timerboard/templates/timerboard/view.html:57 #: allianceauth/timerboard/templates/timerboard/view.html:224 #: allianceauth/timerboard/templates/timerboard/view.html:397 msgid "Hostile" -msgstr "" +msgstr "Ostile" #: allianceauth/timerboard/form.py:56 #: allianceauth/timerboard/templates/timerboard/view.html:67 #: allianceauth/timerboard/templates/timerboard/view.html:234 #: allianceauth/timerboard/templates/timerboard/view.html:407 msgid "Neutral" -msgstr "" +msgstr "Neutrale" #: allianceauth/timerboard/form.py:58 #: allianceauth/timerboard/templates/timerboard/view.html:31 #: allianceauth/timerboard/templates/timerboard/view.html:198 #: allianceauth/timerboard/templates/timerboard/view.html:371 msgid "Details" -msgstr "" +msgstr "Dettagli" #: allianceauth/timerboard/form.py:60 msgid "Planet/Moon" -msgstr "" +msgstr "Pianeta/Luna" #: allianceauth/timerboard/form.py:61 msgid "Structure Type" -msgstr "" +msgstr "Tipologia di struttura" #: allianceauth/timerboard/form.py:62 msgid "Timer Type" -msgstr "" +msgstr "Tipologia di timer" #: allianceauth/timerboard/form.py:63 #: allianceauth/timerboard/templates/timerboard/view.html:32 #: allianceauth/timerboard/templates/timerboard/view.html:199 #: allianceauth/timerboard/templates/timerboard/view.html:372 msgid "Objective" -msgstr "" +msgstr "Obiettivo" #: allianceauth/timerboard/form.py:64 msgid "Days Remaining" -msgstr "" +msgstr "Giorni rimanenti" #: allianceauth/timerboard/form.py:65 msgid "Hours Remaining" -msgstr "" +msgstr "Ore rimanenti" #: allianceauth/timerboard/form.py:67 msgid "Minutes Remaining" -msgstr "" +msgstr "Minuti rimanenti " #: allianceauth/timerboard/form.py:69 msgid "Important" -msgstr "" +msgstr "Importante" #: allianceauth/timerboard/form.py:70 msgid "Corp-Restricted" -msgstr "" +msgstr "Limitato alla corporazione" #: allianceauth/timerboard/models.py:14 msgid "Not Specified" -msgstr "" +msgstr "Non specificato" #: allianceauth/timerboard/models.py:15 msgid "Shield" -msgstr "" +msgstr "Scudo" #: allianceauth/timerboard/models.py:16 msgid "Armor" -msgstr "" +msgstr "Armatura" #: allianceauth/timerboard/models.py:17 msgid "Hull" -msgstr "" +msgstr "Struttura" #: allianceauth/timerboard/models.py:18 msgid "Final" -msgstr "" +msgstr "Ultimo" #: allianceauth/timerboard/models.py:19 msgid "Anchoring" -msgstr "" +msgstr "In ancoraggio" #: allianceauth/timerboard/models.py:20 msgid "Unanchoring" -msgstr "" +msgstr "In disancoraggio" #: allianceauth/timerboard/templates/timerboard/timer_confirm_delete.html:11 msgid "Delete Timer" -msgstr "" +msgstr "Elimina timer " #: allianceauth/timerboard/templates/timerboard/timer_confirm_delete.html:19 #, python-format msgid "Are you sure you want to delete timer \"%(object)s\"?" -msgstr "" +msgstr "Sei sicuro di voler eliminare il timer \"%(object)s\"?" #: allianceauth/timerboard/templates/timerboard/timer_create_form.html:5 #: allianceauth/timerboard/templates/timerboard/timer_create_form.html:13 msgid "Create Timer" -msgstr "" +msgstr "Crea timer" #: allianceauth/timerboard/templates/timerboard/timer_create_form.html:9 #: allianceauth/timerboard/templates/timerboard/view.html:15 msgid "Create Structure Timer" -msgstr "" +msgstr "Crea timer struttura" #: allianceauth/timerboard/templates/timerboard/timer_update_form.html:5 #: allianceauth/timerboard/templates/timerboard/timer_update_form.html:9 #: allianceauth/timerboard/templates/timerboard/timer_update_form.html:13 msgid "Update Structure Timer" -msgstr "" +msgstr "Aggiorna timer struttura" #: allianceauth/timerboard/templates/timerboard/view.html:6 msgid "Structure Timer Management" -msgstr "" +msgstr "Gestione timer strutture" #: allianceauth/timerboard/templates/timerboard/view.html:11 msgid "Structure Timers" -msgstr "" +msgstr "Timer delle strutture" #: allianceauth/timerboard/templates/timerboard/view.html:27 msgid "Corp Timers" -msgstr "" +msgstr "Timer di corporazione" #: allianceauth/timerboard/templates/timerboard/view.html:34 #: allianceauth/timerboard/templates/timerboard/view.html:201 #: allianceauth/timerboard/templates/timerboard/view.html:374 msgid "Structure" -msgstr "" +msgstr "Struttura" #: allianceauth/timerboard/templates/timerboard/view.html:193 msgid "Next Timers" -msgstr "" +msgstr "Timer prossimi" #: allianceauth/timerboard/templates/timerboard/view.html:366 msgid "Past Timers" -msgstr "" +msgstr "Timer passati" #: allianceauth/timerboard/views.py:74 #, python-format msgid "Added new timer in %(system)s at %(time)s." -msgstr "" +msgstr "Aggiunto un nuovo timer in %(system)salle %(time)s." #: allianceauth/timerboard/views.py:82 msgid "Saved changes to the timer." -msgstr "" +msgstr "Salvati i cambiamenti al timer." diff --git a/allianceauth/locale/ja/LC_MESSAGES/django.po b/allianceauth/locale/ja/LC_MESSAGES/django.po index 4e560a81..86b8a848 100644 --- a/allianceauth/locale/ja/LC_MESSAGES/django.po +++ b/allianceauth/locale/ja/LC_MESSAGES/django.po @@ -4,8 +4,9 @@ # FIRST AUTHOR , YEAR. # # Translators: -# Foch Petain , 2020 +# Foch Petain , 2023 # kotaneko, 2023 +# Joel Falknau , 2023 # #, fuzzy msgid "" @@ -13,8 +14,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-10-09 18:20+1000\n" -"PO-Revision-Date: 2020-02-18 03:14+0000\n" -"Last-Translator: kotaneko, 2023\n" +"PO-Revision-Date: 2023-10-08 09:23+0000\n" +"Last-Translator: Joel Falknau , 2023\n" "Language-Team: Japanese (https://app.transifex.com/alliance-auth/teams/107430/ja/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/allianceauth/locale/ko_KR/LC_MESSAGES/django.po b/allianceauth/locale/ko_KR/LC_MESSAGES/django.po index 9bbe48bc..e289e85a 100644 --- a/allianceauth/locale/ko_KR/LC_MESSAGES/django.po +++ b/allianceauth/locale/ko_KR/LC_MESSAGES/django.po @@ -4,13 +4,13 @@ # FIRST AUTHOR , YEAR. # # Translators: -# None None , 2020 -# Seowon Jung , 2020 -# Olgeda Choi , 2020 -# Lahty , 2020 -# Joel Falknau , 2020 -# ThatRagingKid, 2022 -# jackfrost, 2022 +# None None , 2023 +# Joel Falknau , 2023 +# Seowon Jung , 2023 +# Olgeda Choi , 2023 +# ThatRagingKid, 2023 +# Lahty , 2023 +# jackfrost, 2023 # #, fuzzy msgid "" @@ -18,8 +18,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-10-09 18:20+1000\n" -"PO-Revision-Date: 2020-02-18 03:14+0000\n" -"Last-Translator: jackfrost, 2022\n" +"PO-Revision-Date: 2023-10-08 09:23+0000\n" +"Last-Translator: jackfrost, 2023\n" "Language-Team: Korean (Korea) (https://app.transifex.com/alliance-auth/teams/107430/ko_KR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/allianceauth/locale/ru/LC_MESSAGES/django.po b/allianceauth/locale/ru/LC_MESSAGES/django.po index 61cbd7f6..2de69488 100644 --- a/allianceauth/locale/ru/LC_MESSAGES/django.po +++ b/allianceauth/locale/ru/LC_MESSAGES/django.po @@ -4,9 +4,9 @@ # FIRST AUTHOR , YEAR. # # Translators: -# Alexander Gess , 2020 -# Yuriy K , 2020 -# Андрей Зубков , 2020 +# Yuriy K , 2023 +# Андрей Зубков , 2023 +# Alexander Gess , 2023 # Filipp Chertiev , 2023 # #, fuzzy @@ -15,7 +15,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-10-09 18:20+1000\n" -"PO-Revision-Date: 2020-02-18 03:14+0000\n" +"PO-Revision-Date: 2023-10-08 09:23+0000\n" "Last-Translator: Filipp Chertiev , 2023\n" "Language-Team: Russian (https://app.transifex.com/alliance-auth/teams/107430/ru/)\n" "MIME-Version: 1.0\n" diff --git a/allianceauth/locale/uk/LC_MESSAGES/django.po b/allianceauth/locale/uk/LC_MESSAGES/django.po index 658bd119..c89292c5 100644 --- a/allianceauth/locale/uk/LC_MESSAGES/django.po +++ b/allianceauth/locale/uk/LC_MESSAGES/django.po @@ -4,6 +4,7 @@ # FIRST AUTHOR , YEAR. # # Translators: +# Denys Ivchenko, 2023 # Kristof Swensen, 2023 # #, fuzzy @@ -12,7 +13,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-10-09 18:20+1000\n" -"PO-Revision-Date: 2020-02-18 03:14+0000\n" +"PO-Revision-Date: 2023-10-08 09:23+0000\n" "Last-Translator: Kristof Swensen, 2023\n" "Language-Team: Ukrainian (https://app.transifex.com/alliance-auth/teams/107430/uk/)\n" "MIME-Version: 1.0\n" @@ -32,7 +33,7 @@ msgstr "Google Analytics V4" #: allianceauth/authentication/decorators.py:37 msgid "A main character is required to perform that action. Add one below." msgstr "" -"Для виконання цієї дії потрібен головний персонаж. Додайте його нижче." +"Для виконання цієї дії потрібен основний персонаж. Додайте його нижче." #: allianceauth/authentication/forms.py:12 msgid "Email" @@ -124,7 +125,7 @@ msgstr "Додати персонажа" #: allianceauth/authentication/templates/authentication/dashboard.html:115 msgid "Change Main" -msgstr "Змінити головного персонажа" +msgstr "Змінити основного персонажа" #: allianceauth/authentication/templates/authentication/dashboard.html:125 msgid "Group Memberships" @@ -352,7 +353,7 @@ msgstr "Не вдалося зібрати статистику корпорац #: allianceauth/fleetactivitytracking/auth_hooks.py:9 msgid "Fleet Activity Tracking" -msgstr "Відстеження активності флоту" +msgstr "Відстеження активності флотів" #: allianceauth/fleetactivitytracking/forms.py:6 allianceauth/srp/form.py:8 #: allianceauth/srp/templates/srp/management.html:35 @@ -456,7 +457,7 @@ msgstr "Корабель" #: allianceauth/timerboard/templates/timerboard/view.html:202 #: allianceauth/timerboard/templates/timerboard/view.html:375 msgid "Eve Time" -msgstr "Час в грі" +msgstr "Ігровий час" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:33 #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:36 @@ -560,16 +561,16 @@ msgstr "Fats" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticscorpview.html:4 msgid "Fatlink Corp Statistics" -msgstr "Статистика корпорації Fatlink" +msgstr "Статистика фатів корпорації" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticscorpview.html:23 #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:24 msgid "Average fats" -msgstr "Середній показник fats" +msgstr "Середній показник фатів" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:4 msgid "Fatlink statistics" -msgstr "Статистика Fatlink" +msgstr "Статистика фатів" #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:20 msgid "Ticker" @@ -625,7 +626,7 @@ msgid "" "Cannot register the fleet participation for {character.character_name}. The " "character needs to be online." msgstr "" -"Не можна зареєструвати участь в флоті для {character.character_name}. " +"Не вдалося зареєструвати участь в флоті для {character.character_name}. " "Персонаж повинен бути в мережі." #: allianceauth/groupmanagement/auth_hooks.py:17 @@ -659,8 +660,7 @@ msgstr "" #: allianceauth/groupmanagement/models.py:113 msgid "Group is hidden from users but can still join with the correct link." msgstr "" -"Група прихована від користувачів, але можна приєднатися з правильним " -"посиланням." +"Група прихована від користувачів, але можна приєднатися за посиланням." #: allianceauth/groupmanagement/models.py:119 msgid "" @@ -1045,7 +1045,7 @@ msgstr "Ви вже є членом цієї групи." #: allianceauth/groupmanagement/views.py:358 msgid "You already have a pending application for that group." -msgstr "У вас вже є очікуюча заявка на вступ до цієї групи." +msgstr "Ви вже подали заявку на вступ до цієї групи." #: allianceauth/groupmanagement/views.py:367 #, python-format @@ -1062,7 +1062,7 @@ msgstr "Ви не є учасником цієї групи" #: allianceauth/groupmanagement/views.py:393 msgid "You already have a pending leave request for that group." -msgstr "Ви вже маєте очікувану запит на вихід з цієї групи." +msgstr "Ви вже подали запит на вихід з цієї групи." #: allianceauth/groupmanagement/views.py:409 #, python-format @@ -1321,7 +1321,7 @@ msgstr "Всі прочитані повідомлення видалено." #: allianceauth/optimer/auth_hooks.py:10 msgid "Fleet Operations" -msgstr "Операції флоту" +msgstr "Флотові операції" #: allianceauth/optimer/form.py:12 #: allianceauth/optimer/templates/optimer/fleetoptable.html:11 @@ -1345,7 +1345,7 @@ msgstr "Тип операції" #: allianceauth/optimer/form.py:17 #: allianceauth/srp/templates/srp/management.html:38 msgid "Fleet Commander" -msgstr "Командувач флоту" +msgstr "Командир флоту" #: allianceauth/optimer/form.py:22 allianceauth/srp/form.py:14 #: allianceauth/srp/templates/srp/data.html:91 @@ -1400,7 +1400,7 @@ msgstr "Немає наступних таймерів." #: allianceauth/optimer/templates/optimer/management.html:33 msgid "Past Fleet Operations" -msgstr "Минулі флотові операції" +msgstr "Завершені флотові операції" #: allianceauth/optimer/templates/optimer/management.html:37 #: allianceauth/timerboard/templates/timerboard/view.html:535 @@ -1484,7 +1484,7 @@ msgstr "Стани" #: allianceauth/services/abstract.py:72 msgid "That service account already exists" -msgstr "Такий обліковий запис сервісу вже існує" +msgstr "Такий сервісний обліковий запис вже існує" #: allianceauth/services/abstract.py:103 #, python-brace-format @@ -1505,7 +1505,7 @@ msgstr "Командир флоту:" #: allianceauth/services/forms.py:8 msgid "Fleet Comms:" -msgstr "Комунікації флоту:" +msgstr "Голосовий канал флоту:" #: allianceauth/services/forms.py:9 msgid "Fleet Type:" @@ -1545,7 +1545,7 @@ msgstr "Ні" #: allianceauth/services/forms.py:16 msgid "Important?*" -msgstr "Важливо?*" +msgstr "Важливий?*" #: allianceauth/services/forms.py:21 allianceauth/services/forms.py:31 msgid "Password" @@ -1614,7 +1614,7 @@ msgstr "Ви не маєте прав на доступ до Discourse." #: allianceauth/services/modules/discourse/views.py:34 msgid "You must have a main character set to access Discourse." -msgstr "Ви повинні мати головний персонаж, щоб отримати доступ до Discourse." +msgstr "Ви повинні мати основний персонаж, щоб отримати доступ до Discourse." #: allianceauth/services/modules/discourse/views.py:44 msgid "" @@ -1702,7 +1702,7 @@ msgstr "Відправлено трансляцію Jabber на %s" #: allianceauth/services/modules/openfire/views.py:144 msgid "Set jabber password." -msgstr "Встановлення пароля Jabber." +msgstr "Встановити пароль Jabber." #: allianceauth/services/modules/phpbb3/views.py:34 msgid "Activated forum account." @@ -1713,7 +1713,7 @@ msgstr "Активований обліковий запис форуму." #: allianceauth/services/modules/phpbb3/views.py:78 #: allianceauth/services/modules/phpbb3/views.py:101 msgid "An error occurred while processing your forum account." -msgstr "Виникла помилка під час обробки вашого облікового запису форуму." +msgstr "Виникла помилка під час обробки вашого облікового запису на форумі." #: allianceauth/services/modules/phpbb3/views.py:53 msgid "Deactivated forum account." @@ -1721,11 +1721,11 @@ msgstr "Деактивований обліковий запис форуму." #: allianceauth/services/modules/phpbb3/views.py:70 msgid "Reset forum password." -msgstr "Скидання пароля форуму." +msgstr "Скинути пароль форуму." #: allianceauth/services/modules/phpbb3/views.py:98 msgid "Set forum password." -msgstr "Встановлення пароля форуму." +msgstr "Встановити пароль форуму." #: allianceauth/services/modules/smf/views.py:52 msgid "Activated SMF account." @@ -1744,11 +1744,11 @@ msgstr "Деактивований обліковий запис SMF." #: allianceauth/services/modules/smf/views.py:95 msgid "Reset SMF password." -msgstr "Скидання пароля SMF." +msgstr "Скинути пароль SMF." #: allianceauth/services/modules/smf/views.py:121 msgid "Set SMF password." -msgstr "Встановлення пароля SMF." +msgstr "Встановити пароль SMF." #: allianceauth/services/modules/teamspeak3/forms.py:14 #, python-format @@ -1761,7 +1761,7 @@ msgstr "Оновити групи TS3" #: allianceauth/services/modules/teamspeak3/templates/services/teamspeak3/teamspeakjoin.html:5 msgid "Verify Teamspeak" -msgstr "Перевірте Teamspeak" +msgstr "Перевірити Teamspeak" #: allianceauth/services/modules/teamspeak3/templates/services/teamspeak3/teamspeakjoin.html:10 msgid "Verify Teamspeak Identity" @@ -1869,11 +1869,11 @@ msgstr "Керування послугами" #: allianceauth/services/templates/services/services.html:9 msgid "Available Services" -msgstr "Доступні послуги" +msgstr "Доступні сервіси" #: allianceauth/services/templates/services/services.html:14 msgid "Service" -msgstr "Послуга" +msgstr "Сервіс" #: allianceauth/services/templates/services/services.html:16 msgid "Domain" @@ -1881,7 +1881,7 @@ msgstr "Домен" #: allianceauth/srp/auth_hooks.py:13 msgid "Ship Replacement" -msgstr "Компенсація за корабель" +msgstr "Компенсації" #: allianceauth/srp/form.py:9 #: allianceauth/srp/templates/srp/management.html:36 diff --git a/allianceauth/locale/zh_Hans/LC_MESSAGES/django.po b/allianceauth/locale/zh_Hans/LC_MESSAGES/django.po index 81806592..b7767ec2 100644 --- a/allianceauth/locale/zh_Hans/LC_MESSAGES/django.po +++ b/allianceauth/locale/zh_Hans/LC_MESSAGES/django.po @@ -4,9 +4,10 @@ # FIRST AUTHOR , YEAR. # # Translators: -# Joel Falknau , 2020 -# Jesse . , 2020 -# Aaron BuBu <351793078@qq.com>, 2020 +# Jesse . , 2023 +# Aaron BuBu <351793078@qq.com>, 2023 +# Joel Falknau , 2023 +# Shen Yang, 2023 # #, fuzzy msgid "" @@ -14,8 +15,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-10-09 18:20+1000\n" -"PO-Revision-Date: 2020-02-18 03:14+0000\n" -"Last-Translator: Aaron BuBu <351793078@qq.com>, 2020\n" +"PO-Revision-Date: 2023-10-08 09:23+0000\n" +"Last-Translator: Shen Yang, 2023\n" "Language-Team: Chinese Simplified (https://app.transifex.com/alliance-auth/teams/107430/zh-Hans/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -46,48 +47,48 @@ msgstr "" #: allianceauth/authentication/models.py:80 msgid "English" -msgstr "" +msgstr "英语" #: allianceauth/authentication/models.py:81 msgid "German" -msgstr "" +msgstr "德语" #: allianceauth/authentication/models.py:82 msgid "Spanish" -msgstr "" +msgstr "西班牙语" #: allianceauth/authentication/models.py:83 msgid "Chinese Simplified" -msgstr "" +msgstr "简体中文" #: allianceauth/authentication/models.py:84 msgid "Russian" -msgstr "" +msgstr "俄语" #: allianceauth/authentication/models.py:85 msgid "Korean" -msgstr "" +msgstr "韩语" #: allianceauth/authentication/models.py:86 msgid "French" -msgstr "" +msgstr "法语" #: allianceauth/authentication/models.py:87 msgid "Japanese" -msgstr "" +msgstr "日语" #: allianceauth/authentication/models.py:88 msgid "Italian" -msgstr "" +msgstr "意大利语" #: allianceauth/authentication/models.py:91 msgid "Language" -msgstr "" +msgstr "语言" #: allianceauth/authentication/models.py:96 #: allianceauth/templates/allianceauth/night-toggle.html:6 msgid "Night Mode" -msgstr "" +msgstr "夜间模式" #: allianceauth/authentication/models.py:110 #, python-format @@ -696,7 +697,7 @@ msgstr "" #: allianceauth/groupmanagement/models.py:215 msgid "reason" -msgstr "" +msgstr "原因" #: allianceauth/groupmanagement/models.py:215 msgid "Reason why this name is reserved." @@ -754,7 +755,7 @@ msgstr "操作者" #: allianceauth/groupmanagement/templates/groupmanagement/audit.html:48 msgid "Removed" -msgstr "" +msgstr "已移除" #: allianceauth/groupmanagement/templates/groupmanagement/audit.html:60 msgid "All times displayed are EVE/UTC." @@ -1198,11 +1199,11 @@ msgstr "添加评论" #: allianceauth/notifications/models.py:21 msgid "danger" -msgstr "" +msgstr "危险" #: allianceauth/notifications/models.py:22 msgid "warning" -msgstr "" +msgstr "警告" #: allianceauth/notifications/models.py:23 msgid "info" @@ -1343,7 +1344,7 @@ msgstr "当前EVE游戏内时间" #: allianceauth/optimer/templates/optimer/management.html:26 msgid "Next Fleet Operations" -msgstr "" +msgstr "下一个舰队任务" #: allianceauth/optimer/templates/optimer/management.html:30 #: allianceauth/timerboard/templates/timerboard/view.html:362 @@ -1352,7 +1353,7 @@ msgstr "没有快到的时间节点,歇一会吧" #: allianceauth/optimer/templates/optimer/management.html:33 msgid "Past Fleet Operations" -msgstr "" +msgstr "过去的舰队任务" #: allianceauth/optimer/templates/optimer/management.html:37 #: allianceauth/timerboard/templates/timerboard/view.html:535 @@ -2257,15 +2258,15 @@ msgstr "" #: allianceauth/timerboard/models.py:15 msgid "Shield" -msgstr "" +msgstr "护盾" #: allianceauth/timerboard/models.py:16 msgid "Armor" -msgstr "" +msgstr "装甲" #: allianceauth/timerboard/models.py:17 msgid "Hull" -msgstr "" +msgstr "结构" #: allianceauth/timerboard/models.py:18 msgid "Final" @@ -2273,11 +2274,11 @@ msgstr "" #: allianceauth/timerboard/models.py:19 msgid "Anchoring" -msgstr "" +msgstr "铆钉" #: allianceauth/timerboard/models.py:20 msgid "Unanchoring" -msgstr "" +msgstr "解锚" #: allianceauth/timerboard/templates/timerboard/timer_confirm_delete.html:11 msgid "Delete Timer" From 322131cd4f178b81a41f7a4d4eef38a4fef0fb49 Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Wed, 8 Nov 2023 23:56:16 +1000 Subject: [PATCH 22/23] Update source language strings --- allianceauth/locale/en/LC_MESSAGES/django.po | 238 +++++++++++-------- 1 file changed, 135 insertions(+), 103 deletions(-) diff --git a/allianceauth/locale/en/LC_MESSAGES/django.po b/allianceauth/locale/en/LC_MESSAGES/django.po index cc639fd7..1c14c6ca 100644 --- a/allianceauth/locale/en/LC_MESSAGES/django.po +++ b/allianceauth/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-10-09 18:20+1000\n" +"POT-Creation-Date: 2023-11-08 23:55+1000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -26,7 +26,7 @@ msgstr "" msgid "Google Analytics V4" msgstr "" -#: allianceauth/authentication/decorators.py:37 +#: allianceauth/authentication/decorators.py:49 msgid "A main character is required to perform that action. Add one below." msgstr "" @@ -39,63 +39,68 @@ msgstr "" msgid "You are not allowed to add or remove these restricted groups: %s" msgstr "" -#: allianceauth/authentication/models.py:80 +#: allianceauth/authentication/models.py:71 msgid "English" msgstr "" -#: allianceauth/authentication/models.py:81 +#: allianceauth/authentication/models.py:72 msgid "German" msgstr "" -#: allianceauth/authentication/models.py:82 +#: allianceauth/authentication/models.py:73 msgid "Spanish" msgstr "" -#: allianceauth/authentication/models.py:83 +#: allianceauth/authentication/models.py:74 msgid "Chinese Simplified" msgstr "" -#: allianceauth/authentication/models.py:84 +#: allianceauth/authentication/models.py:75 msgid "Russian" msgstr "" -#: allianceauth/authentication/models.py:85 +#: allianceauth/authentication/models.py:76 msgid "Korean" msgstr "" -#: allianceauth/authentication/models.py:86 +#: allianceauth/authentication/models.py:77 msgid "French" msgstr "" -#: allianceauth/authentication/models.py:87 +#: allianceauth/authentication/models.py:78 msgid "Japanese" msgstr "" -#: allianceauth/authentication/models.py:88 +#: allianceauth/authentication/models.py:79 msgid "Italian" msgstr "" -#: allianceauth/authentication/models.py:91 -msgid "Language" +#: allianceauth/authentication/models.py:80 +msgid "Ukrainian" msgstr "" #: allianceauth/authentication/models.py:96 +msgid "Language" +msgstr "" + +#: allianceauth/authentication/models.py:101 #: allianceauth/templates/allianceauth/night-toggle.html:6 msgid "Night Mode" msgstr "" -#: allianceauth/authentication/models.py:110 +#: allianceauth/authentication/models.py:115 #, python-format msgid "State changed to: %s" msgstr "" -#: allianceauth/authentication/models.py:111 +#: allianceauth/authentication/models.py:116 #, python-format msgid "Your user's state is now: %(state)s" msgstr "" #: allianceauth/authentication/templates/authentication/dashboard.html:4 #: allianceauth/authentication/templates/authentication/dashboard.html:7 +#: allianceauth/authentication/templates/authentication/tokens.html:4 #: allianceauth/templates/allianceauth/side-menu.html:10 msgid "Dashboard" msgstr "" @@ -151,8 +156,49 @@ msgstr "" msgid "Alliance" msgstr "" +#: allianceauth/authentication/templates/authentication/tokens.html:7 +#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:62 +msgid "Token Management" +msgstr "" + +#: allianceauth/authentication/templates/authentication/tokens.html:12 +msgid "Scopes" +msgstr "" + +#: allianceauth/authentication/templates/authentication/tokens.html:13 +#: allianceauth/hrapplications/templates/hrapplications/management.html:28 +#: allianceauth/hrapplications/templates/hrapplications/management.html:83 +#: allianceauth/hrapplications/templates/hrapplications/management.html:127 +#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27 +#: allianceauth/hrapplications/templates/hrapplications/view.html:73 +#: allianceauth/srp/templates/srp/data.html:101 +#: allianceauth/srp/templates/srp/management.html:44 +msgid "Actions" +msgstr "" + +#: allianceauth/authentication/templates/authentication/tokens.html:14 +#: allianceauth/corputils/templates/corputils/corpstats.html:74 +#: allianceauth/corputils/templates/corputils/corpstats.html:112 +#: allianceauth/corputils/templates/corputils/corpstats.html:156 +#: allianceauth/corputils/templates/corputils/search.html:13 +#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22 +#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26 +#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30 +#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29 +#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55 +#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112 +msgid "Character" +msgstr "" + +#: allianceauth/authentication/templates/authentication/tokens.html:28 +msgid "" +"This page is a best attempt, but backups or database logs can still contain " +"your tokens. Always revoke tokens on https://community.eveonline.com/support/" +"third-party-applications/ where possible." +msgstr "" + #: allianceauth/authentication/templates/public/login.html:6 -#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:58 +#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:69 msgid "Login" msgstr "" @@ -184,47 +230,47 @@ msgstr "" msgid "Invalid or expired activation link." msgstr "" -#: allianceauth/authentication/views.py:77 +#: allianceauth/authentication/views.py:118 #, python-format msgid "" "Cannot change main character to %(char)s: character owned by a different " "account." msgstr "" -#: allianceauth/authentication/views.py:83 +#: allianceauth/authentication/views.py:124 #, python-format msgid "Changed main character to %(char)s" msgstr "" -#: allianceauth/authentication/views.py:92 +#: allianceauth/authentication/views.py:133 #, python-format msgid "Added %(name)s to your account." msgstr "" -#: allianceauth/authentication/views.py:94 +#: allianceauth/authentication/views.py:135 #, python-format msgid "Failed to add %(name)s to your account: they already have an account." msgstr "" -#: allianceauth/authentication/views.py:133 +#: allianceauth/authentication/views.py:174 msgid "Unable to authenticate as the selected character." msgstr "" -#: allianceauth/authentication/views.py:197 +#: allianceauth/authentication/views.py:238 msgid "Registration token has expired." msgstr "" -#: allianceauth/authentication/views.py:252 +#: allianceauth/authentication/views.py:296 msgid "" "Sent confirmation email. Please follow the link to confirm your email " "address." msgstr "" -#: allianceauth/authentication/views.py:257 +#: allianceauth/authentication/views.py:301 msgid "Confirmed your email address. Please login to continue." msgstr "" -#: allianceauth/authentication/views.py:262 +#: allianceauth/authentication/views.py:306 msgid "Registration of new accounts is not allowed at this time." msgstr "" @@ -267,19 +313,6 @@ msgstr "" msgid "Last update:" msgstr "" -#: allianceauth/corputils/templates/corputils/corpstats.html:74 -#: allianceauth/corputils/templates/corputils/corpstats.html:112 -#: allianceauth/corputils/templates/corputils/corpstats.html:156 -#: allianceauth/corputils/templates/corputils/search.html:13 -#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22 -#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26 -#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30 -#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29 -#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55 -#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112 -msgid "Character" -msgstr "" - #: allianceauth/corputils/templates/corputils/corpstats.html:75 #: allianceauth/corputils/templates/corputils/search.html:14 #: allianceauth/groupmanagement/templates/groupmanagement/audit.html:31 @@ -611,36 +644,41 @@ msgstr "" msgid "Group Management" msgstr "" -#: allianceauth/groupmanagement/forms.py:15 +#: allianceauth/groupmanagement/forms.py:18 +#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35 +msgid "Users" +msgstr "" + +#: allianceauth/groupmanagement/forms.py:52 msgid "This name has been reserved and can not be used for groups." msgstr "" -#: allianceauth/groupmanagement/forms.py:25 +#: allianceauth/groupmanagement/forms.py:62 msgid "(auto)" msgstr "" -#: allianceauth/groupmanagement/forms.py:34 +#: allianceauth/groupmanagement/forms.py:71 msgid "There already exists a group with that name." msgstr "" -#: allianceauth/groupmanagement/models.py:105 +#: allianceauth/groupmanagement/models.py:104 msgid "" "Internal group, users cannot see, join or request to join this group." "
    Used for groups such as Members, Corp_*, Alliance_* etc.
    Overrides " "Hidden and Open options when selected." msgstr "" -#: allianceauth/groupmanagement/models.py:113 +#: allianceauth/groupmanagement/models.py:112 msgid "Group is hidden from users but can still join with the correct link." msgstr "" -#: allianceauth/groupmanagement/models.py:119 +#: allianceauth/groupmanagement/models.py:118 msgid "" "Group is open and users will be automatically added upon request.
    If the " "group is not open users will need their request manually approved." msgstr "" -#: allianceauth/groupmanagement/models.py:126 +#: allianceauth/groupmanagement/models.py:125 msgid "" "Group is public. Any registered user is able to join this group, with " "visibility based on the other options set for this group.
    Auth will not " @@ -648,65 +686,65 @@ msgid "" "authenticated." msgstr "" -#: allianceauth/groupmanagement/models.py:135 +#: allianceauth/groupmanagement/models.py:134 msgid "" "Group is restricted. This means that adding or removing users for this group " "requires a superuser admin." msgstr "" -#: allianceauth/groupmanagement/models.py:144 +#: allianceauth/groupmanagement/models.py:143 msgid "" "Group leaders can process requests for this group. Use the auth." "group_management permission to allow a user to manage all groups.
    " msgstr "" -#: allianceauth/groupmanagement/models.py:154 +#: allianceauth/groupmanagement/models.py:153 msgid "" "Members of leader groups can process requests for this group. Use the " "auth.group_management permission to allow a user to manage all " "groups.
    " msgstr "" -#: allianceauth/groupmanagement/models.py:163 +#: allianceauth/groupmanagement/models.py:162 msgid "" "States listed here will have the ability to join this group provided they " "have the proper permissions.
    " msgstr "" -#: allianceauth/groupmanagement/models.py:171 +#: allianceauth/groupmanagement/models.py:170 msgid "" "Short description (max. 512 characters) of the group shown to users." msgstr "" -#: allianceauth/groupmanagement/models.py:178 +#: allianceauth/groupmanagement/models.py:177 msgid "Can request non-public groups" msgstr "" -#: allianceauth/groupmanagement/models.py:209 +#: allianceauth/groupmanagement/models.py:208 msgid "name" msgstr "" -#: allianceauth/groupmanagement/models.py:212 +#: allianceauth/groupmanagement/models.py:211 msgid "Name that can not be used for groups." msgstr "" -#: allianceauth/groupmanagement/models.py:215 +#: allianceauth/groupmanagement/models.py:214 msgid "reason" msgstr "" -#: allianceauth/groupmanagement/models.py:215 +#: allianceauth/groupmanagement/models.py:214 msgid "Reason why this name is reserved." msgstr "" -#: allianceauth/groupmanagement/models.py:218 +#: allianceauth/groupmanagement/models.py:217 msgid "created by" msgstr "" -#: allianceauth/groupmanagement/models.py:223 +#: allianceauth/groupmanagement/models.py:222 msgid "created at" msgstr "" -#: allianceauth/groupmanagement/models.py:223 +#: allianceauth/groupmanagement/models.py:222 msgid "Date when this entry was created" msgstr "" @@ -933,86 +971,86 @@ msgstr "" msgid "Group Membership" msgstr "" -#: allianceauth/groupmanagement/views.py:163 +#: allianceauth/groupmanagement/views.py:166 #, python-format msgid "Removed user %(user)s from group %(group)s." msgstr "" -#: allianceauth/groupmanagement/views.py:165 +#: allianceauth/groupmanagement/views.py:168 msgid "User does not exist in that group" msgstr "" -#: allianceauth/groupmanagement/views.py:168 +#: allianceauth/groupmanagement/views.py:171 msgid "Group does not exist" msgstr "" -#: allianceauth/groupmanagement/views.py:195 +#: allianceauth/groupmanagement/views.py:198 #, python-format msgid "Accepted application from %(mainchar)s to %(group)s." msgstr "" -#: allianceauth/groupmanagement/views.py:201 -#: allianceauth/groupmanagement/views.py:232 +#: allianceauth/groupmanagement/views.py:204 +#: allianceauth/groupmanagement/views.py:235 #, python-format msgid "" "An unhandled error occurred while processing the application from " "%(mainchar)s to %(group)s." msgstr "" -#: allianceauth/groupmanagement/views.py:226 +#: allianceauth/groupmanagement/views.py:229 #, python-format msgid "Rejected application from %(mainchar)s to %(group)s." msgstr "" -#: allianceauth/groupmanagement/views.py:261 +#: allianceauth/groupmanagement/views.py:264 #, python-format msgid "Accepted application from %(mainchar)s to leave %(group)s." msgstr "" -#: allianceauth/groupmanagement/views.py:266 -#: allianceauth/groupmanagement/views.py:298 +#: allianceauth/groupmanagement/views.py:269 +#: allianceauth/groupmanagement/views.py:301 #, python-format msgid "" "An unhandled error occurred while processing the application from " "%(mainchar)s to leave %(group)s." msgstr "" -#: allianceauth/groupmanagement/views.py:292 +#: allianceauth/groupmanagement/views.py:295 #, python-format msgid "Rejected application from %(mainchar)s to leave %(group)s." msgstr "" -#: allianceauth/groupmanagement/views.py:336 -#: allianceauth/groupmanagement/views.py:346 +#: allianceauth/groupmanagement/views.py:339 +#: allianceauth/groupmanagement/views.py:349 msgid "You cannot join that group" msgstr "" -#: allianceauth/groupmanagement/views.py:341 +#: allianceauth/groupmanagement/views.py:344 msgid "You are already a member of that group." msgstr "" -#: allianceauth/groupmanagement/views.py:358 +#: allianceauth/groupmanagement/views.py:361 msgid "You already have a pending application for that group." msgstr "" -#: allianceauth/groupmanagement/views.py:367 +#: allianceauth/groupmanagement/views.py:370 #, python-format msgid "Applied to group %(group)s." msgstr "" -#: allianceauth/groupmanagement/views.py:377 +#: allianceauth/groupmanagement/views.py:380 msgid "You cannot leave that group" msgstr "" -#: allianceauth/groupmanagement/views.py:381 +#: allianceauth/groupmanagement/views.py:384 msgid "You are not a member of that group" msgstr "" -#: allianceauth/groupmanagement/views.py:393 +#: allianceauth/groupmanagement/views.py:396 msgid "You already have a pending leave request for that group." msgstr "" -#: allianceauth/groupmanagement/views.py:409 +#: allianceauth/groupmanagement/views.py:412 #, python-format msgid "Applied to leave group %(group)s." msgstr "" @@ -1074,16 +1112,6 @@ msgstr "" msgid "Username" msgstr "" -#: allianceauth/hrapplications/templates/hrapplications/management.html:28 -#: allianceauth/hrapplications/templates/hrapplications/management.html:83 -#: allianceauth/hrapplications/templates/hrapplications/management.html:127 -#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27 -#: allianceauth/hrapplications/templates/hrapplications/view.html:73 -#: allianceauth/srp/templates/srp/data.html:101 -#: allianceauth/srp/templates/srp/management.html:44 -msgid "Actions" -msgstr "" - #: allianceauth/hrapplications/templates/hrapplications/management.html:38 #: allianceauth/hrapplications/templates/hrapplications/management.html:99 #: allianceauth/hrapplications/templates/hrapplications/management.html:143 @@ -1422,10 +1450,6 @@ msgstr "" msgid "Code Name" msgstr "" -#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35 -msgid "Users" -msgstr "" - #: allianceauth/permissions_tool/templates/permissions_tool/overview.html:41 msgid "States" msgstr "" @@ -2146,11 +2170,11 @@ msgid "" msgstr "" #: allianceauth/templates/allianceauth/admin-status/overview.html:95 -#, python-format -msgid "" -"\n" -" %(queue_length)s queued tasks\n" -" " +msgid "running" +msgstr "" + +#: allianceauth/templates/allianceauth/admin-status/overview.html:96 +msgid "queued" msgstr "" #: allianceauth/templates/allianceauth/top-menu-admin.html:9 @@ -2166,11 +2190,11 @@ msgid "AA Support Discord" msgstr "" #: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:10 -#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:14 +#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:16 msgid "User Menu" msgstr "" -#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:56 +#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:67 msgid "Logout" msgstr "" @@ -2226,22 +2250,30 @@ msgid "Objective" msgstr "" #: allianceauth/timerboard/form.py:64 -msgid "Days Remaining" +msgid "Absolute Timer" msgstr "" #: allianceauth/timerboard/form.py:65 -msgid "Hours Remaining" +msgid "Date and Time" +msgstr "" + +#: allianceauth/timerboard/form.py:66 +msgid "Days Remaining" msgstr "" #: allianceauth/timerboard/form.py:67 -msgid "Minutes Remaining" +msgid "Hours Remaining" msgstr "" #: allianceauth/timerboard/form.py:69 +msgid "Minutes Remaining" +msgstr "" + +#: allianceauth/timerboard/form.py:71 msgid "Important" msgstr "" -#: allianceauth/timerboard/form.py:70 +#: allianceauth/timerboard/form.py:72 msgid "Corp-Restricted" msgstr "" From 9ce19390403ad43817a73134497435bffcf63a18 Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Thu, 9 Nov 2023 00:00:28 +1000 Subject: [PATCH 23/23] Version Bump 3.8.0 --- allianceauth/__init__.py | 2 +- allianceauth/locale/de/LC_MESSAGES/django.mo | Bin 37872 -> 37984 bytes allianceauth/locale/es/LC_MESSAGES/django.mo | Bin 37814 -> 37819 bytes .../locale/fr_FR/LC_MESSAGES/django.mo | Bin 37724 -> 37715 bytes .../locale/it_IT/LC_MESSAGES/django.mo | Bin 17209 -> 38636 bytes allianceauth/locale/ja/LC_MESSAGES/django.mo | Bin 41641 -> 41667 bytes .../locale/ko_KR/LC_MESSAGES/django.mo | Bin 36909 -> 36909 bytes allianceauth/locale/ru/LC_MESSAGES/django.mo | Bin 47123 -> 47123 bytes allianceauth/locale/uk/LC_MESSAGES/django.mo | Bin 48143 -> 48104 bytes .../locale/zh_Hans/LC_MESSAGES/django.mo | Bin 27229 -> 28075 bytes docker/.env.example | 2 +- docker/Dockerfile | 2 +- 12 files changed, 3 insertions(+), 3 deletions(-) diff --git a/allianceauth/__init__.py b/allianceauth/__init__.py index d4748f2c..d458df19 100644 --- a/allianceauth/__init__.py +++ b/allianceauth/__init__.py @@ -5,7 +5,7 @@ manage online service access. # This will make sure the app is always imported when # Django starts so that shared_task will use this app. -__version__ = '3.7.1' +__version__ = '3.8.0' __title__ = 'Alliance Auth' __url__ = 'https://gitlab.com/allianceauth/allianceauth' NAME = f'{__title__} v{__version__}' diff --git a/allianceauth/locale/de/LC_MESSAGES/django.mo b/allianceauth/locale/de/LC_MESSAGES/django.mo index 58c63685e71b5fd8a2fa33262e44681a76b4510b..c403cb25dd97f1956d10801ebb266782ffb8b30c 100644 GIT binary patch delta 5280 zcmZwI32;@_9mnzeLLduESPTMTxr8;4AObCvXdw`y0#aF3ERg%i&C4Und-1)SXd>_c z!wvzw&{n~%N&zV<^D2&%sx|7ggIH*%hzk~>tt{4Mq&Oq3_WR4dWOSx844-q(J@1_V z`JW}9?@2kcH|6;cvJ&?ghS9XZFgoK!?21>hJ$71X7?ZFUPR0e;4xhwy+>1T&AYO+@ zF$d3J5Bv{y$LvLhaXsc^M=VB-KWmYZFtRBuq(M5UA8bGk_#_U-LpT~wV=wGdY8Y)X zAJuOZ4#Zn94Xe;Z2a9nBPQmwZBAOO`(XtX=hkZ0?rJtf!dSlQq_-EAe-~D(B>v85{ zZ-S$kLH#eNOq@oo?4PKBE@KvElo>`}?1@_OI2?+_I1;N96gp6N%i8OJ z<(KeQ>}Pu`sK7g@??VOhwQp*<7eFV})(pUIc(djjDB?y`AP=MV>Q^`n zU&boDfDJe=G7WFR(D9f1lU>3a-&Q~wyXz|?TdI0++*f(9ClO7)Mi zB?G9Gy@nb1w(lw5v#6ARf+hGh>UTv;ycJK!RO+Rub{nl*hWF8e>W-v zhfuem+4m&s&|N^KGPTkhsE2O>>iZH^2#i96--<}!q_Pi@*(w>j%KNj2J1k?gcP??+_ zA^+-F>NiyS9TTX4)}U5!!1oX;6R)6FcpOvk0&)S2PjDj6ih9?}MP=x9)Rw%D`u(S< zv+-?|{41i=8ZW|3>_oi_D#a%16yJpXa2|HSI@EycQ2lrMK7(4>OaAv`s7#$f6F)&^ zw&T6txWf|^G|&|6jCc8lQ9o?(U4#1JLpT+m_uH@frp3H1>W0dw>DPz*^>L`Jn2bYk z8tN=1;uI8d6KaosiCu7??{860^D)%nIfq$z6_wid@s_J^?ij`+m|N=| z;@{zZ>PJz5+*j8!Pr^u0&;;91_j3>G&>iu86BXcbRDgd+4RFc-{w2Og{l7R7Pu=G| z={`uLp?-=YweHvykzfn#>6V;$5ScNy^PSh!V7nS-CQMcg=D$s9H znag;)bmh*jYW-Hg4(jXFb6BJ7dB!-g~uuAZ9eS#4r)c0@ducO{f5-p$3|VTF5;(21o z2dHb9+UTvU2dZO#)c4_7gtKuH?m(^V6e<({!d$$9+UuUHz06ET1>~T{TZ+o`8Z>qP zw^Ptwy?{632~p#~`R+n1mwUWW>N8!B_VQHSvmYHLsUo{}bF%7q)-ho|c z;n)5U+3YoPmmbHD==PQ4_y~%G^oRMCVZt z&o`*U+Ix$a`a)E{x!3_is9WP;drYjSpj7WbrRvwHjwewoJ%^g$BARGy^?ukNHE;nc zgA-7PY8Gmxm6(DF%*RzY1)swq_-`D*XQR(HULzWcP=9o`;LZ3ts$r8w{MwjVR2wgEK2i~@jfBjy zupPH)s&vB9h#8JMrX7x$w_3F|&f*FyW>q?TwPWScSeYHG3NNl0VU{!>3E5_C#IYmp z+Y4?z*p4|P3}$g+VaJJI`yOq~ORibiCD0~Z5pf@0bbm&y z+S05H)1`E|J3ZLZ%?@7YRt2-%!=>4+^-HCLTFd#C*;=l!hP0OVTLW9mm#kdByyrWi z4RJ39r?u9jjYFvqbDI{=$eI!h*}+IS9=A=FXu5AL&T&)9Mz{7|(RjT(tL*d6XIDHn zXlOLJ#9r*=#m}zT<<79T^qfa(NJr3$+2-VEtR@<}wxni^d~p|UiM{jQ}` za!+M?z+GmW?%P#)9T>u_YCgnt{5Vn8H)&R92D-Hl9JH-i&*k@F~>%H~6ni0x)MIi2It zayu3=Nut?&gmK+18*|IMP)q(;DQD8Ea_r=(O+N_?DyH`& zJ5o#BF>?@cMI$^$ikTZ+ZO*o11mb2jb$9P{#EaKX6ooX4ywPuACcicW( rb26+53+4TC+=*MW`)QQ8wof^W>!tku8y4Go!tMD`x8&SyJ5&A#{`D-u delta 5217 zcmZwJd3aRS8OQNENeBr9!oCDBm#~C@2@ohnWJy>8A|M5nHkM^FxtR>f%*0uMgk>NC zg2;LiaeL4zT0pHj3RMwWQ>xk25eGw_yhE!tVGWcET61 z2Oh_6_!)M=77GlcEB3@TI2<+q_ytD7=uBe<4`e0kg9hw~+ps_G!D0A1wnt+jlR^j7 z!ribh7Gg`Bg(jBcI9!G$_yS&w-=YE<=}ou;yoND`2QT1Qyo41Rz&}gzUaZGXK4*c= zm`Q&pDiaT&BHN4F&_T?`*D(iAqawbD12DDHFb3n*2^v{6evTRtz*ZPX4P1qad@oMH zcX2fKw+v$@`cNBr#`Q321Fv9jd>56;?_4`pIT_AJWhyb2hCV36ws`8w=D!^BeqfQua)6hhppi-R@a5AyX z^)}SRw(I?_k77E{pTep5Yt+Q4i=2qtVjBHC)bo5)pv9<6PsWa{Z_K8l>i46LVkznt ztVI>uF4P(BL#6U4YN9{6e(t_ct#Qu$D%5vHn1>};fIiH`P1q9e!Vau&>~>!~jV z9FCKA`YTZD6fACDCt(bwp#>(OuGP;_MHg~iirQc!>WFrtCb%C}8+-5+K7l2;VToZ( z#A8^B+5D&s#-HEfUZZMf@OYqx(>qd&cb_ z!#4C!q89us>L~w#ITp_M$%ymC<>qz(Om?zaoh8U=VIVrR-Vkg)gEa`7`0VIlPXy@0Xc3gv+pb>RV zZ1?$Y>`woH+dqyP_c7{dzD8Zoj9ZGkNsPP9e4}XINcm{`Ho3+k{#-ipcLuGmgeuu-G|EPbEx7yio;po zI8I|Ewz$nX+p*Y!{sL5LE!0GD)C6l#N3|7;@ll+Kr?4juTJIdi6l_WV2GsAsT+|T; zP-lNDCN%MVG!(&p)O9?9THp_uj-R>y6Lm!2peAgy!HFanZ=ydCwZYY>_nS})?#90O z94bTaVFrG&f&6RW*F4ZhTHWrXxI1bCeNY=1g>fu(`v*}I97Y}8%czOZpys*YzE9og z)It_s%kvSaj7CuNHtN2s7&h=gJG={((nF|UzAvyp_PfI{uES}lg?C~m?#3+Ki>>hh z>gZlV1@;Omqo+_AK98xGw#g~tj06oWG!<0?t8fH9=XxH8(9hrOr240*g?*?6f~W-& zsG_|SRjkjVQhyRP?sLpSV~cZZ+MqU^$fKcD7hwTTLJbU~QnVbkz^!QF-KY z9e#j=anN?dpbm|ju@XN-CN!?IonOQt>ZtBP1@sUqpeIoQ9K@FT?QEiv#)H>TXLlSm z@Q=*{_@4~6qW_Vd{N$?oYugMd98z33bfh_C*r=hy?Yi;;PjT{|@(U>?Wle`7W@W&N zT4rfYED#QvO9GKf(+Y&lDc*Qp%vbG=czrP|Vpdq8rUS8nKUQRp55!`YS=DsNZ`r5k zO-}b)(YUXAyDz^-L!5Rj5DdnOjM8{C7GY%6d7TW-ALU80qV~Q8OYK1mSEg220sENi&9iq{ zTY8trBPIbY@mANG(U?_jg(@v`LO4;`KK#V_fbgpQu{s z>Fl?f9_Fh^%xs98{RSwr1<_=m>K&fU$yU@?T^nXEM*@ZEWsC{%!)($ZOWZk^THibssH+AwtystE^!UIL9rl6TitcvYfH?~erZ+z8bcU?2-`}<+Pv8HX-4=)83T9ABm%_)zkFu8YK z%;O2#z1Qdc*yQ?ADdwcY>E1vs^%611bFZ2nrYP{4 ztuIZ!x&DZ!^Ar+p`mNdkHNsV$Mdk5&-|cx_7gMltT}dm}5Hq7hS?%R&+ox~Ovokin zV}G=9S#B^8Gi&$>;HH$uW7VcpFpHb7PbFiQ-%&q$lxfTf1X*QHeVq~XQioiuICC21 zRv^Z*!8)s!A=IcbC+zn#V1{>bz^}9=M{K&mQ+T~Mq$op#rVp8_U)1!*t9TYPXH%Oz z2~qnovnmj>U)((3V?OI(~w^(Bv7D z0%_O>r=t3Ip!zSN=7}0_%qSd*tj+B7Xi#MnJi$&-fQ^Z#V<47c2v(vJT!qc?E!39n zMZH&tTG4f9=tN_h5~rgoG61!JhcFRGU=Q@>(NJc)o!9YU;+TBxSO1~LZ z+Wn}+PP*q8QCoQ%m6-37Hi4EHMBEm2mSU0P;hAh2Gk8#q+S`~(_7G-aGVyrSO4eW! zzKX5zBx+B8a{h+_#9>d_#G)~rI0aSeLFkLy&<}TEF!P%|H2it+DJtWWsDaMmFua6H zAhp1*Gz+zoQ7)c{sze3q_sdZWdC~bk>P($NZRL3v*JEquHw`pY;_%6KqF7Ys$*594 zh#Gi2YM>%iWoBU_?nJHVENX>ys0v*{-GT;ef+16k>40GvfW6SuDeq4s5+A|4aT@Ac zRpC9j)%72B{Xe5W&wUDwiN|2n`>CkPWTVC%iwQUdyWl$1dxufKKUYZo18H1v4{o4V z_z(6*zo~X*{jojqU<|?n)Bt6!-*fRo)L~qKs>D`QBGoS5kEz6mQ5Cy6mHKO-#zl4y zgHS7uLX{{BN8&>`7+=SZSdVeos@PU61GSLR=!5yFl23M)U3nySN;cc@-+5EzW9GDQi)cIe=}k4wXm)suC@x+XY0RZcD7yGwC$+ z;t*8EdA7rpVGi+PJcxC83pYP)%p%nm(w?Y(h=29b4kN z?)k^=`3Vf?`Pb^#{l7*-CA)>nuuZwmyd$O%r=t3&ph~>}H9-}I;aZHq9TM% z^?!%a#P!$>n^)N1--n*=`#>66@dVTgN>E?0a@0U;u?4=2Drq%p;tx@W^)$A{pRhIF zLTzQlOuN!9s090CERI1P`sZd+|704~JkSr$qZ0TXKf(soiVw}Q2^>YO{46%cA5qun zBI^6#H{15dpc3tZNtlTmXBz63l%p23em3>jwb;%BU57oW_y{(_Z%`AQ!36vlm3hn@ zZU$zfCOC*OcmoqLoN+s2Ka9iz7cauQiQmCCc-(W1OW2hMX09z+H&lu5$M!e|^}}*h zDc7M^xD%E5N2to3Lap>H>X6l;4>jg$2#ChrKOoJTHny4;mS$1g4|*bR+i0w^1)% zMorYD(jL-KXC&&n#i2@?hMIUVD$()I3fI31b=I~ZTj`m1-3xnAhv*CU!ZlPPf1_@N z&vSNfo1so|80z@|)Y%z|s=x%yz(S11ZKw&4x&G6r-~E7HbpNl?&`Klb+k5>eY9%kB zUVIySVlBquFR1T9`17`ZFe=dz&OFp9pNdhq7M1Y(sOx+I@4?m!=x2VDPD7dJVgOD+ zA1p#8@HFZW%|;El0kxO=oyVMKP+N2fRe?WHTibo1J)BRWFL4!W%hsZ&Q@GW2971Jw z1nbd>TEYXB zuoPALd8p^BaWt++t@u~e;WA5XLJ_Eh??v5~k?4;#SPWFHxV~R?F1HDyky4QQw2e7i@oTR4Ip}_Ixa=)FpUlD^V+7 zje4&ZHO~R$ea{@Bp;LX%b=<^YVxJW@k(Q_dqnt_Dh&T(AZ~*qgQq-4nCn~|?n2uLa zTh(c$br`CD7Pis-f00Ii9@JoW{0mv6Nm#}IKHQ5Mz<0In?~dA66}^K~x+W)eP3je$l$PE-WpznzMBwP+(xOSxSw;EJ L7S}A#jZga@b742i delta 4017 zcmXZcc~F-{9LMn$6%a)Z^8gipo@j^xim0Gij;Pq-Z5rZ*Ct{%BO^;V8o*m&+d1>yU%lYhu?u6etVaOc&n-z zQ*Wd(ZH+OTUoggpUtkZc!YFK)VN5jk#S+ZLrRX=xn4Y){{qZCQ;~5-*6&Qv|nZ|@; zKMcSO?0{LB#xuQXl+vLIe#Ah$j1gFgk74!EHjzfym^cYFJ{TKf4%Wn%Q46d@EnJFP zcpEmt53nwNi>>kUXwR6=H2lXHQy;sdb}$(A;8<*fxv0d}V>8^0-S8N8!TZ<|JB?)y zoQxXZjvBv$S|@UxF~e~nvNyBSqd}ET;CQ=07FH+D!P=OIAy|k?a5aYFyQm}Ek9w{G zwWCUBNR~0Rh!as2Nkwg-560jCOhj)14Q2Mevl0gq`zF{IW}p_F?_7l{{YF%2526w~ z<@zt9j`AKVv1$`-0>M~^xIXGGwLq?iXVPiRrlSmXw!TUB5~g50@hH?z)?ysKiS_Ul z>P#;>|HB~S(8)Hj#@K+k1FF=$(I2;B0Pepk<*1Fk>fDREQ>Rf!`IC#Quo3Hr#p z_@{3C7YwBTA-2Q7Y4-U9RAtgp^A5+yaU!@nY0vT#2g07E~f-E?GI@3rOw@2NT6x0z8MxFf()SvSeH@*RbiQjh~!@9)Y*EDn~DsTvz zJp1BMtVKB0#rderi%Nu;3%`=T<= zumdI!pC?|5N3jAQ;KrGJV)%Bxov?KQe?j6zRK=<=6mO#D^_yiAYJl2MJnFe*4AJ-h z6b+r(Ak+~IM_saU_yfL(ov<%|sdOyFG(3sA10i#a;je4Dpepk=YJqJSj(c4HQP+PG z8_<773-21dpIf{PP)DE&yf3SSiM8z0}ucJy@hFbU|)MY)3k$4ds;a${GhR?S< zjYcKd1EX;m>e9b7pZdqsD5FC!{Dey2PdtuyP&+=nz$Wl1YUk&$I$l71Mwe0l2fso) z?n5OSjd7Tanr9m7E6GP~sI-v!>$BKKhdzgLRD2x$@Egf0Xt&UoxFVQ3qwd-!-+zehISgh)PC2`qIU8c>cJh@8TVmZ z{0;R#2z%L%r=b!Z;LJeX^2yi?i&3B5UexD&37ccRR~Tn~lSo6E4@LceGO-3uK_xI9 zb&2MnCR~p?%Y)9(o!_C3=nAR=f1!>xcA34LT=yjUCQtkHsL2wKcs;eh?7tY<)YqOi`wx<)N}7)0DiWD`p=?qnhs^u zYo$GcbkqbxQJ+t~a~bNnw=f2`U{CxC_3N#>%1#`GI*K;v!$fR>!>}vP#kN@P(dbFz z0&3!>tL<%Wg|&#g;-kcz=@>-+K&*oqsESQNRct=S;X+KpeW<%oiLJ2B8oO|R)ZOs% zY1F2%3st%UsELoF{^h4ppVzObirhn$K4PsM?~E$tbEq>Pjw*FFJ~~R&&ex!x+lN}` z5c0fdj?>VsKJNx@V=(bUR3gE}cEU(!4EoWZf^nFNT`(8*r`(B3@C0_lYpA1YR$}ds z8lR03`u<;~(Tk4vFaiHYHfdU~Gv;aBkD8!bsU43+9nBcjQA|bctN?Wcg)Uxh1&pD|&2!OZe?BinWTAGY~3 Aj{pDw diff --git a/allianceauth/locale/fr_FR/LC_MESSAGES/django.mo b/allianceauth/locale/fr_FR/LC_MESSAGES/django.mo index 0ce53fff6632dc9bf699a4e8f5999c03e3e341ef..26fac9e22624a53a2d07bba981e186c54865789f 100644 GIT binary patch delta 4002 zcmXZfc~F-{9LMn$Q4mDv=LsnOKtu!y40Qq(LGT){G#WukMGh}S6V1EF`vC3GY09gn zbWl6Im{QBoawf0Q%A;now8@cgb8I$S#ao2xdyZd`~_q*TyKF`PxwE>rF0}hsk zd$moB=}=(I5M#`VLSrUi(0F6UVhN_;$If4HA$=bY$r|j9fknoIVJ5b~p*Ru8Vgw#S zAAW(scooy}dXe!=77gF?#x%z<7=#7b0Vks-F2X3>i0yEX`@P=vzeCOc9X0SWF z@2!bO^O7(Wb1)W1PV|iFMPoJtk+>UMVLis-1x&(wsK}!y*@feAApJ}ngv&4sPq}`; zWc&M2%wxO;bMR|?0e!{Bl;diT#!MP_QIU_EVk4Y{O65${N#>(6QiJVrHzwk7Y>Brp z2Jd4sK2c)l_eTXj#Py%S1p4DK1HBbA6yc{h08J^^0NJRNZpLujin@w@s6dWmYrKkW z@D3{AM%29EGJ?Qx)OalFxn%5$**KN`O*xHO3|z#{*pIyEBt@u`EWr@mgH?DKRSOBs zj>jDIV>yQ6I#i%rP?@U5XR#ieqi>ou5<}VF_-QD@9;j6IL2a0eqi~e_eJ6IIzXzM) zdDI5qplat1DuAZb?Q`L%Or@jN9f2ysLR5frurvFcRWx+RyHF`Qh8^*u9>BY(386Er zF{tsLsMm80wm=VqaRX|-&8TADi-C9q;D@3`^P zr~tom{RY%?_g%jcb+^qaBwa-qDihsM#hZq@vTRi52BQKfpGE$)P$dKUQY}WEqy}{r zJ8>u;#=-aywZOnio60GuJ6(f1*$z}q96)V&8Wq?DRLZZQA8()zXuR1rH3_H;@UAdE-$5&2jzp7*78!r?;O*A_MhUgtt-e zb>0g$@&eQXlTevifV%q)sFQ6$rFt9cj(4GI<~(YhJE-R#;S(4**V+y_uxAo!=q~!B z4+o(p7N7#EzzcX5BbpfVMiuozfA2h7-C6VP{E?^)o;?7{x&~DnAD|Zg2OpmlwL#!Qo0+z#^<%I- zCZYn(#whkTW8J_k)X6>c;TBX4)S@;xh1%deYN1Qm78|ewnnm`xNYwmT)LYXFd*f)- zcVG=hVl{d#Y3!z<2oIsE`BT*RB~(B+P$~Tjb+X{acH>A?ic?X=I2=`6g{Tuw$5yxm zpTcTP$ItL-{Btq+*Mdn)Y~+2Nxu^w(yZ-a2$jeX}nSq+O4x8eesONWJFWisH)J@bU zy8(5OR!i-{;!uI6E+zju`2YsA&@ha`k=PBVp+1?f;yA2Br80DxeJ%&}ToI<>YSh(y z{l==$wmGNwD@sU8ibwh*JS5@WC$JK;Xm0;f@_{0UVHf1qBw2dI;(kafZ! zR3@TPSD1qO5M`p)%f?*Pe|(bBdzXeDyokD!Yp4%No8`6^`k>y5k*Ey{QAIb)xe6oc zZ^Z4&Vh^OK#uP=WMcPyRLWIRhvJm@@vE$G*8ApbhS83t6R>gf{kD2ELTDVoX7~x} z+kFz1>dUANZ(|@nKz&O8LltG}M*D|H1?JIz-+2#pg}pb~*Eb)Pfyu5v6_t6fibevB zjo1zAup?eW-O;}oiV-i{2^~?X?TtG5VC;^?sLa)1OWcV%zoE+kqt^WuS;sSh zuh{zvKdiK@*#BhR_JYqd{|7Uu BD{24$ delta 4011 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 YgKxk_EE!sYw6+3u=8_u)>lq3D7xq5mTmS$7 delta 6737 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 diff --git a/allianceauth/locale/ja/LC_MESSAGES/django.mo b/allianceauth/locale/ja/LC_MESSAGES/django.mo index d917d5a9a8c412a05fddc3cf316ff79e319ae565..09421c026c9636b6f6c3e68470f72fdadd85e6d6 100644 GIT binary patch delta 4045 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 M`31EHb7F@5573E7oB#j- diff --git a/allianceauth/locale/ko_KR/LC_MESSAGES/django.mo b/allianceauth/locale/ko_KR/LC_MESSAGES/django.mo index 235e7c8af907fbd188ce184f5aa0e50c67ac599e..acb3fa85a8e642c7459c31cee64d598b8e35efa6 100644 GIT binary patch delta 34 qcmZ3xfNAXlrVX88yvDkQ2D%0o3I>)|M#ht;g{d+cZ{8DDXbAwuOA7!1 delta 34 qcmZ3xfNAXlrVX88yau`kM!JR;3I@hjh9;Azg{d+cZQc`BXbAwt$qM)Y diff --git a/allianceauth/locale/ru/LC_MESSAGES/django.mo b/allianceauth/locale/ru/LC_MESSAGES/django.mo index d342dbcf5f2039b44981714ac1d79eb48d893d54..e41d5000ffc535ba56fb119a47538a502d6cacf7 100644 GIT binary patch delta 28 kcmbRIfobvwrVYtayvDkQ2D%0o3I>)|M#h^9q87&j0F#9YfB*mh delta 28 kcmbRIfobvwrVYtayau`kM!JR;3I@hjh9;W}q87&j0FyHbc>n+a diff --git a/allianceauth/locale/uk/LC_MESSAGES/django.mo b/allianceauth/locale/uk/LC_MESSAGES/django.mo index d14537e99def09a881a3bc57152acfdce48fc437..3a8c0d0db9b16797b55b5cfb3dfbe30ba920d3e7 100644 GIT binary patch delta 4109 zcmY+`c~n)$9l-HH79#?(Ba8S@a2HTSMO1K!M&kmh)g(nlQx!r4v0|bnK0s8WRjF4& z0}=_cRTRP%1QoRLB=OXweJ`G-LXSrn!E55w^*9Ernnm70WcDC06P47cRkl?tR#Lc@5h#5wqLJb?q)fG6_w4rXst zDw=ve&czD!#b4t+{1|O`i*(9-4=@3Pw=3n3OK~)=MG3UnPNA7XBl=+akF=R6smw!J z-~jsLNy~F60rsM7VAT$#mSHwZy%S}jTPQpK!fKBwP-+78DJTKjGbqS_{Wt=va5#3O z416D>aKQRKYNt+V3dYmE9%WoP%D4-di0|M${0~atDKF}cJ%tg}Hz4EeY7d3SXsE^n ztVg+2eY%6Xk15m#zob+uE=D<`GL*~oHp=fqb}6+8m!M><9OJMSWyemGK)*%VaM*6S zYn*=^g@rU^p>#Zt67e0B!2W_>_&1b^U4E>0=#PV`KY`OR4M*YulzxpUm#qtB!5cUc z?^ty=o?Zm&t56Cua5~1~YLo%{FbH48aoA@4-iL0~AA4D;pQ1N%Pt|KU3w`$J%en+* z-aR-RYf#2rLJ9CH+GU6DQIN~`0nWrfSw<4w66$L(9BVNGdr&SETQ0iQ14(3O61R@q-Yn) zdg9qMvZ_unf7U%J;BR&*C9$#*a}lQ+`A#53EPosJ(@Pr06C} zD*I5*_)DCC-bZ!HW}@`V!6+=mG_1i<_ytN}{^k1B#GtgtqTH!;lyL{q7h8~Z?5c-C zG!6Z@4hK*sTF2F%g!vePH7J?rwAyc=C-pCJ1pXUkfzV?*#mVSHeLarHT#Ut&D4*VU zaJ0Pt&nUV5SeiJO`gN3d zKY;SRm{_4Roq*}Aua;U3)fi9RL^=C=mTr~$uUs@rCg!3WuEuHj15CzplvKZqE$Dty zsZH39b8z@6rIzDrlsk78?Wq(#r!XDkUe%XrGX_#`LOFsSOvO)8&U9jx-q8x2Ono;_ z!6uBuehfj+YMr4`DBqc6^u>i3j^D2)|I#s^hG2Zf>Uai&s5j%|cn#;F`)Qrx#h6Zg z6;8zllnMK+-~Wzs7Y5bn_Grsg96@^qJ`B8u{L9%k(I7kirPc9|mILTVd-!X5p~)x{ zXQC`vflT59M{Jdi@MTQOC=q{y zGND_8ULXSH%;uszqYPYyW!R5*aTazp>bvn3%DY!hI-p@FcO(&Id=^UJ$8n6j|4s^W zYwx1$+`CzSB4?mPJQv5{N|aRYM7f-Yu^j7A0-p9W{T*3`@@jVA<5-Kc@y{rki$16O z&%oiVuU1l!)MlX#3(*r#<27tTFU)Gu6BM94*D@T5*Dw@6M7d<&;1lR`UcdJ>7)HGw zB{SDi`u_^;%PHKakccxbaDi|uN=AN<+34G<1KN$U^L;oTt55=e3uR}0R{H~#j0Lyp z%Q^==sApgXK8GoIy^Z|;kb-(cr)m?Pi`VgX0z=SBo()D9R^&|&u}}=px%u;@UNJTo4fc{U>6dz z>gd)P%f77COVnF10AsG`0F%(4`g0hFJJAadq1>^klN5X?)L9MfDDSoh{qO_xe&p_C z?}W)y;wQ(?w8baQnwns4dp6v|z1Lan=rPMPXAkys^f=mV&QeFOv&gyEan)I2WNvxE zT$uG6cP~11IEx(Z&I)I-F*Y~GlWuL!5@&^@-Av0(bunIi!_PRKcg6_Gi#9iGo9Gp| z-(fPK*U|3ia&+6A2k2gGRu#6oJTlbSP!M9QCvl+e}!N!R_Ij+oVxY*0x99_;L zhrgG|@6HMvTzeRBn{z)QSDKTG*SZ?h z8beI8bimz}h)na~NB-WGOwcYJon?*=<9x*!^Uc%y-HlOoLB{&JGSU35?jzTswU6xn zv&OfLO-%u=-&?-OC~6w*{b2rF_WybF*%)I^xsc>xT-Z9;%)993 z5`E0kWg~!2M~97odmR^LL(+DMbRFfF%TA`O4K}(vMh$(WgZXtw${>AoMtNqqxw@;{ F^}h*BOECZd delta 4203 zcmZwJdr(!!9l-HLUSd%ZL_rWQ_#mR<6*Z+`MHC+xwXr&#(cp75Af`&xD8%R$L5zw* zIEn_r2Vi|g1&$YpppNNiG&adOO=oPaMw`*rq|v5{9gU5#-(UA++CTEwXMcOo+5PQr zcMsfq)S>KghlV>Lo;6CTh1p8Iir29Pr{pMAgMLet+KaUqhof_q>VgX#^RO$i2m50g z_Czlx;)fWF-{A-hTB_7o9E~wpxKw#m4;lyP5L+-AKf)I<@D-)VNzK5S*oKUyLVm4O zCtQn>Sc36*040&j7=;h84|ZCn)BsFCd2c%Q!mMQ;rMlBtL&rcY#h+s{?!t#yi(8lL z6%5H!svq$}9F3bX1TWzoyoN4pr<^k0O&pGaE0hYwRP2k>P!e6?p>dSP9_)f+S8AuD zlyW}G1o;?>TO6xV5nfbpx?Hk^$TA4Zv|9S7rWr@!-SRDn1SB|*g*cSB0%gVTp(J`AWx+pr zUCtW&@1l`G$1Icw_n~Bb1tqZ?7>svOw&H7)75c7aU-4)7Jf>qG%tv`{56WRXiZbD8 z9E4Y#_+J>!{HoI%`o(xmB%X-!!fKR(w&8PF?fiZb{fHmpTlg(FdVsF zmpU6Gh>KC)t3esJ7Co{;lZNa~JIYF~Vls9hyG%?)S=lCx#zPo~?_m_)MS0$5gYHkk zaN;>ATd)#GVI8{hHp+Y53aNiD8bb>83zM)L@m!QG$U{k}2)E%G?1vLJ>MdD{J&5yB zo-aeGTrJ9iT2NMc3CG|yOu~pFrNZ!qA~Kgfnny=0=AvX)iZOTuUHHD!e-9;LzhZs; z`e3*ZUp)K-uWq6m{Jwv)UeKmDSrGkuQRX?ZMPJKSbP?b1(2x>8MOnebtvd7B*oSxt z%HiAM^jD&+=n$@B;ATuG9#P822v;NLQ+3D`?G2YN0l3bKOLX9XdJjD>~yOV@{C^^ctnzc($yaFY`osI`_H1SE4 zdw(ATF|txuIu@rhze;vGwxXN(Aj;nV-tlXUBo5uJD=`@Th%;~mW@0L?M=A9gdJ^Q`A;dX2 z3@dRcUdEpI7^OlX)%r{fM5$mBM&Y<>>Msw@qoW6|aUR@(;l#UfJf6UG{061OBWoxf zjzvjuC(3{qP=3FOau&XD`h)lB-=D+Y^k<+XzHlG)m%S~gLss1EJb2adZ`h4~-~IX) zgrf{R31z}u48jr&#d6HRI*h@4C=&%9(BqH9Y~sl%6>IX)aM8GfGJyX-%D~T1N*PnDujx=sC!US6x78@Oa4XW}Znj#n@R>ksRRZaF@{{`5b^BQCe_loBW70L(-=YVOf@*gP{pxomxaS2AB(g~HIto$t;h=)-Uw^3Gh*Xe(Z zQn9!OeONOwfH()Ua5<*o?;5E8A{xPsx>T>?SmG9(hEGs3&ur3%a1qMsUyBJ?g^764 z@gd6n?rZ7<(orgsgYmcyrDBJ$A6_&)`kH+~hYUR6w4P`@MiXbDRHguB;8TttqEz7T zj^SQ?xYAHox)fi+6(}qI2;DfSS)a8ml**QSXh_V%}F0xEx@Us4XFE3cN(tK&z7@weaUTL<@S`EgL<@L@0)AJ?=cRg%1*o7{u$z_@L z2D{Qc^~Nb5qhdu^&~Dd+1*=|JvTUhwuDVCy5AB-u>wJog-k$P~Owz==n~g?KLUP9eQ>V!mPRoI30MkYQ>ZxcEF*rUexM`C>W$w;X0 zZ6qI^(UXx{tOgg0Jon$M8+nba&C;Veen$Ahm@d>`R@+1Y3Rz;mlPLjyOye~do%Z)} z*HLK_k%F@wUYEVo#Xy^-YIc#m!`>`oGl5;k0~FFoThhaLxg^YJ_I8bKr+=r6^?&ck Xa8el4@}_mr`)ZWWk1~h0zU%uRcCC$g diff --git a/allianceauth/locale/zh_Hans/LC_MESSAGES/django.mo b/allianceauth/locale/zh_Hans/LC_MESSAGES/django.mo index f0be3a20005565d75377e7cfaba5019628f88b15..d24dad4aeb33a6fb2d1015590c7bd27dd1f14a63 100644 GIT binary patch delta 9770 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