Merge lp:~rajeevs1992/mailman.client/mailmancli into lp:mailman.client
- mailmancli
- Merge into trunk
Status: | Needs review |
---|---|
Proposed branch: | lp:~rajeevs1992/mailman.client/mailmancli |
Merge into: | lp:mailman.client |
Diff against target: |
4955 lines (+4719/-1) 39 files modified
README.rst (+29/-1) conf.py (+330/-0) setup.py (+4/-0) src/mailmanclient.egg-info/PKG-INFO (+14/-0) src/mailmanclient.egg-info/SOURCES.txt (+59/-0) src/mailmanclient.egg-info/dependency_links.txt (+1/-0) src/mailmanclient.egg-info/requires.txt (+5/-0) src/mailmanclient.egg-info/top_level.txt (+1/-0) src/mailmanclient/cli/client/cmdparser.py (+365/-0) src/mailmanclient/cli/client/parsers/README.txt (+190/-0) src/mailmanclient/cli/client/parsers/_set.py (+64/-0) src/mailmanclient/cli/client/parsers/base.py (+62/-0) src/mailmanclient/cli/client/parsers/create.py (+86/-0) src/mailmanclient/cli/client/parsers/delete.py (+101/-0) src/mailmanclient/cli/client/parsers/disable.py (+63/-0) src/mailmanclient/cli/client/parsers/enable.py (+63/-0) src/mailmanclient/cli/client/parsers/show.py (+101/-0) src/mailmanclient/cli/client/parsers/show_var.py (+63/-0) src/mailmanclient/cli/client/parsers/subscribe.py (+84/-0) src/mailmanclient/cli/client/parsers/unset.py (+63/-0) src/mailmanclient/cli/client/parsers/unsubscribe.py (+83/-0) src/mailmanclient/cli/client/parsers/update.py (+114/-0) src/mailmanclient/cli/client/shell.py (+394/-0) src/mailmanclient/cli/core/domains.py (+136/-0) src/mailmanclient/cli/core/lists.py (+227/-0) src/mailmanclient/cli/core/misc.py (+69/-0) src/mailmanclient/cli/core/preferences.py (+96/-0) src/mailmanclient/cli/core/users.py (+189/-0) src/mailmanclient/cli/docs/using_cli_shell.txt (+150/-0) src/mailmanclient/cli/docs/using_cli_tools.txt (+311/-0) src/mailmanclient/cli/docs/writing_a_new_command.txt (+57/-0) src/mailmanclient/cli/lib/colors.py (+32/-0) src/mailmanclient/cli/lib/mailman_utils.py (+117/-0) src/mailmanclient/cli/lib/utils.py (+216/-0) src/mailmanclient/cli/mmclient (+46/-0) src/mailmanclient/cli/tests/test_domain.py (+223/-0) src/mailmanclient/cli/tests/test_list.py (+285/-0) src/mailmanclient/cli/tests/test_preference.py (+99/-0) src/mailmanclient/cli/tests/test_user.py (+127/-0) |
To merge this branch: | bzr merge lp:~rajeevs1992/mailman.client/mailmancli |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mailman Coders | Pending | ||
Review via email: mp+236052@code.launchpad.net |
Commit message
Adds Command line tools and command line shell for mailman.client
Description of the change
GSoC project "Mailman CLI"
The branch contains the Mailman CLI shell as well as the command line tools built as a part of the GSoC 2014, Under the mentors Stephen J Turnbull, Abhilash Raj and Barry Warsaw.
Unmerged revisions
- 75. By Rajeev S
-
- fixed bug in update global preference, which is readonly
- fixed/improved a few test casesGlobal preferences are readonly, which is mentioned in the mmclient docs.
Option to edit the global preferences, which were previously allowed in
CLI are removed. - 74. By Rajeev S
-
merged with base
- 73. By Rajeev S
-
Ported CLI to Py3
- 72. By Rajeev S
-
- made the docs sphinx compatiable
- added more docs - 71. By Rajeev S
-
- added more tests, for the preferences methods
- added a check for HTTPErrors to make sure that
correct errors are displayed
- scrubbed more code to enhance readability
- added readme for parsers - 70. By Rajeev S
-
- modifed the setup.py to use scripts instead of entry_points
- added acks to Google and Mentors in file headers
- improved code for connection verification
- improved the `get_listing` function; moved to utils
- added colors as a seperate file, as per Steve's suggestion - 69. By Rajeev S
-
- adds backup and restore tool
- fixed up installation routines
- refactored code to make it installable
- modified `in list` filter to support regular
expressions
- updated docs and existing tests - 68. By Rajeev S
-
- added expoort to csv function for domains, users
and lists
- updated shell to support object names with whitespaces - 67. By Rajeev S
-
- switched command parsing to YACC and LEX
using python PLY module - 66. By Rajeev S
-
- added update preference command
- introduced regex based validation for all commands
- regex stored in config.ini
- added docstrings aka help for all commands
- help stings printed upon error
Preview Diff
1 | === modified file 'README.rst' | |||
2 | --- README.rst 2015-01-01 19:34:58 +0000 | |||
3 | +++ README.rst 2015-03-17 19:08:34 +0000 | |||
4 | @@ -1,4 +1,9 @@ | |||
6 | 1 | Python bindings for the Mailman 3 REST API. | 1 | =========================================================== |
7 | 2 | mailman.client - Python bindings for the Mailman 3 REST API | ||
8 | 3 | =========================================================== | ||
9 | 4 | |||
10 | 5 | This package is called ``mailman.client``. | ||
11 | 6 | |||
12 | 2 | 7 | ||
13 | 3 | .. | 8 | .. |
14 | 4 | This file is part of mailman.client. | 9 | This file is part of mailman.client. |
15 | @@ -48,6 +53,15 @@ | |||
16 | 48 | See the Launchpad project page for access to the Bazaar branch, bug report, | 53 | See the Launchpad project page for access to the Bazaar branch, bug report, |
17 | 49 | etc. | 54 | etc. |
18 | 50 | 55 | ||
19 | 56 | Documentation | ||
20 | 57 | ============= | ||
21 | 58 | |||
22 | 59 | A `simple guide`_ to using the library is available within this package, in | ||
23 | 60 | the form of doctests. The manual is also available online in the Cheeseshop | ||
24 | 61 | at: | ||
25 | 62 | |||
26 | 63 | http://package.python.org/mailman.client | ||
27 | 64 | |||
28 | 51 | 65 | ||
29 | 52 | Acknowledgements | 66 | Acknowledgements |
30 | 53 | ================ | 67 | ================ |
31 | @@ -57,3 +71,17 @@ | |||
32 | 57 | 71 | ||
33 | 58 | .. _`Cheese Shop`: http://pypi.python.org/mailman.client | 72 | .. _`Cheese Shop`: http://pypi.python.org/mailman.client |
34 | 59 | .. _Launchpad: https://launchpad.net/mailman.client | 73 | .. _Launchpad: https://launchpad.net/mailman.client |
35 | 74 | |||
36 | 75 | Table of Contents | ||
37 | 76 | ================= | ||
38 | 77 | |||
39 | 78 | .. toctree:: | ||
40 | 79 | |||
41 | 80 | src/mailmanclient/docs/using.txt | ||
42 | 81 | src/mailmanclient/cli/docs/using_cli_shell.txt | ||
43 | 82 | src/mailmanclient/cli/docs/using_cli_tools.txt | ||
44 | 83 | src/mailmanclient/cli/docs/writing_a_new_command.txt | ||
45 | 84 | src/mailmanclient/cli/client/parsers/README.txt | ||
46 | 85 | src/mailmanclient/NEWS.txt | ||
47 | 86 | |||
48 | 87 | .. _`simple guide`: docs/using.html | ||
49 | 60 | 88 | ||
50 | === added file 'conf.py' | |||
51 | --- conf.py 1970-01-01 00:00:00 +0000 | |||
52 | +++ conf.py 2015-03-17 19:08:34 +0000 | |||
53 | @@ -0,0 +1,330 @@ | |||
54 | 1 | # -*- coding: utf-8 -*- | ||
55 | 2 | # | ||
56 | 3 | # Mailman CLI documentation build configuration file, created by | ||
57 | 4 | # sphinx-quickstart on Sun Aug 17 13:11:12 2014. | ||
58 | 5 | # | ||
59 | 6 | # This file is execfile()d with the current directory set to its | ||
60 | 7 | # containing dir. | ||
61 | 8 | # | ||
62 | 9 | # Note that not all possible configuration values are present in this | ||
63 | 10 | # autogenerated file. | ||
64 | 11 | # | ||
65 | 12 | # All configuration values have a default; values that are commented out | ||
66 | 13 | # serve to show the default. | ||
67 | 14 | |||
68 | 15 | import sys | ||
69 | 16 | import os | ||
70 | 17 | |||
71 | 18 | # If extensions (or modules to document with autodoc) are in another directory, | ||
72 | 19 | # add these directories to sys.path here. If the directory is relative to the | ||
73 | 20 | # documentation root, use os.path.abspath to make it absolute, like shown here. | ||
74 | 21 | #sys.path.insert(0, os.path.abspath('.')) | ||
75 | 22 | |||
76 | 23 | # -- General configuration ------------------------------------------------ | ||
77 | 24 | |||
78 | 25 | # If your documentation needs a minimal Sphinx version, state it here. | ||
79 | 26 | #needs_sphinx = '1.0' | ||
80 | 27 | |||
81 | 28 | # Add any Sphinx extension module names here, as strings. They can be | ||
82 | 29 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom | ||
83 | 30 | # ones. | ||
84 | 31 | extensions = [ | ||
85 | 32 | 'sphinx.ext.autodoc', | ||
86 | 33 | ] | ||
87 | 34 | |||
88 | 35 | # Add any paths that contain templates here, relative to this directory. | ||
89 | 36 | templates_path = ['_templates'] | ||
90 | 37 | |||
91 | 38 | # The suffix of source filenames. | ||
92 | 39 | source_suffix = '.txt' | ||
93 | 40 | |||
94 | 41 | # The encoding of source files. | ||
95 | 42 | #source_encoding = 'utf-8-sig' | ||
96 | 43 | |||
97 | 44 | # The master toctree document. | ||
98 | 45 | master_doc = 'README' | ||
99 | 46 | |||
100 | 47 | # General information about the project. | ||
101 | 48 | project = u'Mailman CLI' | ||
102 | 49 | copyright = u'2014, Rajeev S' | ||
103 | 50 | |||
104 | 51 | # The version info for the project you're documenting, acts as replacement for | ||
105 | 52 | # |version| and |release|, also used in various other places throughout the | ||
106 | 53 | # built documents. | ||
107 | 54 | # | ||
108 | 55 | # The short X.Y version. | ||
109 | 56 | version = '1' | ||
110 | 57 | # The full version, including alpha/beta/rc tags. | ||
111 | 58 | release = '1' | ||
112 | 59 | |||
113 | 60 | # The language for content autogenerated by Sphinx. Refer to documentation | ||
114 | 61 | # for a list of supported languages. | ||
115 | 62 | #language = None | ||
116 | 63 | |||
117 | 64 | # There are two options for replacing |today|: either, you set today to some | ||
118 | 65 | # non-false value, then it is used: | ||
119 | 66 | #today = '' | ||
120 | 67 | # Else, today_fmt is used as the format for a strftime call. | ||
121 | 68 | #today_fmt = '%B %d, %Y' | ||
122 | 69 | |||
123 | 70 | # List of patterns, relative to source directory, that match files and | ||
124 | 71 | # directories to ignore when looking for source files. | ||
125 | 72 | exclude_patterns = ['_build'] | ||
126 | 73 | |||
127 | 74 | # The reST default role (used for this markup: `text`) to use for all | ||
128 | 75 | # documents. | ||
129 | 76 | #default_role = None | ||
130 | 77 | |||
131 | 78 | # If true, '()' will be appended to :func: etc. cross-reference text. | ||
132 | 79 | #add_function_parentheses = True | ||
133 | 80 | |||
134 | 81 | # If true, the current module name will be prepended to all description | ||
135 | 82 | # unit titles (such as .. function::). | ||
136 | 83 | #add_module_names = True | ||
137 | 84 | |||
138 | 85 | # If true, sectionauthor and moduleauthor directives will be shown in the | ||
139 | 86 | # output. They are ignored by default. | ||
140 | 87 | #show_authors = False | ||
141 | 88 | |||
142 | 89 | # The name of the Pygments (syntax highlighting) style to use. | ||
143 | 90 | pygments_style = 'sphinx' | ||
144 | 91 | |||
145 | 92 | # A list of ignored prefixes for module index sorting. | ||
146 | 93 | #modindex_common_prefix = [] | ||
147 | 94 | |||
148 | 95 | # If true, keep warnings as "system message" paragraphs in the built documents. | ||
149 | 96 | #keep_warnings = False | ||
150 | 97 | |||
151 | 98 | |||
152 | 99 | # -- Options for HTML output ---------------------------------------------- | ||
153 | 100 | |||
154 | 101 | # The theme to use for HTML and HTML Help pages. See the documentation for | ||
155 | 102 | # a list of builtin themes. | ||
156 | 103 | html_theme = 'default' | ||
157 | 104 | |||
158 | 105 | # Theme options are theme-specific and customize the look and feel of a theme | ||
159 | 106 | # further. For a list of options available for each theme, see the | ||
160 | 107 | # documentation. | ||
161 | 108 | #html_theme_options = {} | ||
162 | 109 | |||
163 | 110 | # Add any paths that contain custom themes here, relative to this directory. | ||
164 | 111 | #html_theme_path = [] | ||
165 | 112 | |||
166 | 113 | # The name for this set of Sphinx documents. If None, it defaults to | ||
167 | 114 | # "<project> v<release> documentation". | ||
168 | 115 | #html_title = None | ||
169 | 116 | |||
170 | 117 | # A shorter title for the navigation bar. Default is the same as html_title. | ||
171 | 118 | #html_short_title = None | ||
172 | 119 | |||
173 | 120 | # The name of an image file (relative to this directory) to place at the top | ||
174 | 121 | # of the sidebar. | ||
175 | 122 | #html_logo = None | ||
176 | 123 | |||
177 | 124 | # The name of an image file (within the static path) to use as favicon of the | ||
178 | 125 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 | ||
179 | 126 | # pixels large. | ||
180 | 127 | #html_favicon = None | ||
181 | 128 | |||
182 | 129 | # Add any paths that contain custom static files (such as style sheets) here, | ||
183 | 130 | # relative to this directory. They are copied after the builtin static files, | ||
184 | 131 | # so a file named "default.css" will overwrite the builtin "default.css". | ||
185 | 132 | html_static_path = ['_static'] | ||
186 | 133 | |||
187 | 134 | # Add any extra paths that contain custom files (such as robots.txt or | ||
188 | 135 | # .htaccess) here, relative to this directory. These files are copied | ||
189 | 136 | # directly to the root of the documentation. | ||
190 | 137 | #html_extra_path = [] | ||
191 | 138 | |||
192 | 139 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, | ||
193 | 140 | # using the given strftime format. | ||
194 | 141 | #html_last_updated_fmt = '%b %d, %Y' | ||
195 | 142 | |||
196 | 143 | # If true, SmartyPants will be used to convert quotes and dashes to | ||
197 | 144 | # typographically correct entities. | ||
198 | 145 | #html_use_smartypants = True | ||
199 | 146 | |||
200 | 147 | # Custom sidebar templates, maps document names to template names. | ||
201 | 148 | #html_sidebars = {} | ||
202 | 149 | |||
203 | 150 | # Additional templates that should be rendered to pages, maps page names to | ||
204 | 151 | # template names. | ||
205 | 152 | #html_additional_pages = {} | ||
206 | 153 | |||
207 | 154 | # If false, no module index is generated. | ||
208 | 155 | #html_domain_indices = True | ||
209 | 156 | |||
210 | 157 | # If false, no index is generated. | ||
211 | 158 | #html_use_index = True | ||
212 | 159 | |||
213 | 160 | # If true, the index is split into individual pages for each letter. | ||
214 | 161 | #html_split_index = False | ||
215 | 162 | |||
216 | 163 | # If true, links to the reST sources are added to the pages. | ||
217 | 164 | #html_show_sourcelink = True | ||
218 | 165 | |||
219 | 166 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. | ||
220 | 167 | #html_show_sphinx = True | ||
221 | 168 | |||
222 | 169 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. | ||
223 | 170 | #html_show_copyright = True | ||
224 | 171 | |||
225 | 172 | # If true, an OpenSearch description file will be output, and all pages will | ||
226 | 173 | # contain a <link> tag referring to it. The value of this option must be the | ||
227 | 174 | # base URL from which the finished HTML is served. | ||
228 | 175 | #html_use_opensearch = '' | ||
229 | 176 | |||
230 | 177 | # This is the file name suffix for HTML files (e.g. ".xhtml"). | ||
231 | 178 | #html_file_suffix = None | ||
232 | 179 | |||
233 | 180 | # Output file base name for HTML help builder. | ||
234 | 181 | htmlhelp_basename = 'MailmanCLIdoc' | ||
235 | 182 | |||
236 | 183 | |||
237 | 184 | # -- Options for LaTeX output --------------------------------------------- | ||
238 | 185 | |||
239 | 186 | latex_elements = { | ||
240 | 187 | # The paper size ('letterpaper' or 'a4paper'). | ||
241 | 188 | #'papersize': 'letterpaper', | ||
242 | 189 | |||
243 | 190 | # The font size ('10pt', '11pt' or '12pt'). | ||
244 | 191 | #'pointsize': '10pt', | ||
245 | 192 | |||
246 | 193 | # Additional stuff for the LaTeX preamble. | ||
247 | 194 | #'preamble': '', | ||
248 | 195 | } | ||
249 | 196 | |||
250 | 197 | # Grouping the document tree into LaTeX files. List of tuples | ||
251 | 198 | # (source start file, target name, title, | ||
252 | 199 | # author, documentclass [howto, manual, or own class]). | ||
253 | 200 | latex_documents = [ | ||
254 | 201 | ('README', 'MailmanCLI.tex', u'Mailman CLI Documentation', | ||
255 | 202 | u'Rajeev S', 'manual'), | ||
256 | 203 | ] | ||
257 | 204 | |||
258 | 205 | # The name of an image file (relative to this directory) to place at the top of | ||
259 | 206 | # the title page. | ||
260 | 207 | #latex_logo = None | ||
261 | 208 | |||
262 | 209 | # For "manual" documents, if this is true, then toplevel headings are parts, | ||
263 | 210 | # not chapters. | ||
264 | 211 | #latex_use_parts = False | ||
265 | 212 | |||
266 | 213 | # If true, show page references after internal links. | ||
267 | 214 | #latex_show_pagerefs = False | ||
268 | 215 | |||
269 | 216 | # If true, show URL addresses after external links. | ||
270 | 217 | #latex_show_urls = False | ||
271 | 218 | |||
272 | 219 | # Documents to append as an appendix to all manuals. | ||
273 | 220 | #latex_appendices = [] | ||
274 | 221 | |||
275 | 222 | # If false, no module index is generated. | ||
276 | 223 | #latex_domain_indices = True | ||
277 | 224 | |||
278 | 225 | |||
279 | 226 | # -- Options for manual page output --------------------------------------- | ||
280 | 227 | |||
281 | 228 | # One entry per manual page. List of tuples | ||
282 | 229 | # (source start file, name, description, authors, manual section). | ||
283 | 230 | man_pages = [ | ||
284 | 231 | ('README', 'mailmancli', u'Mailman CLI Documentation', | ||
285 | 232 | [u'Rajeev S'], 1) | ||
286 | 233 | ] | ||
287 | 234 | |||
288 | 235 | # If true, show URL addresses after external links. | ||
289 | 236 | #man_show_urls = False | ||
290 | 237 | |||
291 | 238 | |||
292 | 239 | # -- Options for Texinfo output ------------------------------------------- | ||
293 | 240 | |||
294 | 241 | # Grouping the document tree into Texinfo files. List of tuples | ||
295 | 242 | # (source start file, target name, title, author, | ||
296 | 243 | # dir menu entry, description, category) | ||
297 | 244 | texinfo_documents = [ | ||
298 | 245 | ('README', 'MailmanCLI', u'Mailman CLI Documentation', | ||
299 | 246 | u'Rajeev S', 'MailmanCLI', 'One line description of project.', | ||
300 | 247 | 'Miscellaneous'), | ||
301 | 248 | ] | ||
302 | 249 | |||
303 | 250 | # Documents to append as an appendix to all manuals. | ||
304 | 251 | #texinfo_appendices = [] | ||
305 | 252 | |||
306 | 253 | # If false, no module index is generated. | ||
307 | 254 | #texinfo_domain_indices = True | ||
308 | 255 | |||
309 | 256 | # How to display URL addresses: 'footnote', 'no', or 'inline'. | ||
310 | 257 | #texinfo_show_urls = 'footnote' | ||
311 | 258 | |||
312 | 259 | # If true, do not generate a @detailmenu in the "Top" node's menu. | ||
313 | 260 | #texinfo_no_detailmenu = False | ||
314 | 261 | |||
315 | 262 | |||
316 | 263 | # -- Options for Epub output ---------------------------------------------- | ||
317 | 264 | |||
318 | 265 | # Bibliographic Dublin Core info. | ||
319 | 266 | epub_title = u'Mailman CLI' | ||
320 | 267 | epub_author = u'Rajeev S' | ||
321 | 268 | epub_publisher = u'Rajeev S' | ||
322 | 269 | epub_copyright = u'2014, Rajeev S' | ||
323 | 270 | |||
324 | 271 | # The basename for the epub file. It defaults to the project name. | ||
325 | 272 | #epub_basename = u'Mailman CLI' | ||
326 | 273 | |||
327 | 274 | # The HTML theme for the epub output. Since the default themes are not optimized | ||
328 | 275 | # for small screen space, using the same theme for HTML and epub output is | ||
329 | 276 | # usually not wise. This defaults to 'epub', a theme designed to save visual | ||
330 | 277 | # space. | ||
331 | 278 | #epub_theme = 'epub' | ||
332 | 279 | |||
333 | 280 | # The language of the text. It defaults to the language option | ||
334 | 281 | # or en if the language is not set. | ||
335 | 282 | #epub_language = '' | ||
336 | 283 | |||
337 | 284 | # The scheme of the identifier. Typical schemes are ISBN or URL. | ||
338 | 285 | #epub_scheme = '' | ||
339 | 286 | |||
340 | 287 | # The unique identifier of the text. This can be a ISBN number | ||
341 | 288 | # or the project homepage. | ||
342 | 289 | #epub_identifier = '' | ||
343 | 290 | |||
344 | 291 | # A unique identification for the text. | ||
345 | 292 | #epub_uid = '' | ||
346 | 293 | |||
347 | 294 | # A tuple containing the cover image and cover page html template filenames. | ||
348 | 295 | #epub_cover = () | ||
349 | 296 | |||
350 | 297 | # A sequence of (type, uri, title) tuples for the guide element of content.opf. | ||
351 | 298 | #epub_guide = () | ||
352 | 299 | |||
353 | 300 | # HTML files that should be inserted before the pages created by sphinx. | ||
354 | 301 | # The format is a list of tuples containing the path and title. | ||
355 | 302 | #epub_pre_files = [] | ||
356 | 303 | |||
357 | 304 | # HTML files shat should be inserted after the pages created by sphinx. | ||
358 | 305 | # The format is a list of tuples containing the path and title. | ||
359 | 306 | #epub_post_files = [] | ||
360 | 307 | |||
361 | 308 | # A list of files that should not be packed into the epub file. | ||
362 | 309 | epub_exclude_files = ['search.html'] | ||
363 | 310 | |||
364 | 311 | # The depth of the table of contents in toc.ncx. | ||
365 | 312 | #epub_tocdepth = 3 | ||
366 | 313 | |||
367 | 314 | # Allow duplicate toc entries. | ||
368 | 315 | #epub_tocdup = True | ||
369 | 316 | |||
370 | 317 | # Choose between 'default' and 'includehidden'. | ||
371 | 318 | #epub_tocscope = 'default' | ||
372 | 319 | |||
373 | 320 | # Fix unsupported image types using the PIL. | ||
374 | 321 | #epub_fix_images = False | ||
375 | 322 | |||
376 | 323 | # Scale large images. | ||
377 | 324 | #epub_max_image_width = 0 | ||
378 | 325 | |||
379 | 326 | # How to display URL addresses: 'footnote', 'no', or 'inline'. | ||
380 | 327 | #epub_show_urls = 'inline' | ||
381 | 328 | |||
382 | 329 | # If false, no index is generated. | ||
383 | 330 | #epub_use_index = True | ||
384 | 0 | 331 | ||
385 | === modified file 'setup.py' | |||
386 | --- setup.py 2015-01-01 21:26:10 +0000 | |||
387 | +++ setup.py 2015-03-17 19:08:34 +0000 | |||
388 | @@ -30,6 +30,7 @@ | |||
389 | 30 | packages=find_packages('src'), | 30 | packages=find_packages('src'), |
390 | 31 | package_dir = {'': 'src'}, | 31 | package_dir = {'': 'src'}, |
391 | 32 | include_package_data=True, | 32 | include_package_data=True, |
392 | 33 | scripts=['src/mailmanclient/cli/mmclient'], | ||
393 | 33 | maintainer='Barry Warsaw', | 34 | maintainer='Barry Warsaw', |
394 | 34 | maintainer_email='barry@list.org', | 35 | maintainer_email='barry@list.org', |
395 | 35 | description=description('README.rst'), | 36 | description=description('README.rst'), |
396 | @@ -42,5 +43,8 @@ | |||
397 | 42 | install_requires=[ | 43 | install_requires=[ |
398 | 43 | 'httplib2', | 44 | 'httplib2', |
399 | 44 | 'six', | 45 | 'six', |
400 | 46 | 'mock', | ||
401 | 47 | 'tabulate', | ||
402 | 48 | 'ply', | ||
403 | 45 | ], | 49 | ], |
404 | 46 | ) | 50 | ) |
405 | 47 | 51 | ||
406 | === added directory 'src/mailmanclient.egg-info' | |||
407 | === added file 'src/mailmanclient.egg-info/PKG-INFO' | |||
408 | --- src/mailmanclient.egg-info/PKG-INFO 1970-01-01 00:00:00 +0000 | |||
409 | +++ src/mailmanclient.egg-info/PKG-INFO 2015-03-17 19:08:34 +0000 | |||
410 | @@ -0,0 +1,14 @@ | |||
411 | 1 | Metadata-Version: 1.1 | ||
412 | 2 | Name: mailmanclient | ||
413 | 3 | Version: 1.0.0 | ||
414 | 4 | Summary: Python bindings for the Mailman 3 REST API. | ||
415 | 5 | Home-page: http://launchpad.net/mailman.client | ||
416 | 6 | Author: Barry Warsaw | ||
417 | 7 | Author-email: barry@list.org | ||
418 | 8 | License: LGPLv3 | ||
419 | 9 | Download-URL: https://launchpad.net/mailman.client/+download | ||
420 | 10 | Description: src/mailmanclient/README.rst | ||
421 | 11 | |||
422 | 12 | src/mailmanclient/NEWS.rst | ||
423 | 13 | |||
424 | 14 | Platform: UNKNOWN | ||
425 | 0 | 15 | ||
426 | === added file 'src/mailmanclient.egg-info/SOURCES.txt' | |||
427 | --- src/mailmanclient.egg-info/SOURCES.txt 1970-01-01 00:00:00 +0000 | |||
428 | +++ src/mailmanclient.egg-info/SOURCES.txt 2015-03-17 19:08:34 +0000 | |||
429 | @@ -0,0 +1,59 @@ | |||
430 | 1 | MANIFEST.in | ||
431 | 2 | Makefile | ||
432 | 3 | README.rst | ||
433 | 4 | README.txt | ||
434 | 5 | conf.py | ||
435 | 6 | distribute_setup.py | ||
436 | 7 | setup.cfg | ||
437 | 8 | setup.py | ||
438 | 9 | setup_helpers.py | ||
439 | 10 | template.py | ||
440 | 11 | src/mailmanclient/NEWS.txt | ||
441 | 12 | src/mailmanclient/__init__.py | ||
442 | 13 | src/mailmanclient/_client.py | ||
443 | 14 | src/mailmanclient.egg-info/PKG-INFO | ||
444 | 15 | src/mailmanclient.egg-info/SOURCES.txt | ||
445 | 16 | src/mailmanclient.egg-info/dependency_links.txt | ||
446 | 17 | src/mailmanclient.egg-info/requires.txt | ||
447 | 18 | src/mailmanclient.egg-info/top_level.txt | ||
448 | 19 | src/mailmanclient/cli/__init__.py | ||
449 | 20 | src/mailmanclient/cli/mmclient | ||
450 | 21 | src/mailmanclient/cli/client/__init__.py | ||
451 | 22 | src/mailmanclient/cli/client/cmdparser.py | ||
452 | 23 | src/mailmanclient/cli/client/shell.py | ||
453 | 24 | src/mailmanclient/cli/client/parsers/README.txt | ||
454 | 25 | src/mailmanclient/cli/client/parsers/__init__.py | ||
455 | 26 | src/mailmanclient/cli/client/parsers/_set.py | ||
456 | 27 | src/mailmanclient/cli/client/parsers/base.py | ||
457 | 28 | src/mailmanclient/cli/client/parsers/create.py | ||
458 | 29 | src/mailmanclient/cli/client/parsers/delete.py | ||
459 | 30 | src/mailmanclient/cli/client/parsers/disable.py | ||
460 | 31 | src/mailmanclient/cli/client/parsers/enable.py | ||
461 | 32 | src/mailmanclient/cli/client/parsers/show.py | ||
462 | 33 | src/mailmanclient/cli/client/parsers/show_var.py | ||
463 | 34 | src/mailmanclient/cli/client/parsers/subscribe.py | ||
464 | 35 | src/mailmanclient/cli/client/parsers/unset.py | ||
465 | 36 | src/mailmanclient/cli/client/parsers/unsubscribe.py | ||
466 | 37 | src/mailmanclient/cli/client/parsers/update.py | ||
467 | 38 | src/mailmanclient/cli/core/__init__.py | ||
468 | 39 | src/mailmanclient/cli/core/domains.py | ||
469 | 40 | src/mailmanclient/cli/core/lists.py | ||
470 | 41 | src/mailmanclient/cli/core/misc.py | ||
471 | 42 | src/mailmanclient/cli/core/preferences.py | ||
472 | 43 | src/mailmanclient/cli/core/users.py | ||
473 | 44 | src/mailmanclient/cli/docs/using_cli_shell.txt | ||
474 | 45 | src/mailmanclient/cli/docs/using_cli_tools.txt | ||
475 | 46 | src/mailmanclient/cli/docs/writing_a_new_command.txt | ||
476 | 47 | src/mailmanclient/cli/lib/__init__.py | ||
477 | 48 | src/mailmanclient/cli/lib/colors.py | ||
478 | 49 | src/mailmanclient/cli/lib/mailman_utils.py | ||
479 | 50 | src/mailmanclient/cli/lib/utils.py | ||
480 | 51 | src/mailmanclient/cli/tests/__init__.py | ||
481 | 52 | src/mailmanclient/cli/tests/test_domain.py | ||
482 | 53 | src/mailmanclient/cli/tests/test_list.py | ||
483 | 54 | src/mailmanclient/cli/tests/test_preference.py | ||
484 | 55 | src/mailmanclient/cli/tests/test_user.py | ||
485 | 56 | src/mailmanclient/docs/__init__.py | ||
486 | 57 | src/mailmanclient/docs/using.txt | ||
487 | 58 | src/mailmanclient/tests/__init__.py | ||
488 | 59 | src/mailmanclient/tests/test_docs.py | ||
489 | 0 | \ No newline at end of file | 60 | \ No newline at end of file |
490 | 1 | 61 | ||
491 | === added file 'src/mailmanclient.egg-info/dependency_links.txt' | |||
492 | --- src/mailmanclient.egg-info/dependency_links.txt 1970-01-01 00:00:00 +0000 | |||
493 | +++ src/mailmanclient.egg-info/dependency_links.txt 2015-03-17 19:08:34 +0000 | |||
494 | @@ -0,0 +1,1 @@ | |||
495 | 1 | |||
496 | 0 | 2 | ||
497 | === added file 'src/mailmanclient.egg-info/requires.txt' | |||
498 | --- src/mailmanclient.egg-info/requires.txt 1970-01-01 00:00:00 +0000 | |||
499 | +++ src/mailmanclient.egg-info/requires.txt 2015-03-17 19:08:34 +0000 | |||
500 | @@ -0,0 +1,5 @@ | |||
501 | 1 | httplib2 | ||
502 | 2 | six | ||
503 | 3 | mock | ||
504 | 4 | tabulate | ||
505 | 5 | ply | ||
506 | 0 | 6 | ||
507 | === added file 'src/mailmanclient.egg-info/top_level.txt' | |||
508 | --- src/mailmanclient.egg-info/top_level.txt 1970-01-01 00:00:00 +0000 | |||
509 | +++ src/mailmanclient.egg-info/top_level.txt 2015-03-17 19:08:34 +0000 | |||
510 | @@ -0,0 +1,1 @@ | |||
511 | 1 | mailmanclient | ||
512 | 0 | 2 | ||
513 | === added directory 'src/mailmanclient/cli' | |||
514 | === added file 'src/mailmanclient/cli/__init__.py' | |||
515 | === added directory 'src/mailmanclient/cli/client' | |||
516 | === added file 'src/mailmanclient/cli/client/__init__.py' | |||
517 | === added file 'src/mailmanclient/cli/client/cmdparser.py' | |||
518 | --- src/mailmanclient/cli/client/cmdparser.py 1970-01-01 00:00:00 +0000 | |||
519 | +++ src/mailmanclient/cli/client/cmdparser.py 2015-03-17 19:08:34 +0000 | |||
520 | @@ -0,0 +1,365 @@ | |||
521 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
522 | 2 | # | ||
523 | 3 | # This file is part of mailman.client. | ||
524 | 4 | # | ||
525 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
526 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
527 | 7 | # Free Software Foundation, version 3 of the License. | ||
528 | 8 | # | ||
529 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
530 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
531 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
532 | 12 | # License for more details. | ||
533 | 13 | # | ||
534 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
535 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
536 | 16 | # | ||
537 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
538 | 18 | # | ||
539 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
540 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
541 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
542 | 22 | # Barry Warsaw <barry@list.org> | ||
543 | 23 | |||
544 | 24 | from argparse import ArgumentParser | ||
545 | 25 | from mailmanclient.cli.core.misc import Misc | ||
546 | 26 | from mailmanclient.cli.core.users import Users | ||
547 | 27 | from mailmanclient.cli.core.lists import Lists | ||
548 | 28 | from mailmanclient.cli.core.domains import Domains | ||
549 | 29 | from mailmanclient.cli.core.preferences import Preferences | ||
550 | 30 | from mailmanclient.cli.lib.mailman_utils import MailmanUtils | ||
551 | 31 | |||
552 | 32 | utils = MailmanUtils() | ||
553 | 33 | |||
554 | 34 | |||
555 | 35 | class CmdParser(): | ||
556 | 36 | def __init__(self, command): | ||
557 | 37 | parser = ArgumentParser(description='Mailman Command Tools') | ||
558 | 38 | self.initialize_options(parser) | ||
559 | 39 | self.arguments = vars(parser.parse_args()) | ||
560 | 40 | |||
561 | 41 | def initialize_options(self, parser): | ||
562 | 42 | action = parser.add_subparsers(dest='action') | ||
563 | 43 | |||
564 | 44 | # Parser for the action `show` | ||
565 | 45 | action_show = action.add_parser('show') | ||
566 | 46 | scope = action_show.add_subparsers(dest='scope') | ||
567 | 47 | |||
568 | 48 | # Show lists | ||
569 | 49 | show_list = scope.add_parser('list') | ||
570 | 50 | show_list.add_argument('list', | ||
571 | 51 | help='List details about LIST', | ||
572 | 52 | nargs='?') | ||
573 | 53 | show_list.add_argument('-d', | ||
574 | 54 | '--domain', | ||
575 | 55 | help='Filter by DOMAIN') | ||
576 | 56 | show_list.add_argument('-v', | ||
577 | 57 | '--verbose', | ||
578 | 58 | help='Detailed listing', | ||
579 | 59 | action='store_true') | ||
580 | 60 | show_list.add_argument('--no-header', | ||
581 | 61 | help='Omit headings in detailed listing', | ||
582 | 62 | action='store_true') | ||
583 | 63 | show_list.add_argument('--csv', | ||
584 | 64 | help='Output as CSV, Specify filename') | ||
585 | 65 | |||
586 | 66 | # Show domains | ||
587 | 67 | show_domain = scope.add_parser('domain') | ||
588 | 68 | show_domain.add_argument('domain', | ||
589 | 69 | help='List details about DOMAIN', | ||
590 | 70 | nargs='?') | ||
591 | 71 | show_domain.add_argument('-v', | ||
592 | 72 | '--verbose', | ||
593 | 73 | help='Detailed listing', | ||
594 | 74 | action='store_true') | ||
595 | 75 | show_domain.add_argument('--no-header', | ||
596 | 76 | help='Omit headings in detailed listing', | ||
597 | 77 | action='store_true') | ||
598 | 78 | show_domain.add_argument('--csv', | ||
599 | 79 | help='Output as CSV, Specify filename') | ||
600 | 80 | |||
601 | 81 | # Show users | ||
602 | 82 | show_user = scope.add_parser('user') | ||
603 | 83 | show_user.add_argument('user', | ||
604 | 84 | help='List details about USER', | ||
605 | 85 | nargs='?') | ||
606 | 86 | show_user.add_argument('-v', | ||
607 | 87 | '--verbose', | ||
608 | 88 | help='Detailed listing', | ||
609 | 89 | action='store_true') | ||
610 | 90 | show_user.add_argument('--no-header', | ||
611 | 91 | help='Omit headings in detailed listing', | ||
612 | 92 | action='store_true') | ||
613 | 93 | show_user.add_argument('-l', | ||
614 | 94 | '--list', | ||
615 | 95 | help='Specify list name', | ||
616 | 96 | dest='list_name') | ||
617 | 97 | show_user.add_argument('--csv', | ||
618 | 98 | help='Output as CSV, Specify filename') | ||
619 | 99 | |||
620 | 100 | # Show preferences | ||
621 | 101 | preferences = ['receive_list_copy', 'hide_address', | ||
622 | 102 | 'preferred_language', 'acknowledge_posts', | ||
623 | 103 | 'delivery_mode', 'receive_own_postings', | ||
624 | 104 | 'http_etag', 'self_link', 'delivery_status'] | ||
625 | 105 | show_preference = scope.add_parser('preference') | ||
626 | 106 | show_scope = show_preference.add_subparsers(dest='show_scope') | ||
627 | 107 | |||
628 | 108 | show_scope.add_parser('global') | ||
629 | 109 | |||
630 | 110 | user_show = show_scope.add_parser('user') | ||
631 | 111 | user_show.add_argument('--email', | ||
632 | 112 | help='Email of user whose ' | ||
633 | 113 | 'preference is to be shown', | ||
634 | 114 | required=True) | ||
635 | 115 | |||
636 | 116 | address_show = show_scope.add_parser('address') | ||
637 | 117 | address_show.add_argument('--email', | ||
638 | 118 | help='Address whose preference' | ||
639 | 119 | ' is to be shown', | ||
640 | 120 | required=True) | ||
641 | 121 | |||
642 | 122 | member_show = show_scope.add_parser('member') | ||
643 | 123 | member_show.add_argument('--email', | ||
644 | 124 | help='Address whose preference' | ||
645 | 125 | ' is to be shown', | ||
646 | 126 | required=True) | ||
647 | 127 | member_show.add_argument('--list', | ||
648 | 128 | help='FQDN name of list', | ||
649 | 129 | required=True) | ||
650 | 130 | |||
651 | 131 | show_preference.add_argument('key', | ||
652 | 132 | help='Specify setting name', | ||
653 | 133 | choices=preferences) | ||
654 | 134 | |||
655 | 135 | # Parser for the action `create` | ||
656 | 136 | action_create = action.add_parser('create') | ||
657 | 137 | scope = action_create.add_subparsers(dest='scope') | ||
658 | 138 | |||
659 | 139 | # Create list | ||
660 | 140 | create_list = scope.add_parser('list') | ||
661 | 141 | create_list.add_argument('list', | ||
662 | 142 | help='List name. e.g., list@domain.org') | ||
663 | 143 | # Create domain | ||
664 | 144 | create_domain = scope.add_parser('domain') | ||
665 | 145 | create_domain.add_argument('domain', | ||
666 | 146 | help='Create domain DOMAIN') | ||
667 | 147 | create_domain.add_argument('--contact', | ||
668 | 148 | help='Contact address for domain') | ||
669 | 149 | # Create users | ||
670 | 150 | create_user = scope.add_parser('user') | ||
671 | 151 | create_user.add_argument('email', | ||
672 | 152 | help='Create user foo@bar.com') | ||
673 | 153 | create_user.add_argument('--password', | ||
674 | 154 | help='User password', | ||
675 | 155 | required=True) | ||
676 | 156 | create_user.add_argument('--name', | ||
677 | 157 | help='Display name of the user', | ||
678 | 158 | required=True) | ||
679 | 159 | |||
680 | 160 | # Parser for the action `delete` | ||
681 | 161 | action_delete = action.add_parser('delete') | ||
682 | 162 | scope = action_delete.add_subparsers(dest='scope') | ||
683 | 163 | |||
684 | 164 | # Delete list | ||
685 | 165 | delete_list = scope.add_parser('list') | ||
686 | 166 | delete_list.add_argument('list', | ||
687 | 167 | help='List name. e.g., list@domain.org') | ||
688 | 168 | delete_list.add_argument('--yes', | ||
689 | 169 | help='Force delete', | ||
690 | 170 | action='store_true') | ||
691 | 171 | # Delete domain | ||
692 | 172 | delete_domain = scope.add_parser('domain') | ||
693 | 173 | delete_domain.add_argument('domain', | ||
694 | 174 | help='Domain name. e.g., domain.org') | ||
695 | 175 | delete_domain.add_argument('--yes', | ||
696 | 176 | help='Force delete', | ||
697 | 177 | action='store_true') | ||
698 | 178 | # Delete user | ||
699 | 179 | delete_user = scope.add_parser('user') | ||
700 | 180 | delete_user.add_argument('user', | ||
701 | 181 | help='User email e.g., foo@bar.com') | ||
702 | 182 | delete_user.add_argument('--yes', | ||
703 | 183 | help='Force delete', | ||
704 | 184 | action='store_true') | ||
705 | 185 | # Show Members of a list | ||
706 | 186 | action_show_member = action.add_parser('show-members') | ||
707 | 187 | scope = action_show_member.add_subparsers(dest='scope') | ||
708 | 188 | show_member = scope.add_parser('list') | ||
709 | 189 | show_member.add_argument('list', | ||
710 | 190 | help='Show members of LIST') | ||
711 | 191 | show_member.add_argument('-v', | ||
712 | 192 | '--verbose', | ||
713 | 193 | help='Detailed listing', | ||
714 | 194 | action='store_true') | ||
715 | 195 | show_member.add_argument('--no-header', | ||
716 | 196 | help='Omit headings in detailed listing', | ||
717 | 197 | action='store_true') | ||
718 | 198 | |||
719 | 199 | # Parser for the action `subscribe` | ||
720 | 200 | action_subscribe = action.add_parser('subscribe') | ||
721 | 201 | scope = action_subscribe.add_subparsers(dest='scope') | ||
722 | 202 | subscribe_user = scope.add_parser('user') | ||
723 | 203 | subscribe_user.add_argument('users', | ||
724 | 204 | help='User email list', | ||
725 | 205 | nargs='+') | ||
726 | 206 | subscribe_user.add_argument('-l', | ||
727 | 207 | '--list', | ||
728 | 208 | help='Specify list name', | ||
729 | 209 | dest='list_name', | ||
730 | 210 | required=True) | ||
731 | 211 | subscribe_user.add_argument('--quiet', | ||
732 | 212 | help='Do not display feedback', | ||
733 | 213 | action='store_true') | ||
734 | 214 | |||
735 | 215 | # Parser for the action `unsubscribe` | ||
736 | 216 | action_subscribe = action.add_parser('unsubscribe') | ||
737 | 217 | scope = action_subscribe.add_subparsers(dest='scope') | ||
738 | 218 | subscribe_user = scope.add_parser('user') | ||
739 | 219 | subscribe_user.add_argument('users', | ||
740 | 220 | help='User email list', | ||
741 | 221 | nargs='+') | ||
742 | 222 | subscribe_user.add_argument('-l', | ||
743 | 223 | '--list', | ||
744 | 224 | help='Specify list name', | ||
745 | 225 | dest='list_name', | ||
746 | 226 | required=True) | ||
747 | 227 | subscribe_user.add_argument('--quiet', | ||
748 | 228 | help='Do not display feedback', | ||
749 | 229 | action='store_true') | ||
750 | 230 | # Moderation Tools | ||
751 | 231 | |||
752 | 232 | # Add Moderator | ||
753 | 233 | action_add_moderator = action.add_parser('add-moderator') | ||
754 | 234 | scope = action_add_moderator.add_subparsers(dest='scope') | ||
755 | 235 | add_moderator = scope.add_parser('list') | ||
756 | 236 | add_moderator.add_argument('list', | ||
757 | 237 | help='Specify list name') | ||
758 | 238 | add_moderator.add_argument('-u', | ||
759 | 239 | '--user', | ||
760 | 240 | help='User email list', | ||
761 | 241 | dest='users', | ||
762 | 242 | nargs='+', | ||
763 | 243 | required=True) | ||
764 | 244 | add_moderator.add_argument('--quiet', | ||
765 | 245 | help='Do not display feedback', | ||
766 | 246 | action='store_true') | ||
767 | 247 | # Add Owner | ||
768 | 248 | action_add_owner = action.add_parser('add-owner') | ||
769 | 249 | scope = action_add_owner.add_subparsers(dest='scope') | ||
770 | 250 | add_owner = scope.add_parser('list') | ||
771 | 251 | add_owner.add_argument('list', | ||
772 | 252 | help='Specify list name') | ||
773 | 253 | add_owner.add_argument('-u', | ||
774 | 254 | '--user', | ||
775 | 255 | help='User email list', | ||
776 | 256 | dest='users', | ||
777 | 257 | nargs='+') | ||
778 | 258 | add_owner.add_argument('--quiet', | ||
779 | 259 | help='Do not display feedback', | ||
780 | 260 | action='store_true') | ||
781 | 261 | # Remove Moderator | ||
782 | 262 | action_remove_moderator = action.add_parser('remove-moderator') | ||
783 | 263 | scope = action_remove_moderator.add_subparsers(dest='scope') | ||
784 | 264 | remove_moderator = scope.add_parser('list') | ||
785 | 265 | remove_moderator.add_argument('list', | ||
786 | 266 | help='Specify list name') | ||
787 | 267 | remove_moderator.add_argument('-u', | ||
788 | 268 | '--user', | ||
789 | 269 | dest='users', | ||
790 | 270 | help='User email list', | ||
791 | 271 | nargs='+') | ||
792 | 272 | remove_moderator.add_argument('--quiet', | ||
793 | 273 | help='Do not display feedback', | ||
794 | 274 | action='store_true') | ||
795 | 275 | # Remove Owner | ||
796 | 276 | action_remove_owner = action.add_parser('remove-owner') | ||
797 | 277 | scope = action_remove_owner.add_subparsers(dest='scope') | ||
798 | 278 | remove_owner = scope.add_parser('list') | ||
799 | 279 | remove_owner.add_argument('list', | ||
800 | 280 | help='Specify list name') | ||
801 | 281 | remove_owner.add_argument('-u', | ||
802 | 282 | '--user', | ||
803 | 283 | help='User email list', | ||
804 | 284 | dest='users', | ||
805 | 285 | nargs='+') | ||
806 | 286 | remove_owner.add_argument('--quiet', | ||
807 | 287 | help='Do not display feedback', | ||
808 | 288 | action='store_true') | ||
809 | 289 | # Edit preferences | ||
810 | 290 | action_update = action.add_parser('update') | ||
811 | 291 | scope = action_update.add_subparsers(dest='scope') | ||
812 | 292 | update_preference = scope.add_parser('preference') | ||
813 | 293 | update_scope = update_preference.add_subparsers(dest='update_scope') | ||
814 | 294 | |||
815 | 295 | user_update = update_scope.add_parser('user') | ||
816 | 296 | user_update.add_argument('--email', | ||
817 | 297 | help='Email of user whose ' | ||
818 | 298 | 'preference is to be changed', | ||
819 | 299 | required=True) | ||
820 | 300 | |||
821 | 301 | address_update = update_scope.add_parser('address') | ||
822 | 302 | address_update.add_argument('--email', | ||
823 | 303 | help='Address whose preference' | ||
824 | 304 | ' is to be changed', | ||
825 | 305 | required=True) | ||
826 | 306 | |||
827 | 307 | member_update = update_scope.add_parser('member') | ||
828 | 308 | member_update.add_argument('--email', | ||
829 | 309 | help='Address whose preference' | ||
830 | 310 | ' is to be changed', | ||
831 | 311 | required=True) | ||
832 | 312 | member_update.add_argument('--list', | ||
833 | 313 | help='FQDN name of list', | ||
834 | 314 | required=True) | ||
835 | 315 | |||
836 | 316 | update_preference.add_argument('key', | ||
837 | 317 | help='Specify setting name', | ||
838 | 318 | choices=preferences) | ||
839 | 319 | update_preference.add_argument('value', | ||
840 | 320 | help='Specify setting value') | ||
841 | 321 | # Backup Tool | ||
842 | 322 | action_backup = action.add_parser('backup') | ||
843 | 323 | action_backup.add_argument('output', | ||
844 | 324 | help='Specify file to write backup') | ||
845 | 325 | |||
846 | 326 | # Restore Tool | ||
847 | 327 | action_backup = action.add_parser('restore') | ||
848 | 328 | action_backup.add_argument('backup', | ||
849 | 329 | help='Specify backup file location') | ||
850 | 330 | # Global options | ||
851 | 331 | parser.add_argument('--host', help='REST API host address') | ||
852 | 332 | parser.add_argument('--port', help='REST API host port') | ||
853 | 333 | parser.add_argument('--restuser', help='REST API username') | ||
854 | 334 | parser.add_argument('--restpass', help='REST API password') | ||
855 | 335 | |||
856 | 336 | def run(self): | ||
857 | 337 | host = self.arguments['host'] | ||
858 | 338 | port = self.arguments['port'] | ||
859 | 339 | username = self.arguments['restuser'] | ||
860 | 340 | password = self.arguments['restpass'] | ||
861 | 341 | client = utils.connect(host=host, port=port, | ||
862 | 342 | username=username, password=password) | ||
863 | 343 | if 'scope' not in self.arguments: | ||
864 | 344 | self.run_misc_actions() | ||
865 | 345 | return | ||
866 | 346 | scopes = {} | ||
867 | 347 | scopes['user'] = Users | ||
868 | 348 | scopes['list'] = Lists | ||
869 | 349 | scopes['domain'] = Domains | ||
870 | 350 | scopes['preference'] = Preferences | ||
871 | 351 | self.arguments['action'] = self.arguments['action'].replace('-', '_') | ||
872 | 352 | try: | ||
873 | 353 | scope_object = scopes[self.arguments['scope']](client) | ||
874 | 354 | action_name = self.arguments['action'] | ||
875 | 355 | action = getattr(scope_object, action_name) | ||
876 | 356 | action(self.arguments) | ||
877 | 357 | except Exception as e: | ||
878 | 358 | utils.error(e) | ||
879 | 359 | exit(1) | ||
880 | 360 | |||
881 | 361 | def run_misc_actions(self): | ||
882 | 362 | action_name = self.arguments['action'] | ||
883 | 363 | misc = Misc() | ||
884 | 364 | action = getattr(misc, action_name) | ||
885 | 365 | action(self.arguments) | ||
886 | 0 | 366 | ||
887 | === added directory 'src/mailmanclient/cli/client/parsers' | |||
888 | === added file 'src/mailmanclient/cli/client/parsers/README.txt' | |||
889 | --- src/mailmanclient/cli/client/parsers/README.txt 1970-01-01 00:00:00 +0000 | |||
890 | +++ src/mailmanclient/cli/client/parsers/README.txt 2015-03-17 19:08:34 +0000 | |||
891 | @@ -0,0 +1,190 @@ | |||
892 | 1 | Mailman Shell Parsers | ||
893 | 2 | ********************** | ||
894 | 3 | |||
895 | 4 | This directory consists of the various parsers that | ||
896 | 5 | have been built for use with the mailman shell. The shell | ||
897 | 6 | parser has been built in such a way that each command has | ||
898 | 7 | a different and independent parser, so that adding new commands | ||
899 | 8 | can be done flexibly and easily, without worrying about the | ||
900 | 9 | existing code. | ||
901 | 10 | |||
902 | 11 | The `show` command | ||
903 | 12 | ================= | ||
904 | 13 | |||
905 | 14 | The command to display the mailman objects | ||
906 | 15 | |||
907 | 16 | Tokens | ||
908 | 17 | ------ | ||
909 | 18 | :: | ||
910 | 19 | |||
911 | 20 | SHOW : 'show' | ||
912 | 21 | SCOPE : '(user|domain|list)s?' | ||
913 | 22 | WHERE : 'where' | ||
914 | 23 | OP : '=|in|like' | ||
915 | 24 | AND : 'and' | ||
916 | 25 | STRING : '`([a-zA-Z0-9_@\.\*\-\$ ]*)`' | ||
917 | 26 | |||
918 | 27 | Grammar | ||
919 | 28 | ------- | ||
920 | 29 | :: | ||
921 | 30 | |||
922 | 31 | S : SHOW SCOPE FILTER ; | ||
923 | 32 | FILTER : WHERE EXP | ; | ||
924 | 33 | EXP : STRING OP STRING CONJ ; | ||
925 | 34 | CONJ : AND EXP | ; | ||
926 | 35 | |||
927 | 36 | The `create` command | ||
928 | 37 | ==================== | ||
929 | 38 | |||
930 | 39 | The commands to create mailman objects | ||
931 | 40 | |||
932 | 41 | Tokens | ||
933 | 42 | ------ | ||
934 | 43 | :: | ||
935 | 44 | |||
936 | 45 | CREATE : 'create' | ||
937 | 46 | SCOPE : 'user|domain|list' | ||
938 | 47 | WITH : 'with' | ||
939 | 48 | AND : 'and' | ||
940 | 49 | STRING : '`([a-zA-Z0-9_@\.\*\-\$ ]*)`' | ||
941 | 50 | |||
942 | 51 | Grammar | ||
943 | 52 | ------- | ||
944 | 53 | :: | ||
945 | 54 | |||
946 | 55 | S : CREATE SCOPE WITH EXP ; | ||
947 | 56 | EXP : STRING "=" STRING CONJ ; | ||
948 | 57 | CONJ : AND EXP | ; | ||
949 | 58 | |||
950 | 59 | The `delete` command | ||
951 | 60 | ==================== | ||
952 | 61 | |||
953 | 62 | The commands to delete mailman objects | ||
954 | 63 | |||
955 | 64 | Tokens | ||
956 | 65 | ------ | ||
957 | 66 | :: | ||
958 | 67 | |||
959 | 68 | DELETE : 'delete' | ||
960 | 69 | SCOPE : '(user|domain|list)s?' | ||
961 | 70 | WHERE : 'where' | ||
962 | 71 | OP : '=|in|like' | ||
963 | 72 | AND : 'and' | ||
964 | 73 | STRING : '`([a-zA-Z0-9_@\.\*\-\$ ]*)`' | ||
965 | 74 | |||
966 | 75 | Grammar | ||
967 | 76 | ------- | ||
968 | 77 | :: | ||
969 | 78 | |||
970 | 79 | S : DELETE SCOPE FILTER ; | ||
971 | 80 | FILTER : WHERE EXP | ; | ||
972 | 81 | EXP : STRING OP STRING CONJ ; | ||
973 | 82 | CONJ : AND EXP | ; | ||
974 | 83 | |||
975 | 84 | The `subscribe` Command | ||
976 | 85 | ===================== | ||
977 | 86 | |||
978 | 87 | The commands to subscribe a list of users to a mailing lists | ||
979 | 88 | |||
980 | 89 | Tokens | ||
981 | 90 | ------ | ||
982 | 91 | :: | ||
983 | 92 | |||
984 | 93 | SUBSCRIBE : 'subscribe' | ||
985 | 94 | USER : '(user)?' | ||
986 | 95 | TO : 'to' | ||
987 | 96 | STRING : '`([a-zA-Z0-9_@\.\*\-\$ ]*)`' | ||
988 | 97 | |||
989 | 98 | Grammar | ||
990 | 99 | ------- | ||
991 | 100 | :: | ||
992 | 101 | |||
993 | 102 | S : SUBSCRIBE USER USERLIST TO STRING ; | ||
994 | 103 | USERLIST : STRING NEXT ; | ||
995 | 104 | NEXT : USERLIST | ; | ||
996 | 105 | |||
997 | 106 | The `unsubscribe` Command | ||
998 | 107 | ========================= | ||
999 | 108 | |||
1000 | 109 | The commands to unsubscribe a list of users from a mailing lists | ||
1001 | 110 | |||
1002 | 111 | Tokens | ||
1003 | 112 | ------ | ||
1004 | 113 | :: | ||
1005 | 114 | |||
1006 | 115 | UNSUBSCRIBE : 'unsubscribe' | ||
1007 | 116 | USER : '(user)?' | ||
1008 | 117 | FROM : 'from' | ||
1009 | 118 | STRING : '`([a-zA-Z0-9_@\.\*\-\$ ]*)`' | ||
1010 | 119 | |||
1011 | 120 | Grammar | ||
1012 | 121 | ------- | ||
1013 | 122 | :: | ||
1014 | 123 | |||
1015 | 124 | S : UNSUBSCRIBE USER USERLIST TO STRING ; | ||
1016 | 125 | USERLIST : STRING NEXT ; | ||
1017 | 126 | NEXT : USERLIST | ; | ||
1018 | 127 | |||
1019 | 128 | The `unset` command | ||
1020 | 129 | =================== | ||
1021 | 130 | |||
1022 | 131 | Command to unset a shell variable | ||
1023 | 132 | |||
1024 | 133 | Tokens | ||
1025 | 134 | ------ | ||
1026 | 135 | :: | ||
1027 | 136 | |||
1028 | 137 | UNSET : 'unset' | ||
1029 | 138 | STRING : '`([a-zA-Z0-9_@\.\*\-\$ ]*)`' | ||
1030 | 139 | |||
1031 | 140 | Grammar | ||
1032 | 141 | ------- | ||
1033 | 142 | :: | ||
1034 | 143 | |||
1035 | 144 | S : UNSET STRING ; | ||
1036 | 145 | |||
1037 | 146 | The `set` Command | ||
1038 | 147 | ================= | ||
1039 | 148 | |||
1040 | 149 | Command to set a shell variable | ||
1041 | 150 | |||
1042 | 151 | Tokens | ||
1043 | 152 | ------ | ||
1044 | 153 | :: | ||
1045 | 154 | |||
1046 | 155 | SET : 'set' | ||
1047 | 156 | STRING : '`([a-zA-Z0-9_@\.\*\-\$ ]*)`' | ||
1048 | 157 | |||
1049 | 158 | Grammar | ||
1050 | 159 | ------- | ||
1051 | 160 | :: | ||
1052 | 161 | |||
1053 | 162 | S : SET STRING "=" STRING ; | ||
1054 | 163 | |||
1055 | 164 | The `update` command | ||
1056 | 165 | ==================== | ||
1057 | 166 | |||
1058 | 167 | Command to update a preference | ||
1059 | 168 | |||
1060 | 169 | Tokens | ||
1061 | 170 | ------ | ||
1062 | 171 | :: | ||
1063 | 172 | |||
1064 | 173 | UPDATE : 'update' | ||
1065 | 174 | PREFERENCE : 'preference' | ||
1066 | 175 | STRING : '`([a-zA-Z0-9_@\.\*\-\$ ]*)`' | ||
1067 | 176 | TO : 'to' | ||
1068 | 177 | WITH : 'with' | ||
1069 | 178 | AND : 'and' | ||
1070 | 179 | FOR : 'for' | ||
1071 | 180 | GLOBALLY : 'globally' | ||
1072 | 181 | DOMAIN : 'user|address|member' | ||
1073 | 182 | |||
1074 | 183 | Grammar | ||
1075 | 184 | ------- | ||
1076 | 185 | :: | ||
1077 | 186 | |||
1078 | 187 | S : UPDATE PREFERENCE STRING TO STRING E ; | ||
1079 | 188 | E : GLOBALLY | FOR DOMAIN WITH EXP ; | ||
1080 | 189 | EXP : STRING "=" STRING CONJ ; | ||
1081 | 190 | CONJ : AND EXP | ; | ||
1082 | 0 | 191 | ||
1083 | === added file 'src/mailmanclient/cli/client/parsers/__init__.py' | |||
1084 | === added file 'src/mailmanclient/cli/client/parsers/_set.py' | |||
1085 | --- src/mailmanclient/cli/client/parsers/_set.py 1970-01-01 00:00:00 +0000 | |||
1086 | +++ src/mailmanclient/cli/client/parsers/_set.py 2015-03-17 19:08:34 +0000 | |||
1087 | @@ -0,0 +1,64 @@ | |||
1088 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
1089 | 2 | # | ||
1090 | 3 | # This file is part of mailman.client. | ||
1091 | 4 | # | ||
1092 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
1093 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
1094 | 7 | # Free Software Foundation, version 3 of the License. | ||
1095 | 8 | # | ||
1096 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
1097 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
1098 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
1099 | 12 | # License for more details. | ||
1100 | 13 | # | ||
1101 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
1102 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
1103 | 16 | # | ||
1104 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
1105 | 18 | # | ||
1106 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
1107 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
1108 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
1109 | 22 | # Barry Warsaw <barry@list.org> | ||
1110 | 23 | |||
1111 | 24 | import ply.yacc as yacc | ||
1112 | 25 | from mailmanclient.cli.client.parsers.base import Parser | ||
1113 | 26 | |||
1114 | 27 | |||
1115 | 28 | class Set(Parser): | ||
1116 | 29 | tokens = ('SET', 'STRING') | ||
1117 | 30 | literals = ['=', '`'] | ||
1118 | 31 | t_ignore = " \t" | ||
1119 | 32 | |||
1120 | 33 | def t_SET(self, t): | ||
1121 | 34 | r'set' | ||
1122 | 35 | return t | ||
1123 | 36 | |||
1124 | 37 | def t_STRING(self, t): | ||
1125 | 38 | r'`([a-zA-Z0-9_@\.\*\-\$ ]*)`' | ||
1126 | 39 | t.value = t.value.replace('`', '') | ||
1127 | 40 | return t | ||
1128 | 41 | |||
1129 | 42 | def t_newline(self, t): | ||
1130 | 43 | r'\n+' | ||
1131 | 44 | t.lexer.lineno += t.value.count("\n") | ||
1132 | 45 | return | ||
1133 | 46 | |||
1134 | 47 | def t_error(self, t): | ||
1135 | 48 | raise Exception("Illegal character '%s'" % t.value[0]) | ||
1136 | 49 | t.lexer.skip(1) | ||
1137 | 50 | |||
1138 | 51 | def p_statement_scope(self, p): | ||
1139 | 52 | '''S : SET STRING "=" STRING''' | ||
1140 | 53 | self.arguments['key'] = p[2] | ||
1141 | 54 | self.arguments['value'] = p[4] | ||
1142 | 55 | |||
1143 | 56 | def p_error(self, p): | ||
1144 | 57 | if p: | ||
1145 | 58 | raise Exception("Syntax error at '%s'" % p.value) | ||
1146 | 59 | else: | ||
1147 | 60 | raise Exception("Syntax error : Incomplete Command") | ||
1148 | 61 | |||
1149 | 62 | def parse(self, shell): | ||
1150 | 63 | yacc.parse(shell.line) | ||
1151 | 64 | return self.arguments | ||
1152 | 0 | 65 | ||
1153 | === added file 'src/mailmanclient/cli/client/parsers/base.py' | |||
1154 | --- src/mailmanclient/cli/client/parsers/base.py 1970-01-01 00:00:00 +0000 | |||
1155 | +++ src/mailmanclient/cli/client/parsers/base.py 2015-03-17 19:08:34 +0000 | |||
1156 | @@ -0,0 +1,62 @@ | |||
1157 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
1158 | 2 | # | ||
1159 | 3 | # This file is part of mailman.client. | ||
1160 | 4 | # | ||
1161 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
1162 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
1163 | 7 | # Free Software Foundation, version 3 of the License. | ||
1164 | 8 | # | ||
1165 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
1166 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
1167 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
1168 | 12 | # License for more details. | ||
1169 | 13 | # | ||
1170 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
1171 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
1172 | 16 | # | ||
1173 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
1174 | 18 | # | ||
1175 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
1176 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
1177 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
1178 | 22 | # Barry Warsaw <barry@list.org> | ||
1179 | 23 | |||
1180 | 24 | import os | ||
1181 | 25 | import ply.lex as lex | ||
1182 | 26 | import ply.yacc as yacc | ||
1183 | 27 | |||
1184 | 28 | |||
1185 | 29 | class Parser: | ||
1186 | 30 | """ | ||
1187 | 31 | Base class for a lexer/parser that has the rules defined as methods | ||
1188 | 32 | """ | ||
1189 | 33 | tokens = () | ||
1190 | 34 | precedence = () | ||
1191 | 35 | arguments = {} | ||
1192 | 36 | |||
1193 | 37 | def __init__(self, **kw): | ||
1194 | 38 | self.debug = kw.get('debug', 0) | ||
1195 | 39 | self.names = {} | ||
1196 | 40 | self.arguments = {} | ||
1197 | 41 | try: | ||
1198 | 42 | modname = os.path.split(os.path.splitext(__file__)[0])[1] + "_" | ||
1199 | 43 | modname += self.__class__.__name__ | ||
1200 | 44 | except: | ||
1201 | 45 | modname = "parser"+"_"+self.__class__.__name__ | ||
1202 | 46 | self.debugfile = modname + ".dbg" | ||
1203 | 47 | self.tabmodule = modname + "_" + "parsetab" | ||
1204 | 48 | |||
1205 | 49 | if not os.path.exists('/tmp/parser_files'): | ||
1206 | 50 | os.mkdir('/tmp/parser_files') | ||
1207 | 51 | |||
1208 | 52 | lex.lex(module=self, debug=self.debug) | ||
1209 | 53 | yacc.yacc(module=self, | ||
1210 | 54 | debug=self.debug, | ||
1211 | 55 | debugfile=self.debugfile, | ||
1212 | 56 | tabmodule=self.tabmodule, | ||
1213 | 57 | outputdir='/tmp/parser_files') | ||
1214 | 58 | |||
1215 | 59 | def stem(self, token): | ||
1216 | 60 | if token.value[-1] == 's': | ||
1217 | 61 | token.value = token.value[:-1] | ||
1218 | 62 | return token | ||
1219 | 0 | 63 | ||
1220 | === added file 'src/mailmanclient/cli/client/parsers/create.py' | |||
1221 | --- src/mailmanclient/cli/client/parsers/create.py 1970-01-01 00:00:00 +0000 | |||
1222 | +++ src/mailmanclient/cli/client/parsers/create.py 2015-03-17 19:08:34 +0000 | |||
1223 | @@ -0,0 +1,86 @@ | |||
1224 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
1225 | 2 | # | ||
1226 | 3 | # This file is part of mailman.client. | ||
1227 | 4 | # | ||
1228 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
1229 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
1230 | 7 | # Free Software Foundation, version 3 of the License. | ||
1231 | 8 | # | ||
1232 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
1233 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
1234 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
1235 | 12 | # License for more details. | ||
1236 | 13 | # | ||
1237 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
1238 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
1239 | 16 | # | ||
1240 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
1241 | 18 | # | ||
1242 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
1243 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
1244 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
1245 | 22 | # Barry Warsaw <barry@list.org> | ||
1246 | 23 | |||
1247 | 24 | import ply.yacc as yacc | ||
1248 | 25 | from mailmanclient.cli.client.parsers.base import Parser | ||
1249 | 26 | |||
1250 | 27 | |||
1251 | 28 | class Create(Parser): | ||
1252 | 29 | tokens = ('CREATE', 'SCOPE', 'STRING', 'WITH', 'AND') | ||
1253 | 30 | literals = ['+', '`', '='] | ||
1254 | 31 | t_ignore = " \t" | ||
1255 | 32 | |||
1256 | 33 | def t_CREATE(self, t): | ||
1257 | 34 | r'create' | ||
1258 | 35 | return t | ||
1259 | 36 | |||
1260 | 37 | def t_SCOPE(self, t): | ||
1261 | 38 | 'user|domain|list' | ||
1262 | 39 | return t | ||
1263 | 40 | |||
1264 | 41 | def t_WITH(self, t): | ||
1265 | 42 | 'with' | ||
1266 | 43 | return t | ||
1267 | 44 | |||
1268 | 45 | def t_AND(self, t): | ||
1269 | 46 | 'and' | ||
1270 | 47 | return t | ||
1271 | 48 | |||
1272 | 49 | def t_STRING(self, t): | ||
1273 | 50 | r'`([a-zA-Z0-9_@\.\*\-\$ ]*)`' | ||
1274 | 51 | t.value = t.value.replace('`', '') | ||
1275 | 52 | return t | ||
1276 | 53 | |||
1277 | 54 | def t_newline(self, t): | ||
1278 | 55 | r'\n+' | ||
1279 | 56 | t.lexer.lineno += t.value.count("\n") | ||
1280 | 57 | return | ||
1281 | 58 | |||
1282 | 59 | def t_error(self, t): | ||
1283 | 60 | raise Exception("Illegal character '%s'" % t.value[0]) | ||
1284 | 61 | t.lexer.skip(1) | ||
1285 | 62 | |||
1286 | 63 | def p_start_statement(self, p): | ||
1287 | 64 | '''S : CREATE SCOPE WITH EXP''' | ||
1288 | 65 | self.arguments['scope'] = p[2] | ||
1289 | 66 | |||
1290 | 67 | def p_exp_condition(self, p): | ||
1291 | 68 | '''EXP : STRING "=" STRING CONJ''' | ||
1292 | 69 | if 'properties' not in self.arguments: | ||
1293 | 70 | self.arguments['properties'] = {} | ||
1294 | 71 | self.arguments['properties'][p[1]] = p[3] | ||
1295 | 72 | |||
1296 | 73 | def p_conj_exp(self, p): | ||
1297 | 74 | ''' CONJ : AND EXP | ||
1298 | 75 | |''' | ||
1299 | 76 | pass | ||
1300 | 77 | |||
1301 | 78 | def p_error(self, p): | ||
1302 | 79 | if p: | ||
1303 | 80 | raise Exception("Syntax error at '%s'" % p.value) | ||
1304 | 81 | else: | ||
1305 | 82 | raise Exception("Syntax error : Incomplete Command") | ||
1306 | 83 | |||
1307 | 84 | def parse(self, shell): | ||
1308 | 85 | yacc.parse(shell.line) | ||
1309 | 86 | return self.arguments | ||
1310 | 0 | 87 | ||
1311 | === added file 'src/mailmanclient/cli/client/parsers/delete.py' | |||
1312 | --- src/mailmanclient/cli/client/parsers/delete.py 1970-01-01 00:00:00 +0000 | |||
1313 | +++ src/mailmanclient/cli/client/parsers/delete.py 2015-03-17 19:08:34 +0000 | |||
1314 | @@ -0,0 +1,101 @@ | |||
1315 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
1316 | 2 | # | ||
1317 | 3 | # This file is part of mailman.client. | ||
1318 | 4 | # | ||
1319 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
1320 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
1321 | 7 | # Free Software Foundation, version 3 of the License. | ||
1322 | 8 | # | ||
1323 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
1324 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
1325 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
1326 | 12 | # License for more details. | ||
1327 | 13 | # | ||
1328 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
1329 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
1330 | 16 | # | ||
1331 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
1332 | 18 | # | ||
1333 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
1334 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
1335 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
1336 | 22 | # Barry Warsaw <barry@list.org> | ||
1337 | 23 | |||
1338 | 24 | import ply.yacc as yacc | ||
1339 | 25 | from mailmanclient.cli.client.parsers.base import Parser | ||
1340 | 26 | from mailmanclient.cli.lib.mailman_utils import MailmanUtils | ||
1341 | 27 | |||
1342 | 28 | |||
1343 | 29 | class Delete(Parser): | ||
1344 | 30 | tokens = ('DELETE', 'SCOPE', 'STRING', 'WHERE', 'OP', 'AND') | ||
1345 | 31 | literals = ['+', '`'] | ||
1346 | 32 | t_ignore = " \t" | ||
1347 | 33 | |||
1348 | 34 | def t_DELETE(self, t): | ||
1349 | 35 | r'delete' | ||
1350 | 36 | return t | ||
1351 | 37 | |||
1352 | 38 | def t_SCOPE(self, t): | ||
1353 | 39 | '(user|domain|list)s?' | ||
1354 | 40 | return self.stem(t) | ||
1355 | 41 | |||
1356 | 42 | def t_WHERE(self, t): | ||
1357 | 43 | 'where' | ||
1358 | 44 | return t | ||
1359 | 45 | |||
1360 | 46 | def t_OP(self, t): | ||
1361 | 47 | '=|in|like' | ||
1362 | 48 | return t | ||
1363 | 49 | |||
1364 | 50 | def t_AND(self, t): | ||
1365 | 51 | 'and' | ||
1366 | 52 | return t | ||
1367 | 53 | |||
1368 | 54 | def t_STRING(self, t): | ||
1369 | 55 | r'`([a-zA-Z0-9_@\.\*\-\$ ]*)`' | ||
1370 | 56 | t.value = t.value.replace('`', '') | ||
1371 | 57 | return t | ||
1372 | 58 | |||
1373 | 59 | def t_newline(self, t): | ||
1374 | 60 | r'\n+' | ||
1375 | 61 | t.lexer.lineno += t.value.count("\n") | ||
1376 | 62 | return | ||
1377 | 63 | |||
1378 | 64 | def t_error(self, t): | ||
1379 | 65 | raise Exception("Illegal character '%s'" % t.value[0]) | ||
1380 | 66 | t.lexer.skip(1) | ||
1381 | 67 | |||
1382 | 68 | def p_statement_scope(self, p): | ||
1383 | 69 | '''S : DELETE SCOPE FILTER''' | ||
1384 | 70 | self.arguments['scope'] = p[2] | ||
1385 | 71 | |||
1386 | 72 | def p_filter(self, p): | ||
1387 | 73 | '''FILTER : WHERE EXP | ||
1388 | 74 | |''' | ||
1389 | 75 | pass | ||
1390 | 76 | |||
1391 | 77 | def p_exp_condition(self, p): | ||
1392 | 78 | '''EXP : STRING OP STRING CONJ''' | ||
1393 | 79 | if 'filters' not in self.arguments: | ||
1394 | 80 | self.arguments['filters'] = [] | ||
1395 | 81 | if p[2] == 'in': | ||
1396 | 82 | self.arguments['filters'].append((p[3], p[2], p[1])) | ||
1397 | 83 | else: | ||
1398 | 84 | self.arguments['filters'].append((p[1], p[2], p[3])) | ||
1399 | 85 | |||
1400 | 86 | def p_conj_exp(self, p): | ||
1401 | 87 | ''' CONJ : AND EXP | ||
1402 | 88 | |''' | ||
1403 | 89 | pass | ||
1404 | 90 | |||
1405 | 91 | def p_error(self, p): | ||
1406 | 92 | if p: | ||
1407 | 93 | raise Exception("Syntax error at '%s'" % p.value) | ||
1408 | 94 | else: | ||
1409 | 95 | raise Exception("Syntax error : Incomplete Command") | ||
1410 | 96 | |||
1411 | 97 | def parse(self, shell): | ||
1412 | 98 | yacc.parse(shell.line) | ||
1413 | 99 | utils = MailmanUtils() | ||
1414 | 100 | self.arguments = utils.add_reserved_vars(self.arguments, shell) | ||
1415 | 101 | return self.arguments | ||
1416 | 0 | 102 | ||
1417 | === added file 'src/mailmanclient/cli/client/parsers/disable.py' | |||
1418 | --- src/mailmanclient/cli/client/parsers/disable.py 1970-01-01 00:00:00 +0000 | |||
1419 | +++ src/mailmanclient/cli/client/parsers/disable.py 2015-03-17 19:08:34 +0000 | |||
1420 | @@ -0,0 +1,63 @@ | |||
1421 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
1422 | 2 | # | ||
1423 | 3 | # This file is part of mailman.client. | ||
1424 | 4 | # | ||
1425 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
1426 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
1427 | 7 | # Free Software Foundation, version 3 of the License. | ||
1428 | 8 | # | ||
1429 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
1430 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
1431 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
1432 | 12 | # License for more details. | ||
1433 | 13 | # | ||
1434 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
1435 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
1436 | 16 | # | ||
1437 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
1438 | 18 | # | ||
1439 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
1440 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
1441 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
1442 | 22 | # Barry Warsaw <barry@list.org> | ||
1443 | 23 | |||
1444 | 24 | import ply.yacc as yacc | ||
1445 | 25 | from mailmanclient.cli.client.parsers.base import Parser | ||
1446 | 26 | |||
1447 | 27 | |||
1448 | 28 | class Disable(Parser): | ||
1449 | 29 | tokens = ('DISABLE', 'WHAT') | ||
1450 | 30 | literals = ['=', '`'] | ||
1451 | 31 | t_ignore = " \t" | ||
1452 | 32 | |||
1453 | 33 | def t_DISABLE(self, t): | ||
1454 | 34 | r'disable' | ||
1455 | 35 | return t | ||
1456 | 36 | |||
1457 | 37 | def t_WHAT(self, t): | ||
1458 | 38 | r'env' | ||
1459 | 39 | t.value = t.value.replace('`', '') | ||
1460 | 40 | return t | ||
1461 | 41 | |||
1462 | 42 | def t_newline(self, t): | ||
1463 | 43 | r'\n+' | ||
1464 | 44 | t.lexer.lineno += t.value.count("\n") | ||
1465 | 45 | return | ||
1466 | 46 | |||
1467 | 47 | def t_error(self, t): | ||
1468 | 48 | raise Exception("Illegal character '%s'" % t.value[0]) | ||
1469 | 49 | t.lexer.skip(1) | ||
1470 | 50 | |||
1471 | 51 | def p_statment(self, p): | ||
1472 | 52 | '''S : DISABLE WHAT''' | ||
1473 | 53 | self.arguments['what'] = p[2] | ||
1474 | 54 | |||
1475 | 55 | def p_error(self, p): | ||
1476 | 56 | if p: | ||
1477 | 57 | raise Exception("Syntax error at '%s'" % p.value) | ||
1478 | 58 | else: | ||
1479 | 59 | raise Exception("Syntax error : Incomplete Command") | ||
1480 | 60 | |||
1481 | 61 | def parse(self, shell): | ||
1482 | 62 | yacc.parse(shell.line) | ||
1483 | 63 | return self.arguments | ||
1484 | 0 | 64 | ||
1485 | === added file 'src/mailmanclient/cli/client/parsers/enable.py' | |||
1486 | --- src/mailmanclient/cli/client/parsers/enable.py 1970-01-01 00:00:00 +0000 | |||
1487 | +++ src/mailmanclient/cli/client/parsers/enable.py 2015-03-17 19:08:34 +0000 | |||
1488 | @@ -0,0 +1,63 @@ | |||
1489 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
1490 | 2 | # | ||
1491 | 3 | # This file is part of mailman.client. | ||
1492 | 4 | # | ||
1493 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
1494 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
1495 | 7 | # Free Software Foundation, version 3 of the License. | ||
1496 | 8 | # | ||
1497 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
1498 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
1499 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
1500 | 12 | # License for more details. | ||
1501 | 13 | # | ||
1502 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
1503 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
1504 | 16 | # | ||
1505 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
1506 | 18 | # | ||
1507 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
1508 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
1509 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
1510 | 22 | # Barry Warsaw <barry@list.org> | ||
1511 | 23 | |||
1512 | 24 | import ply.yacc as yacc | ||
1513 | 25 | from mailmanclient.cli.client.parsers.base import Parser | ||
1514 | 26 | |||
1515 | 27 | |||
1516 | 28 | class Enable(Parser): | ||
1517 | 29 | tokens = ('ENABLE', 'WHAT') | ||
1518 | 30 | literals = ['=', '`'] | ||
1519 | 31 | t_ignore = " \t" | ||
1520 | 32 | |||
1521 | 33 | def t_ENABLE(self, t): | ||
1522 | 34 | r'enable' | ||
1523 | 35 | return t | ||
1524 | 36 | |||
1525 | 37 | def t_WHAT(self, t): | ||
1526 | 38 | r'env' | ||
1527 | 39 | t.value = t.value.replace('`', '') | ||
1528 | 40 | return t | ||
1529 | 41 | |||
1530 | 42 | def t_newline(self, t): | ||
1531 | 43 | r'\n+' | ||
1532 | 44 | t.lexer.lineno += t.value.count("\n") | ||
1533 | 45 | return | ||
1534 | 46 | |||
1535 | 47 | def t_error(self, t): | ||
1536 | 48 | raise Exception("Illegal character '%s'" % t.value[0]) | ||
1537 | 49 | t.lexer.skip(1) | ||
1538 | 50 | |||
1539 | 51 | def p_statment(self, p): | ||
1540 | 52 | '''S : ENABLE WHAT''' | ||
1541 | 53 | self.arguments['what'] = p[2] | ||
1542 | 54 | |||
1543 | 55 | def p_error(self, p): | ||
1544 | 56 | if p: | ||
1545 | 57 | raise Exception("Syntax error at '%s'" % p.value) | ||
1546 | 58 | else: | ||
1547 | 59 | raise Exception("Syntax error : Incomplete Command") | ||
1548 | 60 | |||
1549 | 61 | def parse(self, shell): | ||
1550 | 62 | yacc.parse(shell.line) | ||
1551 | 63 | return self.arguments | ||
1552 | 0 | 64 | ||
1553 | === added file 'src/mailmanclient/cli/client/parsers/show.py' | |||
1554 | --- src/mailmanclient/cli/client/parsers/show.py 1970-01-01 00:00:00 +0000 | |||
1555 | +++ src/mailmanclient/cli/client/parsers/show.py 2015-03-17 19:08:34 +0000 | |||
1556 | @@ -0,0 +1,101 @@ | |||
1557 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
1558 | 2 | # | ||
1559 | 3 | # This file is part of mailman.client. | ||
1560 | 4 | # | ||
1561 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
1562 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
1563 | 7 | # Free Software Foundation, version 3 of the License. | ||
1564 | 8 | # | ||
1565 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
1566 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
1567 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
1568 | 12 | # License for more details. | ||
1569 | 13 | # | ||
1570 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
1571 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
1572 | 16 | # | ||
1573 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
1574 | 18 | # | ||
1575 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
1576 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
1577 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
1578 | 22 | # Barry Warsaw <barry@list.org> | ||
1579 | 23 | |||
1580 | 24 | import ply.yacc as yacc | ||
1581 | 25 | from mailmanclient.cli.client.parsers.base import Parser | ||
1582 | 26 | from mailmanclient.cli.lib.mailman_utils import MailmanUtils | ||
1583 | 27 | |||
1584 | 28 | |||
1585 | 29 | class Show(Parser): | ||
1586 | 30 | tokens = ('SHOW', 'SCOPE', 'STRING', 'WHERE', 'OP', 'AND') | ||
1587 | 31 | literals = ['+', '`'] | ||
1588 | 32 | t_ignore = " \t" | ||
1589 | 33 | |||
1590 | 34 | def t_SHOW(self, t): | ||
1591 | 35 | r'show' | ||
1592 | 36 | return t | ||
1593 | 37 | |||
1594 | 38 | def t_SCOPE(self, t): | ||
1595 | 39 | '(user|domain|list)s?' | ||
1596 | 40 | return self.stem(t) | ||
1597 | 41 | |||
1598 | 42 | def t_WHERE(self, t): | ||
1599 | 43 | 'where' | ||
1600 | 44 | return t | ||
1601 | 45 | |||
1602 | 46 | def t_OP(self, t): | ||
1603 | 47 | '=|in|like' | ||
1604 | 48 | return t | ||
1605 | 49 | |||
1606 | 50 | def t_AND(self, t): | ||
1607 | 51 | 'and' | ||
1608 | 52 | return t | ||
1609 | 53 | |||
1610 | 54 | def t_STRING(self, t): | ||
1611 | 55 | r'`([a-zA-Z0-9_@\.\*\-\$ ]*)`' | ||
1612 | 56 | t.value = t.value.replace('`', '') | ||
1613 | 57 | return t | ||
1614 | 58 | |||
1615 | 59 | def t_newline(self, t): | ||
1616 | 60 | r'\n+' | ||
1617 | 61 | t.lexer.lineno += t.value.count("\n") | ||
1618 | 62 | return | ||
1619 | 63 | |||
1620 | 64 | def t_error(self, t): | ||
1621 | 65 | raise Exception("Illegal character '%s'" % t.value[0]) | ||
1622 | 66 | t.lexer.skip(1) | ||
1623 | 67 | |||
1624 | 68 | def p_statement_scope(self, p): | ||
1625 | 69 | '''S : SHOW SCOPE FILTER''' | ||
1626 | 70 | self.arguments['scope'] = p[2] | ||
1627 | 71 | |||
1628 | 72 | def p_filter(self, p): | ||
1629 | 73 | '''FILTER : WHERE EXP | ||
1630 | 74 | |''' | ||
1631 | 75 | pass | ||
1632 | 76 | |||
1633 | 77 | def p_exp_condition(self, p): | ||
1634 | 78 | '''EXP : STRING OP STRING CONJ''' | ||
1635 | 79 | if 'filters' not in self.arguments: | ||
1636 | 80 | self.arguments['filters'] = [] | ||
1637 | 81 | if p[2] == 'in': | ||
1638 | 82 | self.arguments['filters'].append((p[3], p[2], p[1])) | ||
1639 | 83 | else: | ||
1640 | 84 | self.arguments['filters'].append((p[1], p[2], p[3])) | ||
1641 | 85 | |||
1642 | 86 | def p_conj_exp(self, p): | ||
1643 | 87 | ''' CONJ : AND EXP | ||
1644 | 88 | |''' | ||
1645 | 89 | pass | ||
1646 | 90 | |||
1647 | 91 | def p_error(self, p): | ||
1648 | 92 | if p: | ||
1649 | 93 | raise Exception("Syntax error at '%s'" % p.value) | ||
1650 | 94 | else: | ||
1651 | 95 | raise Exception("Syntax error : Incomplete Command") | ||
1652 | 96 | |||
1653 | 97 | def parse(self, shell): | ||
1654 | 98 | yacc.parse(shell.line) | ||
1655 | 99 | utils = MailmanUtils() | ||
1656 | 100 | self.arguments = utils.add_reserved_vars(self.arguments, shell) | ||
1657 | 101 | return self.arguments | ||
1658 | 0 | 102 | ||
1659 | === added file 'src/mailmanclient/cli/client/parsers/show_var.py' | |||
1660 | --- src/mailmanclient/cli/client/parsers/show_var.py 1970-01-01 00:00:00 +0000 | |||
1661 | +++ src/mailmanclient/cli/client/parsers/show_var.py 2015-03-17 19:08:34 +0000 | |||
1662 | @@ -0,0 +1,63 @@ | |||
1663 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
1664 | 2 | # | ||
1665 | 3 | # This file is part of mailman.client. | ||
1666 | 4 | # | ||
1667 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
1668 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
1669 | 7 | # Free Software Foundation, version 3 of the License. | ||
1670 | 8 | # | ||
1671 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
1672 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
1673 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
1674 | 12 | # License for more details. | ||
1675 | 13 | # | ||
1676 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
1677 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
1678 | 16 | # | ||
1679 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
1680 | 18 | # | ||
1681 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
1682 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
1683 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
1684 | 22 | # Barry Warsaw <barry@list.org> | ||
1685 | 23 | |||
1686 | 24 | import ply.yacc as yacc | ||
1687 | 25 | from mailmanclient.cli.client.parsers.base import Parser | ||
1688 | 26 | |||
1689 | 27 | |||
1690 | 28 | class ShowVar(Parser): | ||
1691 | 29 | tokens = ('SHOW', 'STRING') | ||
1692 | 30 | literals = ['=', '`'] | ||
1693 | 31 | t_ignore = " \t" | ||
1694 | 32 | |||
1695 | 33 | def t_SHOW(self, t): | ||
1696 | 34 | r'show_var' | ||
1697 | 35 | return t | ||
1698 | 36 | |||
1699 | 37 | def t_STRING(self, t): | ||
1700 | 38 | r'`([a-zA-Z0-9_@\.\*\-]*)`' | ||
1701 | 39 | t.value = t.value.replace('`', '') | ||
1702 | 40 | return t | ||
1703 | 41 | |||
1704 | 42 | def t_newline(self, t): | ||
1705 | 43 | r'\n+' | ||
1706 | 44 | t.lexer.lineno += t.value.count("\n") | ||
1707 | 45 | return | ||
1708 | 46 | |||
1709 | 47 | def t_error(self, t): | ||
1710 | 48 | raise Exception("Illegal character '%s'" % t.value[0]) | ||
1711 | 49 | t.lexer.skip(1) | ||
1712 | 50 | |||
1713 | 51 | def p_statement_scope(self, p): | ||
1714 | 52 | '''S : SHOW STRING''' | ||
1715 | 53 | self.arguments['key'] = p[2] | ||
1716 | 54 | |||
1717 | 55 | def p_error(self, p): | ||
1718 | 56 | if p: | ||
1719 | 57 | raise Exception("Syntax error at '%s'" % p.value) | ||
1720 | 58 | else: | ||
1721 | 59 | raise Exception("Syntax error : Incomplete Command") | ||
1722 | 60 | |||
1723 | 61 | def parse(self, shell): | ||
1724 | 62 | yacc.parse(shell.line) | ||
1725 | 63 | return self.arguments | ||
1726 | 0 | 64 | ||
1727 | === added file 'src/mailmanclient/cli/client/parsers/subscribe.py' | |||
1728 | --- src/mailmanclient/cli/client/parsers/subscribe.py 1970-01-01 00:00:00 +0000 | |||
1729 | +++ src/mailmanclient/cli/client/parsers/subscribe.py 2015-03-17 19:08:34 +0000 | |||
1730 | @@ -0,0 +1,84 @@ | |||
1731 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
1732 | 2 | # | ||
1733 | 3 | # This file is part of mailman.client. | ||
1734 | 4 | # | ||
1735 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
1736 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
1737 | 7 | # Free Software Foundation, version 3 of the License. | ||
1738 | 8 | # | ||
1739 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
1740 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
1741 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
1742 | 12 | # License for more details. | ||
1743 | 13 | # | ||
1744 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
1745 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
1746 | 16 | # | ||
1747 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
1748 | 18 | # | ||
1749 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
1750 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
1751 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
1752 | 22 | # Barry Warsaw <barry@list.org> | ||
1753 | 23 | |||
1754 | 24 | import ply.yacc as yacc | ||
1755 | 25 | from mailmanclient.cli.client.parsers.base import Parser | ||
1756 | 26 | |||
1757 | 27 | |||
1758 | 28 | class Subscribe(Parser): | ||
1759 | 29 | tokens = ('SUBSCRIBE', 'USER', 'STRING', 'TO') | ||
1760 | 30 | literals = ['+', '`', ','] | ||
1761 | 31 | t_ignore = " \t" | ||
1762 | 32 | |||
1763 | 33 | def t_SUBSCRIBE(self, t): | ||
1764 | 34 | r'subscribe' | ||
1765 | 35 | return t | ||
1766 | 36 | |||
1767 | 37 | def t_USER(self, t): | ||
1768 | 38 | '(user)s?' | ||
1769 | 39 | return self.stem(t) | ||
1770 | 40 | return t | ||
1771 | 41 | |||
1772 | 42 | def t_TO(self, t): | ||
1773 | 43 | 'to' | ||
1774 | 44 | return t | ||
1775 | 45 | |||
1776 | 46 | def t_STRING(self, t): | ||
1777 | 47 | r'`([a-zA-Z0-9_@\.\*\-\$ ]*)`' | ||
1778 | 48 | t.value = t.value.replace('`', '') | ||
1779 | 49 | return t | ||
1780 | 50 | |||
1781 | 51 | def t_newline(self, t): | ||
1782 | 52 | r'\n+' | ||
1783 | 53 | t.lexer.lineno += t.value.count("\n") | ||
1784 | 54 | return | ||
1785 | 55 | |||
1786 | 56 | def t_error(self, t): | ||
1787 | 57 | raise Exception("Illegal character '%s'" % t.value[0]) | ||
1788 | 58 | t.lexer.skip(1) | ||
1789 | 59 | |||
1790 | 60 | def p_statement_subscribe(self, p): | ||
1791 | 61 | '''S : SUBSCRIBE USER USERLIST TO STRING''' | ||
1792 | 62 | self.arguments['list'] = p[5] | ||
1793 | 63 | self.arguments['scope'] = p[2] | ||
1794 | 64 | |||
1795 | 65 | def p_get_users(self, p): | ||
1796 | 66 | '''USERLIST : STRING NEXT''' | ||
1797 | 67 | if 'users' not in self.arguments: | ||
1798 | 68 | self.arguments['users'] = [] | ||
1799 | 69 | self.arguments['users'].append(p[1]) | ||
1800 | 70 | |||
1801 | 71 | def p_next(self, p): | ||
1802 | 72 | '''NEXT : USERLIST | ||
1803 | 73 | |''' | ||
1804 | 74 | pass | ||
1805 | 75 | |||
1806 | 76 | def p_error(self, p): | ||
1807 | 77 | if p: | ||
1808 | 78 | raise Exception("Syntax error at '%s'" % p.value) | ||
1809 | 79 | else: | ||
1810 | 80 | raise Exception("Syntax error : Incomplete Command") | ||
1811 | 81 | |||
1812 | 82 | def parse(self, shell): | ||
1813 | 83 | yacc.parse(shell.line) | ||
1814 | 84 | return self.arguments | ||
1815 | 0 | 85 | ||
1816 | === added file 'src/mailmanclient/cli/client/parsers/unset.py' | |||
1817 | --- src/mailmanclient/cli/client/parsers/unset.py 1970-01-01 00:00:00 +0000 | |||
1818 | +++ src/mailmanclient/cli/client/parsers/unset.py 2015-03-17 19:08:34 +0000 | |||
1819 | @@ -0,0 +1,63 @@ | |||
1820 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
1821 | 2 | # | ||
1822 | 3 | # This file is part of mailman.client. | ||
1823 | 4 | # | ||
1824 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
1825 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
1826 | 7 | # Free Software Foundation, version 3 of the License. | ||
1827 | 8 | # | ||
1828 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
1829 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
1830 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
1831 | 12 | # License for more details. | ||
1832 | 13 | # | ||
1833 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
1834 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
1835 | 16 | # | ||
1836 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
1837 | 18 | # | ||
1838 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
1839 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
1840 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
1841 | 22 | # Barry Warsaw <barry@list.org> | ||
1842 | 23 | |||
1843 | 24 | import ply.yacc as yacc | ||
1844 | 25 | from mailmanclient.cli.client.parsers.base import Parser | ||
1845 | 26 | |||
1846 | 27 | |||
1847 | 28 | class Unset(Parser): | ||
1848 | 29 | tokens = ('UNSET', 'STRING') | ||
1849 | 30 | literals = ['=', '`'] | ||
1850 | 31 | t_ignore = " \t" | ||
1851 | 32 | |||
1852 | 33 | def t_UNSET(self, t): | ||
1853 | 34 | r'unset' | ||
1854 | 35 | return t | ||
1855 | 36 | |||
1856 | 37 | def t_STRING(self, t): | ||
1857 | 38 | r'`([a-zA-Z0-9_@\.\*\-\$ ]*)`' | ||
1858 | 39 | t.value = t.value.replace('`', '') | ||
1859 | 40 | return t | ||
1860 | 41 | |||
1861 | 42 | def t_newline(self, t): | ||
1862 | 43 | r'\n+' | ||
1863 | 44 | t.lexer.lineno += t.value.count("\n") | ||
1864 | 45 | return | ||
1865 | 46 | |||
1866 | 47 | def t_error(self, t): | ||
1867 | 48 | raise Exception("Illegal character '%s'" % t.value[0]) | ||
1868 | 49 | t.lexer.skip(1) | ||
1869 | 50 | |||
1870 | 51 | def p_statement_scope(self, p): | ||
1871 | 52 | '''S : UNSET STRING''' | ||
1872 | 53 | self.arguments['key'] = p[2] | ||
1873 | 54 | |||
1874 | 55 | def p_error(self, p): | ||
1875 | 56 | if p: | ||
1876 | 57 | raise Exception("Syntax error at '%s'" % p.value) | ||
1877 | 58 | else: | ||
1878 | 59 | raise Exception("Syntax error : Incomplete Command") | ||
1879 | 60 | |||
1880 | 61 | def parse(self, shell): | ||
1881 | 62 | yacc.parse(shell.line) | ||
1882 | 63 | return self.arguments | ||
1883 | 0 | 64 | ||
1884 | === added file 'src/mailmanclient/cli/client/parsers/unsubscribe.py' | |||
1885 | --- src/mailmanclient/cli/client/parsers/unsubscribe.py 1970-01-01 00:00:00 +0000 | |||
1886 | +++ src/mailmanclient/cli/client/parsers/unsubscribe.py 2015-03-17 19:08:34 +0000 | |||
1887 | @@ -0,0 +1,83 @@ | |||
1888 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
1889 | 2 | # | ||
1890 | 3 | # This file is part of mailman.client. | ||
1891 | 4 | # | ||
1892 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
1893 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
1894 | 7 | # Free Software Foundation, version 3 of the License. | ||
1895 | 8 | # | ||
1896 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
1897 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
1898 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
1899 | 12 | # License for more details. | ||
1900 | 13 | # | ||
1901 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
1902 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
1903 | 16 | # | ||
1904 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
1905 | 18 | # | ||
1906 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
1907 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
1908 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
1909 | 22 | # Barry Warsaw <barry@list.org> | ||
1910 | 23 | |||
1911 | 24 | import ply.yacc as yacc | ||
1912 | 25 | from mailmanclient.cli.client.parsers.base import Parser | ||
1913 | 26 | |||
1914 | 27 | |||
1915 | 28 | class Unsubscribe(Parser): | ||
1916 | 29 | tokens = ('UNSUBSCRIBE', 'USER', 'STRING', 'FROM') | ||
1917 | 30 | literals = ['+', '`', ','] | ||
1918 | 31 | t_ignore = " \t" | ||
1919 | 32 | |||
1920 | 33 | def t_UNSUBSCRIBE(self, t): | ||
1921 | 34 | r'unsubscribe' | ||
1922 | 35 | return t | ||
1923 | 36 | |||
1924 | 37 | def t_USER(self, t): | ||
1925 | 38 | '(user)s?' | ||
1926 | 39 | return self.stem(t) | ||
1927 | 40 | |||
1928 | 41 | def t_FROM(self, t): | ||
1929 | 42 | 'from' | ||
1930 | 43 | return t | ||
1931 | 44 | |||
1932 | 45 | def t_STRING(self, t): | ||
1933 | 46 | r'`([a-zA-Z0-9_@\.\*\-\$ ]*)`' | ||
1934 | 47 | t.value = t.value.replace('`', '') | ||
1935 | 48 | return t | ||
1936 | 49 | |||
1937 | 50 | def t_newline(self, t): | ||
1938 | 51 | r'\n+' | ||
1939 | 52 | t.lexer.lineno += t.value.count("\n") | ||
1940 | 53 | return | ||
1941 | 54 | |||
1942 | 55 | def t_error(self, t): | ||
1943 | 56 | raise Exception("Illegal character '%s'" % t.value[0]) | ||
1944 | 57 | t.lexer.skip(1) | ||
1945 | 58 | |||
1946 | 59 | def p_statement_unsubscribe(self, p): | ||
1947 | 60 | '''S : UNSUBSCRIBE USER USERLIST FROM STRING''' | ||
1948 | 61 | self.arguments['list'] = p[5] | ||
1949 | 62 | self.arguments['scope'] = p[2] | ||
1950 | 63 | |||
1951 | 64 | def p_get_users(self, p): | ||
1952 | 65 | '''USERLIST : STRING NEXT''' | ||
1953 | 66 | if 'users' not in self.arguments: | ||
1954 | 67 | self.arguments['users'] = [] | ||
1955 | 68 | self.arguments['users'].append(p[1]) | ||
1956 | 69 | |||
1957 | 70 | def p_next(self, p): | ||
1958 | 71 | '''NEXT : USERLIST | ||
1959 | 72 | |''' | ||
1960 | 73 | pass | ||
1961 | 74 | |||
1962 | 75 | def p_error(self, p): | ||
1963 | 76 | if p: | ||
1964 | 77 | raise Exception("Syntax error at '%s'" % p.value) | ||
1965 | 78 | else: | ||
1966 | 79 | raise Exception("Syntax error : Incomplete Command") | ||
1967 | 80 | |||
1968 | 81 | def parse(self, shell): | ||
1969 | 82 | yacc.parse(shell.line) | ||
1970 | 83 | return self.arguments | ||
1971 | 0 | 84 | ||
1972 | === added file 'src/mailmanclient/cli/client/parsers/update.py' | |||
1973 | --- src/mailmanclient/cli/client/parsers/update.py 1970-01-01 00:00:00 +0000 | |||
1974 | +++ src/mailmanclient/cli/client/parsers/update.py 2015-03-17 19:08:34 +0000 | |||
1975 | @@ -0,0 +1,114 @@ | |||
1976 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
1977 | 2 | # | ||
1978 | 3 | # This file is part of mailman.client. | ||
1979 | 4 | # | ||
1980 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
1981 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
1982 | 7 | # Free Software Foundation, version 3 of the License. | ||
1983 | 8 | # | ||
1984 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
1985 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
1986 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
1987 | 12 | # License for more details. | ||
1988 | 13 | # | ||
1989 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
1990 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
1991 | 16 | # | ||
1992 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
1993 | 18 | # | ||
1994 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
1995 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
1996 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
1997 | 22 | # Barry Warsaw <barry@list.org> | ||
1998 | 23 | |||
1999 | 24 | import ply.yacc as yacc | ||
2000 | 25 | from mailmanclient.cli.client.parsers.base import Parser | ||
2001 | 26 | |||
2002 | 27 | |||
2003 | 28 | class Update(Parser): | ||
2004 | 29 | tokens = ('UPDATE', 'PREFERENCE', 'STRING', 'TO', 'WITH', | ||
2005 | 30 | 'AND', 'FOR', 'GLOBALLY', 'DOMAIN') | ||
2006 | 31 | literals = ['=', '`'] | ||
2007 | 32 | t_ignore = " \t" | ||
2008 | 33 | |||
2009 | 34 | def t_UPDATE(self, t): | ||
2010 | 35 | r'update' | ||
2011 | 36 | return t | ||
2012 | 37 | |||
2013 | 38 | def t_PREFERENCE(self, t): | ||
2014 | 39 | 'preference' | ||
2015 | 40 | return t | ||
2016 | 41 | |||
2017 | 42 | def t_WITH(self, t): | ||
2018 | 43 | 'with' | ||
2019 | 44 | return t | ||
2020 | 45 | |||
2021 | 46 | def t_GLOBALLY(self, t): | ||
2022 | 47 | 'globally' | ||
2023 | 48 | return t | ||
2024 | 49 | |||
2025 | 50 | def t_DOMAIN(self, t): | ||
2026 | 51 | 'user|address|member' | ||
2027 | 52 | return t | ||
2028 | 53 | |||
2029 | 54 | def t_FOR(self, t): | ||
2030 | 55 | 'for' | ||
2031 | 56 | return t | ||
2032 | 57 | |||
2033 | 58 | def t_TO(self, t): | ||
2034 | 59 | 'to' | ||
2035 | 60 | return t | ||
2036 | 61 | |||
2037 | 62 | def t_AND(self, t): | ||
2038 | 63 | 'and' | ||
2039 | 64 | return t | ||
2040 | 65 | |||
2041 | 66 | def t_STRING(self, t): | ||
2042 | 67 | r'`([a-zA-Z0-9_@\.\*\-\$ ]*)`' | ||
2043 | 68 | t.value = t.value.replace('`', '') | ||
2044 | 69 | return t | ||
2045 | 70 | |||
2046 | 71 | def t_newline(self, t): | ||
2047 | 72 | r'\n+' | ||
2048 | 73 | t.lexer.lineno += t.value.count("\n") | ||
2049 | 74 | return | ||
2050 | 75 | |||
2051 | 76 | def t_error(self, t): | ||
2052 | 77 | raise Exception("Illegal character '%s'" % t.value[0]) | ||
2053 | 78 | t.lexer.skip(1) | ||
2054 | 79 | |||
2055 | 80 | def p_statement_update(self, p): | ||
2056 | 81 | '''S : UPDATE PREFERENCE STRING TO STRING E''' | ||
2057 | 82 | self.arguments['key'] = p[3] | ||
2058 | 83 | self.arguments['value'] = p[5] | ||
2059 | 84 | |||
2060 | 85 | def p_domain(self, p): | ||
2061 | 86 | '''E : GLOBALLY | ||
2062 | 87 | | FOR DOMAIN WITH EXP''' | ||
2063 | 88 | try: | ||
2064 | 89 | self.arguments['scope'] = p[2] | ||
2065 | 90 | except IndexError: | ||
2066 | 91 | self.arguments['scope'] = p[1] | ||
2067 | 92 | |||
2068 | 93 | def p_exp_condition(self, p): | ||
2069 | 94 | '''EXP : STRING "=" STRING CONJ''' | ||
2070 | 95 | if 'filters' not in self.arguments: | ||
2071 | 96 | self.arguments['filters'] = {} | ||
2072 | 97 | self.arguments['filters'][p[1]] = p[3] | ||
2073 | 98 | |||
2074 | 99 | def p_conj_exp(self, p): | ||
2075 | 100 | ''' CONJ : AND EXP | ||
2076 | 101 | |''' | ||
2077 | 102 | pass | ||
2078 | 103 | |||
2079 | 104 | def p_error(self, p): | ||
2080 | 105 | if p: | ||
2081 | 106 | raise Exception("Syntax error at '%s'" % p.value) | ||
2082 | 107 | else: | ||
2083 | 108 | raise Exception("Syntax error : Incomplete Command") | ||
2084 | 109 | |||
2085 | 110 | def parse(self, shell): | ||
2086 | 111 | yacc.parse(shell.line) | ||
2087 | 112 | if 'filters' not in self.arguments: | ||
2088 | 113 | self.arguments['filters'] = {} | ||
2089 | 114 | return self.arguments | ||
2090 | 0 | 115 | ||
2091 | === added file 'src/mailmanclient/cli/client/shell.py' | |||
2092 | --- src/mailmanclient/cli/client/shell.py 1970-01-01 00:00:00 +0000 | |||
2093 | +++ src/mailmanclient/cli/client/shell.py 2015-03-17 19:08:34 +0000 | |||
2094 | @@ -0,0 +1,394 @@ | |||
2095 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
2096 | 2 | # | ||
2097 | 3 | # This file is part of mailman.client. | ||
2098 | 4 | # | ||
2099 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
2100 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
2101 | 7 | # Free Software Foundation, version 3 of the License. | ||
2102 | 8 | # | ||
2103 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
2104 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
2105 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
2106 | 12 | # License for more details. | ||
2107 | 13 | # | ||
2108 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
2109 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
2110 | 16 | # | ||
2111 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
2112 | 18 | # | ||
2113 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
2114 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
2115 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
2116 | 22 | # Barry Warsaw <barry@list.org> | ||
2117 | 23 | |||
2118 | 24 | from cmd import Cmd | ||
2119 | 25 | from mailmanclient.cli.core.lists import Lists | ||
2120 | 26 | from mailmanclient.cli.core.domains import Domains | ||
2121 | 27 | from mailmanclient.cli.core.users import Users | ||
2122 | 28 | from mailmanclient.cli.core.preferences import Preferences | ||
2123 | 29 | from mailmanclient.cli.lib.mailman_utils import MailmanUtils | ||
2124 | 30 | from mailmanclient.cli.lib.utils import Filter | ||
2125 | 31 | |||
2126 | 32 | utils = MailmanUtils() | ||
2127 | 33 | |||
2128 | 34 | |||
2129 | 35 | class Shell(Cmd): | ||
2130 | 36 | intro = 'Mailman Command Line Interface' | ||
2131 | 37 | prompt = '>>>' | ||
2132 | 38 | env = {} | ||
2133 | 39 | env_on = True | ||
2134 | 40 | scope_classes = {} | ||
2135 | 41 | scope_listing = {} | ||
2136 | 42 | mmclient = None | ||
2137 | 43 | scopes = ['list', 'user', 'domain'] | ||
2138 | 44 | line = None | ||
2139 | 45 | |||
2140 | 46 | def parseline(self, line): | ||
2141 | 47 | """ This function sets the line attribute with the complete | ||
2142 | 48 | command, which is used at the preprocessing stage""" | ||
2143 | 49 | self.line = line | ||
2144 | 50 | return Cmd.parseline(self, line) | ||
2145 | 51 | |||
2146 | 52 | def onecmd(self, s): | ||
2147 | 53 | """ This method overides the Cmd.onecmd method, but eventully | ||
2148 | 54 | calls the Cmd.onecmd function. The purpose of this function | ||
2149 | 55 | is to catch the errors at a single point, rather than all | ||
2150 | 56 | over the code. | ||
2151 | 57 | """ | ||
2152 | 58 | try: | ||
2153 | 59 | return Cmd.onecmd(self, s) | ||
2154 | 60 | except Exception as e: | ||
2155 | 61 | utils.error(e) | ||
2156 | 62 | command = s.split()[0] | ||
2157 | 63 | self.do_help(command) | ||
2158 | 64 | return False | ||
2159 | 65 | |||
2160 | 66 | def emptyline(self): | ||
2161 | 67 | """ Action on empty line entry. If not overridden, the shell executes last | ||
2162 | 68 | command on encountering an empty line. | ||
2163 | 69 | """ | ||
2164 | 70 | return False | ||
2165 | 71 | |||
2166 | 72 | def initialize(self): | ||
2167 | 73 | """ Method to initialize the shell. Two hash tables are initialised, one | ||
2168 | 74 | for storing the class signatures of the mailman Objects and the | ||
2169 | 75 | other to store the lists of each object. | ||
2170 | 76 | """ | ||
2171 | 77 | try: | ||
2172 | 78 | self.mmclient = utils.connect() | ||
2173 | 79 | self.scope_classes['list'] = Lists | ||
2174 | 80 | self.scope_classes['domain'] = Domains | ||
2175 | 81 | self.scope_classes['user'] = Users | ||
2176 | 82 | self.scope_classes['preference'] = Preferences | ||
2177 | 83 | self.refresh_lists() | ||
2178 | 84 | except Exception as e: | ||
2179 | 85 | utils.error(e) | ||
2180 | 86 | exit(1) | ||
2181 | 87 | |||
2182 | 88 | def refresh_lists(self): | ||
2183 | 89 | """ Refreshes the Mailman object list hash tables. | ||
2184 | 90 | Invoke this method explicitly whenever the list contents might | ||
2185 | 91 | get modified. | ||
2186 | 92 | """ | ||
2187 | 93 | self.scope_listing['list'] = self.mmclient.lists | ||
2188 | 94 | self.scope_listing['domain'] = self.mmclient.domains | ||
2189 | 95 | self.scope_listing['user'] = self.mmclient.users | ||
2190 | 96 | |||
2191 | 97 | def do_EOF(self, args): | ||
2192 | 98 | print() | ||
2193 | 99 | print('Bye!') | ||
2194 | 100 | exit(0) | ||
2195 | 101 | |||
2196 | 102 | def do_set(self, args): | ||
2197 | 103 | """ Sets a variable in the environment | ||
2198 | 104 | Usage: | ||
2199 | 105 | set `<variable>` = `<value>` | ||
2200 | 106 | """ | ||
2201 | 107 | from mailmanclient.cli.client.parsers._set import Set | ||
2202 | 108 | parser = Set() | ||
2203 | 109 | arguments = parser.parse(self) | ||
2204 | 110 | key = arguments['key'] | ||
2205 | 111 | value = utils.add_shell_vars(arguments['value'], self) | ||
2206 | 112 | self.env[key] = value | ||
2207 | 113 | utils.warn('`%s` set to value `%s`' % (key, value)) | ||
2208 | 114 | |||
2209 | 115 | def do_unset(self, args): | ||
2210 | 116 | """ Delete a shell environment variable | ||
2211 | 117 | Usage: | ||
2212 | 118 | unset `<var_name>`""" | ||
2213 | 119 | from mailmanclient.cli.client.parsers.unset import Unset | ||
2214 | 120 | parser = Unset() | ||
2215 | 121 | arguments = parser.parse(self) | ||
2216 | 122 | key = arguments['key'] | ||
2217 | 123 | if key in self.env: | ||
2218 | 124 | del self.env[key] | ||
2219 | 125 | utils.warn('Shell Variable `%s` Deleted' % key) | ||
2220 | 126 | else: | ||
2221 | 127 | raise Exception('Invalid Argument `%s`' % key) | ||
2222 | 128 | |||
2223 | 129 | def do_show_var(self, args): | ||
2224 | 130 | """ Show a shell environment variable | ||
2225 | 131 | Usage: | ||
2226 | 132 | show_var `<var_name>`""" | ||
2227 | 133 | from mailmanclient.cli.client.parsers.show_var import ShowVar | ||
2228 | 134 | parser = ShowVar() | ||
2229 | 135 | arguments = parser.parse(self) | ||
2230 | 136 | key = arguments['key'] | ||
2231 | 137 | if key in self.env: | ||
2232 | 138 | utils.emphasize('Value of %s : %s' % (key, self.env[key])) | ||
2233 | 139 | else: | ||
2234 | 140 | raise Exception('Invalid Argument %s' % key) | ||
2235 | 141 | |||
2236 | 142 | def do_disable(self, args): | ||
2237 | 143 | """ Disable the shell environment | ||
2238 | 144 | Usage: | ||
2239 | 145 | disable env""" | ||
2240 | 146 | from mailmanclient.cli.client.parsers.disable import Disable | ||
2241 | 147 | parser = Disable() | ||
2242 | 148 | parser.parse(self) | ||
2243 | 149 | self.env_on = False | ||
2244 | 150 | utils.emphasize('Environment variables disabled') | ||
2245 | 151 | |||
2246 | 152 | def do_enable(self, args): | ||
2247 | 153 | """ Enable the shell environment | ||
2248 | 154 | Usage: | ||
2249 | 155 | enable env""" | ||
2250 | 156 | from mailmanclient.cli.client.parsers.enable import Enable | ||
2251 | 157 | parser = Enable() | ||
2252 | 158 | parser.parse(self) | ||
2253 | 159 | self.env_on = True | ||
2254 | 160 | utils.emphasize('Environment variables enabled') | ||
2255 | 161 | |||
2256 | 162 | def do_show(self, args): | ||
2257 | 163 | """ Show requested mailman objects as a table | ||
2258 | 164 | Usage: | ||
2259 | 165 | show {domain|user|list} where `<object_attribute>` = `<value>` | ||
2260 | 166 | show {domain|user|list} where `<object_attribute>` like `<regex>` | ||
2261 | 167 | show {domain|user|list} where `<regex>` in `<list_attribute>` | ||
2262 | 168 | show {domain|user|list} where <filter2> and <filter2> ...""" | ||
2263 | 169 | from mailmanclient.cli.client.parsers.show import Show | ||
2264 | 170 | parser = Show() | ||
2265 | 171 | arguments = parser.parse(self) | ||
2266 | 172 | scope = arguments['scope'] | ||
2267 | 173 | filtered_list = self.scope_listing[scope] | ||
2268 | 174 | if 'filters' in arguments: | ||
2269 | 175 | for i in arguments['filters']: | ||
2270 | 176 | key, op, value = i | ||
2271 | 177 | value = utils.add_shell_vars(value, self) | ||
2272 | 178 | data_filter = Filter() | ||
2273 | 179 | filtered_list = data_filter.get_results(key, value, op, filtered_list) | ||
2274 | 180 | if not filtered_list: | ||
2275 | 181 | return False | ||
2276 | 182 | scope_object = self.scope_classes[scope](self.mmclient) | ||
2277 | 183 | cmd_arguments = {} | ||
2278 | 184 | if scope == 'list': | ||
2279 | 185 | cmd_arguments['list'] = None | ||
2280 | 186 | cmd_arguments['csv'] = None | ||
2281 | 187 | cmd_arguments['domain'] = None | ||
2282 | 188 | cmd_arguments['verbose'] = True | ||
2283 | 189 | cmd_arguments['no_header'] = False | ||
2284 | 190 | elif scope == 'domain': | ||
2285 | 191 | cmd_arguments['domain'] = None | ||
2286 | 192 | cmd_arguments['csv'] = None | ||
2287 | 193 | cmd_arguments['verbose'] = True | ||
2288 | 194 | cmd_arguments['no_header'] = False | ||
2289 | 195 | elif scope == 'user': | ||
2290 | 196 | cmd_arguments['user'] = None | ||
2291 | 197 | cmd_arguments['csv'] = None | ||
2292 | 198 | cmd_arguments['list_name'] = None | ||
2293 | 199 | cmd_arguments['verbose'] = True | ||
2294 | 200 | cmd_arguments['no_header'] = False | ||
2295 | 201 | scope_object.show(cmd_arguments, filtered_list) | ||
2296 | 202 | |||
2297 | 203 | def do_create(self, args): | ||
2298 | 204 | """ Creates mailman Objects | ||
2299 | 205 | Usage: | ||
2300 | 206 | create user with `email`=`EMAIL` and `password`=`PASSWD` and `name`=`NAME` | ||
2301 | 207 | create domain with `name`=`DOMAIN` and `contact`=`CONTACT` | ||
2302 | 208 | create list with `fqdn_listname`=`LIST`""" | ||
2303 | 209 | from mailmanclient.cli.client.parsers.create import Create | ||
2304 | 210 | parser = Create() | ||
2305 | 211 | arguments = parser.parse(self) | ||
2306 | 212 | scope = arguments['scope'] | ||
2307 | 213 | properties = arguments['properties'] | ||
2308 | 214 | scope_object = self.scope_classes[scope](self.mmclient) | ||
2309 | 215 | cmd_arguments = {} | ||
2310 | 216 | req_args = [] | ||
2311 | 217 | try: | ||
2312 | 218 | if scope == 'list': | ||
2313 | 219 | req_args = ['fqdn_listname'] | ||
2314 | 220 | cmd_arguments['list'] = utils.add_shell_vars(properties['fqdn_listname'], self) | ||
2315 | 221 | elif scope == 'domain': | ||
2316 | 222 | req_args = ['name', 'contact'] | ||
2317 | 223 | cmd_arguments['domain'] = utils.add_shell_vars(properties['name'], self) | ||
2318 | 224 | cmd_arguments['contact'] = utils.add_shell_vars(properties['contact'], self) | ||
2319 | 225 | elif scope == 'user': | ||
2320 | 226 | req_args = ['email', 'password', 'name'] | ||
2321 | 227 | cmd_arguments['email'] = utils.add_shell_vars(properties['email'], self) | ||
2322 | 228 | cmd_arguments['password'] = utils.add_shell_vars(properties['password'], self) | ||
2323 | 229 | cmd_arguments['name'] = utils.add_shell_vars(properties['name'], self) | ||
2324 | 230 | except KeyError: | ||
2325 | 231 | utils.error('Invalid arguments') | ||
2326 | 232 | utils.warn('The required arguments are:') | ||
2327 | 233 | for i in req_args: | ||
2328 | 234 | utils.warn('\t' + i) | ||
2329 | 235 | return False | ||
2330 | 236 | scope_object.create(cmd_arguments) | ||
2331 | 237 | self.refresh_lists() | ||
2332 | 238 | |||
2333 | 239 | def do_delete(self, args): | ||
2334 | 240 | """ Delete specified mailman objects | ||
2335 | 241 | Usage: | ||
2336 | 242 | delete {domain|user|list} where `<object_attribute>` = `<value>` | ||
2337 | 243 | delete {domain|user|list} where `<object_attribute>` like `<regex>` | ||
2338 | 244 | delete {domain|user|list} where `<key>` in `<list_attribute>` | ||
2339 | 245 | delete {domain|user|list} where <filter1> and <filter2> ...""" | ||
2340 | 246 | from mailmanclient.cli.client.parsers.delete import Delete | ||
2341 | 247 | parser = Delete() | ||
2342 | 248 | arguments = parser.parse(self) | ||
2343 | 249 | scope = arguments['scope'] | ||
2344 | 250 | filtered_list = self.scope_listing[scope] | ||
2345 | 251 | if 'filters' in arguments: | ||
2346 | 252 | for i in arguments['filters']: | ||
2347 | 253 | key, op, value = i | ||
2348 | 254 | value = utils.add_shell_vars(value, self) | ||
2349 | 255 | data_filter = Filter() | ||
2350 | 256 | filtered_list = data_filter.get_results(key, value, op, filtered_list) | ||
2351 | 257 | if 'filters' in arguments and arguments['filters'] == []: | ||
2352 | 258 | utils.confirm('Delete all %ss?[y/n]' % scope) | ||
2353 | 259 | ans = input() | ||
2354 | 260 | if ans == 'n': | ||
2355 | 261 | return False | ||
2356 | 262 | for i in filtered_list: | ||
2357 | 263 | if scope == 'list': | ||
2358 | 264 | utils.warn('Deleted ' + i.fqdn_listname) | ||
2359 | 265 | i.delete() | ||
2360 | 266 | elif scope == 'domain': | ||
2361 | 267 | utils.warn('Deleted ' + i.base_url) | ||
2362 | 268 | self.mmclient.delete_domain(i.mail_host) | ||
2363 | 269 | elif scope == 'user': | ||
2364 | 270 | utils.warn('Deleted ' + i.display_name) | ||
2365 | 271 | i.delete() | ||
2366 | 272 | self.refresh_lists() | ||
2367 | 273 | |||
2368 | 274 | def do_subscribe(self, args): | ||
2369 | 275 | """ Subscribes users to a list | ||
2370 | 276 | Usage: | ||
2371 | 277 | subscribe users `<email1>` `<email2>` ... to `<list fqdn_name>`""" | ||
2372 | 278 | from mailmanclient.cli.client.parsers.subscribe import Subscribe | ||
2373 | 279 | parser = Subscribe() | ||
2374 | 280 | arguments = parser.parse(self) | ||
2375 | 281 | users = arguments['users'] | ||
2376 | 282 | cleaned_list = [] | ||
2377 | 283 | for i in users: | ||
2378 | 284 | cleaned_list.append(utils.add_shell_vars(i, self)) | ||
2379 | 285 | users = cleaned_list | ||
2380 | 286 | list_name = utils.add_shell_vars(arguments['list'], self) | ||
2381 | 287 | user_object = self.scope_classes['user'](self.mmclient) | ||
2382 | 288 | cmd_arguments = {} | ||
2383 | 289 | cmd_arguments['users'] = users | ||
2384 | 290 | cmd_arguments['list_name'] = list_name | ||
2385 | 291 | cmd_arguments['quiet'] = False | ||
2386 | 292 | user_object.subscribe(cmd_arguments) | ||
2387 | 293 | self.refresh_lists() | ||
2388 | 294 | |||
2389 | 295 | def do_unsubscribe(self, args): | ||
2390 | 296 | """ Unsubscribes users from a list | ||
2391 | 297 | Usage: | ||
2392 | 298 | unsubscribe users `<email1>` [`<email2>` ...] from `<list fqdn_name>` | ||
2393 | 299 | """ | ||
2394 | 300 | from mailmanclient.cli.client.parsers.unsubscribe import Unsubscribe | ||
2395 | 301 | parser = Unsubscribe() | ||
2396 | 302 | arguments = parser.parse(self) | ||
2397 | 303 | users = arguments['users'] | ||
2398 | 304 | cleaned_list = [] | ||
2399 | 305 | for i in users: | ||
2400 | 306 | cleaned_list.append(utils.add_shell_vars(i, self)) | ||
2401 | 307 | users = cleaned_list | ||
2402 | 308 | list_name = utils.add_shell_vars(arguments['list'], self) | ||
2403 | 309 | user_object = self.scope_classes['user'](self.mmclient) | ||
2404 | 310 | cmd_arguments = {} | ||
2405 | 311 | cmd_arguments['users'] = users | ||
2406 | 312 | cmd_arguments['list_name'] = list_name | ||
2407 | 313 | cmd_arguments['quiet'] = False | ||
2408 | 314 | user_object.unsubscribe(cmd_arguments) | ||
2409 | 315 | self.refresh_lists() | ||
2410 | 316 | |||
2411 | 317 | def do_update(self, args): | ||
2412 | 318 | """ Command to set preferences | ||
2413 | 319 | Usage: | ||
2414 | 320 | |||
2415 | 321 | update preference `<preference_name>` to `<value>` for member with | ||
2416 | 322 | `email` = `foo@bar.com` | ||
2417 | 323 | and `list` = `list@domain.org` | ||
2418 | 324 | |||
2419 | 325 | update preference `<preference_name>` to `<value>` | ||
2420 | 326 | for user with `email` = `foo@bar.com` | ||
2421 | 327 | |||
2422 | 328 | update preference `<preference_name>` to `<value>` | ||
2423 | 329 | for address with `email` = `foo@bar.com`""" | ||
2424 | 330 | from mailmanclient.cli.client.parsers.update import Update | ||
2425 | 331 | parser = Update() | ||
2426 | 332 | arguments = parser.parse(self) | ||
2427 | 333 | scope = arguments['scope'] | ||
2428 | 334 | preferences = self.scope_classes['preference'](self.mmclient) | ||
2429 | 335 | cmd_arguments = {} | ||
2430 | 336 | cmd_arguments['key'] = arguments['key'] | ||
2431 | 337 | cmd_arguments['value'] = arguments['value'] | ||
2432 | 338 | if scope == 'globally': | ||
2433 | 339 | cmd_arguments['update_scope'] = 'global' | ||
2434 | 340 | else: | ||
2435 | 341 | cmd_arguments['update_scope'] = scope | ||
2436 | 342 | for i in arguments['filters']: | ||
2437 | 343 | cmd_arguments[i] = utils.add_shell_vars(arguments['filters'][i], self) | ||
2438 | 344 | preferences.update(cmd_arguments) | ||
2439 | 345 | |||
2440 | 346 | def _complete(self, text, keys): | ||
2441 | 347 | """ Method for computing the auto suggest suggestions | ||
2442 | 348 | """ | ||
2443 | 349 | if not text: | ||
2444 | 350 | completions = keys | ||
2445 | 351 | else: | ||
2446 | 352 | completions = [k | ||
2447 | 353 | for k in keys | ||
2448 | 354 | if k.startswith(text) | ||
2449 | 355 | ] | ||
2450 | 356 | return completions | ||
2451 | 357 | |||
2452 | 358 | def complete_set(self, text, line, begidx, endidx): | ||
2453 | 359 | keys = self.env.keys() | ||
2454 | 360 | keys.extend(self.scopes) | ||
2455 | 361 | return self._complete(text, keys) | ||
2456 | 362 | |||
2457 | 363 | def complete_unset(self, text, line, begidx, endidx): | ||
2458 | 364 | return self._complete(text, self.env.keys()) | ||
2459 | 365 | |||
2460 | 366 | def complete_show_var(self, text, line, begidx, endidx): | ||
2461 | 367 | return self._complete(text, self.env.keys()) | ||
2462 | 368 | |||
2463 | 369 | def complete_delete(self, text, line, begidx, endidx): | ||
2464 | 370 | return self._complete(text, self.scopes) | ||
2465 | 371 | |||
2466 | 372 | def complete_create(self, text, line, begidx, endidx): | ||
2467 | 373 | return self._complete(text, self.scopes) | ||
2468 | 374 | |||
2469 | 375 | def complete_show(self, text, line, begidx, endidx): | ||
2470 | 376 | return self._complete(text, self.scopes) | ||
2471 | 377 | |||
2472 | 378 | def complete_subscribe(self, text, line, begidx, endidx): | ||
2473 | 379 | return self._complete(text, ['user']) | ||
2474 | 380 | |||
2475 | 381 | def complete_unsubscribe(self, text, line, begidx, endidx): | ||
2476 | 382 | return self._complete(text, ['user']) | ||
2477 | 383 | |||
2478 | 384 | def complete_disable(self, text, line, begidx, endidx): | ||
2479 | 385 | disable_list = ['env'] | ||
2480 | 386 | return self._complete(text, disable_list) | ||
2481 | 387 | |||
2482 | 388 | def complete_enable(self, text, line, begidx, endidx): | ||
2483 | 389 | enable_list = ['env'] | ||
2484 | 390 | return self._complete(text, enable_list) | ||
2485 | 391 | |||
2486 | 392 | def complete_update(self, text, line, begidx, endidx): | ||
2487 | 393 | _list = ['preference'] | ||
2488 | 394 | return self._complete(text, _list) | ||
2489 | 0 | 395 | ||
2490 | === added directory 'src/mailmanclient/cli/core' | |||
2491 | === added file 'src/mailmanclient/cli/core/__init__.py' | |||
2492 | === added file 'src/mailmanclient/cli/core/domains.py' | |||
2493 | --- src/mailmanclient/cli/core/domains.py 1970-01-01 00:00:00 +0000 | |||
2494 | +++ src/mailmanclient/cli/core/domains.py 2015-03-17 19:08:34 +0000 | |||
2495 | @@ -0,0 +1,136 @@ | |||
2496 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
2497 | 2 | # | ||
2498 | 3 | # This file is part of mailman.client. | ||
2499 | 4 | # | ||
2500 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
2501 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
2502 | 7 | # Free Software Foundation, version 3 of the License. | ||
2503 | 8 | # | ||
2504 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
2505 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
2506 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
2507 | 12 | # License for more details. | ||
2508 | 13 | # | ||
2509 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
2510 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
2511 | 16 | # | ||
2512 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
2513 | 18 | # | ||
2514 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
2515 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
2516 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
2517 | 22 | # Barry Warsaw <barry@list.org> | ||
2518 | 23 | |||
2519 | 24 | from tabulate import tabulate | ||
2520 | 25 | from six.moves.urllib_error import HTTPError | ||
2521 | 26 | from mailmanclient.cli.lib.utils import Utils | ||
2522 | 27 | |||
2523 | 28 | |||
2524 | 29 | utils = Utils() | ||
2525 | 30 | |||
2526 | 31 | |||
2527 | 32 | class DomainException(Exception): | ||
2528 | 33 | """ Exception on invalid domain """ | ||
2529 | 34 | pass | ||
2530 | 35 | |||
2531 | 36 | |||
2532 | 37 | class Domains(): | ||
2533 | 38 | """Domain related actions.""" | ||
2534 | 39 | |||
2535 | 40 | def __init__(self, client): | ||
2536 | 41 | self.client = client | ||
2537 | 42 | |||
2538 | 43 | def create(self, args): | ||
2539 | 44 | """Create a domain name with specified domain_name. | ||
2540 | 45 | Optionally, the contact address can also be specified. | ||
2541 | 46 | |||
2542 | 47 | :param args: Commandline arguments | ||
2543 | 48 | :type args: dictionary | ||
2544 | 49 | """ | ||
2545 | 50 | domain_name = args['domain'] | ||
2546 | 51 | contact_address = args['contact'] | ||
2547 | 52 | |||
2548 | 53 | try: | ||
2549 | 54 | self.client.create_domain(domain_name, | ||
2550 | 55 | contact_address=contact_address) | ||
2551 | 56 | except HTTPError as e: | ||
2552 | 57 | code = e.getcode() | ||
2553 | 58 | if code == 400: | ||
2554 | 59 | raise DomainException('Domain already exists') | ||
2555 | 60 | else: | ||
2556 | 61 | raise DomainException('An unknown HTTPError has occured') | ||
2557 | 62 | |||
2558 | 63 | def show(self, args, domains_ext=None): | ||
2559 | 64 | """List the domains in the system. | ||
2560 | 65 | |||
2561 | 66 | :param args: Commandline arguments | ||
2562 | 67 | :type args: dictionary | ||
2563 | 68 | """ | ||
2564 | 69 | if args['domain'] is not None: | ||
2565 | 70 | self.describe(args) | ||
2566 | 71 | return | ||
2567 | 72 | |||
2568 | 73 | headers = [] | ||
2569 | 74 | fields = ['base_url'] | ||
2570 | 75 | domains = [] | ||
2571 | 76 | |||
2572 | 77 | if domains_ext: | ||
2573 | 78 | domains = domains_ext | ||
2574 | 79 | else: | ||
2575 | 80 | domains = self.client.domains | ||
2576 | 81 | |||
2577 | 82 | if not args['no_header'] and args['verbose']: | ||
2578 | 83 | headers = ['Base URL', 'Contact address', | ||
2579 | 84 | 'Mail host', 'URL host'] | ||
2580 | 85 | |||
2581 | 86 | if args['verbose']: | ||
2582 | 87 | fields = ['base_url', 'contact_address', 'mail_host', 'url_host'] | ||
2583 | 88 | |||
2584 | 89 | table = utils.get_listing(domains, fields) | ||
2585 | 90 | |||
2586 | 91 | if args['csv']: | ||
2587 | 92 | utils.write_csv(table, headers, args['csv']) | ||
2588 | 93 | else: | ||
2589 | 94 | print(tabulate(table, headers=headers, tablefmt='plain')) | ||
2590 | 95 | |||
2591 | 96 | def describe(self, args): | ||
2592 | 97 | try: | ||
2593 | 98 | domain = self.client.get_domain(args['domain']) | ||
2594 | 99 | except HTTPError as e: | ||
2595 | 100 | code = e.getcode() | ||
2596 | 101 | if code == 404: | ||
2597 | 102 | raise DomainException('Domain not found') | ||
2598 | 103 | else: | ||
2599 | 104 | raise DomainException('An unknown HTTPError has occured') | ||
2600 | 105 | table = [] | ||
2601 | 106 | table.append(['Base URL', domain.base_url]) | ||
2602 | 107 | table.append(['Contact Address', domain.contact_address]) | ||
2603 | 108 | table.append(['Mail Host', domain.mail_host]) | ||
2604 | 109 | table.append(['URL Host', domain.url_host]) | ||
2605 | 110 | utils.set_table_section_heading(table, 'Description') | ||
2606 | 111 | table.append([domain.description, '']) | ||
2607 | 112 | utils.set_table_section_heading(table, 'Lists') | ||
2608 | 113 | for _list in domain.lists: | ||
2609 | 114 | table.append([_list.list_id, '']) | ||
2610 | 115 | print(tabulate(table, tablefmt='plain')) | ||
2611 | 116 | |||
2612 | 117 | def delete(self, args): | ||
2613 | 118 | try: | ||
2614 | 119 | domain = self.client.get_domain(args['domain']) | ||
2615 | 120 | except HTTPError as e: | ||
2616 | 121 | code = e.getcode() | ||
2617 | 122 | if code == 404: | ||
2618 | 123 | raise DomainException('Domain not found') | ||
2619 | 124 | else: | ||
2620 | 125 | raise DomainException('An unknown HTTPError has occured') | ||
2621 | 126 | if not args['yes']: | ||
2622 | 127 | utils.confirm('Domain `%s` has %d lists.Delete?[y/n]' | ||
2623 | 128 | % (args['domain'], len(domain.lists))) | ||
2624 | 129 | confirm = input() | ||
2625 | 130 | if confirm == 'y': | ||
2626 | 131 | args['yes'] = True | ||
2627 | 132 | elif confirm == 'n': | ||
2628 | 133 | return | ||
2629 | 134 | else: | ||
2630 | 135 | raise Exception('Invalid answer') | ||
2631 | 136 | self.client.delete_domain(args['domain']) | ||
2632 | 0 | 137 | ||
2633 | === added file 'src/mailmanclient/cli/core/lists.py' | |||
2634 | --- src/mailmanclient/cli/core/lists.py 1970-01-01 00:00:00 +0000 | |||
2635 | +++ src/mailmanclient/cli/core/lists.py 2015-03-17 19:08:34 +0000 | |||
2636 | @@ -0,0 +1,227 @@ | |||
2637 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
2638 | 2 | # | ||
2639 | 3 | # This file is part of mailman.client. | ||
2640 | 4 | # | ||
2641 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
2642 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
2643 | 7 | # Free Software Foundation, version 3 of the License. | ||
2644 | 8 | # | ||
2645 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
2646 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
2647 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
2648 | 12 | # License for more details. | ||
2649 | 13 | # | ||
2650 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
2651 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
2652 | 16 | # | ||
2653 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
2654 | 18 | # | ||
2655 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
2656 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
2657 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
2658 | 22 | # Barry Warsaw <barry@list.org> | ||
2659 | 23 | |||
2660 | 24 | from tabulate import tabulate | ||
2661 | 25 | from six.moves.urllib_error import HTTPError | ||
2662 | 26 | from mailmanclient.cli.lib.utils import Utils | ||
2663 | 27 | from mailmanclient.cli.core.domains import DomainException | ||
2664 | 28 | |||
2665 | 29 | |||
2666 | 30 | utils = Utils() | ||
2667 | 31 | |||
2668 | 32 | |||
2669 | 33 | class ListException(Exception): | ||
2670 | 34 | """ List Exceptions """ | ||
2671 | 35 | pass | ||
2672 | 36 | |||
2673 | 37 | |||
2674 | 38 | class Lists(): | ||
2675 | 39 | |||
2676 | 40 | """Mailing list related actions.""" | ||
2677 | 41 | |||
2678 | 42 | def __init__(self, client): | ||
2679 | 43 | self. client = client | ||
2680 | 44 | |||
2681 | 45 | def create(self, args): | ||
2682 | 46 | """Create a mailing list with specified list_name | ||
2683 | 47 | in the domain specified by domain_name. | ||
2684 | 48 | |||
2685 | 49 | :param args: Commandline arguments | ||
2686 | 50 | :type args: dictionary | ||
2687 | 51 | """ | ||
2688 | 52 | name = args['list'].split('@') | ||
2689 | 53 | |||
2690 | 54 | try: | ||
2691 | 55 | list_name = name[0] | ||
2692 | 56 | domain_name = name[1] | ||
2693 | 57 | except IndexError: | ||
2694 | 58 | raise ListException('Invalid FQDN list name') | ||
2695 | 59 | |||
2696 | 60 | if list_name.strip() == '' or domain_name.strip() == '': | ||
2697 | 61 | raise ListException('Invalid FQDN list name') | ||
2698 | 62 | |||
2699 | 63 | domain = self.get_domain(domain_name) | ||
2700 | 64 | |||
2701 | 65 | try: | ||
2702 | 66 | domain.create_list(list_name) | ||
2703 | 67 | except HTTPError as e: | ||
2704 | 68 | code = e.getcode() | ||
2705 | 69 | if code == 400: | ||
2706 | 70 | raise ListException('List already exists') | ||
2707 | 71 | else: | ||
2708 | 72 | raise Exception('An unknown HTTPError has occoured') | ||
2709 | 73 | |||
2710 | 74 | def show(self, args, lists_ext=None): | ||
2711 | 75 | """List the mailing lists in the system or under a domain. | ||
2712 | 76 | |||
2713 | 77 | :param args: Commandline arguments | ||
2714 | 78 | :type args: dictionary | ||
2715 | 79 | """ | ||
2716 | 80 | if args['list'] is not None: | ||
2717 | 81 | self.describe(args) | ||
2718 | 82 | return | ||
2719 | 83 | |||
2720 | 84 | lists = [] | ||
2721 | 85 | fields = ['list_id'] | ||
2722 | 86 | headers = [] | ||
2723 | 87 | |||
2724 | 88 | if args['domain']: | ||
2725 | 89 | domain = self.get_domain(args['domain']) | ||
2726 | 90 | lists = domain.lists | ||
2727 | 91 | elif lists_ext: | ||
2728 | 92 | lists = lists_ext | ||
2729 | 93 | else: | ||
2730 | 94 | lists = self.client.lists | ||
2731 | 95 | |||
2732 | 96 | if args['verbose']: | ||
2733 | 97 | fields = ['list_id', 'list_name', | ||
2734 | 98 | 'mail_host', 'display_name', | ||
2735 | 99 | 'fqdn_listname'] | ||
2736 | 100 | |||
2737 | 101 | if not args['no_header'] and args['verbose']: | ||
2738 | 102 | headers = ['ID', 'Name', 'Mail host', 'Display Name', 'FQDN'] | ||
2739 | 103 | |||
2740 | 104 | table = utils.get_listing(lists, fields) | ||
2741 | 105 | |||
2742 | 106 | if args['csv']: | ||
2743 | 107 | utils.write_csv(table, headers, args['csv']) | ||
2744 | 108 | else: | ||
2745 | 109 | print(tabulate(table, headers=headers, tablefmt='plain')) | ||
2746 | 110 | |||
2747 | 111 | def describe(self, args): | ||
2748 | 112 | _list = self.get_list(args['list']) | ||
2749 | 113 | table = [] | ||
2750 | 114 | table.append(['List ID', _list.list_id]) | ||
2751 | 115 | table.append(['List name', _list.list_name]) | ||
2752 | 116 | table.append(['Mail host', _list.mail_host]) | ||
2753 | 117 | utils.set_table_section_heading(table, 'List Settings') | ||
2754 | 118 | for i in _list.settings: | ||
2755 | 119 | table.append([i, str(_list.settings[i])]) | ||
2756 | 120 | utils.set_table_section_heading(table, 'Owners') | ||
2757 | 121 | for owner in _list.owners: | ||
2758 | 122 | table.append([owner, '']) | ||
2759 | 123 | utils.set_table_section_heading(table, 'Moderators') | ||
2760 | 124 | for moderator in _list.moderators: | ||
2761 | 125 | table.append([moderator, '']) | ||
2762 | 126 | utils.set_table_section_heading(table, 'Members') | ||
2763 | 127 | for member in _list.members: | ||
2764 | 128 | email = member.address.split('/')[-1] | ||
2765 | 129 | table.append([email, '']) | ||
2766 | 130 | print(tabulate(table, tablefmt='plain')) | ||
2767 | 131 | |||
2768 | 132 | def add_moderator(self, args): | ||
2769 | 133 | _list = self.get_list(args['list']) | ||
2770 | 134 | users = args['users'] | ||
2771 | 135 | quiet = args['quiet'] | ||
2772 | 136 | for user in users: | ||
2773 | 137 | try: | ||
2774 | 138 | _list.add_moderator(user) | ||
2775 | 139 | if not quiet: | ||
2776 | 140 | utils.warn('Added %s as moderator' % (user)) | ||
2777 | 141 | except Exception as e: | ||
2778 | 142 | if not quiet: | ||
2779 | 143 | utils.error('Failed to add %s : %s ' % | ||
2780 | 144 | (user, e)) | ||
2781 | 145 | |||
2782 | 146 | def add_owner(self, args): | ||
2783 | 147 | _list = self.get_list(args['list']) | ||
2784 | 148 | users = args['users'] | ||
2785 | 149 | quiet = args['quiet'] | ||
2786 | 150 | for user in users: | ||
2787 | 151 | try: | ||
2788 | 152 | _list.add_owner(user) | ||
2789 | 153 | if not quiet: | ||
2790 | 154 | utils.warn('Added %s as owner' % (user)) | ||
2791 | 155 | except Exception as e: | ||
2792 | 156 | if not quiet: | ||
2793 | 157 | utils.error('Failed to add %s : %s ' % | ||
2794 | 158 | (user, e)) | ||
2795 | 159 | |||
2796 | 160 | def remove_moderator(self, args): | ||
2797 | 161 | _list = self.get_list(args['list']) | ||
2798 | 162 | users = args['users'] | ||
2799 | 163 | quiet = args['quiet'] | ||
2800 | 164 | for user in users: | ||
2801 | 165 | try: | ||
2802 | 166 | _list.remove_moderator(user) | ||
2803 | 167 | if not quiet: | ||
2804 | 168 | utils.warn('Removed %s as moderator' % (user)) | ||
2805 | 169 | except Exception as e: | ||
2806 | 170 | if not quiet: | ||
2807 | 171 | utils.error('Failed to remove %s : %s ' % | ||
2808 | 172 | (user, e)) | ||
2809 | 173 | |||
2810 | 174 | def remove_owner(self, args): | ||
2811 | 175 | _list = self.get_list(args['list']) | ||
2812 | 176 | users = args['users'] | ||
2813 | 177 | quiet = args['quiet'] | ||
2814 | 178 | for user in users: | ||
2815 | 179 | try: | ||
2816 | 180 | _list.remove_owner(user) | ||
2817 | 181 | if not quiet: | ||
2818 | 182 | utils.warn('Removed %s as owner' % (user)) | ||
2819 | 183 | except Exception as e: | ||
2820 | 184 | if not quiet: | ||
2821 | 185 | utils.error('Failed to remove %s : %s ' % | ||
2822 | 186 | (user, e)) | ||
2823 | 187 | |||
2824 | 188 | def show_members(self, args): | ||
2825 | 189 | from core.users import Users | ||
2826 | 190 | users = Users(self.client) | ||
2827 | 191 | args['list_name'] = args['list'] | ||
2828 | 192 | args['user'] = None | ||
2829 | 193 | users.show(args) | ||
2830 | 194 | |||
2831 | 195 | def delete(self, args): | ||
2832 | 196 | _list = self.get_list(args['list']) | ||
2833 | 197 | if not args['yes']: | ||
2834 | 198 | utils.confirm('List %s has %d members.Delete?[y/n]' | ||
2835 | 199 | % (args['list'], len(_list.members))) | ||
2836 | 200 | confirm = input() | ||
2837 | 201 | if confirm == 'y': | ||
2838 | 202 | args['yes'] = True | ||
2839 | 203 | elif confirm == 'n': | ||
2840 | 204 | return | ||
2841 | 205 | else: | ||
2842 | 206 | raise Exception('Invalid Answer') | ||
2843 | 207 | _list.delete() | ||
2844 | 208 | |||
2845 | 209 | def get_list(self, listname): | ||
2846 | 210 | try: | ||
2847 | 211 | return self.client.get_list(listname) | ||
2848 | 212 | except HTTPError as e: | ||
2849 | 213 | code = e.getcode() | ||
2850 | 214 | if code == 404: | ||
2851 | 215 | raise ListException('List not found') | ||
2852 | 216 | else: | ||
2853 | 217 | raise Exception('An unknown HTTPError has occoured') | ||
2854 | 218 | |||
2855 | 219 | def get_domain(self, domainname): | ||
2856 | 220 | try: | ||
2857 | 221 | return self.client.get_domain(domainname) | ||
2858 | 222 | except HTTPError as e: | ||
2859 | 223 | code = e.getcode() | ||
2860 | 224 | if code == 404: | ||
2861 | 225 | raise DomainException('Domain not found') | ||
2862 | 226 | else: | ||
2863 | 227 | raise Exception('An unknown HTTPError has occoured') | ||
2864 | 0 | 228 | ||
2865 | === added file 'src/mailmanclient/cli/core/misc.py' | |||
2866 | --- src/mailmanclient/cli/core/misc.py 1970-01-01 00:00:00 +0000 | |||
2867 | +++ src/mailmanclient/cli/core/misc.py 2015-03-17 19:08:34 +0000 | |||
2868 | @@ -0,0 +1,69 @@ | |||
2869 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
2870 | 2 | # | ||
2871 | 3 | # This file is part of mailman.client. | ||
2872 | 4 | # | ||
2873 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
2874 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
2875 | 7 | # Free Software Foundation, version 3 of the License. | ||
2876 | 8 | # | ||
2877 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
2878 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
2879 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
2880 | 12 | # License for more details. | ||
2881 | 13 | # | ||
2882 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
2883 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
2884 | 16 | # | ||
2885 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
2886 | 18 | # | ||
2887 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
2888 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
2889 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
2890 | 22 | # Barry Warsaw <barry@list.org> | ||
2891 | 23 | |||
2892 | 24 | import os | ||
2893 | 25 | import zipfile | ||
2894 | 26 | from mailman.config import config | ||
2895 | 27 | from mailmanclient.cli.lib.utils import Utils | ||
2896 | 28 | |||
2897 | 29 | |||
2898 | 30 | utils = Utils() | ||
2899 | 31 | |||
2900 | 32 | |||
2901 | 33 | class MiscException(Exception): | ||
2902 | 34 | """ Exceptions for miscellaneous actions """ | ||
2903 | 35 | pass | ||
2904 | 36 | |||
2905 | 37 | |||
2906 | 38 | class Misc(): | ||
2907 | 39 | """ Miscellaneous actions """ | ||
2908 | 40 | |||
2909 | 41 | def backup(self, args): | ||
2910 | 42 | config.load() | ||
2911 | 43 | vardir = config.paths['VAR_DIR'] | ||
2912 | 44 | output = args['output'] | ||
2913 | 45 | if not output.endswith('.zip'): | ||
2914 | 46 | output += '.zip' | ||
2915 | 47 | relroot = os.path.abspath(os.path.join(vardir, os.pardir)) | ||
2916 | 48 | with zipfile.ZipFile(output, "w", zipfile.ZIP_DEFLATED) as z: | ||
2917 | 49 | for root, dirs, files in os.walk(vardir): | ||
2918 | 50 | z.write(root, os.path.relpath(root, relroot)) | ||
2919 | 51 | for f in files: | ||
2920 | 52 | filename = os.path.join(root, f) | ||
2921 | 53 | if os.path.isfile(filename): | ||
2922 | 54 | arcname = os.path.join(os.path.relpath(root, relroot), | ||
2923 | 55 | f) | ||
2924 | 56 | z.write(filename, arcname) | ||
2925 | 57 | |||
2926 | 58 | def restore(self, args): | ||
2927 | 59 | config.load() | ||
2928 | 60 | vardir = config.paths['VAR_DIR'] | ||
2929 | 61 | backup = args['backup'] | ||
2930 | 62 | if os.path.exists(vardir): | ||
2931 | 63 | utils.confirm('The existing var_dir will be replaced.Continue?[y/n]') | ||
2932 | 64 | confirm = input() | ||
2933 | 65 | if not confirm == 'y': | ||
2934 | 66 | return | ||
2935 | 67 | vardir += '/../' | ||
2936 | 68 | with zipfile.ZipFile(backup) as zf: | ||
2937 | 69 | zf.extractall(vardir) | ||
2938 | 0 | 70 | ||
2939 | === added file 'src/mailmanclient/cli/core/preferences.py' | |||
2940 | --- src/mailmanclient/cli/core/preferences.py 1970-01-01 00:00:00 +0000 | |||
2941 | +++ src/mailmanclient/cli/core/preferences.py 2015-03-17 19:08:34 +0000 | |||
2942 | @@ -0,0 +1,96 @@ | |||
2943 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
2944 | 2 | # | ||
2945 | 3 | # This file is part of mailman.client. | ||
2946 | 4 | # | ||
2947 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
2948 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
2949 | 7 | # Free Software Foundation, version 3 of the License. | ||
2950 | 8 | # | ||
2951 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
2952 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
2953 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
2954 | 12 | # License for more details. | ||
2955 | 13 | # | ||
2956 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
2957 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
2958 | 16 | # | ||
2959 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
2960 | 18 | # | ||
2961 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
2962 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
2963 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
2964 | 22 | # Barry Warsaw <barry@list.org> | ||
2965 | 23 | |||
2966 | 24 | from mailmanclient.cli.lib.utils import Utils | ||
2967 | 25 | |||
2968 | 26 | |||
2969 | 27 | utils = Utils() | ||
2970 | 28 | |||
2971 | 29 | |||
2972 | 30 | class PreferenceException(Exception): | ||
2973 | 31 | pass | ||
2974 | 32 | |||
2975 | 33 | |||
2976 | 34 | class Preferences(): | ||
2977 | 35 | """Preferences related actions.""" | ||
2978 | 36 | |||
2979 | 37 | def __init__(self, client): | ||
2980 | 38 | self.client = client | ||
2981 | 39 | |||
2982 | 40 | def get_scope_object(self, scope, args): | ||
2983 | 41 | scope_object = None | ||
2984 | 42 | try: | ||
2985 | 43 | if scope == 'global': | ||
2986 | 44 | scope_object = self.client | ||
2987 | 45 | elif scope == 'user': | ||
2988 | 46 | scope_object = self.client.get_user(args['email']) | ||
2989 | 47 | elif scope == 'member': | ||
2990 | 48 | scope_object = self.client.get_member(args['list'], | ||
2991 | 49 | args['email']) | ||
2992 | 50 | else: | ||
2993 | 51 | scope_object = self.client.get_address(args['email']) | ||
2994 | 52 | except: | ||
2995 | 53 | raise PreferenceException('%s not found' % scope.capitalize()) | ||
2996 | 54 | return scope_object | ||
2997 | 55 | |||
2998 | 56 | def update(self, args): | ||
2999 | 57 | """Update a preference specified by the `key` to `value` | ||
3000 | 58 | Preferences can be set at a global, user, address or at | ||
3001 | 59 | a member level. | ||
3002 | 60 | """ | ||
3003 | 61 | scope = args['update_scope'] | ||
3004 | 62 | if scope == 'global': | ||
3005 | 63 | raise PreferenceException('Global preferences are readonly') | ||
3006 | 64 | scope_object = self.get_scope_object(scope, args) | ||
3007 | 65 | preferences = None | ||
3008 | 66 | key = args['key'] | ||
3009 | 67 | value = args['value'] | ||
3010 | 68 | preferences = scope_object.preferences | ||
3011 | 69 | try: | ||
3012 | 70 | preferences[key] | ||
3013 | 71 | except Exception: | ||
3014 | 72 | raise PreferenceException('Saving Preference Failed') | ||
3015 | 73 | if type(preferences[key]).__name__ in ('bool', 'NoneType'): | ||
3016 | 74 | value = value.lower().strip() | ||
3017 | 75 | if value == 'true': | ||
3018 | 76 | value = True | ||
3019 | 77 | elif value == 'false': | ||
3020 | 78 | value = False | ||
3021 | 79 | else: | ||
3022 | 80 | raise PreferenceException('Invalid value for preference.' | ||
3023 | 81 | 'Expected values : True/False') | ||
3024 | 82 | try: | ||
3025 | 83 | preferences[key] = value | ||
3026 | 84 | preferences.save() | ||
3027 | 85 | except Exception: | ||
3028 | 86 | raise PreferenceException('Saving Preference Failed') | ||
3029 | 87 | |||
3030 | 88 | def show(self, args): | ||
3031 | 89 | """Given a preference key, and a specific object, print | ||
3032 | 90 | the current value of the preference for that object.""" | ||
3033 | 91 | scope = args['show_scope'] | ||
3034 | 92 | scope_object = self.get_scope_object(scope, args) | ||
3035 | 93 | preferences = None | ||
3036 | 94 | key = args['key'] | ||
3037 | 95 | preferences = scope_object.preferences | ||
3038 | 96 | print(str(preferences[key])) | ||
3039 | 0 | 97 | ||
3040 | === added file 'src/mailmanclient/cli/core/users.py' | |||
3041 | --- src/mailmanclient/cli/core/users.py 1970-01-01 00:00:00 +0000 | |||
3042 | +++ src/mailmanclient/cli/core/users.py 2015-03-17 19:08:34 +0000 | |||
3043 | @@ -0,0 +1,189 @@ | |||
3044 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
3045 | 2 | # | ||
3046 | 3 | # This file is part of mailman.client. | ||
3047 | 4 | # | ||
3048 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
3049 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
3050 | 7 | # Free Software Foundation, version 3 of the License. | ||
3051 | 8 | # | ||
3052 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
3053 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
3054 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
3055 | 12 | # License for more details. | ||
3056 | 13 | # | ||
3057 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
3058 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
3059 | 16 | # | ||
3060 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
3061 | 18 | # | ||
3062 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
3063 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
3064 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
3065 | 22 | # Barry Warsaw <barry@list.org> | ||
3066 | 23 | |||
3067 | 24 | from tabulate import tabulate | ||
3068 | 25 | from six.moves.urllib_error import HTTPError | ||
3069 | 26 | from mailmanclient.cli.lib.utils import Utils | ||
3070 | 27 | from mailmanclient.cli.core.lists import ListException | ||
3071 | 28 | |||
3072 | 29 | utils = Utils() | ||
3073 | 30 | |||
3074 | 31 | |||
3075 | 32 | class UserException(Exception): | ||
3076 | 33 | """ User Exceptions """ | ||
3077 | 34 | pass | ||
3078 | 35 | |||
3079 | 36 | |||
3080 | 37 | class Users(): | ||
3081 | 38 | |||
3082 | 39 | """User related actions.""" | ||
3083 | 40 | |||
3084 | 41 | def __init__(self, client): | ||
3085 | 42 | self.client = client | ||
3086 | 43 | |||
3087 | 44 | def create(self, args): | ||
3088 | 45 | """Create a user with specified email,password and display name. | ||
3089 | 46 | |||
3090 | 47 | :param args: Commandline arguments | ||
3091 | 48 | :type args: dictionary | ||
3092 | 49 | """ | ||
3093 | 50 | email = args['email'] | ||
3094 | 51 | password = args['password'] | ||
3095 | 52 | display_name = args['name'] | ||
3096 | 53 | |||
3097 | 54 | try: | ||
3098 | 55 | self.client.create_user(email=email, | ||
3099 | 56 | password=password, | ||
3100 | 57 | display_name=display_name) | ||
3101 | 58 | except HTTPError as e: | ||
3102 | 59 | code = e.getcode() | ||
3103 | 60 | if code == 400: | ||
3104 | 61 | raise UserException('User already exists') | ||
3105 | 62 | else: | ||
3106 | 63 | raise UserException('An unknown HTTPError has occured') | ||
3107 | 64 | |||
3108 | 65 | def show(self, args, users_ext=None): | ||
3109 | 66 | """List users in the system. | ||
3110 | 67 | |||
3111 | 68 | |||
3112 | 69 | :param args: Commandline arguments | ||
3113 | 70 | :type args: dictionary | ||
3114 | 71 | """ | ||
3115 | 72 | if args['user'] is not None: | ||
3116 | 73 | self.describe(args) | ||
3117 | 74 | return | ||
3118 | 75 | |||
3119 | 76 | headers = [] | ||
3120 | 77 | fields = ['addresses'] | ||
3121 | 78 | users = [] | ||
3122 | 79 | |||
3123 | 80 | if args['verbose']: | ||
3124 | 81 | fields = ['display_name', 'addresses', 'created_on', 'user_id'] | ||
3125 | 82 | |||
3126 | 83 | if not args['no_header'] and args['verbose']: | ||
3127 | 84 | headers = ['Display Name', 'Address', 'Created on', 'User ID'] | ||
3128 | 85 | |||
3129 | 86 | if args['list_name']: | ||
3130 | 87 | users = self.get_users(args['list_name']) | ||
3131 | 88 | elif users_ext: | ||
3132 | 89 | users = users_ext | ||
3133 | 90 | else: | ||
3134 | 91 | users = self.client.users | ||
3135 | 92 | |||
3136 | 93 | table = utils.get_listing(users, fields) | ||
3137 | 94 | |||
3138 | 95 | if args['csv']: | ||
3139 | 96 | utils.write_csv(table, headers, args['csv']) | ||
3140 | 97 | else: | ||
3141 | 98 | print(tabulate(table, headers=headers, tablefmt='plain')) | ||
3142 | 99 | |||
3143 | 100 | def get_users(self, listname): | ||
3144 | 101 | users = [] | ||
3145 | 102 | _list = self.client.get_list(listname) | ||
3146 | 103 | for member in _list.members: | ||
3147 | 104 | users.append(member.user) | ||
3148 | 105 | return users | ||
3149 | 106 | |||
3150 | 107 | def describe(self, args): | ||
3151 | 108 | ''' Describes a user object ''' | ||
3152 | 109 | user = self.get_user(args['user']) | ||
3153 | 110 | table = [] | ||
3154 | 111 | table.append(['User ID', user.user_id]) | ||
3155 | 112 | table.append(['Display Name', user.display_name]) | ||
3156 | 113 | table.append(['Created on', user.created_on]) | ||
3157 | 114 | table.append(['Self Link', user.self_link]) | ||
3158 | 115 | utils.set_table_section_heading(table, 'User Preferences') | ||
3159 | 116 | preferences = user.preferences._preferences | ||
3160 | 117 | for i in preferences: | ||
3161 | 118 | table.append([i, str(preferences[i])]) | ||
3162 | 119 | utils.set_table_section_heading(table, 'Subscription List IDs') | ||
3163 | 120 | for _list in user.subscription_list_ids: | ||
3164 | 121 | table.append([_list, '']) | ||
3165 | 122 | utils.set_table_section_heading(table, 'Subscriptions') | ||
3166 | 123 | for subscription in user.subscriptions: | ||
3167 | 124 | email = subscription.address.split('/')[-1] | ||
3168 | 125 | table.append([email+' at '+str(subscription.list_id), | ||
3169 | 126 | str(subscription.role)]) | ||
3170 | 127 | print(tabulate(table, tablefmt='plain')) | ||
3171 | 128 | |||
3172 | 129 | def delete(self, args): | ||
3173 | 130 | ''' Deletes a User object ''' | ||
3174 | 131 | user = self.client.get_user(args['user']) | ||
3175 | 132 | if not args['yes']: | ||
3176 | 133 | utils.confirm('Delete user %s?[y/n]' % args['user']) | ||
3177 | 134 | confirm = input() | ||
3178 | 135 | if confirm == 'y': | ||
3179 | 136 | args['yes'] = True | ||
3180 | 137 | elif confirm == 'n': | ||
3181 | 138 | return | ||
3182 | 139 | else: | ||
3183 | 140 | raise Exception('Invalid answer') | ||
3184 | 141 | user.delete() | ||
3185 | 142 | |||
3186 | 143 | def subscribe(self, args): | ||
3187 | 144 | ''' Subsribes a user or a list of users to a list ''' | ||
3188 | 145 | list_name = args['list_name'] | ||
3189 | 146 | emails = args['users'] | ||
3190 | 147 | _list = self.client.get_list(list_name) | ||
3191 | 148 | for i in emails: | ||
3192 | 149 | try: | ||
3193 | 150 | _list.subscribe(i) | ||
3194 | 151 | if not args['quiet']: | ||
3195 | 152 | utils.warn('%s subscribed to %s' % (i, list_name)) | ||
3196 | 153 | except Exception as e: | ||
3197 | 154 | if not args['quiet']: | ||
3198 | 155 | utils.error('Failed to subscribe %s : %s' % (i, e)) | ||
3199 | 156 | |||
3200 | 157 | def unsubscribe(self, args): | ||
3201 | 158 | ''' Unsubsribes a user or a list of users from a list ''' | ||
3202 | 159 | list_name = args['list_name'] | ||
3203 | 160 | emails = args['users'] | ||
3204 | 161 | _list = self.client.get_list(list_name) | ||
3205 | 162 | for i in emails: | ||
3206 | 163 | try: | ||
3207 | 164 | _list.unsubscribe(i) | ||
3208 | 165 | if not args['quiet']: | ||
3209 | 166 | utils.warn('%s unsubscribed from %s' % (i, list_name)) | ||
3210 | 167 | except Exception as e: | ||
3211 | 168 | if not args['quiet']: | ||
3212 | 169 | utils.error('Failed to unsubscribe %s : %s' % (i, e)) | ||
3213 | 170 | |||
3214 | 171 | def get_list(self, listname): | ||
3215 | 172 | try: | ||
3216 | 173 | return self.client.get_list(listname) | ||
3217 | 174 | except HTTPError as e: | ||
3218 | 175 | code = e.getcode() | ||
3219 | 176 | if code == 404: | ||
3220 | 177 | raise ListException('List not found') | ||
3221 | 178 | else: | ||
3222 | 179 | raise ListException('An unknown HTTPError has occured') | ||
3223 | 180 | |||
3224 | 181 | def get_user(self, username): | ||
3225 | 182 | try: | ||
3226 | 183 | return self.client.get_user(username) | ||
3227 | 184 | except HTTPError as e: | ||
3228 | 185 | code = e.getcode() | ||
3229 | 186 | if code == 404: | ||
3230 | 187 | raise UserException('User not found') | ||
3231 | 188 | else: | ||
3232 | 189 | raise UserException('An unknown HTTPError has occured') | ||
3233 | 0 | 190 | ||
3234 | === added directory 'src/mailmanclient/cli/docs' | |||
3235 | === added file 'src/mailmanclient/cli/docs/using_cli_shell.txt' | |||
3236 | --- src/mailmanclient/cli/docs/using_cli_shell.txt 1970-01-01 00:00:00 +0000 | |||
3237 | +++ src/mailmanclient/cli/docs/using_cli_shell.txt 2015-03-17 19:08:34 +0000 | |||
3238 | @@ -0,0 +1,150 @@ | |||
3239 | 1 | The Mailman Command Line Shell | ||
3240 | 2 | ****************************** | ||
3241 | 3 | |||
3242 | 4 | This document describes the usage of the Mailman Command line | ||
3243 | 5 | shell, using which you can query a mailman installation with ease. | ||
3244 | 6 | |||
3245 | 7 | Firing and Exiting the Shell | ||
3246 | 8 | ============================ | ||
3247 | 9 | |||
3248 | 10 | You can start the mailman shell by executing the mmclient command, | ||
3249 | 11 | without any arguments:: | ||
3250 | 12 | |||
3251 | 13 | $ ./mmclient | ||
3252 | 14 | Mailman Command Line Interface | ||
3253 | 15 | >>> | ||
3254 | 16 | |||
3255 | 17 | To exit the shell, use the ``EOF`` character, that is, ``Ctrl + d``. | ||
3256 | 18 | |||
3257 | 19 | Displaying Mailman Objects | ||
3258 | 20 | ========================== | ||
3259 | 21 | |||
3260 | 22 | The shell can be used to display the mailman objects, using the show | ||
3261 | 23 | command. | ||
3262 | 24 | |||
3263 | 25 | For example:: | ||
3264 | 26 | |||
3265 | 27 | >>> show users | ||
3266 | 28 | >>> show domains | ||
3267 | 29 | >>> show lists | ||
3268 | 30 | |||
3269 | 31 | Further, the CLI supports filtering of mailman objects based upon their | ||
3270 | 32 | attribute values or properties, using a `where` clause. For this, the CLI | ||
3271 | 33 | employs 3 filters, which are:: | ||
3272 | 34 | |||
3273 | 35 | = Equality | ||
3274 | 36 | like Case insensitive regular exp mathcing | ||
3275 | 37 | in Search inside a property which list | ||
3276 | 38 | |||
3277 | 39 | These filteres can be used in conjunction by using an ``and`` clause | ||
3278 | 40 | |||
3279 | 41 | Examples: :: | ||
3280 | 42 | |||
3281 | 43 | >>> show users where `display_name` = `Foo` | ||
3282 | 44 | >>> show users where `display_name` like `.*Foo*` | ||
3283 | 45 | >>> show lists where `foo@bar.com` in `moderators` | ||
3284 | 46 | >>> show lists where `foo@bar.com` in `moderators` and `a@b.com` in `owners` | ||
3285 | 47 | |||
3286 | 48 | The Shell Environment | ||
3287 | 49 | ====================== | ||
3288 | 50 | |||
3289 | 51 | The shell provides a facility to create variables that can be used to | ||
3290 | 52 | make the querying easier. | ||
3291 | 53 | |||
3292 | 54 | For using the shell, two commands, ``set`` and ``unset`` are used. | ||
3293 | 55 | |||
3294 | 56 | Example:: | ||
3295 | 57 | |||
3296 | 58 | >>> set `useremail` = `foo@bar.com` | ||
3297 | 59 | |||
3298 | 60 | The variables can be used in the queries as follows:: | ||
3299 | 61 | |||
3300 | 62 | >>> show lists where `$useremail` in `moderators` | ||
3301 | 63 | |||
3302 | 64 | The ``$username`` will be replaced with the value of ``useremail`` | ||
3303 | 65 | |||
3304 | 66 | The environment can be disabled using the `disable environemt` | ||
3305 | 67 | command, that prevents the CLI from replacing the query terms | ||
3306 | 68 | with environment variables, or appending of the specialised | ||
3307 | 69 | variables. | ||
3308 | 70 | |||
3309 | 71 | The disabled environment can be enabled using the `enable env` | ||
3310 | 72 | command.:: | ||
3311 | 73 | |||
3312 | 74 | >>> disable env | ||
3313 | 75 | >>> enable env | ||
3314 | 76 | |||
3315 | 77 | The environment supports a set of special variables, which denote | ||
3316 | 78 | the names of the scopes available in mailman. They are domain, list and | ||
3317 | 79 | user. | ||
3318 | 80 | |||
3319 | 81 | The special environment variables are appended automatically with relevant commands | ||
3320 | 82 | |||
3321 | 83 | For example, if the environment variable domain is set to a domain name, then the | ||
3322 | 84 | `show list ` command automatically applies a domain = <set domain> filter to | ||
3323 | 85 | the result list.:: | ||
3324 | 86 | |||
3325 | 87 | >>> set `domain` = `domain.org` | ||
3326 | 88 | >>> show lists //Shows lists under domain.org | ||
3327 | 89 | >>> disable env | ||
3328 | 90 | >>> show lists //Shows all lists | ||
3329 | 91 | >>> enable env | ||
3330 | 92 | |||
3331 | 93 | The value of stored variables can be viewed using the show_var command:: | ||
3332 | 94 | |||
3333 | 95 | >>> show_var `domain` | ||
3334 | 96 | |||
3335 | 97 | Create Objects | ||
3336 | 98 | ============== | ||
3337 | 99 | |||
3338 | 100 | The Mailman objects can be created using the `create` command | ||
3339 | 101 | |||
3340 | 102 | The create command accepts the object properties and creates | ||
3341 | 103 | the object. | ||
3342 | 104 | |||
3343 | 105 | If the supplied arguments are invalid or insufficient, the list | ||
3344 | 106 | of arguments that are required are displayed. | ||
3345 | 107 | |||
3346 | 108 | The create command can be used as follows:: | ||
3347 | 109 | |||
3348 | 110 | >>> create list where `fqdn_listname` = `list@domain.org` | ||
3349 | 111 | >>> create domain where `domain` = `domain.org` and `contact` = `a@b.com` | ||
3350 | 112 | >>> create user where `email` = `foo@bar.com` and `password` = `a` and `name` = `Foo` | ||
3351 | 113 | |||
3352 | 114 | Delete Objects | ||
3353 | 115 | ============== | ||
3354 | 116 | |||
3355 | 117 | The Mailman objects can be deleted using the delete command. The | ||
3356 | 118 | delete command supports the same filters as those by the show command. | ||
3357 | 119 | |||
3358 | 120 | For example:: | ||
3359 | 121 | |||
3360 | 122 | >>> delete domain where `domain` like `test_.*` | ||
3361 | 123 | |||
3362 | 124 | Subscription | ||
3363 | 125 | ============ | ||
3364 | 126 | |||
3365 | 127 | The subscription commands include two commands, subscribe and | ||
3366 | 128 | unsubscribe users, which are respectively used to subscribe users to a | ||
3367 | 129 | list and unsubscribe users from a list. The commands allow applying | ||
3368 | 130 | the action on a single user or multiple users at a time.:: | ||
3369 | 131 | |||
3370 | 132 | >>> subscribe users `a@b.com` `foo@bar.com` to `list@domain.org` | ||
3371 | 133 | >>> unsubscribe users `a@b.com` `foo@bar.com` from `list@domain.org` | ||
3372 | 134 | |||
3373 | 135 | Update Preferences | ||
3374 | 136 | ================== | ||
3375 | 137 | |||
3376 | 138 | Preferences can be updated using the shell for the following domains | ||
3377 | 139 | - Users | ||
3378 | 140 | - Members | ||
3379 | 141 | - Addresses | ||
3380 | 142 | |||
3381 | 143 | The actions are performed using the update command which can be used as follows:: | ||
3382 | 144 | |||
3383 | 145 | >>> update preference `<preference_name>` to `<value>` for member with `email` = `foo@bar.com` | ||
3384 | 146 | and `list` = `list@domain.org` | ||
3385 | 147 | >>> update preference `<preference_name>` to `<value>` for user with `email` = `foo@bar.com` | ||
3386 | 148 | >>> update preference `<preference_name>` to `<value>` for address with `email` = `foo@bar.com` | ||
3387 | 149 | |||
3388 | 150 | Global preferences are readonly. | ||
3389 | 0 | 151 | ||
3390 | === added file 'src/mailmanclient/cli/docs/using_cli_tools.txt' | |||
3391 | --- src/mailmanclient/cli/docs/using_cli_tools.txt 1970-01-01 00:00:00 +0000 | |||
3392 | +++ src/mailmanclient/cli/docs/using_cli_tools.txt 2015-03-17 19:08:34 +0000 | |||
3393 | @@ -0,0 +1,311 @@ | |||
3394 | 1 | The Mailman Command Line Tools | ||
3395 | 2 | ****************************** | ||
3396 | 3 | |||
3397 | 4 | Initialization | ||
3398 | 5 | ============== | ||
3399 | 6 | |||
3400 | 7 | The CLI can be started by running mmclient [options|arguments] | ||
3401 | 8 | |||
3402 | 9 | If the mmclient is run without any arguments, the shell | ||
3403 | 10 | is started, else the specified action is performed. Use EOF | ||
3404 | 11 | to exit the shell.:: | ||
3405 | 12 | |||
3406 | 13 | $> mmclient | ||
3407 | 14 | Mailman Command Line Interface v1.0 | ||
3408 | 15 | >>> | ||
3409 | 16 | Bye! | ||
3410 | 17 | |||
3411 | 18 | $> mmclient [options] | ||
3412 | 19 | |||
3413 | 20 | If you have non-default login credentials, specify them with the | ||
3414 | 21 | following options:: | ||
3415 | 22 | |||
3416 | 23 | --host HOSTNAME [defaults to http://127.0.0.1] | ||
3417 | 24 | --port PORTNUMBER [defaults to 8001] | ||
3418 | 25 | --restuser USERNAME [defaults to restadmin] | ||
3419 | 26 | --restpass PASSWORD [defaults to restpass] | ||
3420 | 27 | |||
3421 | 28 | Domains | ||
3422 | 29 | ======= | ||
3423 | 30 | |||
3424 | 31 | This section describes the domain related functions that can be performed | ||
3425 | 32 | with the CLI. | ||
3426 | 33 | |||
3427 | 34 | Create a new domain | ||
3428 | 35 | ------------------- | ||
3429 | 36 | |||
3430 | 37 | To create a new domain:: | ||
3431 | 38 | |||
3432 | 39 | $> mmclient create domain testdomain.org | ||
3433 | 40 | |||
3434 | 41 | List Domains | ||
3435 | 42 | ------------ | ||
3436 | 43 | To list the domains in the system:: | ||
3437 | 44 | |||
3438 | 45 | $> mmclient show domain | ||
3439 | 46 | http://domain.org | ||
3440 | 47 | |||
3441 | 48 | To obtain a detailed listing, use the `-v`/`--verbose` switch. | ||
3442 | 49 | The detailed listing of domains displays the domains as a table:: | ||
3443 | 50 | |||
3444 | 51 | $> mmclient show domain -v | ||
3445 | 52 | Base URL Contact address Mail host URL host | ||
3446 | 53 | http://domain.org postmaster@domain.org domain.org domain.org | ||
3447 | 54 | |||
3448 | 55 | In addition, the long listing has a `no-header` switch that can be used | ||
3449 | 56 | to remove the header, making it more comfortable to pipe the output.:: | ||
3450 | 57 | |||
3451 | 58 | $> mmclient show domain -v --no-header | ||
3452 | 59 | http://domain.org postmaster@domain.org domain.org domain.org | ||
3453 | 60 | |||
3454 | 61 | Delete a domain | ||
3455 | 62 | --------------- | ||
3456 | 63 | |||
3457 | 64 | To delete a domian :: | ||
3458 | 65 | $> mmclient delete domain domain.org | ||
3459 | 66 | |||
3460 | 67 | To supress the confirmation message:: | ||
3461 | 68 | |||
3462 | 69 | $> mmclient delete domain domain.org --yes | ||
3463 | 70 | |||
3464 | 71 | To obtain a detailed description of a domain at one glance:: | ||
3465 | 72 | |||
3466 | 73 | $> mmclient show domain domain.org | ||
3467 | 74 | |||
3468 | 75 | Mailing List | ||
3469 | 76 | ============ | ||
3470 | 77 | |||
3471 | 78 | This section describes the mailing list related function that can be | ||
3472 | 79 | performed with the CLI. | ||
3473 | 80 | |||
3474 | 81 | Create a mailing list | ||
3475 | 82 | --------------------- | ||
3476 | 83 | |||
3477 | 84 | To create a mailing list:: | ||
3478 | 85 | |||
3479 | 86 | $> mmclient create list list@domain.org | ||
3480 | 87 | |||
3481 | 88 | Show Mailing lists | ||
3482 | 89 | ------------------- | ||
3483 | 90 | |||
3484 | 91 | Show all mailing lists in the system:: | ||
3485 | 92 | |||
3486 | 93 | $> mmclient show list | ||
3487 | 94 | foo.domain.org | ||
3488 | 95 | bar.example.org | ||
3489 | 96 | |||
3490 | 97 | To display the lists under the domain `domain.org`:: | ||
3491 | 98 | |||
3492 | 99 | $> mmclient show list -d domain.org | ||
3493 | 100 | foo.domain.org | ||
3494 | 101 | |||
3495 | 102 | Further, a switch -v/--verbose can also be used to print a detailed listing:: | ||
3496 | 103 | |||
3497 | 104 | $> mmclient show list --verbose | ||
3498 | 105 | ID Name Mail host Display Name FQDN | ||
3499 | 106 | list.domain.org list domain.org List list@domain.org | ||
3500 | 107 | |||
3501 | 108 | Again, the `show list` supports a `--no-header` switch that removes | ||
3502 | 109 | the header line of the long listing:: | ||
3503 | 110 | |||
3504 | 111 | $> mmclient show list --verbose --no-header | ||
3505 | 112 | list.domain.org list domain.org List list@domain.org | ||
3506 | 113 | |||
3507 | 114 | Delete Mailing list | ||
3508 | 115 | ------------------- | ||
3509 | 116 | |||
3510 | 117 | To delete a list:: | ||
3511 | 118 | |||
3512 | 119 | $> mmclient delete list list@domain.org | ||
3513 | 120 | |||
3514 | 121 | To supress the confirmation message, do:: | ||
3515 | 122 | |||
3516 | 123 | $> mmclient delete list list@domain.org --yes | ||
3517 | 124 | |||
3518 | 125 | To obtain a detailed description of a list at one glance:: | ||
3519 | 126 | |||
3520 | 127 | $> mmclient show list list@domain.org | ||
3521 | 128 | |||
3522 | 129 | Manage list owners, members and moderators:: | ||
3523 | 130 | --------------------------------- | ||
3524 | 131 | |||
3525 | 132 | Adding and removing moderators can be performed using the CLI as follows | ||
3526 | 133 | |||
3527 | 134 | To get a list of members of a mailing list:: | ||
3528 | 135 | |||
3529 | 136 | $> mmclient show-members list list@domain.org | ||
3530 | 137 | |||
3531 | 138 | The above command is equivalent to:: | ||
3532 | 139 | |||
3533 | 140 | $> mmclient show user --list list@domain.com | ||
3534 | 141 | |||
3535 | 142 | The command also supports flags like:: | ||
3536 | 143 | |||
3537 | 144 | --verbose Show a detailed listing | ||
3538 | 145 | --no-header Hide header in detailed listing | ||
3539 | 146 | |||
3540 | 147 | Refer the `show user` command for more details | ||
3541 | 148 | |||
3542 | 149 | Add or remove list owners and moderators | ||
3543 | 150 | ----------------------------------- | ||
3544 | 151 | |||
3545 | 152 | To add moderators or owners:: | ||
3546 | 153 | |||
3547 | 154 | $> mmclient add-moderator list list@domain.org --user a@b.com b@c.com | ||
3548 | 155 | $> mmclient add-owner list list@domain.org --user a@b.com b@c.com | ||
3549 | 156 | |||
3550 | 157 | And to remove moderators or owners:: | ||
3551 | 158 | |||
3552 | 159 | $> mmclient remove-moderator list list@domain.org --user a@b.com b@c.com | ||
3553 | 160 | $> mmclient remove-owner list list@domain.org --user a@b.com b@c.com | ||
3554 | 161 | |||
3555 | 162 | The add and remove commands support the action on a list of users | ||
3556 | 163 | at once. Success or failure messages are provided upon completion or | ||
3557 | 164 | failure of an action. The messages can be supressed by using a quiet flag:: | ||
3558 | 165 | |||
3559 | 166 | $> mmclient remove-moderator list list@domain.org --user a@b.com b@c.com --quiet | ||
3560 | 167 | |||
3561 | 168 | If the action fails for a user, the user is ignored and the action continues | ||
3562 | 169 | without stalling. | ||
3563 | 170 | |||
3564 | 171 | User | ||
3565 | 172 | ==== | ||
3566 | 173 | |||
3567 | 174 | Craete User | ||
3568 | 175 | ----------- | ||
3569 | 176 | |||
3570 | 177 | To create a new user:: | ||
3571 | 178 | |||
3572 | 179 | $> mmclient create user foo@bar.com --name "Foo" --password "password" | ||
3573 | 180 | |||
3574 | 181 | The `show user` command lists a single email ID of each user:: | ||
3575 | 182 | |||
3576 | 183 | $> mmclient show user | ||
3577 | 184 | foo@bar.com | ||
3578 | 185 | |||
3579 | 186 | To list users who are members of a list:: | ||
3580 | 187 | |||
3581 | 188 | $> mmclient show user --list list@domain.org | ||
3582 | 189 | foo@bar.com | ||
3583 | 190 | |||
3584 | 191 | The show command also supports a `--verbose` switch :: | ||
3585 | 192 | |||
3586 | 193 | $> mmclient show user --verbose | ||
3587 | 194 | Display Name Address Created on User ID | ||
3588 | 195 | Foo foo2@bar.com 2014-05-30T00:52:52.564634 220337223817757552725201672981303248133 | ||
3589 | 196 | |||
3590 | 197 | and a `--no-header` switch:: | ||
3591 | 198 | |||
3592 | 199 | $> mmclient show user --verbose --no-header | ||
3593 | 200 | Foo foo2@bar.com 2014-05-30T00:52:52.564634 220337223817757552725201672981303248133 | ||
3594 | 201 | |||
3595 | 202 | Delete User | ||
3596 | 203 | ----------- | ||
3597 | 204 | |||
3598 | 205 | To delete a user:: | ||
3599 | 206 | |||
3600 | 207 | $> mmclient delete user foo@bar.com | ||
3601 | 208 | |||
3602 | 209 | To supress the confirmation message, do:: | ||
3603 | 210 | |||
3604 | 211 | $> mmclient delete user foo@bar.com --yes | ||
3605 | 212 | |||
3606 | 213 | Describe user | ||
3607 | 214 | ------------- | ||
3608 | 215 | |||
3609 | 216 | To obtain a detailed description of a user at one glance:: | ||
3610 | 217 | |||
3611 | 218 | $> mmclient show user foo@bar.com | ||
3612 | 219 | |||
3613 | 220 | Subscription and Unsubscription | ||
3614 | 221 | -------------------------------- | ||
3615 | 222 | |||
3616 | 223 | Users can be subscribed to a mailing list by using the subscribe | ||
3617 | 224 | command:: | ||
3618 | 225 | |||
3619 | 226 | $> mmclient subscribe user user1@bar.com user2@bar.com --list list@domain.org | ||
3620 | 227 | user1@bar.com subscribed to list@domain.org | ||
3621 | 228 | Failed to subscribe user2@bar.com : HTTP Error 409: Member already subscribed | ||
3622 | 229 | |||
3623 | 230 | Multiple users can be subscribed to the list at the same time. | ||
3624 | 231 | |||
3625 | 232 | Similarly, Users can be unsubscribed to a mailing list by using the unsubscribe | ||
3626 | 233 | command:: | ||
3627 | 234 | |||
3628 | 235 | $> mmclient unsubscribe user user1@bar.com user2@bar.com --list list@domain.org | ||
3629 | 236 | user1@bar.com unsubscribed from list@domain.org | ||
3630 | 237 | user2@bar.com unsubscribed from list@domain.org | ||
3631 | 238 | |||
3632 | 239 | The feedback for the subscribe and unsubscribe actions can be supressed by | ||
3633 | 240 | using the --quiet flag:: | ||
3634 | 241 | |||
3635 | 242 | $> mmclient subscribe user user1@bar.com user2@bar.com --list list@domain.org --quiet | ||
3636 | 243 | $> mmclient unsubscribe user user1@bar.com user2@bar.com --list list@domain.org --quiet | ||
3637 | 244 | |||
3638 | 245 | The subscribe and unsubscribe actions continue even if one the users | ||
3639 | 246 | fail to subscribe/unsubscribe to a list. A relevant feedback message is | ||
3640 | 247 | provided if the --quiet flag is not enabled. | ||
3641 | 248 | |||
3642 | 249 | Preferences | ||
3643 | 250 | =========== | ||
3644 | 251 | |||
3645 | 252 | |||
3646 | 253 | Update Preference | ||
3647 | 254 | ----------------- | ||
3648 | 255 | |||
3649 | 256 | Preferences for user,address,member or globally can be updated and retrieved | ||
3650 | 257 | by using the commands of preference scope. | ||
3651 | 258 | |||
3652 | 259 | To update the value of a preference of an user:: | ||
3653 | 260 | |||
3654 | 261 | $> mmclient update preference user --email foo@bar.com [key] [value] | ||
3655 | 262 | |||
3656 | 263 | To update the value of a preference of a member:: | ||
3657 | 264 | |||
3658 | 265 | $> mmclient update preference member --email foo@bar.com --list list@domain.org [key] [value] | ||
3659 | 266 | |||
3660 | 267 | To update the value of a preference of an address:: | ||
3661 | 268 | |||
3662 | 269 | $> mmclient update preference address --email foo@bar.com [key] [value] | ||
3663 | 270 | |||
3664 | 271 | To update the value of a preference globally:: | ||
3665 | 272 | |||
3666 | 273 | $> mmclient update preference global [key] [value] | ||
3667 | 274 | |||
3668 | 275 | View Setting | ||
3669 | 276 | ------------ | ||
3670 | 277 | To view the current value of a preference, use the `mmclient show preference` command | ||
3671 | 278 | in the same way above, obviously, without the `value` argument | ||
3672 | 279 | |||
3673 | 280 | For eg, to view a setting of a member:: | ||
3674 | 281 | |||
3675 | 282 | $> mmclient show preference member --email foo@bar.com --list list@domain.org [key] | ||
3676 | 283 | |||
3677 | 284 | Both the commands try to suggest the possible preference keys upon errors while typing the | ||
3678 | 285 | keys. The commands return `1` upon an invalid key. | ||
3679 | 286 | |||
3680 | 287 | Backup and Restore | ||
3681 | 288 | ================== | ||
3682 | 289 | |||
3683 | 290 | The CLI tools can be used to create backups and restore the backups of the | ||
3684 | 291 | Mailman data. The backup currently supports the backup for SQLite mode. | ||
3685 | 292 | |||
3686 | 293 | Backup | ||
3687 | 294 | ------ | ||
3688 | 295 | |||
3689 | 296 | The backup tools backs up the $var_dir specified by the Mailman configuration | ||
3690 | 297 | as a zip archive to a specified location:: | ||
3691 | 298 | |||
3692 | 299 | $> mmclient backup ~/backup.zip | ||
3693 | 300 | |||
3694 | 301 | Restore | ||
3695 | 302 | ------- | ||
3696 | 303 | To restore the backup, specfiy the path to the backup file:: | ||
3697 | 304 | |||
3698 | 305 | $> mmclient restore ~/backup.zip | ||
3699 | 306 | |||
3700 | 307 | Please remember to stop the mailman runner before performing | ||
3701 | 308 | the backup and restore operations. | ||
3702 | 309 | |||
3703 | 310 | The paths for backup and restore are read from the Mailman configuration | ||
3704 | 311 | file. | ||
3705 | 0 | 312 | ||
3706 | === added file 'src/mailmanclient/cli/docs/writing_a_new_command.txt' | |||
3707 | --- src/mailmanclient/cli/docs/writing_a_new_command.txt 1970-01-01 00:00:00 +0000 | |||
3708 | +++ src/mailmanclient/cli/docs/writing_a_new_command.txt 2015-03-17 19:08:34 +0000 | |||
3709 | @@ -0,0 +1,57 @@ | |||
3710 | 1 | Writing a new command | ||
3711 | 2 | ********************* | ||
3712 | 3 | |||
3713 | 4 | There are two types of commands in the CLI project, either add a new command | ||
3714 | 5 | to the CLI tools, that gives a normal terminal command, or build a command | ||
3715 | 6 | for the Mailman custom shell. | ||
3716 | 7 | |||
3717 | 8 | Writing a new command for Command tools | ||
3718 | 9 | ======================================= | ||
3719 | 10 | |||
3720 | 11 | To write a new command for the command line tools, the following | ||
3721 | 12 | steps are to be followed. | ||
3722 | 13 | |||
3723 | 14 | - Decide a command name and arguments expected | ||
3724 | 15 | - Decide whether the command comes under a scope. Currently | ||
3725 | 16 | the following scopes are supported | ||
3726 | 17 | |||
3727 | 18 | - users | ||
3728 | 19 | - domains | ||
3729 | 20 | - preferences | ||
3730 | 21 | - lists | ||
3731 | 22 | |||
3732 | 23 | The new command can either be under any of these scopes or | ||
3733 | 24 | can exist independently without a scope. | ||
3734 | 25 | |||
3735 | 26 | - If the new command BAR is to be added to an existing scope ``FOO``, | ||
3736 | 27 | the command would look like ``FOO BAR``, where ``FOO`` is the action and | ||
3737 | 28 | BAR is the scope | ||
3738 | 29 | - Add a new parser to the `action` parser as:: | ||
3739 | 30 | |||
3740 | 31 | new_cmd = action.add_parser('FOO') | ||
3741 | 32 | |||
3742 | 33 | Add the scope as follows:: | ||
3743 | 34 | |||
3744 | 35 | scope = new_cmd.add_subparser(dest='scope') | ||
3745 | 36 | FOO_BAR = scope.add_parser('BAR') | ||
3746 | 37 | |||
3747 | 38 | - Add the arguments as follows:: | ||
3748 | 39 | |||
3749 | 40 | FOO_BAR.add_argument('-x','--xxxx',help='<help text>',[required=True/False]) | ||
3750 | 41 | |||
3751 | 42 | - Add the action method in the ``core/bar.py`` file, to the Bar class. In effect, the action | ||
3752 | 43 | method would be ``core.bar.Bar.action``. Note that the function name must be same as the | ||
3753 | 44 | action name | ||
3754 | 45 | |||
3755 | 46 | - If there is no specific scope, skip the scope parser and add the action the Misc class | ||
3756 | 47 | under ``core/misc.py``. The action would be ``core.misc.Misc.action`` | ||
3757 | 48 | |||
3758 | 49 | Writing a new command for the Shell | ||
3759 | 50 | =================================== | ||
3760 | 51 | |||
3761 | 52 | To write a new shell command, first add a new parser for the command to the ``client/parsers`` directory. | ||
3762 | 53 | |||
3763 | 54 | Add the command method to the ``client/shell.py`` | ||
3764 | 55 | |||
3765 | 56 | Import the parser in the corresponding method and parse the user input, present in the ``self.line`` attribute | ||
3766 | 57 | to obtain the arguments. Perform the action. | ||
3767 | 0 | 58 | ||
3768 | === added directory 'src/mailmanclient/cli/lib' | |||
3769 | === added file 'src/mailmanclient/cli/lib/__init__.py' | |||
3770 | === added file 'src/mailmanclient/cli/lib/colors.py' | |||
3771 | --- src/mailmanclient/cli/lib/colors.py 1970-01-01 00:00:00 +0000 | |||
3772 | +++ src/mailmanclient/cli/lib/colors.py 2015-03-17 19:08:34 +0000 | |||
3773 | @@ -0,0 +1,32 @@ | |||
3774 | 1 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
3775 | 2 | # | ||
3776 | 3 | # This file is part of mailman.client. | ||
3777 | 4 | # | ||
3778 | 5 | # mailman.client is free software: you can redistribute it and/or modify it | ||
3779 | 6 | # under the terms of the GNU Lesser General Public License as published by the | ||
3780 | 7 | # Free Software Foundation, version 3 of the License. | ||
3781 | 8 | # | ||
3782 | 9 | # mailman.client is distributed in the hope that it will be useful, but | ||
3783 | 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
3784 | 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
3785 | 12 | # License for more details. | ||
3786 | 13 | # | ||
3787 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
3788 | 15 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
3789 | 16 | # | ||
3790 | 17 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
3791 | 18 | # | ||
3792 | 19 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
3793 | 20 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
3794 | 21 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
3795 | 22 | # Barry Warsaw <barry@list.org> | ||
3796 | 23 | |||
3797 | 24 | GREY = "\033[90m%s\033[0m" | ||
3798 | 25 | RED = "\033[91m%s\033[0m" | ||
3799 | 26 | GREEN = "\033[92m%s\033[0m" | ||
3800 | 27 | YELLOW = "\033[93m%s\033[0m" | ||
3801 | 28 | BLUE = "\033[94m%s\033[0m" | ||
3802 | 29 | PURPLE = "\033[95m%s\033[0m" | ||
3803 | 30 | CYAN = "\033[96m%s\033[0m" | ||
3804 | 31 | WHITE = "\033[97m%s\033[0m" | ||
3805 | 32 | BLACK = "\033[98m%s\033[0m" | ||
3806 | 0 | 33 | ||
3807 | === added file 'src/mailmanclient/cli/lib/mailman_utils.py' | |||
3808 | --- src/mailmanclient/cli/lib/mailman_utils.py 1970-01-01 00:00:00 +0000 | |||
3809 | +++ src/mailmanclient/cli/lib/mailman_utils.py 2015-03-17 19:08:34 +0000 | |||
3810 | @@ -0,0 +1,117 @@ | |||
3811 | 1 | #!/usr/bin/python | ||
3812 | 2 | |||
3813 | 3 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
3814 | 4 | # | ||
3815 | 5 | # This file is part of mailman.client. | ||
3816 | 6 | # | ||
3817 | 7 | # mailman.client is free software: you can redistribute it and/or modify it | ||
3818 | 8 | # under the terms of the GNU Lesser General Public License as published by the | ||
3819 | 9 | # Free Software Foundation, version 3 of the License. | ||
3820 | 10 | # | ||
3821 | 11 | # mailman.client is distributed in the hope that it will be useful, but | ||
3822 | 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
3823 | 13 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
3824 | 14 | # License for more details. | ||
3825 | 15 | # | ||
3826 | 16 | # You should have received a copy of the GNU Lesser General Public License | ||
3827 | 17 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
3828 | 18 | # | ||
3829 | 19 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
3830 | 20 | # | ||
3831 | 21 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
3832 | 22 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
3833 | 23 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
3834 | 24 | # Barry Warsaw <barry@list.org> | ||
3835 | 25 | |||
3836 | 26 | from mailmanclient import Client, MailmanConnectionError | ||
3837 | 27 | from mailman.config import config | ||
3838 | 28 | from mailmanclient.cli.lib.utils import Utils | ||
3839 | 29 | |||
3840 | 30 | |||
3841 | 31 | class MailmanUtils(Utils): | ||
3842 | 32 | |||
3843 | 33 | """ Utilities relating to Mailman | ||
3844 | 34 | Client or the REST API | ||
3845 | 35 | """ | ||
3846 | 36 | |||
3847 | 37 | def __init__(self): | ||
3848 | 38 | config.load() | ||
3849 | 39 | |||
3850 | 40 | def connect(self, *args, **kwargs): | ||
3851 | 41 | """ Connect to Mailman REST API using the arguments specified. | ||
3852 | 42 | Missing arguments are decided from the mailman.cfg file | ||
3853 | 43 | return a client object. | ||
3854 | 44 | """ | ||
3855 | 45 | host, port, username, password = self.get_credentials_from_config() | ||
3856 | 46 | |||
3857 | 47 | if 'host' in kwargs and kwargs['host']: | ||
3858 | 48 | host = kwargs['host'] | ||
3859 | 49 | if 'port' in kwargs and kwargs['port']: | ||
3860 | 50 | port = kwargs['port'] | ||
3861 | 51 | if 'username' in kwargs and kwargs['username']: | ||
3862 | 52 | username = kwargs['username'] | ||
3863 | 53 | if 'password' in kwargs and kwargs['password']: | ||
3864 | 54 | password = kwargs['password'] | ||
3865 | 55 | |||
3866 | 56 | client = Client('%s:%s/3.0' % (host, port), | ||
3867 | 57 | username, | ||
3868 | 58 | password) | ||
3869 | 59 | try: | ||
3870 | 60 | client.system | ||
3871 | 61 | except MailmanConnectionError as e: | ||
3872 | 62 | self.error(e) | ||
3873 | 63 | exit(1) | ||
3874 | 64 | return client | ||
3875 | 65 | |||
3876 | 66 | def get_credentials_from_config(self): | ||
3877 | 67 | """ Returns the credentials required for logging on to | ||
3878 | 68 | the Mailman REST API, that are read from the Mailman | ||
3879 | 69 | configuration. | ||
3880 | 70 | """ | ||
3881 | 71 | host = 'http://' + config.schema['webservice']['hostname'] | ||
3882 | 72 | port = config.schema['webservice']['port'] | ||
3883 | 73 | username = config.schema['webservice']['admin_user'] | ||
3884 | 74 | password = config.schema['webservice']['admin_pass'] | ||
3885 | 75 | return host, port, username, password | ||
3886 | 76 | |||
3887 | 77 | def get_new_domain_name(self): | ||
3888 | 78 | """ Generates the name of a non existent domain """ | ||
3889 | 79 | client = self.connect() | ||
3890 | 80 | while True: | ||
3891 | 81 | domain_name = self.get_random_string(10) + '.com' | ||
3892 | 82 | try: | ||
3893 | 83 | client.get_domain(domain_name) | ||
3894 | 84 | continue | ||
3895 | 85 | except Exception: | ||
3896 | 86 | return domain_name | ||
3897 | 87 | |||
3898 | 88 | def add_shell_vars(self, arg, shell): | ||
3899 | 89 | """ Replaces the variables used in the command with thier respective | ||
3900 | 90 | values if the values are present in the shell environment, else | ||
3901 | 91 | use the variable as such. | ||
3902 | 92 | """ | ||
3903 | 93 | if not shell.env_on or not arg: | ||
3904 | 94 | return arg | ||
3905 | 95 | if arg[0] == '$' and arg[1:] in shell.env: | ||
3906 | 96 | arg = shell.env[arg[1:]] | ||
3907 | 97 | return arg | ||
3908 | 98 | |||
3909 | 99 | def add_reserved_vars(self, args, shell): | ||
3910 | 100 | """ Adds the reserved variables to a filter query. The reserved variables | ||
3911 | 101 | are domain, list and user, which are added to respective scopes and | ||
3912 | 102 | atrribute names. | ||
3913 | 103 | """ | ||
3914 | 104 | scope = args['scope'] | ||
3915 | 105 | if 'filters' not in args: | ||
3916 | 106 | args['filters'] = [] | ||
3917 | 107 | if not shell.env_on: | ||
3918 | 108 | return args | ||
3919 | 109 | filters = args['filters'] | ||
3920 | 110 | if scope == 'list': | ||
3921 | 111 | if 'domain' in shell.env: | ||
3922 | 112 | filters.append(('mail_host', '=', shell.env['domain'])) | ||
3923 | 113 | elif scope == 'user': | ||
3924 | 114 | if 'list' in shell.env: | ||
3925 | 115 | filters.append((shell.env['list'], 'in', 'subscriptions')) | ||
3926 | 116 | args['filters'] = filters | ||
3927 | 117 | return args | ||
3928 | 0 | 118 | ||
3929 | === added file 'src/mailmanclient/cli/lib/utils.py' | |||
3930 | --- src/mailmanclient/cli/lib/utils.py 1970-01-01 00:00:00 +0000 | |||
3931 | +++ src/mailmanclient/cli/lib/utils.py 2015-03-17 19:08:34 +0000 | |||
3932 | @@ -0,0 +1,216 @@ | |||
3933 | 1 | #!/usr/bin/python | ||
3934 | 2 | |||
3935 | 3 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
3936 | 4 | # | ||
3937 | 5 | # This file is part of mailman.client. | ||
3938 | 6 | # | ||
3939 | 7 | # mailman.client is free software: you can redistribute it and/or modify it | ||
3940 | 8 | # under the terms of the GNU Lesser General Public License as published by the | ||
3941 | 9 | # Free Software Foundation, version 3 of the License. | ||
3942 | 10 | # | ||
3943 | 11 | # mailman.client is distributed in the hope that it will be useful, but | ||
3944 | 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
3945 | 13 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
3946 | 14 | # License for more details. | ||
3947 | 15 | # | ||
3948 | 16 | # You should have received a copy of the GNU Lesser General Public License | ||
3949 | 17 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
3950 | 18 | # | ||
3951 | 19 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
3952 | 20 | # | ||
3953 | 21 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
3954 | 22 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
3955 | 23 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
3956 | 24 | # Barry Warsaw <barry@list.org> | ||
3957 | 25 | |||
3958 | 26 | import re | ||
3959 | 27 | import sys | ||
3960 | 28 | import csv | ||
3961 | 29 | from hashlib import sha1 | ||
3962 | 30 | from datetime import datetime | ||
3963 | 31 | from mailmanclient.cli.lib import colors | ||
3964 | 32 | |||
3965 | 33 | |||
3966 | 34 | class Utils(): | ||
3967 | 35 | """ General utilities to be used across the CLI """ | ||
3968 | 36 | |||
3969 | 37 | WARN = colors.CYAN | ||
3970 | 38 | ERROR = colors.RED | ||
3971 | 39 | CONFIRM = colors.GREEN | ||
3972 | 40 | EMPHASIZE = colors.PURPLE | ||
3973 | 41 | |||
3974 | 42 | # Give colored output on the CLI" | ||
3975 | 43 | def warn(self, message): | ||
3976 | 44 | print(self.WARN % message) | ||
3977 | 45 | |||
3978 | 46 | def error(self, message): | ||
3979 | 47 | sys.stderr.write((self.ERROR + '\n') % message) | ||
3980 | 48 | |||
3981 | 49 | def confirm(self, message): | ||
3982 | 50 | print(self.CONFIRM % message) | ||
3983 | 51 | |||
3984 | 52 | def emphasize(self, message): | ||
3985 | 53 | print(self.EMPHASIZE % message) | ||
3986 | 54 | |||
3987 | 55 | def return_emphasize(self, message): | ||
3988 | 56 | return self.EMPHASIZE % message | ||
3989 | 57 | # End Colors! | ||
3990 | 58 | |||
3991 | 59 | def get_random_string(self, length): | ||
3992 | 60 | """ Returns short random strings, less than 40 bytes in length. | ||
3993 | 61 | |||
3994 | 62 | :param length: Length of the random string to be returned | ||
3995 | 63 | :type length: int | ||
3996 | 64 | """ | ||
3997 | 65 | if length > 40: | ||
3998 | 66 | raise Exception('Specify length less than 40') | ||
3999 | 67 | return sha1(str(datetime.now()).encode('utf-8')).hexdigest()[:length] | ||
4000 | 68 | |||
4001 | 69 | def set_table_section_heading(self, table, heading): | ||
4002 | 70 | table.append(['', '']) | ||
4003 | 71 | table.append([heading, '']) | ||
4004 | 72 | table.append(['=============', '']) | ||
4005 | 73 | |||
4006 | 74 | def write_csv(self, table, headers, filename): | ||
4007 | 75 | if table == []: | ||
4008 | 76 | return | ||
4009 | 77 | |||
4010 | 78 | if 'csv' not in filename: | ||
4011 | 79 | filename += '.csv' | ||
4012 | 80 | |||
4013 | 81 | f = open(filename, 'wb') | ||
4014 | 82 | writer = csv.writer(f, quoting=csv.QUOTE_ALL) | ||
4015 | 83 | if headers: | ||
4016 | 84 | writer.writerow(headers) | ||
4017 | 85 | for row in table: | ||
4018 | 86 | writer.writerow(row) | ||
4019 | 87 | f.close() | ||
4020 | 88 | |||
4021 | 89 | return | ||
4022 | 90 | |||
4023 | 91 | def stem(self, arguments): | ||
4024 | 92 | """ Allows the scope to be in singular or plural | ||
4025 | 93 | |||
4026 | 94 | :param arguments: The sys.argv, passed from mmclient | ||
4027 | 95 | :type arguments: list | ||
4028 | 96 | """ | ||
4029 | 97 | scope = arguments[2] | ||
4030 | 98 | if scope[-1] == 's': | ||
4031 | 99 | scope = scope[:-1] | ||
4032 | 100 | arguments[2] = scope | ||
4033 | 101 | return arguments | ||
4034 | 102 | |||
4035 | 103 | def get_listing(self, objects, fields): | ||
4036 | 104 | """ Tabulates the set of objects by using the values of each of the | ||
4037 | 105 | fileds. """ | ||
4038 | 106 | table = [] | ||
4039 | 107 | for obj in objects: | ||
4040 | 108 | row = [] | ||
4041 | 109 | for field in fields: | ||
4042 | 110 | try: | ||
4043 | 111 | value = getattr(obj, field) | ||
4044 | 112 | except: | ||
4045 | 113 | value = 'None' | ||
4046 | 114 | |||
4047 | 115 | _type = type(value).__name__ | ||
4048 | 116 | if _type == '_Addresses': | ||
4049 | 117 | row.append(str(value[0])) | ||
4050 | 118 | else: | ||
4051 | 119 | row.append(str(value)) | ||
4052 | 120 | |||
4053 | 121 | table.append(row) | ||
4054 | 122 | return table | ||
4055 | 123 | |||
4056 | 124 | |||
4057 | 125 | class Filter(): | ||
4058 | 126 | """ This class manages the filtering tasks for the show and delete commands | ||
4059 | 127 | The class supports three filters, equality, regular expression search | ||
4060 | 128 | and list search. | ||
4061 | 129 | """ | ||
4062 | 130 | |||
4063 | 131 | def get_results(self, *args): | ||
4064 | 132 | op = args[2] | ||
4065 | 133 | if op == '=': | ||
4066 | 134 | return self.equality(*args) | ||
4067 | 135 | elif op == 'like': | ||
4068 | 136 | return self.like(*args) | ||
4069 | 137 | elif op == 'in': | ||
4070 | 138 | return self.in_list(*args) | ||
4071 | 139 | else: | ||
4072 | 140 | raise Exception('Invalid operator: %s ' % (op)) | ||
4073 | 141 | |||
4074 | 142 | def equality(self, key, value, op, data_set): | ||
4075 | 143 | copy_set = data_set[:] | ||
4076 | 144 | for i in data_set: | ||
4077 | 145 | try: | ||
4078 | 146 | obj_value = getattr(i, key) | ||
4079 | 147 | if obj_value != value: | ||
4080 | 148 | copy_set.remove(i) | ||
4081 | 149 | except AttributeError: | ||
4082 | 150 | raise Exception('Invalid filter : %s' % key) | ||
4083 | 151 | return copy_set | ||
4084 | 152 | |||
4085 | 153 | def in_list(self, key, value, op, data_set): | ||
4086 | 154 | copy_set = data_set[:] | ||
4087 | 155 | flag = False | ||
4088 | 156 | for i in data_set: | ||
4089 | 157 | try: | ||
4090 | 158 | the_list = getattr(i, key) | ||
4091 | 159 | except KeyError: | ||
4092 | 160 | copy_set.remove(i) | ||
4093 | 161 | continue | ||
4094 | 162 | except AttributeError: | ||
4095 | 163 | raise Exception('Invalid filter : %s' % key) | ||
4096 | 164 | |||
4097 | 165 | if key == 'members': | ||
4098 | 166 | for j in the_list: | ||
4099 | 167 | if self.match_pattern(j.email, value): | ||
4100 | 168 | flag = True | ||
4101 | 169 | break | ||
4102 | 170 | elif key == 'lists': | ||
4103 | 171 | for j in the_list: | ||
4104 | 172 | if (self.match_pattern(j.list_id, value) | ||
4105 | 173 | or self.match_pattern(j.fqdn_listname, value)): | ||
4106 | 174 | flag = True | ||
4107 | 175 | break | ||
4108 | 176 | elif key == 'subscriptions': | ||
4109 | 177 | value = value.replace('@', '.') | ||
4110 | 178 | for j in the_list: | ||
4111 | 179 | if self.match_pattern(j.list_id, value): | ||
4112 | 180 | flag = True | ||
4113 | 181 | break | ||
4114 | 182 | else: | ||
4115 | 183 | for j in the_list: | ||
4116 | 184 | if self.match_pattern(j, value): | ||
4117 | 185 | flag = True | ||
4118 | 186 | break | ||
4119 | 187 | if not flag: | ||
4120 | 188 | copy_set.remove(i) | ||
4121 | 189 | flag = False | ||
4122 | 190 | return copy_set | ||
4123 | 191 | |||
4124 | 192 | def like(self, key, value, op, data_set): | ||
4125 | 193 | copy_set = data_set[:] | ||
4126 | 194 | for i in data_set: | ||
4127 | 195 | obj_value = None | ||
4128 | 196 | try: | ||
4129 | 197 | obj_value = getattr(i, key) | ||
4130 | 198 | except KeyError: | ||
4131 | 199 | copy_set.remove(i) | ||
4132 | 200 | except AttributeError: | ||
4133 | 201 | raise Exception('Invalid filter : %s' % key) | ||
4134 | 202 | if not self.match_pattern(obj_value, value): | ||
4135 | 203 | copy_set.remove(i) | ||
4136 | 204 | return copy_set | ||
4137 | 205 | |||
4138 | 206 | def match_pattern(self, string, value): | ||
4139 | 207 | """ Regular expression matcher, returns the match object | ||
4140 | 208 | or None | ||
4141 | 209 | """ | ||
4142 | 210 | pattern = None | ||
4143 | 211 | try: | ||
4144 | 212 | pattern = re.compile(value.lower()) | ||
4145 | 213 | except: | ||
4146 | 214 | raise Exception('Invalid pattern : %s' % value) | ||
4147 | 215 | string = str(string).lower() | ||
4148 | 216 | return pattern.match(string) | ||
4149 | 0 | 217 | ||
4150 | === added file 'src/mailmanclient/cli/mmclient' | |||
4151 | --- src/mailmanclient/cli/mmclient 1970-01-01 00:00:00 +0000 | |||
4152 | +++ src/mailmanclient/cli/mmclient 2015-03-17 19:08:34 +0000 | |||
4153 | @@ -0,0 +1,46 @@ | |||
4154 | 1 | #!/usr/bin/python | ||
4155 | 2 | |||
4156 | 3 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
4157 | 4 | # | ||
4158 | 5 | # This file is part of mailman.client. | ||
4159 | 6 | # | ||
4160 | 7 | # mailman.client is free software: you can redistribute it and/or modify it | ||
4161 | 8 | # under the terms of the GNU Lesser General Public License as published by the | ||
4162 | 9 | # Free Software Foundation, version 3 of the License. | ||
4163 | 10 | # | ||
4164 | 11 | # mailman.client is distributed in the hope that it will be useful, but | ||
4165 | 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
4166 | 13 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
4167 | 14 | # License for more details. | ||
4168 | 15 | # | ||
4169 | 16 | # You should have received a copy of the GNU Lesser General Public License | ||
4170 | 17 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
4171 | 18 | # | ||
4172 | 19 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
4173 | 20 | # | ||
4174 | 21 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
4175 | 22 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
4176 | 23 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
4177 | 24 | # Barry Warsaw <barry@list.org> | ||
4178 | 25 | |||
4179 | 26 | import sys | ||
4180 | 27 | from mailmanclient.cli.lib.utils import Utils | ||
4181 | 28 | from mailmanclient.cli.client.shell import Shell | ||
4182 | 29 | from mailmanclient.cli.client.cmdparser import CmdParser | ||
4183 | 30 | try: | ||
4184 | 31 | # If the mmclient is invoked with arguments, trigger the command | ||
4185 | 32 | # line tools, else trigger the commandline shell | ||
4186 | 33 | sys.argv[1] | ||
4187 | 34 | utils = Utils() | ||
4188 | 35 | arguments = None | ||
4189 | 36 | try: | ||
4190 | 37 | arguments = utils.stem(sys.argv) | ||
4191 | 38 | except IndexError: | ||
4192 | 39 | pass | ||
4193 | 40 | c = CmdParser(arguments) | ||
4194 | 41 | c.run() | ||
4195 | 42 | except IndexError: | ||
4196 | 43 | # No arguments supplied.Start the shell. | ||
4197 | 44 | s = Shell() | ||
4198 | 45 | s.initialize() | ||
4199 | 46 | s.cmdloop() | ||
4200 | 0 | 47 | ||
4201 | === added directory 'src/mailmanclient/cli/tests' | |||
4202 | === added file 'src/mailmanclient/cli/tests/__init__.py' | |||
4203 | === added file 'src/mailmanclient/cli/tests/test_domain.py' | |||
4204 | --- src/mailmanclient/cli/tests/test_domain.py 1970-01-01 00:00:00 +0000 | |||
4205 | +++ src/mailmanclient/cli/tests/test_domain.py 2015-03-17 19:08:34 +0000 | |||
4206 | @@ -0,0 +1,223 @@ | |||
4207 | 1 | #!/usr/bin/python | ||
4208 | 2 | |||
4209 | 3 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
4210 | 4 | # | ||
4211 | 5 | # This file is part of mailman.client. | ||
4212 | 6 | # | ||
4213 | 7 | # mailman.client is free software: you can redistribute it and/or modify it | ||
4214 | 8 | # under the terms of the GNU Lesser General Public License as published by the | ||
4215 | 9 | # Free Software Foundation, version 3 of the License. | ||
4216 | 10 | # | ||
4217 | 11 | # mailman.client is distributed in the hope that it will be useful, but | ||
4218 | 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
4219 | 13 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
4220 | 14 | # License for more details. | ||
4221 | 15 | # | ||
4222 | 16 | # You should have received a copy of the GNU Lesser General Public License | ||
4223 | 17 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
4224 | 18 | # | ||
4225 | 19 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
4226 | 20 | # | ||
4227 | 21 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
4228 | 22 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
4229 | 23 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
4230 | 24 | # Barry Warsaw <barry@list.org> | ||
4231 | 25 | |||
4232 | 26 | import random | ||
4233 | 27 | import unittest | ||
4234 | 28 | from mock import patch | ||
4235 | 29 | from six.moves.urllib_error import HTTPError | ||
4236 | 30 | from io import StringIO | ||
4237 | 31 | from mailmanclient.cli.core.domains import Domains, DomainException | ||
4238 | 32 | from mailmanclient.cli.lib.mailman_utils import MailmanUtils | ||
4239 | 33 | |||
4240 | 34 | |||
4241 | 35 | class TestCreateDomain(unittest.TestCase): | ||
4242 | 36 | |||
4243 | 37 | domain_names = [] | ||
4244 | 38 | utils = MailmanUtils() | ||
4245 | 39 | |||
4246 | 40 | def setUp(self): | ||
4247 | 41 | self.client = self.utils.connect() | ||
4248 | 42 | self.domain = Domains(self.client) | ||
4249 | 43 | self.test_domain = self.utils.get_new_domain_name() | ||
4250 | 44 | self.domain_names.append(self.test_domain) | ||
4251 | 45 | self.client.create_domain(self.test_domain) | ||
4252 | 46 | |||
4253 | 47 | def test_normal_create(self): | ||
4254 | 48 | self.new_domain = self.utils.get_new_domain_name() | ||
4255 | 49 | self.domain_names.append(self.new_domain) | ||
4256 | 50 | args = {} | ||
4257 | 51 | args['domain'] = self.new_domain | ||
4258 | 52 | args['contact'] = 'a@b.com' | ||
4259 | 53 | self.domain.create(args) | ||
4260 | 54 | |||
4261 | 55 | def test_create_existent_domain(self): | ||
4262 | 56 | args = {} | ||
4263 | 57 | args['domain'] = self.test_domain | ||
4264 | 58 | args['contact'] = 'a@b.com' | ||
4265 | 59 | self.assertRaises(DomainException, self.domain.create, args) | ||
4266 | 60 | |||
4267 | 61 | def test_no_postmaster(self): | ||
4268 | 62 | self.new_domain = self.utils.get_new_domain_name() | ||
4269 | 63 | self.domain_names.append(self.new_domain) | ||
4270 | 64 | args = {} | ||
4271 | 65 | args['domain'] = self.new_domain | ||
4272 | 66 | args['contact'] = None | ||
4273 | 67 | self.domain.create(args) | ||
4274 | 68 | |||
4275 | 69 | def tearDown(self): | ||
4276 | 70 | for domain in self.domain_names: | ||
4277 | 71 | try: | ||
4278 | 72 | self.client.delete_domain(domain) | ||
4279 | 73 | except Exception: | ||
4280 | 74 | pass | ||
4281 | 75 | |||
4282 | 76 | |||
4283 | 77 | class TestShowDomain(unittest.TestCase): | ||
4284 | 78 | |||
4285 | 79 | domain_names = [] | ||
4286 | 80 | utils = MailmanUtils() | ||
4287 | 81 | |||
4288 | 82 | def setUp(self): | ||
4289 | 83 | self.client = self.utils.connect() | ||
4290 | 84 | self.domain = Domains(self.client) | ||
4291 | 85 | |||
4292 | 86 | @patch('sys.stdout', new_callable=StringIO) | ||
4293 | 87 | def test_normal_show(self, output): | ||
4294 | 88 | ndomains = len(self.client.domains) | ||
4295 | 89 | args = {} | ||
4296 | 90 | args['no_header'] = False | ||
4297 | 91 | args['verbose'] = False | ||
4298 | 92 | args['csv'] = None | ||
4299 | 93 | args['domain'] = None | ||
4300 | 94 | self.domain.show(args) | ||
4301 | 95 | domain_list = output.getvalue().split('\n') | ||
4302 | 96 | count = len(domain_list) - 1 | ||
4303 | 97 | self.assertEqual(ndomains, count) | ||
4304 | 98 | |||
4305 | 99 | @patch('sys.stdout', new_callable=StringIO) | ||
4306 | 100 | def test_verbose_show(self, output): | ||
4307 | 101 | args = {} | ||
4308 | 102 | args['no_header'] = False | ||
4309 | 103 | args['verbose'] = True | ||
4310 | 104 | args['csv'] = None | ||
4311 | 105 | args['domain'] = None | ||
4312 | 106 | test_domain = random.randint(0, len(self.client.domains) - 1) | ||
4313 | 107 | test_domain = self.client.domains[test_domain] | ||
4314 | 108 | self.domain.show(args) | ||
4315 | 109 | domain_list = output.getvalue().split('\n') | ||
4316 | 110 | domain = '' | ||
4317 | 111 | for domain in domain_list: | ||
4318 | 112 | if test_domain.base_url in domain: | ||
4319 | 113 | break | ||
4320 | 114 | domain = domain.split() | ||
4321 | 115 | cleaned_domain = [] | ||
4322 | 116 | for attribute in domain: | ||
4323 | 117 | if attribute: | ||
4324 | 118 | cleaned_domain.append(attribute) | ||
4325 | 119 | self.assertEqual(cleaned_domain[0], test_domain.base_url) | ||
4326 | 120 | self.assertEqual(cleaned_domain[1], test_domain.contact_address) | ||
4327 | 121 | self.assertEqual(cleaned_domain[2], test_domain.mail_host) | ||
4328 | 122 | self.assertEqual(cleaned_domain[3], test_domain.url_host) | ||
4329 | 123 | |||
4330 | 124 | @patch('sys.stdout', new_callable=StringIO) | ||
4331 | 125 | def test_no_header(self, output): | ||
4332 | 126 | args = {} | ||
4333 | 127 | args['no_header'] = True | ||
4334 | 128 | args['csv'] = None | ||
4335 | 129 | args['verbose'] = True | ||
4336 | 130 | args['domain'] = None | ||
4337 | 131 | test_domain = random.randint(0, len(self.client.domains) - 1) | ||
4338 | 132 | test_domain = self.client.domains[test_domain] | ||
4339 | 133 | self.domain.show(args) | ||
4340 | 134 | domain_list = output.getvalue().split('\n') | ||
4341 | 135 | line_one = domain_list[0].split() | ||
4342 | 136 | self.assertNotEqual(line_one[0], 'Base') | ||
4343 | 137 | domain = '' | ||
4344 | 138 | for domain in domain_list: | ||
4345 | 139 | if test_domain.base_url in domain: | ||
4346 | 140 | break | ||
4347 | 141 | domain = domain.split() | ||
4348 | 142 | cleaned_domain = [] | ||
4349 | 143 | for attribute in domain: | ||
4350 | 144 | if attribute: | ||
4351 | 145 | cleaned_domain.append(attribute) | ||
4352 | 146 | self.assertEqual(cleaned_domain[0], test_domain.base_url) | ||
4353 | 147 | self.assertEqual(cleaned_domain[1], test_domain.contact_address) | ||
4354 | 148 | self.assertEqual(cleaned_domain[2], test_domain.mail_host) | ||
4355 | 149 | self.assertEqual(cleaned_domain[3], test_domain.url_host) | ||
4356 | 150 | |||
4357 | 151 | def tearDown(self): | ||
4358 | 152 | for domain in self.domain_names: | ||
4359 | 153 | try: | ||
4360 | 154 | self.client.delete_domain(domain) | ||
4361 | 155 | except Exception: | ||
4362 | 156 | pass | ||
4363 | 157 | |||
4364 | 158 | |||
4365 | 159 | class TestDeleteDomain(unittest.TestCase): | ||
4366 | 160 | |||
4367 | 161 | domain_names = [] | ||
4368 | 162 | utils = MailmanUtils() | ||
4369 | 163 | |||
4370 | 164 | def setUp(self): | ||
4371 | 165 | self.client = self.utils.connect() | ||
4372 | 166 | self.domain = Domains(self.client) | ||
4373 | 167 | |||
4374 | 168 | def test_normal_delete(self): | ||
4375 | 169 | new_domain = self.utils.get_new_domain_name() | ||
4376 | 170 | self.domain_names.append(new_domain) | ||
4377 | 171 | self.client.create_domain(new_domain) | ||
4378 | 172 | args = {} | ||
4379 | 173 | args['domain'] = new_domain | ||
4380 | 174 | with patch('builtins.input', return_value='y'): | ||
4381 | 175 | args['yes'] = True | ||
4382 | 176 | self.domain.delete(args) | ||
4383 | 177 | self.assertRaises(HTTPError, self.client.get_domain, new_domain) | ||
4384 | 178 | |||
4385 | 179 | def test_delete_cancel(self): | ||
4386 | 180 | new_domain = self.utils.get_new_domain_name() | ||
4387 | 181 | self.domain_names.append(new_domain) | ||
4388 | 182 | self.client.create_domain(new_domain) | ||
4389 | 183 | args = {} | ||
4390 | 184 | args['domain'] = new_domain | ||
4391 | 185 | with patch('builtins.input', return_value='n'): | ||
4392 | 186 | args['yes'] = False | ||
4393 | 187 | self.domain.delete(args) | ||
4394 | 188 | self.assertRaises(HTTPError, self.client.create_domain, new_domain) | ||
4395 | 189 | |||
4396 | 190 | def test_delete_invalid_confirm(self): | ||
4397 | 191 | new_domain = self.utils.get_new_domain_name() | ||
4398 | 192 | self.domain_names.append(new_domain) | ||
4399 | 193 | self.client.create_domain(new_domain) | ||
4400 | 194 | args = {} | ||
4401 | 195 | args['domain'] = new_domain | ||
4402 | 196 | args['yes'] = False | ||
4403 | 197 | with patch('builtins.input', return_value='no'): | ||
4404 | 198 | self.assertRaises(Exception, self.domain.delete, args) | ||
4405 | 199 | |||
4406 | 200 | def test_delete_without_confirm(self): | ||
4407 | 201 | new_domain = self.utils.get_new_domain_name() | ||
4408 | 202 | self.domain_names.append(new_domain) | ||
4409 | 203 | self.client.create_domain(new_domain) | ||
4410 | 204 | args = {} | ||
4411 | 205 | args['domain'] = new_domain | ||
4412 | 206 | args['yes'] = True | ||
4413 | 207 | self.domain.delete(args) | ||
4414 | 208 | self.assertRaises(HTTPError, self.client.get_domain, new_domain) | ||
4415 | 209 | |||
4416 | 210 | def test_delete_invalid_domain(self): | ||
4417 | 211 | new_domain = self.utils.get_new_domain_name() | ||
4418 | 212 | self.domain_names.append(new_domain) | ||
4419 | 213 | args = {} | ||
4420 | 214 | args['domain'] = new_domain | ||
4421 | 215 | args['yes'] = True | ||
4422 | 216 | self.assertRaises(DomainException, self.domain.delete, args) | ||
4423 | 217 | |||
4424 | 218 | def tearDown(self): | ||
4425 | 219 | for domain in self.domain_names: | ||
4426 | 220 | try: | ||
4427 | 221 | self.client.delete_domain(domain) | ||
4428 | 222 | except Exception: | ||
4429 | 223 | pass | ||
4430 | 0 | 224 | ||
4431 | === added file 'src/mailmanclient/cli/tests/test_list.py' | |||
4432 | --- src/mailmanclient/cli/tests/test_list.py 1970-01-01 00:00:00 +0000 | |||
4433 | +++ src/mailmanclient/cli/tests/test_list.py 2015-03-17 19:08:34 +0000 | |||
4434 | @@ -0,0 +1,285 @@ | |||
4435 | 1 | #!/usr/bin/python | ||
4436 | 2 | |||
4437 | 3 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
4438 | 4 | # | ||
4439 | 5 | # This file is part of mailman.client. | ||
4440 | 6 | # | ||
4441 | 7 | # mailman.client is free software: you can redistribute it and/or modify it | ||
4442 | 8 | # under the terms of the GNU Lesser General Public License as published by the | ||
4443 | 9 | # Free Software Foundation, version 3 of the License. | ||
4444 | 10 | # | ||
4445 | 11 | # mailman.client is distributed in the hope that it will be useful, but | ||
4446 | 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
4447 | 13 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
4448 | 14 | # License for more details. | ||
4449 | 15 | # | ||
4450 | 16 | # You should have received a copy of the GNU Lesser General Public License | ||
4451 | 17 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
4452 | 18 | # | ||
4453 | 19 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
4454 | 20 | # | ||
4455 | 21 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
4456 | 22 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
4457 | 23 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
4458 | 24 | # Barry Warsaw <barry@list.org> | ||
4459 | 25 | |||
4460 | 26 | import unittest | ||
4461 | 27 | from mock import patch | ||
4462 | 28 | from six.moves.urllib_error import HTTPError | ||
4463 | 29 | from io import StringIO | ||
4464 | 30 | from mailmanclient.cli.core.lists import Lists, ListException | ||
4465 | 31 | from mailmanclient.cli.core.domains import DomainException | ||
4466 | 32 | from mailmanclient.cli.lib.mailman_utils import MailmanUtils | ||
4467 | 33 | |||
4468 | 34 | |||
4469 | 35 | class TestCreateList(unittest.TestCase): | ||
4470 | 36 | |||
4471 | 37 | domain_names = [] | ||
4472 | 38 | utils = MailmanUtils() | ||
4473 | 39 | |||
4474 | 40 | def setUp(self): | ||
4475 | 41 | self.client = self.utils.connect() | ||
4476 | 42 | self._list = Lists(self.client) | ||
4477 | 43 | self.test_domain = self.utils.get_new_domain_name() | ||
4478 | 44 | self.domain_names.append(self.test_domain) | ||
4479 | 45 | self.client.create_domain(self.test_domain) | ||
4480 | 46 | |||
4481 | 47 | # Raise exception if domain create falied. | ||
4482 | 48 | self.domain = self.client.get_domain(self.test_domain) | ||
4483 | 49 | |||
4484 | 50 | def test_normal_create(self): | ||
4485 | 51 | args = {} | ||
4486 | 52 | list_name = self.utils.get_random_string(5) | ||
4487 | 53 | list_name += '@' + self.test_domain | ||
4488 | 54 | args['list'] = list_name | ||
4489 | 55 | self._list.create(args) | ||
4490 | 56 | |||
4491 | 57 | def test_create_existent_list(self): | ||
4492 | 58 | list_name = self.utils.get_random_string(5) | ||
4493 | 59 | self.domain.create_list(list_name) | ||
4494 | 60 | args = {} | ||
4495 | 61 | list_name += '@' + self.test_domain | ||
4496 | 62 | args['list'] = list_name | ||
4497 | 63 | self.assertRaises(ListException, self._list.create, args) | ||
4498 | 64 | |||
4499 | 65 | def test_invalid_fqdn_create(self): | ||
4500 | 66 | test_list = self.utils.get_random_string(5) | ||
4501 | 67 | invalid_name_1 = test_list + '@' | ||
4502 | 68 | invalid_name_2 = '@' + self.test_domain | ||
4503 | 69 | invalid_name_3 = (test_list + '@' + | ||
4504 | 70 | self.utils.get_new_domain_name()) | ||
4505 | 71 | invalid_name_4 = self.test_domain | ||
4506 | 72 | args = {} | ||
4507 | 73 | args['list'] = invalid_name_1 | ||
4508 | 74 | self.assertRaises(ListException, self._list.create, args) | ||
4509 | 75 | args['list'] = invalid_name_2 | ||
4510 | 76 | self.assertRaises(ListException, self._list.create, args) | ||
4511 | 77 | args['list'] = invalid_name_3 | ||
4512 | 78 | self.assertRaises(DomainException, self._list.create, args) | ||
4513 | 79 | args['list'] = invalid_name_4 | ||
4514 | 80 | self.assertRaises(ListException, self._list.create, args) | ||
4515 | 81 | |||
4516 | 82 | def tearDown(self): | ||
4517 | 83 | for domain in self.domain_names: | ||
4518 | 84 | try: | ||
4519 | 85 | self.client.delete_domain(domain) | ||
4520 | 86 | except Exception: | ||
4521 | 87 | pass | ||
4522 | 88 | |||
4523 | 89 | |||
4524 | 90 | class TestShowList(unittest.TestCase): | ||
4525 | 91 | |||
4526 | 92 | domain_names = [] | ||
4527 | 93 | utils = MailmanUtils() | ||
4528 | 94 | |||
4529 | 95 | def setUp(self): | ||
4530 | 96 | self.client = self.utils.connect() | ||
4531 | 97 | self._list = Lists(self.client) | ||
4532 | 98 | self.test_domain = self.utils.get_new_domain_name() | ||
4533 | 99 | self.test_list = self.utils.get_random_string(5) | ||
4534 | 100 | self.domain_names.append(self.test_domain) | ||
4535 | 101 | self.client.create_domain(self.test_domain) | ||
4536 | 102 | |||
4537 | 103 | # Raise exception if domain create falied. | ||
4538 | 104 | self.domain = self.client.get_domain(self.test_domain) | ||
4539 | 105 | self.domain.create_list(self.test_list) | ||
4540 | 106 | |||
4541 | 107 | @patch('sys.stdout', new_callable=StringIO) | ||
4542 | 108 | def test_normal_show(self, output): | ||
4543 | 109 | nlists = len(self.client.lists) | ||
4544 | 110 | args = {} | ||
4545 | 111 | args['no_header'] = False | ||
4546 | 112 | args['csv'] = None | ||
4547 | 113 | args['verbose'] = False | ||
4548 | 114 | args['domain'] = None | ||
4549 | 115 | args['list'] = None | ||
4550 | 116 | self._list.show(args) | ||
4551 | 117 | mlist_list = output.getvalue().split('\n') | ||
4552 | 118 | count = len(mlist_list) - 1 | ||
4553 | 119 | self.assertEqual(nlists, count) | ||
4554 | 120 | |||
4555 | 121 | @patch('sys.stdout', new_callable=StringIO) | ||
4556 | 122 | def test_filter_show(self, output): | ||
4557 | 123 | nlists = len(self.domain.lists) | ||
4558 | 124 | args = {} | ||
4559 | 125 | args['no_header'] = False | ||
4560 | 126 | args['csv'] = None | ||
4561 | 127 | args['verbose'] = False | ||
4562 | 128 | args['domain'] = self.test_domain | ||
4563 | 129 | args['list'] = None | ||
4564 | 130 | self._list.show(args) | ||
4565 | 131 | mlist_list = output.getvalue().split('\n') | ||
4566 | 132 | count = len(mlist_list) - 1 | ||
4567 | 133 | self.assertEqual(nlists, count) | ||
4568 | 134 | |||
4569 | 135 | @patch('sys.stdout', new_callable=StringIO) | ||
4570 | 136 | def test_verbose_show(self, output): | ||
4571 | 137 | args = {} | ||
4572 | 138 | args['no_header'] = False | ||
4573 | 139 | args['csv'] = None | ||
4574 | 140 | args['verbose'] = True | ||
4575 | 141 | args['domain'] = None | ||
4576 | 142 | args['list'] = None | ||
4577 | 143 | self._list.show(args) | ||
4578 | 144 | mlists = output.getvalue().split('\n') | ||
4579 | 145 | test_list = '%s@%s' % (self.test_list, self.test_domain) | ||
4580 | 146 | mlist = '' | ||
4581 | 147 | for mlist in mlists: | ||
4582 | 148 | if test_list in mlist: | ||
4583 | 149 | break | ||
4584 | 150 | mlist = mlist.split() | ||
4585 | 151 | cleaned_list = [] | ||
4586 | 152 | for attribute in mlist: | ||
4587 | 153 | if attribute: | ||
4588 | 154 | cleaned_list.append(attribute) | ||
4589 | 155 | mlist = self.client.get_list(test_list) | ||
4590 | 156 | self.assertEqual(cleaned_list[0], mlist.list_id) | ||
4591 | 157 | self.assertEqual(cleaned_list[1], mlist.list_name) | ||
4592 | 158 | self.assertEqual(cleaned_list[2], mlist.mail_host) | ||
4593 | 159 | self.assertEqual(cleaned_list[3], mlist.display_name) | ||
4594 | 160 | self.assertEqual(cleaned_list[4], mlist.fqdn_listname) | ||
4595 | 161 | |||
4596 | 162 | @patch('sys.stdout', new_callable=StringIO) | ||
4597 | 163 | def test_filter_verbose_show(self, output): | ||
4598 | 164 | args = {} | ||
4599 | 165 | args['no_header'] = False | ||
4600 | 166 | args['csv'] = None | ||
4601 | 167 | args['verbose'] = True | ||
4602 | 168 | args['domain'] = self.test_domain | ||
4603 | 169 | args['list'] = None | ||
4604 | 170 | self._list.show(args) | ||
4605 | 171 | mlists = output.getvalue().split('\n') | ||
4606 | 172 | mlist = '' | ||
4607 | 173 | test_list = '%s@%s' % (self.test_list, self.test_domain) | ||
4608 | 174 | for mlist in mlists: | ||
4609 | 175 | if test_list in mlist: | ||
4610 | 176 | break | ||
4611 | 177 | mlist = mlist.split() | ||
4612 | 178 | cleaned_list = [] | ||
4613 | 179 | for attribute in mlist: | ||
4614 | 180 | if attribute: | ||
4615 | 181 | cleaned_list.append(attribute) | ||
4616 | 182 | mlist = self.client.get_list(test_list) | ||
4617 | 183 | self.assertEqual(cleaned_list[0], mlist.list_id) | ||
4618 | 184 | self.assertEqual(cleaned_list[1], mlist.list_name) | ||
4619 | 185 | self.assertEqual(cleaned_list[2], mlist.mail_host) | ||
4620 | 186 | self.assertEqual(cleaned_list[3], mlist.display_name) | ||
4621 | 187 | self.assertEqual(cleaned_list[4], mlist.fqdn_listname) | ||
4622 | 188 | |||
4623 | 189 | @patch('sys.stdout', new_callable=StringIO) | ||
4624 | 190 | def test_no_header(self, output): | ||
4625 | 191 | args = {} | ||
4626 | 192 | args['no_header'] = False | ||
4627 | 193 | args['csv'] = None | ||
4628 | 194 | args['verbose'] = True | ||
4629 | 195 | args['domain'] = None | ||
4630 | 196 | args['list'] = None | ||
4631 | 197 | self._list.show(args) | ||
4632 | 198 | mlists = output.getvalue().split('\n') | ||
4633 | 199 | line_one = mlists[0].split() | ||
4634 | 200 | self.assertNotEqual(line_one[0], 'Base') | ||
4635 | 201 | mlist = '' | ||
4636 | 202 | for mlist in mlists: | ||
4637 | 203 | if self.test_list in mlist: | ||
4638 | 204 | break | ||
4639 | 205 | mlist = mlist.split() | ||
4640 | 206 | cleaned_list = [] | ||
4641 | 207 | for attribute in mlist: | ||
4642 | 208 | if attribute: | ||
4643 | 209 | cleaned_list.append(attribute) | ||
4644 | 210 | mlist = self.client.get_list('%s@%s' % (self.test_list, | ||
4645 | 211 | self.test_domain)) | ||
4646 | 212 | self.assertEqual(cleaned_list[0], mlist.list_id) | ||
4647 | 213 | self.assertEqual(cleaned_list[1], mlist.list_name) | ||
4648 | 214 | self.assertEqual(cleaned_list[2], mlist.mail_host) | ||
4649 | 215 | self.assertEqual(cleaned_list[3], mlist.display_name) | ||
4650 | 216 | self.assertEqual(cleaned_list[4], mlist.fqdn_listname) | ||
4651 | 217 | |||
4652 | 218 | def tearDown(self): | ||
4653 | 219 | for domain in self.domain_names: | ||
4654 | 220 | try: | ||
4655 | 221 | self.client.delete_domain(domain) | ||
4656 | 222 | except Exception: | ||
4657 | 223 | pass | ||
4658 | 224 | |||
4659 | 225 | |||
4660 | 226 | class TestDeleteList(unittest.TestCase): | ||
4661 | 227 | |||
4662 | 228 | domain_names = [] | ||
4663 | 229 | utils = MailmanUtils() | ||
4664 | 230 | |||
4665 | 231 | def setUp(self): | ||
4666 | 232 | self.client = self.utils.connect() | ||
4667 | 233 | self._list = Lists(self.client) | ||
4668 | 234 | self.test_domain = self.utils.get_new_domain_name() | ||
4669 | 235 | self.test_list = self.utils.get_random_string(5) | ||
4670 | 236 | self.domain_names.append(self.test_domain) | ||
4671 | 237 | self.client.create_domain(self.test_domain) | ||
4672 | 238 | |||
4673 | 239 | # Raise exception if domain create falied. | ||
4674 | 240 | self.domain = self.client.get_domain(self.test_domain) | ||
4675 | 241 | self.domain.create_list(self.test_list) | ||
4676 | 242 | |||
4677 | 243 | def test_normal_delete(self): | ||
4678 | 244 | new_list = self.utils.get_random_string(5) | ||
4679 | 245 | self.domain.create_list(new_list) | ||
4680 | 246 | args = {} | ||
4681 | 247 | args['list'] = '%s@%s' % (new_list, self.test_domain) | ||
4682 | 248 | with patch('builtins.input', return_value='y'): | ||
4683 | 249 | args['yes'] = True | ||
4684 | 250 | self._list.delete(args) | ||
4685 | 251 | self.assertRaises(HTTPError, self.client.get_list, args['list']) | ||
4686 | 252 | |||
4687 | 253 | def test_delete_cancel(self): | ||
4688 | 254 | new_list = self.utils.get_random_string(5) | ||
4689 | 255 | self.domain.create_list(new_list) | ||
4690 | 256 | args = {} | ||
4691 | 257 | args['list'] = '%s@%s' % (new_list, self.test_domain) | ||
4692 | 258 | with patch('builtins.input', return_value='n'): | ||
4693 | 259 | args['yes'] = False | ||
4694 | 260 | self._list.delete(args) | ||
4695 | 261 | self.assertRaises(HTTPError, self.domain.create_list, args['list']) | ||
4696 | 262 | |||
4697 | 263 | def test_delete_invalid_confirm(self): | ||
4698 | 264 | new_list = self.utils.get_random_string(5) | ||
4699 | 265 | self.domain.create_list(new_list) | ||
4700 | 266 | args = {} | ||
4701 | 267 | args['list'] = '%s@%s' % (new_list, self.test_domain) | ||
4702 | 268 | with patch('builtins.input', return_value='no'): | ||
4703 | 269 | self.assertRaises(Exception, self._list.delete, args) | ||
4704 | 270 | |||
4705 | 271 | def test_delete_without_confirm(self): | ||
4706 | 272 | new_list = self.utils.get_random_string(5) | ||
4707 | 273 | self.domain.create_list(new_list) | ||
4708 | 274 | args = {} | ||
4709 | 275 | args['list'] = '%s@%s' % (new_list, self.test_domain) | ||
4710 | 276 | args['yes'] = True | ||
4711 | 277 | self._list.delete(args) | ||
4712 | 278 | self.assertRaises(HTTPError, self.client.get_list, args['list']) | ||
4713 | 279 | |||
4714 | 280 | def tearDown(self): | ||
4715 | 281 | for domain in self.domain_names: | ||
4716 | 282 | try: | ||
4717 | 283 | self.client.delete_domain(domain) | ||
4718 | 284 | except Exception: | ||
4719 | 285 | pass | ||
4720 | 0 | 286 | ||
4721 | === added file 'src/mailmanclient/cli/tests/test_preference.py' | |||
4722 | --- src/mailmanclient/cli/tests/test_preference.py 1970-01-01 00:00:00 +0000 | |||
4723 | +++ src/mailmanclient/cli/tests/test_preference.py 2015-03-17 19:08:34 +0000 | |||
4724 | @@ -0,0 +1,99 @@ | |||
4725 | 1 | #!/usr/bin/python | ||
4726 | 2 | |||
4727 | 3 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
4728 | 4 | # | ||
4729 | 5 | # This file is part of mailman.client. | ||
4730 | 6 | # | ||
4731 | 7 | # mailman.client is free software: you can redistribute it and/or modify it | ||
4732 | 8 | # under the terms of the GNU Lesser General Public License as published by the | ||
4733 | 9 | # Free Software Foundation, version 3 of the License. | ||
4734 | 10 | # | ||
4735 | 11 | # mailman.client is distributed in the hope that it will be useful, but | ||
4736 | 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
4737 | 13 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
4738 | 14 | # License for more details. | ||
4739 | 15 | # | ||
4740 | 16 | # You should have received a copy of the GNU Lesser General Public License | ||
4741 | 17 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
4742 | 18 | # | ||
4743 | 19 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
4744 | 20 | # | ||
4745 | 21 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
4746 | 22 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
4747 | 23 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
4748 | 24 | # Barry Warsaw <barry@list.org> | ||
4749 | 25 | |||
4750 | 26 | import unittest | ||
4751 | 27 | from mailmanclient.cli.core.preferences import Preferences | ||
4752 | 28 | from mailmanclient.cli.lib.mailman_utils import MailmanUtils | ||
4753 | 29 | |||
4754 | 30 | |||
4755 | 31 | utils = MailmanUtils() | ||
4756 | 32 | |||
4757 | 33 | |||
4758 | 34 | class TestUpdate(unittest.TestCase): | ||
4759 | 35 | |||
4760 | 36 | new_objects = [] | ||
4761 | 37 | |||
4762 | 38 | test_user = None | ||
4763 | 39 | test_domain = None | ||
4764 | 40 | test_list = None | ||
4765 | 41 | test_address = None | ||
4766 | 42 | test_member = None | ||
4767 | 43 | |||
4768 | 44 | def setUp(self): | ||
4769 | 45 | self.client = utils.connect() | ||
4770 | 46 | self.preferences = Preferences(self.client) | ||
4771 | 47 | self.test_user = 'a@' + utils.get_random_string(5) + '.com' | ||
4772 | 48 | self.test_user = self.client.create_user(self.test_user, | ||
4773 | 49 | display_name='a', | ||
4774 | 50 | password='a') | ||
4775 | 51 | self.new_objects.append(self.test_user) | ||
4776 | 52 | |||
4777 | 53 | self.test_domain = self.client.create_domain(utils.get_random_string(5) | ||
4778 | 54 | + '.org') | ||
4779 | 55 | self.new_objects.append(self.test_domain) | ||
4780 | 56 | self.test_list = self.test_domain.create_list(utils.get_random_string(5)) | ||
4781 | 57 | self.new_objects.append(self.test_list) | ||
4782 | 58 | |||
4783 | 59 | self.test_member = self.test_list.subscribe(self.test_user.addresses[0]) | ||
4784 | 60 | |||
4785 | 61 | self.test_address = self.test_user.addresses[0] | ||
4786 | 62 | |||
4787 | 63 | def test_user(self): | ||
4788 | 64 | args = {} | ||
4789 | 65 | args['update_scope'] = 'user' | ||
4790 | 66 | args['email'] = self.test_user.addresses[0] | ||
4791 | 67 | args['key'] = 'receive_list_copy' | ||
4792 | 68 | args['value'] = 'False' | ||
4793 | 69 | self.preferences.update(args) | ||
4794 | 70 | self.assertFalse(self.test_user.preferences['receive_list_copy']) | ||
4795 | 71 | |||
4796 | 72 | def test_address(self): | ||
4797 | 73 | args = {} | ||
4798 | 74 | args['update_scope'] = 'address' | ||
4799 | 75 | args['email'] = self.test_address | ||
4800 | 76 | args['key'] = 'receive_list_copy' | ||
4801 | 77 | args['value'] = 'False' | ||
4802 | 78 | self.preferences.update(args) | ||
4803 | 79 | self.assertFalse(self.test_address.preferences['receive_list_copy']) | ||
4804 | 80 | |||
4805 | 81 | def test_member(self): | ||
4806 | 82 | args = {} | ||
4807 | 83 | args['update_scope'] = 'member' | ||
4808 | 84 | args['email'] = self.test_member.email | ||
4809 | 85 | args['list'] = self.test_list.fqdn_listname | ||
4810 | 86 | args['key'] = 'receive_list_copy' | ||
4811 | 87 | args['value'] = 'False' | ||
4812 | 88 | self.preferences.update(args) | ||
4813 | 89 | self.assertFalse(self.test_member.preferences['receive_list_copy']) | ||
4814 | 90 | |||
4815 | 91 | def tearDown(self): | ||
4816 | 92 | for obj in self.new_objects: | ||
4817 | 93 | try: | ||
4818 | 94 | if type(obj).__name__ == '_Domain': | ||
4819 | 95 | self.client.delete_domain(obj.base_url) | ||
4820 | 96 | else: | ||
4821 | 97 | obj.delete() | ||
4822 | 98 | except: | ||
4823 | 99 | pass | ||
4824 | 0 | 100 | ||
4825 | === added file 'src/mailmanclient/cli/tests/test_user.py' | |||
4826 | --- src/mailmanclient/cli/tests/test_user.py 1970-01-01 00:00:00 +0000 | |||
4827 | +++ src/mailmanclient/cli/tests/test_user.py 2015-03-17 19:08:34 +0000 | |||
4828 | @@ -0,0 +1,127 @@ | |||
4829 | 1 | #!/usr/bin/python | ||
4830 | 2 | |||
4831 | 3 | # Copyright (C) 2010-2014 by the Free Software Foundation, Inc. | ||
4832 | 4 | # | ||
4833 | 5 | # This file is part of mailman.client. | ||
4834 | 6 | # | ||
4835 | 7 | # mailman.client is free software: you can redistribute it and/or modify it | ||
4836 | 8 | # under the terms of the GNU Lesser General Public License as published by the | ||
4837 | 9 | # Free Software Foundation, version 3 of the License. | ||
4838 | 10 | # | ||
4839 | 11 | # mailman.client is distributed in the hope that it will be useful, but | ||
4840 | 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
4841 | 13 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
4842 | 14 | # License for more details. | ||
4843 | 15 | # | ||
4844 | 16 | # You should have received a copy of the GNU Lesser General Public License | ||
4845 | 17 | # along with mailman.client. If not, see <http://www.gnu.org/licenses/>. | ||
4846 | 18 | # | ||
4847 | 19 | # This file is part of the Mailman CLI Project, Google Summer Of Code, 2014 | ||
4848 | 20 | # | ||
4849 | 21 | # Author : Rajeev S <rajeevs1992@gmail.com> | ||
4850 | 22 | # Mentors : Stephen J. Turnbull <stephen@xemacs.org> | ||
4851 | 23 | # Abhilash Raj <raj.abhilash1@gmail.com> | ||
4852 | 24 | # Barry Warsaw <barry@list.org> | ||
4853 | 25 | |||
4854 | 26 | import unittest | ||
4855 | 27 | from mailmanclient.cli.core.users import Users, UserException | ||
4856 | 28 | from mailmanclient.cli.lib.mailman_utils import MailmanUtils | ||
4857 | 29 | |||
4858 | 30 | |||
4859 | 31 | class TestCreateUser(unittest.TestCase): | ||
4860 | 32 | |||
4861 | 33 | utils = MailmanUtils() | ||
4862 | 34 | new_users = [] | ||
4863 | 35 | |||
4864 | 36 | def setUp(self): | ||
4865 | 37 | self.client = self.utils.connect() | ||
4866 | 38 | self.users = Users(self.client) | ||
4867 | 39 | self.test_user = 'a@' + self.utils.get_random_string(5) + '.org' | ||
4868 | 40 | self.new_users.append(self.test_user) | ||
4869 | 41 | self.client.create_user(email=self.test_user, | ||
4870 | 42 | password='abcdefgh', | ||
4871 | 43 | display_name='abc') | ||
4872 | 44 | self.test_list = self.client.lists[0] | ||
4873 | 45 | self.test_list.subscribe(self.test_user) | ||
4874 | 46 | |||
4875 | 47 | # Test if user created else setup fails. | ||
4876 | 48 | self.client.get_user(self.test_user) | ||
4877 | 49 | |||
4878 | 50 | def test_normal_create(self): | ||
4879 | 51 | args = {} | ||
4880 | 52 | new_user = 'a@' + self.utils.get_random_string(5) + '.org' | ||
4881 | 53 | self.new_users.append(new_user) | ||
4882 | 54 | args['email'] = new_user | ||
4883 | 55 | args['password'] = 'abc' | ||
4884 | 56 | args['name'] = 'abc' | ||
4885 | 57 | self.users.create(args) | ||
4886 | 58 | self.assertRaises(UserException, self.users.create, args) | ||
4887 | 59 | |||
4888 | 60 | def test_create_existent_user(self): | ||
4889 | 61 | args = {} | ||
4890 | 62 | args['email'] = self.test_user | ||
4891 | 63 | args['password'] = 'abc' | ||
4892 | 64 | args['name'] = 'abc' | ||
4893 | 65 | self.assertRaises(UserException, self.users.create, args) | ||
4894 | 66 | |||
4895 | 67 | def tearDown(self): | ||
4896 | 68 | for user in self.new_users: | ||
4897 | 69 | try: | ||
4898 | 70 | u = self.client.get_user(user) | ||
4899 | 71 | u.delete() | ||
4900 | 72 | except Exception as e: | ||
4901 | 73 | print(e) | ||
4902 | 74 | |||
4903 | 75 | |||
4904 | 76 | class TestSubscription(unittest.TestCase): | ||
4905 | 77 | |||
4906 | 78 | utils = MailmanUtils() | ||
4907 | 79 | new_users = [] | ||
4908 | 80 | domain_list = [] | ||
4909 | 81 | |||
4910 | 82 | def setUp(self): | ||
4911 | 83 | self.client = self.utils.connect() | ||
4912 | 84 | self.users = Users(self.client) | ||
4913 | 85 | |||
4914 | 86 | self.test_domain = self.utils.get_new_domain_name() | ||
4915 | 87 | self.domain_list.append(self.test_domain) | ||
4916 | 88 | self.client.create_domain(self.test_domain) | ||
4917 | 89 | |||
4918 | 90 | self.test_user = self.utils.get_random_string(8) + '@domain.org' | ||
4919 | 91 | self.new_users.append(self.test_user) | ||
4920 | 92 | self.client.create_user(email=self.test_user, | ||
4921 | 93 | password='abcdefgh', | ||
4922 | 94 | display_name='abc') | ||
4923 | 95 | self.client.get_user(self.test_user) | ||
4924 | 96 | domain = self.client.get_domain(self.test_domain) | ||
4925 | 97 | self.test_list = (self.utils.get_random_string(8) + | ||
4926 | 98 | '@' + self.test_domain) | ||
4927 | 99 | domain.create_list(self.test_list.split('@')[0]) | ||
4928 | 100 | |||
4929 | 101 | # Test if user created else setup fails. | ||
4930 | 102 | self.client.get_user(self.test_user) | ||
4931 | 103 | |||
4932 | 104 | def test_subscribe_to_list(self): | ||
4933 | 105 | print(self.test_user) | ||
4934 | 106 | _list = self.client.get_list(self.test_list) | ||
4935 | 107 | nmembers = len(_list.members) | ||
4936 | 108 | args = {} | ||
4937 | 109 | args['users'] = ['a2b@b.com', 'ab4@c.com', 'a8d@e.com'] | ||
4938 | 110 | self.new_users.extend(args['users']) | ||
4939 | 111 | args['list_name'] = self.test_list | ||
4940 | 112 | args['quiet'] = False | ||
4941 | 113 | self.users.subscribe(args) | ||
4942 | 114 | self.assertEqual(nmembers + 3, len(_list.members)) | ||
4943 | 115 | |||
4944 | 116 | def tearDown(self): | ||
4945 | 117 | for i in self.new_users: | ||
4946 | 118 | try: | ||
4947 | 119 | user = self.client.get_user(i) | ||
4948 | 120 | user.delete() | ||
4949 | 121 | except Exception: | ||
4950 | 122 | pass | ||
4951 | 123 | for i in self.domain_list: | ||
4952 | 124 | try: | ||
4953 | 125 | self.client.delete_domain(i) | ||
4954 | 126 | except Exception: | ||
4955 | 127 | pass |