shadowsocks-manager 0.1.2__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. bin/ssm-dev-start +34 -0
  2. bin/ssm-dev-stop +20 -0
  3. bin/ssm-setup +221 -0
  4. bin/ssm-test +113 -0
  5. shadowsocks_manager/.env +18 -0
  6. shadowsocks_manager/__init__.py +0 -0
  7. shadowsocks_manager/__main__.py +45 -0
  8. shadowsocks_manager/args_formatter/__init__.py +74 -0
  9. shadowsocks_manager/args_formatter/tests.py +42 -0
  10. shadowsocks_manager/domain/__init__.py +0 -0
  11. shadowsocks_manager/domain/admin.py +78 -0
  12. shadowsocks_manager/domain/apps.py +10 -0
  13. shadowsocks_manager/domain/fixtures/nameserver.json +1 -0
  14. shadowsocks_manager/domain/migrations/__init__.py +0 -0
  15. shadowsocks_manager/domain/models.py +265 -0
  16. shadowsocks_manager/domain/serializers.py +25 -0
  17. shadowsocks_manager/domain/tests.py +138 -0
  18. shadowsocks_manager/domain/urls.py +18 -0
  19. shadowsocks_manager/domain/views.py +38 -0
  20. shadowsocks_manager/dynamicmethod/__init__.py +0 -0
  21. shadowsocks_manager/dynamicmethod/admin.py +8 -0
  22. shadowsocks_manager/dynamicmethod/apps.py +10 -0
  23. shadowsocks_manager/dynamicmethod/migrations/__init__.py +0 -0
  24. shadowsocks_manager/dynamicmethod/models.py +96 -0
  25. shadowsocks_manager/dynamicmethod/tests.py +8 -0
  26. shadowsocks_manager/dynamicmethod/views.py +8 -0
  27. shadowsocks_manager/fixtures/auth.group.json +1 -0
  28. shadowsocks_manager/fixtures/django_celery_beat.crontabschedule.json +38 -0
  29. shadowsocks_manager/fixtures/django_celery_beat.intervalschedule.json +10 -0
  30. shadowsocks_manager/fixtures/django_celery_beat.periodictask.json +108 -0
  31. shadowsocks_manager/fixtures/sites.site.json +1 -0
  32. shadowsocks_manager/manage.py +29 -0
  33. shadowsocks_manager/notification/__init__.py +0 -0
  34. shadowsocks_manager/notification/admin.py +18 -0
  35. shadowsocks_manager/notification/apps.py +10 -0
  36. shadowsocks_manager/notification/fixtures/template.json +13 -0
  37. shadowsocks_manager/notification/migrations/__init__.py +0 -0
  38. shadowsocks_manager/notification/models.py +66 -0
  39. shadowsocks_manager/notification/serializers.py +13 -0
  40. shadowsocks_manager/notification/tests.py +93 -0
  41. shadowsocks_manager/notification/urls.py +16 -0
  42. shadowsocks_manager/notification/views.py +19 -0
  43. shadowsocks_manager/retry/__init__.py +68 -0
  44. shadowsocks_manager/retry/tests.py +42 -0
  45. shadowsocks_manager/shadowsocks_manager/__init__.py +6 -0
  46. shadowsocks_manager/shadowsocks_manager/celery.py +27 -0
  47. shadowsocks_manager/shadowsocks_manager/settings.py +217 -0
  48. shadowsocks_manager/shadowsocks_manager/urls.py +31 -0
  49. shadowsocks_manager/shadowsocks_manager/wsgi.py +19 -0
  50. shadowsocks_manager/shadowsocksz/__init__.py +0 -0
  51. shadowsocks_manager/shadowsocksz/admin.py +188 -0
  52. shadowsocks_manager/shadowsocksz/apps.py +10 -0
  53. shadowsocks_manager/shadowsocksz/fixtures/config.json +1 -0
  54. shadowsocks_manager/shadowsocksz/management/__init__.py +0 -0
  55. shadowsocks_manager/shadowsocksz/management/commands/__init__.py +0 -0
  56. shadowsocks_manager/shadowsocksz/management/commands/shadowsocks_config.py +24 -0
  57. shadowsocks_manager/shadowsocksz/migrations/__init__.py +0 -0
  58. shadowsocks_manager/shadowsocksz/models.py +1024 -0
  59. shadowsocks_manager/shadowsocksz/serializers.py +41 -0
  60. shadowsocks_manager/shadowsocksz/tasks.py +21 -0
  61. shadowsocks_manager/shadowsocksz/tests.py +470 -0
  62. shadowsocks_manager/shadowsocksz/urls.py +20 -0
  63. shadowsocks_manager/shadowsocksz/views.py +53 -0
  64. shadowsocks_manager/singleton/__init__.py +0 -0
  65. shadowsocks_manager/singleton/admin.py +8 -0
  66. shadowsocks_manager/singleton/apps.py +10 -0
  67. shadowsocks_manager/singleton/migrations/__init__.py +0 -0
  68. shadowsocks_manager/singleton/models.py +46 -0
  69. shadowsocks_manager/singleton/tests.py +8 -0
  70. shadowsocks_manager/singleton/views.py +8 -0
  71. shadowsocks_manager/statistic/__init__.py +0 -0
  72. shadowsocks_manager/statistic/admin.py +78 -0
  73. shadowsocks_manager/statistic/apps.py +10 -0
  74. shadowsocks_manager/statistic/migrations/__init__.py +0 -0
  75. shadowsocks_manager/statistic/models.py +308 -0
  76. shadowsocks_manager/statistic/serializers.py +19 -0
  77. shadowsocks_manager/statistic/tasks.py +17 -0
  78. shadowsocks_manager/statistic/tests.py +99 -0
  79. shadowsocks_manager/statistic/urls.py +16 -0
  80. shadowsocks_manager/statistic/views.py +26 -0
  81. shadowsocks_manager/utils/__init__.py +0 -0
  82. shadowsocks_manager/utils/celery.py +28 -0
  83. shadowsocks_manager/utils/createsuperuser.py +57 -0
  84. shadowsocks_manager/utils/dotenv.py +70 -0
  85. shadowsocks_manager/utils/manage.py +29 -0
  86. shadowsocks_manager/utils/uwsgi.py +27 -0
  87. shadowsocks_manager-0.1.2.data/scripts/ssm-dev-start +34 -0
  88. shadowsocks_manager-0.1.2.data/scripts/ssm-dev-stop +20 -0
  89. shadowsocks_manager-0.1.2.data/scripts/ssm-setup +221 -0
  90. shadowsocks_manager-0.1.2.data/scripts/ssm-test +113 -0
  91. shadowsocks_manager-0.1.2.dist-info/LICENSE +21 -0
  92. shadowsocks_manager-0.1.2.dist-info/METADATA +532 -0
  93. shadowsocks_manager-0.1.2.dist-info/RECORD +96 -0
  94. shadowsocks_manager-0.1.2.dist-info/WHEEL +6 -0
  95. shadowsocks_manager-0.1.2.dist-info/entry_points.txt +7 -0
  96. shadowsocks_manager-0.1.2.dist-info/top_level.txt +2 -0
bin/ssm-dev-start ADDED
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env bash
2
+
3
+ #? Description:
4
+ #? Start the Django server, and the Celery beat and worker.
5
+ #? If you need to run the server under a specific Python environment, make
6
+ #? sure to activate it before to run the server.
7
+ #?
8
+ #? Usage:
9
+ #? ssm-dev-start.sh [[IP:]PORT]
10
+ #?
11
+ #? Options:
12
+ #? [[IP:]PORT]
13
+ #?
14
+ #? The IP address and the port that the Django server is listening on.
15
+ #? The default IP address is `127.0.0.1`.
16
+ #? The default PORT is `8000`.
17
+ #?
18
+
19
+ # exit on any error
20
+ set -e -o pipefail
21
+
22
+ function main () {
23
+ declare listen=$1
24
+
25
+ # don't quote the variable $listen, leave it this way on purpose
26
+ # shellcheck disable=SC2086
27
+ ssm-manage runserver $listen --insecure &
28
+ sleep 1
29
+ ssm-celery -A shadowsocks_manager worker -l info -B &
30
+ }
31
+
32
+ main "$@"
33
+
34
+ exit
bin/ssm-dev-stop ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env bash
2
+
3
+ #? Description:
4
+ #? Stop the Django server, and the Celery beat and worker.
5
+ #?
6
+ #? Usage:
7
+ #? ssm-dev-stop.sh
8
+ #?
9
+
10
+ function main () {
11
+ # Kill the Celery processes
12
+ pkill -f "celery -A shadowsocks_manager"
13
+
14
+ # Kill the Django runserver process
15
+ pkill -f "python manage.py runserver"
16
+ }
17
+
18
+ main "$@"
19
+
20
+ exit
bin/ssm-setup ADDED
@@ -0,0 +1,221 @@
1
+ #!/usr/bin/env bash
2
+
3
+ #? Description:
4
+ #? Setup shadowsocks-manager in your Python environment.
5
+ #? If you need to run the setup under a specific Python environment, make
6
+ #? sure to activate it before to run the setup.
7
+ #?
8
+ #? Usage:
9
+ #? ssm-setup.sh [-e ENV ...]
10
+ #? [-c] [-m] [-l] [-u USERNAME -p PASSWORD [-M EMAIL]] [-r PORT_BEGIN] [-R PORT_END] [-h]
11
+ #?
12
+ #? Options:
13
+ #? [-e ENV ...]
14
+ #?
15
+ #? Set the environment variables in KEY=VALUE format for .env file.
16
+ #? The .env file is used by Django settings.
17
+ #? This option can be used multiple times.
18
+ #?
19
+ #? The valid KEYs are:
20
+ #?
21
+ #? - SSM_SECRET_KEY
22
+ #?
23
+ #? Set Django's SECRET_KEY.
24
+ #? The default value is hardcoded in the .env file and Django's settings.
25
+ #? Do not use the default value in production environment.
26
+ #? Below command will generate a random SECRET_KEY:
27
+ #? ```sh
28
+ #? $ od -vN 25 -An -tx1 /dev/urandom | tr -d ' \n'
29
+ #? ```
30
+ #?
31
+ #? - SSM_DEBUG
32
+ #?
33
+ #? Set Django's DEBUG.
34
+ #? The value can be 'True' or 'False'.
35
+ #? The default value depends on the .env file and Django's settings.
36
+ #? Do not use value SSM_DEBUG=True in production environment.
37
+ #?
38
+ #? - SSM_TIME_ZONE
39
+ #?
40
+ #? Set Django's TIME_ZONE.
41
+ #? The value can be any valid timezone name.
42
+ #? The default value depends on the .env file and Django's settings.
43
+ #?
44
+ #? - SSM_DATA_HOME
45
+ #?
46
+ #? Set the base directory for the Django database and static files.
47
+ #? The default value depends on the .env file and Django's settings.
48
+ #?
49
+ #? - SSM_MEMCACHED_HOST, SSM_MEMCACHED_PORT
50
+ #?
51
+ #? Set the Memcached server's host and port which are used by Django cache.
52
+ #? The default value depends on the .env file and Django's settings.
53
+ #?
54
+ #? - SSM_RABBITMQ_HOST, SSM_RABBITMQ_PORT
55
+ #?
56
+ #? Set the RabbitMQ server's host and port which are used by Celery.
57
+ #? The default value depends on the .env file and Django's settings.
58
+ #?
59
+ #? However, this script will not check the validity of the KEYs and VALUEs.
60
+ #?
61
+ #? [-c]
62
+ #?
63
+ #? Collect Django static files.
64
+ #? This is necessary for the first time setup.
65
+ #?
66
+ #? [-m]
67
+ #?
68
+ #? Migrate Django database.
69
+ #? This is necessary for the first time setup.
70
+ #?
71
+ #? [-l]
72
+ #?
73
+ #? Load Django fixtures.
74
+ #? This is necessary for the first time setup.
75
+ #?
76
+ #? [-u USERNAME]
77
+ #?
78
+ #? Username for shadowsocks-manager administrator.
79
+ #? No default value.
80
+ #? This is necessary for the first time setup.
81
+ #?
82
+ #? [-p PASSWORD]
83
+ #?
84
+ #? Password for shadowsocks-manager administrator'.
85
+ #? No default value.
86
+ #? This is necessary for the first time setup.
87
+ #?
88
+ #? [-M EMAIL]
89
+ #?
90
+ #? Email for the shadowsocks-manager administrator.
91
+ #? Also, be used as the sender of the account notification Email.
92
+ #? No default value.
93
+ #?
94
+ #? [-r PORT_BEGIN]
95
+ #?
96
+ #? The beginning port number for Shadowsocks nodes.
97
+ #? The default value depends on the Django fixture data.
98
+ #?
99
+ #? [-R PORT_END]
100
+ #?
101
+ #? The ending port number for Shadowsocks nodes.
102
+ #? The default value depends on the Django fixture data.
103
+ #?
104
+ #? [-h]
105
+ #?
106
+ #? This help.
107
+ #?
108
+ #? Example:
109
+ #? # First time setup in development environment:
110
+ #? $ ssm-setup -c -m -l -u admin -p yourpassword
111
+ #?
112
+ #? # Update a development environment to be production ready:
113
+ #? $ ssm-setup -e SSM_SECRET_KEY=yourkey -e SSM_DEBUG=False
114
+ #?
115
+ #? # First time setup in production environment:
116
+ #? $ ssm-setup -e SSM_SECRET_KEY=yourkey -e SSM_DEBUG=False -c -m -l -u admin -p yourpassword -M admin@yourdomain.com
117
+ #?
118
+
119
+ # exit on any error
120
+ set -e -o pipefail
121
+
122
+ function usage () {
123
+ awk '/^#\?/ {sub("^[ ]*#\\?[ ]?", ""); print}' "$0" \
124
+ | awk '{gsub(/^[^ ]+.*/, "\033[1m&\033[0m"); print}'
125
+ }
126
+
127
+ function check-os () {
128
+ if [[ $(uname) != 'Linux' && $(uname) != 'Darwin' ]]; then
129
+ printf "fatal: this script support Linux and MacOS only.\n" >&2
130
+ return 255
131
+ fi
132
+ }
133
+
134
+ function main () {
135
+ declare -a envs
136
+ declare collect_flag migrate_flag loaddata_flag username password email port_begin port_end \
137
+ OPTIND OPTARG opt
138
+
139
+ while getopts e:cmlu:p:M:r:R:h opt; do
140
+ case $opt in
141
+ e)
142
+ envs+=("$OPTARG")
143
+ ;;
144
+ c)
145
+ collect_flag=1
146
+ ;;
147
+ m)
148
+ migrate_flag=1
149
+ ;;
150
+ l)
151
+ loaddata_flag=1
152
+ ;;
153
+ u)
154
+ username=$OPTARG
155
+ ;;
156
+ p)
157
+ password=$OPTARG
158
+ ;;
159
+ M)
160
+ email=$OPTARG
161
+ ;;
162
+ r)
163
+ port_begin=$OPTARG
164
+ ;;
165
+ R)
166
+ port_end=$OPTARG
167
+ ;;
168
+ *)
169
+ usage
170
+ exit 255
171
+ ;;
172
+ esac
173
+ done
174
+
175
+ check-os
176
+
177
+ if [[ $# -eq 0 ]]; then
178
+ usage
179
+ exit 255
180
+ fi
181
+
182
+ if [[ -n ${envs[*]} ]]; then
183
+ ssm-dotenv -w "${envs[@]}"
184
+ fi
185
+
186
+ if [[ -n $collect_flag ]]; then
187
+ ssm-manage collectstatic --no-input -c
188
+ fi
189
+
190
+ if [[ -n $migrate_flag ]]; then
191
+ ssm-manage makemigrations
192
+ ssm-manage migrate
193
+ fi
194
+
195
+ if [[ -n $loaddata_flag ]]; then
196
+ ssm-manage loaddata fixtures/auth.group.json \
197
+ fixtures/sites.site.json \
198
+ fixtures/django_celery_beat.crontabschedule.json \
199
+ fixtures/django_celery_beat.intervalschedule.json \
200
+ fixtures/django_celery_beat.periodictask.json \
201
+ config.json \
202
+ template.json \
203
+ nameserver.json
204
+ fi
205
+
206
+ if [[ -n $username && -n $password ]]; then
207
+ ssm-createsuperuser --username "$username" --password "$password" --email "$email"
208
+ fi
209
+
210
+ if [[ -n $port_begin ]]; then
211
+ ssm-manage shadowsocks_config --port-begin "$port_begin"
212
+ fi
213
+
214
+ if [[ -n $port_end ]]; then
215
+ ssm-manage shadowsocks_config --port-end "$port_end"
216
+ fi
217
+ }
218
+
219
+ main "$@"
220
+
221
+ exit
bin/ssm-test ADDED
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env bash
2
+
3
+ #? Description:
4
+ #? Test shadowsocks-manager in your Python environment.
5
+ #? If you need to run the setup under a specific Python environment, make
6
+ #? sure to activate it before to run the setup.
7
+ #?
8
+ #? Usage:
9
+ #? ssm-test.sh [-t] [-c] [-g [-o OUTFILE]] [-u] [-h]
10
+ #?
11
+ #? Options:
12
+ #? [-t]
13
+ #?
14
+ #? Run the test.
15
+ #?
16
+ #? [-c]
17
+ #?
18
+ #? Run the test with coverage.
19
+ #?
20
+ #? [-g]
21
+ #?
22
+ #? Generate coverage report with the previous coverage data.
23
+ #?
24
+ #? [-o OUTFILE]
25
+ #?
26
+ #? The output file for the coverage report.
27
+ #? The default is `coverage.xml`.
28
+ #?
29
+ #? [-u]
30
+ #?
31
+ #? Upload the coverage report to codecov.io.
32
+ #?
33
+ #? [-h]
34
+ #?
35
+ #? This help.
36
+ #?
37
+ #? Environment:
38
+ #? The following environment variables are used by this script:
39
+ #?
40
+ #? - CODECOV_TOKEN
41
+ #?
42
+ #? Required if -u is provided.
43
+ #?
44
+ #? Example:
45
+ #? # run the test without coverage, and generate coverage report, and upload it
46
+ #? $ ssm-test.sh -c -g -u
47
+ #?
48
+
49
+ # exit on any error
50
+ set -e -o pipefail
51
+
52
+ function usage () {
53
+ awk '/^#\?/ {sub("^[ ]*#\\?[ ]?", ""); print}' "$0" \
54
+ | awk '{gsub(/^[^ ]+.*/, "\033[1m&\033[0m"); print}'
55
+ }
56
+
57
+ function main () {
58
+ declare test=0 coverage=0 report=0 outfile_opt upload=0 \
59
+ OPTIND OPTARG opt
60
+
61
+ while getopts tcgo:u opt; do
62
+ case $opt in
63
+ t)
64
+ test=1
65
+ ;;
66
+ c)
67
+ coverage=1
68
+ ;;
69
+ g)
70
+ report=1
71
+ ;;
72
+ o)
73
+ outfile_opt=(-o "$OPTARG")
74
+ ;;
75
+ u)
76
+ upload=1
77
+ ;;
78
+ *)
79
+ usage
80
+ exit 255
81
+ ;;
82
+ esac
83
+ done
84
+
85
+ if [[ $# -eq 0 ]]; then
86
+ usage
87
+ exit 255
88
+ fi
89
+
90
+ # run the test
91
+ if [[ ${test} -eq 1 ]]; then
92
+ ssm-manage test --no-input -v 2
93
+ fi
94
+
95
+ # run the test with coverage
96
+ if [[ ${coverage} -eq 1 ]]; then
97
+ ssm coverage run manage.py test --no-input -v 2
98
+ fi
99
+
100
+ # generate coverage report
101
+ if [[ ${report} -eq 1 ]]; then
102
+ ssm coverage xml "${outfile_opt[@]}"
103
+ fi
104
+
105
+ # upload coverage report
106
+ if [[ ${upload} -eq 1 ]]; then
107
+ ssm codecovcli upload-process
108
+ fi
109
+ }
110
+
111
+ main "$@"
112
+
113
+ exit
@@ -0,0 +1,18 @@
1
+ # Django settings: SECRET_KEY
2
+ # SECURITY WARNING: keep the secret key used in production secret!
3
+ SSM_SECRET_KEY=ef24ff499c58a21711385e8a6b31a7680fb41765b8ca0cb451
4
+
5
+ # Django settings: DEBUG
6
+ # SECURITY WARNING: don't run with debug turned on in production!
7
+ SSM_DEBUG=True
8
+
9
+ # Django settings: TIME_ZONE
10
+ SSM_TIME_ZONE=UTC
11
+
12
+ # Django settings: CACHES
13
+ SSM_MEMCACHED_HOST=localhost
14
+ SSM_MEMCACHED_PORT=11211
15
+
16
+ # Django settings: CELERY_BROKER_URL
17
+ SSM_RABBITMQ_HOST=localhost
18
+ SSM_RABBITMQ_PORT=5672
File without changes
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env python
2
+ import os
3
+ import sys
4
+ import subprocess
5
+ from docopt import docopt
6
+
7
+
8
+ def main():
9
+ """
10
+ Description:
11
+ Make the proxy call after adding the django root to the python path and changing the current directory to the django root.
12
+
13
+ Usage:
14
+ ssm COMMAND [OPTIONS]
15
+
16
+ Options:
17
+ COMMAND The command to be run.
18
+ OPTIONS All options are transparently passing to the called command.
19
+
20
+ Returns:
21
+ None
22
+
23
+ Example:
24
+ $ ssm python manage.py runserver
25
+ $ ssm uwsgi --ini uwsgi.ini
26
+ $ ssm celery -A shadowsocks_manager worker -l info
27
+ """
28
+ #docopt(main.__doc__)
29
+
30
+ django_root = os.path.dirname(os.path.abspath(__file__))
31
+
32
+ # add the django root to the python path to allow django commands to be run from any directory
33
+ if django_root not in sys.path:
34
+ sys.path.insert(0, django_root)
35
+
36
+ # change dir to the django root to allow the dir-sensitive commands(such as loaddata) to be run from any directory
37
+ os.chdir(django_root)
38
+
39
+
40
+ # make the proxy call
41
+ return subprocess.call(sys.argv[1:])
42
+
43
+
44
+ if __name__ == '__main__':
45
+ sys.exit(main())
@@ -0,0 +1,74 @@
1
+ # py2.7 and py3 compatibility imports
2
+ from __future__ import unicode_literals
3
+ from builtins import range
4
+ from builtins import object
5
+ from functools import reduce
6
+
7
+
8
+ class Formatter(object):
9
+ """
10
+ Return the input-syntax string presentation of args and kwargs list, delimited by comma `, `.
11
+ The value of the args and kwargs are formatted as the canonical string presentation.
12
+
13
+ Usage:
14
+ >>> f = Formatter(*args, **kwargs)
15
+ >>> print(f)
16
+
17
+ Example:
18
+ >>> print(Formatter('foo', 1, x='bar', y=2))
19
+ 'foo', 1, x='bar', y=2
20
+
21
+ Use Case:
22
+ # log the input arguments of methods.
23
+ def foo(*args, **kwargs):
24
+ message = Formatter(*args, **kwargs).to_string())
25
+ logger.debug('foo: {}'.format(message))
26
+ """
27
+
28
+ def __init__(self, *args, **kwargs):
29
+ """
30
+ Initialize the Formatter to have two members: args, kwargs
31
+ """
32
+ self.args = args
33
+ self.kwargs = kwargs
34
+
35
+ def __str__(self, *args, **kwargs):
36
+ return self.to_string(*args, **kwargs)
37
+
38
+ def args_to_string(self):
39
+ """
40
+ Return the canonical string presentation of args list, delimited by comma `, `.
41
+ """
42
+ if self.args:
43
+ self.args = [repr(arg) for arg in self.args]
44
+ formatter = ['{}' for count in range(len(self.args))]
45
+ return ', '.join(formatter).format(*self.args)
46
+
47
+
48
+ def kwargs_to_string(self):
49
+ """
50
+ Return the input-syntax string presentation of kwargs list, delimited by comma `, `.
51
+ The value of the kwargs are formatted as the canonical string presentation.
52
+ """
53
+ if self.kwargs:
54
+ formatter = ['{}={}' for count in range(len(self.kwargs))]
55
+ return ', '.join(formatter).format(
56
+ *reduce((lambda x, y: x + y), [list([k, repr(v)]) for k,v in list(self.kwargs.items())]))
57
+
58
+ def to_string(self):
59
+ """
60
+ Return the input-syntax string presentation of args and kwargs list, delimited by comma `, `.
61
+ The value of the args and kwargs are formatted as the canonical string presentation.
62
+ Be noted to the differences:
63
+ * An empty string `` is returned if no args and kwargs found.
64
+ * The input empty string `` is returned as the literal "``" with the additional quoting.
65
+ * The input NoneType None is returned as the literal `None` without additional quoting.
66
+
67
+ Example:
68
+ >>> Formatter('foo', 1, x='bar', y=2).to_string()
69
+ "'foo', 1, x='bar', y=2"
70
+ """
71
+
72
+ items = [self.args_to_string(), self.kwargs_to_string()]
73
+ items = [item for item in items if item is not None]
74
+ return ', '.join(items)
@@ -0,0 +1,42 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # py2.7 and py3 compatibility imports
4
+ from __future__ import unicode_literals
5
+ from __future__ import absolute_import
6
+ from builtins import str
7
+
8
+ from unittest import TestCase
9
+
10
+ from . import Formatter
11
+
12
+ # Create your tests here.
13
+ class FormatterTestCase(TestCase):
14
+ def test(self):
15
+ # no args and kwargs
16
+ self.assertEqual(Formatter().to_string(), '')
17
+ # one arg as None
18
+ self.assertEqual(Formatter(None).to_string(), 'None')
19
+ # one arg as empty string
20
+ self.assertEqual(Formatter('').to_string(), repr(''))
21
+ # two simple args
22
+ self.assertEqual(Formatter('foo', 1).to_string(), '{}, 1'.format(repr('foo')))
23
+ # one arg as list
24
+ self.assertEqual(Formatter(['foo', 1]).to_string(), '[{}, 1]'.format(repr('foo')))
25
+ # one arg as dict
26
+ self.assertEqual(Formatter({'foo': 1}).to_string(), repr({'foo': 1}))
27
+ # on arg as tuple
28
+ self.assertEqual(Formatter(('foo', 1)).to_string(), repr(('foo', 1)))
29
+ # two simple kwargs, take care of the order, so works with both py2 and py3
30
+ self.assertEqual(Formatter(y=2, x='bar').to_string(), 'y=2, x={}'.format(repr('bar')))
31
+ # one kwarg as list
32
+ self.assertEqual(Formatter(x=['bar', 2]).to_string(), 'x={}'.format(repr(['bar', 2])))
33
+ # one kwarg as dict
34
+ self.assertEqual(Formatter(x={'bar': 2}).to_string(), 'x={}'.format(repr({'bar': 2})))
35
+ # one kwarg as tuple
36
+ self.assertEqual(Formatter(x=('bar', 2)).to_string(), 'x={}'.format(repr(('bar', 2))))
37
+ # two simple args and two simple kwargs, take care of the order, so works with both py2 and py3
38
+ self.assertEqual(
39
+ Formatter('foo', 1, y=2, x='bar').to_string(),
40
+ '{}, 1, y=2, x={}'.format(repr('foo'), repr('bar')))
41
+ # __str__()
42
+ self.assertEqual(str(Formatter(None)), 'None')
File without changes
@@ -0,0 +1,78 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # py2.7 and py3 compatibility imports
4
+ from __future__ import unicode_literals
5
+
6
+ import json
7
+ from django.contrib import admin, messages
8
+
9
+ from .models import NameServer, Domain, Record
10
+
11
+
12
+ # Register your models here.
13
+
14
+ @admin.register(NameServer)
15
+ class NameServerAdmin(admin.ModelAdmin):
16
+ fields = ('name', 'api_cls_name', 'user', 'credential',
17
+ 'dt_created', 'dt_updated')
18
+
19
+ readonly_fields = ('dt_created', 'dt_updated')
20
+
21
+ list_display = ('name', 'api_cls_name', 'user', 'is_api_accessible',
22
+ 'dt_created', 'dt_updated')
23
+
24
+ def is_api_accessible(self, obj):
25
+ return obj.is_api_accessible
26
+
27
+ is_api_accessible.boolean = True
28
+ is_api_accessible.short_description = 'API'
29
+
30
+
31
+ @admin.register(Domain)
32
+ class DomainAdmin(admin.ModelAdmin):
33
+ fields = ('name', 'nameserver',
34
+ 'dt_created', 'dt_updated')
35
+
36
+ readonly_fields = ('dt_created', 'dt_updated')
37
+
38
+ list_display = ('name', 'nameserver',
39
+ 'dt_created', 'dt_updated')
40
+
41
+
42
+ @admin.register(Record)
43
+ class RecordAdmin(admin.ModelAdmin):
44
+ fields = ('host', 'domain', 'type', 'answer', 'site',
45
+ 'dt_created', 'dt_updated')
46
+
47
+ readonly_fields = ('dt_created', 'dt_updated')
48
+
49
+ list_display = ('host', 'domain', 'type', 'answer', 'answer_from_dns_api', 'is_matching_dns_api',
50
+ 'answer_from_dns_query', 'is_matching_dns_query', 'site',
51
+ 'dt_created', 'dt_updated')
52
+
53
+ def answer_from_dns_api(self, obj):
54
+ return list(obj.answer_from_dns_api) if obj.answer_from_dns_api is not None else obj.answer_from_dns_api
55
+
56
+ def answer_from_dns_query(self, obj):
57
+ return list(obj.answer_from_dns_query) if obj.answer_from_dns_query is not None else obj.answer_from_dns_query
58
+
59
+ def is_matching_dns_api(self, obj):
60
+ return obj.is_matching_dns_api
61
+
62
+ is_matching_dns_api.boolean = True
63
+ is_matching_dns_api.short_description = 'DNS API'
64
+
65
+ def is_matching_dns_query(self, obj):
66
+ return obj.is_matching_dns_query
67
+
68
+ is_matching_dns_query.boolean = True
69
+ is_matching_dns_query.short_description = 'DNS Query'
70
+
71
+ def sync_to_dns(self, request, queryset):
72
+ for obj in queryset:
73
+ result = obj.sync_to_dns()
74
+ messages.info(request, '{0}: {1}'.format(obj.host, json.dumps(result)))
75
+
76
+ sync_to_dns.short_description = 'Synchronize DNS records to DNS server for Selected Domain'
77
+
78
+ actions = (sync_to_dns,)
@@ -0,0 +1,10 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # py2.7 and py3 compatibility imports
4
+ from __future__ import unicode_literals
5
+
6
+ from django.apps import AppConfig
7
+
8
+
9
+ class DomainConfig(AppConfig):
10
+ name = 'domain'
@@ -0,0 +1 @@
1
+ [{"model": "domain.nameserver", "pk": 1, "fields": {"name": "name.com", "api_cls_name": "NameNsApi", "user": null, "credential": null, "dt_created": "2021-01-12T16:58:21.432Z", "dt_updated": "2021-01-14T12:25:28.865Z"}}]
File without changes