##// END OF EJS Templates
marcink -
r1544:f82cdb15 merge beta
parent child Browse files
Show More
@@ -1,225 +1,237 b''
1 import logging
1 import logging
2 import traceback
2 import traceback
3 import formencode
3 import formencode
4
4
5 from formencode import htmlfill
5 from formencode import htmlfill
6 from operator import itemgetter
6 from operator import itemgetter
7
7
8 from pylons import request, response, session, tmpl_context as c, url
8 from pylons import request, response, session, tmpl_context as c, url
9 from pylons.controllers.util import abort, redirect
9 from pylons.controllers.util import abort, redirect
10 from pylons.i18n.translation import _
10 from pylons.i18n.translation import _
11
11
12 from sqlalchemy.exc import IntegrityError
13
12 from rhodecode.lib import helpers as h
14 from rhodecode.lib import helpers as h
13 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
15 from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator
14 HasPermissionAnyDecorator
15 from rhodecode.lib.base import BaseController, render
16 from rhodecode.lib.base import BaseController, render
16 from rhodecode.model.db import Group
17 from rhodecode.model.db import Group
17 from rhodecode.model.repos_group import ReposGroupModel
18 from rhodecode.model.repos_group import ReposGroupModel
18 from rhodecode.model.forms import ReposGroupForm
19 from rhodecode.model.forms import ReposGroupForm
19
20
20 log = logging.getLogger(__name__)
21 log = logging.getLogger(__name__)
21
22
22
23
23 class ReposGroupsController(BaseController):
24 class ReposGroupsController(BaseController):
24 """REST Controller styled on the Atom Publishing Protocol"""
25 """REST Controller styled on the Atom Publishing Protocol"""
25 # To properly map this controller, ensure your config/routing.py
26 # To properly map this controller, ensure your config/routing.py
26 # file has a resource setup:
27 # file has a resource setup:
27 # map.resource('repos_group', 'repos_groups')
28 # map.resource('repos_group', 'repos_groups')
28
29
29 @LoginRequired()
30 @LoginRequired()
30 def __before__(self):
31 def __before__(self):
31 super(ReposGroupsController, self).__before__()
32 super(ReposGroupsController, self).__before__()
32
33
33 def __load_defaults(self):
34 def __load_defaults(self):
34
35
35 c.repo_groups = [('', '')]
36 c.repo_groups = [('', '')]
36 parents_link = lambda k: h.literal('»'.join(k))
37 parents_link = lambda k: h.literal('»'.join(k))
37
38
38 c.repo_groups.extend([(x.group_id, parents_link(x.full_path_splitted))
39 c.repo_groups.extend([(x.group_id, parents_link(x.full_path_splitted))
39 for x in self.sa.query(Group).all()])
40 for x in self.sa.query(Group).all()])
40
41
41 c.repo_groups = sorted(c.repo_groups,
42 c.repo_groups = sorted(c.repo_groups,
42 key=lambda t: t[1].split('»')[0])
43 key=lambda t: t[1].split('»')[0])
43 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
44 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
44
45
45 def __load_data(self, group_id):
46 def __load_data(self, group_id):
46 """
47 """
47 Load defaults settings for edit, and update
48 Load defaults settings for edit, and update
48
49
49 :param group_id:
50 :param group_id:
50 """
51 """
51 self.__load_defaults()
52 self.__load_defaults()
52
53
53 repo_group = Group.get(group_id)
54 repo_group = Group.get(group_id)
54
55
55 data = repo_group.get_dict()
56 data = repo_group.get_dict()
56
57
57 data['group_name'] = repo_group.name
58 data['group_name'] = repo_group.name
58
59
59 return data
60 return data
60
61
61 @HasPermissionAnyDecorator('hg.admin')
62 @HasPermissionAnyDecorator('hg.admin')
62 def index(self, format='html'):
63 def index(self, format='html'):
63 """GET /repos_groups: All items in the collection"""
64 """GET /repos_groups: All items in the collection"""
64 # url('repos_groups')
65 # url('repos_groups')
65
66
66 sk = lambda g:g.parents[0].group_name if g.parents else g.group_name
67 sk = lambda g:g.parents[0].group_name if g.parents else g.group_name
67 c.groups = sorted(Group.query().all(), key=sk)
68 c.groups = sorted(Group.query().all(), key=sk)
68 return render('admin/repos_groups/repos_groups_show.html')
69 return render('admin/repos_groups/repos_groups_show.html')
69
70
70 @HasPermissionAnyDecorator('hg.admin')
71 @HasPermissionAnyDecorator('hg.admin')
71 def create(self):
72 def create(self):
72 """POST /repos_groups: Create a new item"""
73 """POST /repos_groups: Create a new item"""
73 # url('repos_groups')
74 # url('repos_groups')
74 self.__load_defaults()
75 self.__load_defaults()
75 repos_group_model = ReposGroupModel()
76 repos_group_model = ReposGroupModel()
76 repos_group_form = ReposGroupForm(available_groups=
77 repos_group_form = ReposGroupForm(available_groups=
77 c.repo_groups_choices)()
78 c.repo_groups_choices)()
78 try:
79 try:
79 form_result = repos_group_form.to_python(dict(request.POST))
80 form_result = repos_group_form.to_python(dict(request.POST))
80 repos_group_model.create(form_result)
81 repos_group_model.create(form_result)
81 h.flash(_('created repos group %s') \
82 h.flash(_('created repos group %s') \
82 % form_result['group_name'], category='success')
83 % form_result['group_name'], category='success')
83 #TODO: in futureaction_logger(, '', '', '', self.sa)
84 #TODO: in futureaction_logger(, '', '', '', self.sa)
84 except formencode.Invalid, errors:
85 except formencode.Invalid, errors:
85
86
86 return htmlfill.render(
87 return htmlfill.render(
87 render('admin/repos_groups/repos_groups_add.html'),
88 render('admin/repos_groups/repos_groups_add.html'),
88 defaults=errors.value,
89 defaults=errors.value,
89 errors=errors.error_dict or {},
90 errors=errors.error_dict or {},
90 prefix_error=False,
91 prefix_error=False,
91 encoding="UTF-8")
92 encoding="UTF-8")
92 except Exception:
93 except Exception:
93 log.error(traceback.format_exc())
94 log.error(traceback.format_exc())
94 h.flash(_('error occurred during creation of repos group %s') \
95 h.flash(_('error occurred during creation of repos group %s') \
95 % request.POST.get('group_name'), category='error')
96 % request.POST.get('group_name'), category='error')
96
97
97 return redirect(url('repos_groups'))
98 return redirect(url('repos_groups'))
98
99
99
100
100 @HasPermissionAnyDecorator('hg.admin')
101 @HasPermissionAnyDecorator('hg.admin')
101 def new(self, format='html'):
102 def new(self, format='html'):
102 """GET /repos_groups/new: Form to create a new item"""
103 """GET /repos_groups/new: Form to create a new item"""
103 # url('new_repos_group')
104 # url('new_repos_group')
104 self.__load_defaults()
105 self.__load_defaults()
105 return render('admin/repos_groups/repos_groups_add.html')
106 return render('admin/repos_groups/repos_groups_add.html')
106
107
107 @HasPermissionAnyDecorator('hg.admin')
108 @HasPermissionAnyDecorator('hg.admin')
108 def update(self, id):
109 def update(self, id):
109 """PUT /repos_groups/id: Update an existing item"""
110 """PUT /repos_groups/id: Update an existing item"""
110 # Forms posted to this method should contain a hidden field:
111 # Forms posted to this method should contain a hidden field:
111 # <input type="hidden" name="_method" value="PUT" />
112 # <input type="hidden" name="_method" value="PUT" />
112 # Or using helpers:
113 # Or using helpers:
113 # h.form(url('repos_group', id=ID),
114 # h.form(url('repos_group', id=ID),
114 # method='put')
115 # method='put')
115 # url('repos_group', id=ID)
116 # url('repos_group', id=ID)
116
117
117 self.__load_defaults()
118 self.__load_defaults()
118 c.repos_group = Group.get(id)
119 c.repos_group = Group.get(id)
119
120
120 repos_group_model = ReposGroupModel()
121 repos_group_model = ReposGroupModel()
121 repos_group_form = ReposGroupForm(edit=True,
122 repos_group_form = ReposGroupForm(edit=True,
122 old_data=c.repos_group.get_dict(),
123 old_data=c.repos_group.get_dict(),
123 available_groups=
124 available_groups=
124 c.repo_groups_choices)()
125 c.repo_groups_choices)()
125 try:
126 try:
126 form_result = repos_group_form.to_python(dict(request.POST))
127 form_result = repos_group_form.to_python(dict(request.POST))
127 repos_group_model.update(id, form_result)
128 repos_group_model.update(id, form_result)
128 h.flash(_('updated repos group %s') \
129 h.flash(_('updated repos group %s') \
129 % form_result['group_name'], category='success')
130 % form_result['group_name'], category='success')
130 #TODO: in futureaction_logger(, '', '', '', self.sa)
131 #TODO: in futureaction_logger(, '', '', '', self.sa)
131 except formencode.Invalid, errors:
132 except formencode.Invalid, errors:
132
133
133 return htmlfill.render(
134 return htmlfill.render(
134 render('admin/repos_groups/repos_groups_edit.html'),
135 render('admin/repos_groups/repos_groups_edit.html'),
135 defaults=errors.value,
136 defaults=errors.value,
136 errors=errors.error_dict or {},
137 errors=errors.error_dict or {},
137 prefix_error=False,
138 prefix_error=False,
138 encoding="UTF-8")
139 encoding="UTF-8")
139 except Exception:
140 except Exception:
140 log.error(traceback.format_exc())
141 log.error(traceback.format_exc())
141 h.flash(_('error occurred during update of repos group %s') \
142 h.flash(_('error occurred during update of repos group %s') \
142 % request.POST.get('group_name'), category='error')
143 % request.POST.get('group_name'), category='error')
143
144
144 return redirect(url('repos_groups'))
145 return redirect(url('repos_groups'))
145
146
146
147
147 @HasPermissionAnyDecorator('hg.admin')
148 @HasPermissionAnyDecorator('hg.admin')
148 def delete(self, id):
149 def delete(self, id):
149 """DELETE /repos_groups/id: Delete an existing item"""
150 """DELETE /repos_groups/id: Delete an existing item"""
150 # Forms posted to this method should contain a hidden field:
151 # Forms posted to this method should contain a hidden field:
151 # <input type="hidden" name="_method" value="DELETE" />
152 # <input type="hidden" name="_method" value="DELETE" />
152 # Or using helpers:
153 # Or using helpers:
153 # h.form(url('repos_group', id=ID),
154 # h.form(url('repos_group', id=ID),
154 # method='delete')
155 # method='delete')
155 # url('repos_group', id=ID)
156 # url('repos_group', id=ID)
156
157
157 repos_group_model = ReposGroupModel()
158 repos_group_model = ReposGroupModel()
158 gr = Group.get(id)
159 gr = Group.get(id)
159 repos = gr.repositories.all()
160 repos = gr.repositories.all()
160 if repos:
161 if repos:
161 h.flash(_('This group contains %s repositores and cannot be '
162 h.flash(_('This group contains %s repositores and cannot be '
162 'deleted' % len(repos)),
163 'deleted' % len(repos)),
163 category='error')
164 category='error')
164 return redirect(url('repos_groups'))
165 return redirect(url('repos_groups'))
165
166
166 try:
167 try:
167 repos_group_model.delete(id)
168 repos_group_model.delete(id)
168 h.flash(_('removed repos group %s' % gr.group_name), category='success')
169 h.flash(_('removed repos group %s' % gr.group_name), category='success')
169 #TODO: in future action_logger(, '', '', '', self.sa)
170 #TODO: in future action_logger(, '', '', '', self.sa)
171 except IntegrityError, e:
172 if e.message.find('groups_group_parent_id_fkey'):
173 log.error(traceback.format_exc())
174 h.flash(_('Cannot delete this group it still contains '
175 'subgroups'),
176 category='warning')
177 else:
178 log.error(traceback.format_exc())
179 h.flash(_('error occurred during deletion of repos '
180 'group %s' % gr.group_name), category='error')
181
170 except Exception:
182 except Exception:
171 log.error(traceback.format_exc())
183 log.error(traceback.format_exc())
172 h.flash(_('error occurred during deletion of repos group %s' % gr.group_name),
184 h.flash(_('error occurred during deletion of repos '
173 category='error')
185 'group %s' % gr.group_name), category='error')
174
186
175 return redirect(url('repos_groups'))
187 return redirect(url('repos_groups'))
176
188
177 def show_by_name(self, group_name):
189 def show_by_name(self, group_name):
178 id_ = Group.get_by_group_name(group_name).group_id
190 id_ = Group.get_by_group_name(group_name).group_id
179 return self.show(id_)
191 return self.show(id_)
180
192
181 def show(self, id, format='html'):
193 def show(self, id, format='html'):
182 """GET /repos_groups/id: Show a specific item"""
194 """GET /repos_groups/id: Show a specific item"""
183 # url('repos_group', id=ID)
195 # url('repos_group', id=ID)
184
196
185 c.group = Group.get(id)
197 c.group = Group.get(id)
186
198
187 if c.group:
199 if c.group:
188 c.group_repos = c.group.repositories.all()
200 c.group_repos = c.group.repositories.all()
189 else:
201 else:
190 return redirect(url('home'))
202 return redirect(url('home'))
191
203
192 #overwrite our cached list with current filter
204 #overwrite our cached list with current filter
193 gr_filter = c.group_repos
205 gr_filter = c.group_repos
194 c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter)
206 c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter)
195
207
196 c.repos_list = c.cached_repo_list
208 c.repos_list = c.cached_repo_list
197
209
198 c.repo_cnt = 0
210 c.repo_cnt = 0
199
211
200 c.groups = self.sa.query(Group).order_by(Group.group_name)\
212 c.groups = self.sa.query(Group).order_by(Group.group_name)\
201 .filter(Group.group_parent_id == id).all()
213 .filter(Group.group_parent_id == id).all()
202
214
203 return render('admin/repos_groups/repos_groups.html')
215 return render('admin/repos_groups/repos_groups.html')
204
216
205 @HasPermissionAnyDecorator('hg.admin')
217 @HasPermissionAnyDecorator('hg.admin')
206 def edit(self, id, format='html'):
218 def edit(self, id, format='html'):
207 """GET /repos_groups/id/edit: Form to edit an existing item"""
219 """GET /repos_groups/id/edit: Form to edit an existing item"""
208 # url('edit_repos_group', id=ID)
220 # url('edit_repos_group', id=ID)
209
221
210 id_ = int(id)
222 id_ = int(id)
211
223
212 c.repos_group = Group.get(id_)
224 c.repos_group = Group.get(id_)
213 defaults = self.__load_data(id_)
225 defaults = self.__load_data(id_)
214
226
215 # we need to exclude this group from the group list for editing
227 # we need to exclude this group from the group list for editing
216 c.repo_groups = filter(lambda x:x[0] != id_, c.repo_groups)
228 c.repo_groups = filter(lambda x:x[0] != id_, c.repo_groups)
217
229
218 return htmlfill.render(
230 return htmlfill.render(
219 render('admin/repos_groups/repos_groups_edit.html'),
231 render('admin/repos_groups/repos_groups_edit.html'),
220 defaults=defaults,
232 defaults=defaults,
221 encoding="UTF-8",
233 encoding="UTF-8",
222 force_defaults=False
234 force_defaults=False
223 )
235 )
224
236
225
237
@@ -1,162 +1,164 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.user_group
3 rhodecode.model.user_group
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 users groups model for RhodeCode
6 users groups model for RhodeCode
7
7
8 :created_on: Jan 25, 2011
8 :created_on: Jan 25, 2011
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import os
26 import os
27 import logging
27 import logging
28 import traceback
28 import traceback
29 import shutil
29 import shutil
30
30
31 from pylons.i18n.translation import _
31 from pylons.i18n.translation import _
32
32
33 from vcs.utils.lazy import LazyProperty
33 from vcs.utils.lazy import LazyProperty
34
34
35 from rhodecode.model import BaseModel
35 from rhodecode.model import BaseModel
36 from rhodecode.model.caching_query import FromCache
36 from rhodecode.model.caching_query import FromCache
37 from rhodecode.model.db import Group, RhodeCodeUi
37 from rhodecode.model.db import Group, RhodeCodeUi
38
38
39 log = logging.getLogger(__name__)
39 log = logging.getLogger(__name__)
40
40
41
41
42 class ReposGroupModel(BaseModel):
42 class ReposGroupModel(BaseModel):
43
43
44 @LazyProperty
44 @LazyProperty
45 def repos_path(self):
45 def repos_path(self):
46 """
46 """
47 Get's the repositories root path from database
47 Get's the repositories root path from database
48 """
48 """
49
49
50 q = RhodeCodeUi.get_by_key('/').one()
50 q = RhodeCodeUi.get_by_key('/').one()
51 return q.ui_value
51 return q.ui_value
52
52
53 def __create_group(self, group_name):
53 def __create_group(self, group_name):
54 """
54 """
55 makes repositories group on filesystem
55 makes repositories group on filesystem
56
56
57 :param repo_name:
57 :param repo_name:
58 :param parent_id:
58 :param parent_id:
59 """
59 """
60
60
61 create_path = os.path.join(self.repos_path, group_name)
61 create_path = os.path.join(self.repos_path, group_name)
62 log.debug('creating new group in %s', create_path)
62 log.debug('creating new group in %s', create_path)
63
63
64 if os.path.isdir(create_path):
64 if os.path.isdir(create_path):
65 raise Exception('That directory already exists !')
65 raise Exception('That directory already exists !')
66
66
67 os.makedirs(create_path)
67 os.makedirs(create_path)
68
68
69 def __rename_group(self, old, new):
69 def __rename_group(self, old, new):
70 """
70 """
71 Renames a group on filesystem
71 Renames a group on filesystem
72
72
73 :param group_name:
73 :param group_name:
74 """
74 """
75
75
76 if old == new:
76 if old == new:
77 log.debug('skipping group rename')
77 log.debug('skipping group rename')
78 return
78 return
79
79
80 log.debug('renaming repos group from %s to %s', old, new)
80 log.debug('renaming repos group from %s to %s', old, new)
81
81
82
82
83 old_path = os.path.join(self.repos_path, old)
83 old_path = os.path.join(self.repos_path, old)
84 new_path = os.path.join(self.repos_path, new)
84 new_path = os.path.join(self.repos_path, new)
85
85
86 log.debug('renaming repos paths from %s to %s', old_path, new_path)
86 log.debug('renaming repos paths from %s to %s', old_path, new_path)
87
87
88 if os.path.isdir(new_path):
88 if os.path.isdir(new_path):
89 raise Exception('Was trying to rename to already '
89 raise Exception('Was trying to rename to already '
90 'existing dir %s' % new_path)
90 'existing dir %s' % new_path)
91 shutil.move(old_path, new_path)
91 shutil.move(old_path, new_path)
92
92
93 def __delete_group(self, group):
93 def __delete_group(self, group):
94 """
94 """
95 Deletes a group from a filesystem
95 Deletes a group from a filesystem
96
96
97 :param group: instance of group from database
97 :param group: instance of group from database
98 """
98 """
99 paths = group.full_path.split(Group.url_sep())
99 paths = group.full_path.split(Group.url_sep())
100 paths = os.sep.join(paths)
100 paths = os.sep.join(paths)
101
101
102 rm_path = os.path.join(self.repos_path, paths)
102 rm_path = os.path.join(self.repos_path, paths)
103 if os.path.isdir(rm_path):
104 # delete only if that path really exists
103 os.rmdir(rm_path)
105 os.rmdir(rm_path)
104
106
105 def create(self, form_data):
107 def create(self, form_data):
106 try:
108 try:
107 new_repos_group = Group()
109 new_repos_group = Group()
108 new_repos_group.group_description = form_data['group_description']
110 new_repos_group.group_description = form_data['group_description']
109 new_repos_group.parent_group = Group.get(form_data['group_parent_id'])
111 new_repos_group.parent_group = Group.get(form_data['group_parent_id'])
110 new_repos_group.group_name = new_repos_group.get_new_name(form_data['group_name'])
112 new_repos_group.group_name = new_repos_group.get_new_name(form_data['group_name'])
111
113
112 self.sa.add(new_repos_group)
114 self.sa.add(new_repos_group)
113
115
114 self.__create_group(new_repos_group.group_name)
116 self.__create_group(new_repos_group.group_name)
115
117
116 self.sa.commit()
118 self.sa.commit()
117 return new_repos_group
119 return new_repos_group
118 except:
120 except:
119 log.error(traceback.format_exc())
121 log.error(traceback.format_exc())
120 self.sa.rollback()
122 self.sa.rollback()
121 raise
123 raise
122
124
123 def update(self, repos_group_id, form_data):
125 def update(self, repos_group_id, form_data):
124
126
125 try:
127 try:
126 repos_group = Group.get(repos_group_id)
128 repos_group = Group.get(repos_group_id)
127 old_path = repos_group.full_path
129 old_path = repos_group.full_path
128
130
129 #change properties
131 #change properties
130 repos_group.group_description = form_data['group_description']
132 repos_group.group_description = form_data['group_description']
131 repos_group.parent_group = Group.get(form_data['group_parent_id'])
133 repos_group.parent_group = Group.get(form_data['group_parent_id'])
132 repos_group.group_name = repos_group.get_new_name(form_data['group_name'])
134 repos_group.group_name = repos_group.get_new_name(form_data['group_name'])
133
135
134 new_path = repos_group.full_path
136 new_path = repos_group.full_path
135
137
136 self.sa.add(repos_group)
138 self.sa.add(repos_group)
137
139
138 self.__rename_group(old_path, new_path)
140 self.__rename_group(old_path, new_path)
139
141
140 # we need to get all repositories from this new group and
142 # we need to get all repositories from this new group and
141 # rename them accordingly to new group path
143 # rename them accordingly to new group path
142 for r in repos_group.repositories:
144 for r in repos_group.repositories:
143 r.repo_name = r.get_new_name(r.just_name)
145 r.repo_name = r.get_new_name(r.just_name)
144 self.sa.add(r)
146 self.sa.add(r)
145
147
146 self.sa.commit()
148 self.sa.commit()
147 return repos_group
149 return repos_group
148 except:
150 except:
149 log.error(traceback.format_exc())
151 log.error(traceback.format_exc())
150 self.sa.rollback()
152 self.sa.rollback()
151 raise
153 raise
152
154
153 def delete(self, users_group_id):
155 def delete(self, users_group_id):
154 try:
156 try:
155 users_group = Group.get(users_group_id)
157 users_group = Group.get(users_group_id)
156 self.sa.delete(users_group)
158 self.sa.delete(users_group)
157 self.__delete_group(users_group)
159 self.__delete_group(users_group)
158 self.sa.commit()
160 self.sa.commit()
159 except:
161 except:
160 log.error(traceback.format_exc())
162 log.error(traceback.format_exc())
161 self.sa.rollback()
163 self.sa.rollback()
162 raise
164 raise
General Comments 0
You need to be logged in to leave comments. Login now