##// END OF EJS Templates
fixed Example celery config to ampq,...
marcink -
r752:89b9037d beta
parent child Browse files
Show More
@@ -1,77 +1,79
1 # List of modules to import when celery starts.
1 # List of modules to import when celery starts.
2 import sys
2 import sys
3 import os
3 import os
4 import ConfigParser
4 import ConfigParser
5 root = os.getcwd()
5 root = os.getcwd()
6
6
7 PYLONS_CONFIG_NAME = 'production.ini'
7 PYLONS_CONFIG_NAME = 'production.ini'
8
8
9 sys.path.append(root)
9 sys.path.append(root)
10 config = ConfigParser.ConfigParser({'here':root})
10 config = ConfigParser.ConfigParser({'here':root})
11 config.read('%s/%s' % (root, PYLONS_CONFIG_NAME))
11 config.read('%s/%s' % (root, PYLONS_CONFIG_NAME))
12 PYLONS_CONFIG = config
12 PYLONS_CONFIG = config
13
13
14 CELERY_IMPORTS = ("rhodecode.lib.celerylib.tasks",)
14 CELERY_IMPORTS = ("rhodecode.lib.celerylib.tasks",)
15
15
16 ## Result store settings.
16 ## Result store settings.
17 CELERY_RESULT_BACKEND = "database"
17 CELERY_RESULT_BACKEND = "amqp"
18 CELERY_RESULT_DBURI = dict(config.items('app:main'))['sqlalchemy.db1.url']
18 CELERY_AMQP_TASK_RESULT_EXPIRES = 18000 # 5 hours.
19
20 #CELERY_RESULT_DBURI = dict(config.items('app:main'))['sqlalchemy.db1.url']
19 CELERY_RESULT_SERIALIZER = 'json'
21 CELERY_RESULT_SERIALIZER = 'json'
20
22
21
23
22 BROKER_CONNECTION_MAX_RETRIES = 30
24 BROKER_CONNECTION_MAX_RETRIES = 30
23
25
24 ## Broker settings.
26 ## Broker settings.
25 BROKER_HOST = "localhost"
27 BROKER_HOST = "localhost"
26 BROKER_PORT = 5672
28 BROKER_PORT = 5672
27 BROKER_VHOST = "rabbitmqhost"
29 BROKER_VHOST = "rabbitmqhost"
28 BROKER_USER = "rabbitmq"
30 BROKER_USER = "rabbitmq"
29 BROKER_PASSWORD = "qweqwe"
31 BROKER_PASSWORD = "qweqwe"
30
32
31 ## Worker settings
33 ## Worker settings
32 ## If you're doing mostly I/O you can have more processes,
34 ## If you're doing mostly I/O you can have more processes,
33 ## but if mostly spending CPU, try to keep it close to the
35 ## but if mostly spending CPU, try to keep it close to the
34 ## number of CPUs on your machine. If not set, the number of CPUs/cores
36 ## number of CPUs on your machine. If not set, the number of CPUs/cores
35 ## available will be used.
37 ## available will be used.
36 CELERYD_CONCURRENCY = 2
38 CELERYD_CONCURRENCY = 2
37 # CELERYD_LOG_FILE = "celeryd.log"
39 # CELERYD_LOG_FILE = "celeryd.log"
38 CELERYD_LOG_LEVEL = "DEBUG"
40 CELERYD_LOG_LEVEL = "DEBUG"
39 CELERYD_MAX_TASKS_PER_CHILD = 3
41 CELERYD_MAX_TASKS_PER_CHILD = 3
40
42
41 #Tasks will never be sent to the queue, but executed locally instead.
43 #Tasks will never be sent to the queue, but executed locally instead.
42 CELERY_ALWAYS_EAGER = False
44 CELERY_ALWAYS_EAGER = False
43 if PYLONS_CONFIG_NAME == 'test.ini':
45 if PYLONS_CONFIG_NAME == 'test.ini':
44 #auto eager for tests
46 #auto eager for tests
45 CELERY_ALWAYS_EAGER = True
47 CELERY_ALWAYS_EAGER = True
46
48
47 #===============================================================================
49 #===============================================================================
48 # EMAIL SETTINGS
50 # EMAIL SETTINGS
49 #===============================================================================
51 #===============================================================================
50 pylons_email_config = dict(config.items('DEFAULT'))
52 pylons_email_config = dict(config.items('DEFAULT'))
51
53
52 CELERY_SEND_TASK_ERROR_EMAILS = True
54 CELERY_SEND_TASK_ERROR_EMAILS = True
53
55
54 #List of (name, email_address) tuples for the admins that should receive error e-mails.
56 #List of (name, email_address) tuples for the admins that should receive error e-mails.
55 ADMINS = [('Administrator', pylons_email_config.get('email_to'))]
57 ADMINS = [('Administrator', pylons_email_config.get('email_to'))]
56
58
57 #The e-mail address this worker sends e-mails from. Default is "celery@localhost".
59 #The e-mail address this worker sends e-mails from. Default is "celery@localhost".
58 SERVER_EMAIL = pylons_email_config.get('error_email_from')
60 SERVER_EMAIL = pylons_email_config.get('error_email_from')
59
61
60 #The mail server to use. Default is "localhost".
62 #The mail server to use. Default is "localhost".
61 MAIL_HOST = pylons_email_config.get('smtp_server')
63 MAIL_HOST = pylons_email_config.get('smtp_server')
62
64
63 #Username (if required) to log on to the mail server with.
65 #Username (if required) to log on to the mail server with.
64 MAIL_HOST_USER = pylons_email_config.get('smtp_username')
66 MAIL_HOST_USER = pylons_email_config.get('smtp_username')
65
67
66 #Password (if required) to log on to the mail server with.
68 #Password (if required) to log on to the mail server with.
67 MAIL_HOST_PASSWORD = pylons_email_config.get('smtp_password')
69 MAIL_HOST_PASSWORD = pylons_email_config.get('smtp_password')
68
70
69 MAIL_PORT = pylons_email_config.get('smtp_port')
71 MAIL_PORT = pylons_email_config.get('smtp_port')
70
72
71
73
72 #===============================================================================
74 #===============================================================================
73 # INSTRUCTIONS FOR RABBITMQ
75 # INSTRUCTIONS FOR RABBITMQ
74 #===============================================================================
76 #===============================================================================
75 # rabbitmqctl add_user rabbitmq qweqwe
77 # rabbitmqctl add_user rabbitmq qweqwe
76 # rabbitmqctl add_vhost rabbitmqhost
78 # rabbitmqctl add_vhost rabbitmqhost
77 # rabbitmqctl set_permissions -p rabbitmqhost rabbitmq ".*" ".*" ".*"
79 # rabbitmqctl set_permissions -p rabbitmqhost rabbitmq ".*" ".*" ".*"
@@ -1,324 +1,324
1 from celery.decorators import task
1 from celery.decorators import task
2
2
3 import os
3 import os
4 import traceback
4 import traceback
5 from time import mktime
5 from time import mktime
6
6
7 from operator import itemgetter
7 from operator import itemgetter
8 from pylons.i18n.translation import _
8 from pylons.i18n.translation import _
9 from rhodecode.lib.celerylib import run_task, locked_task
9 from rhodecode.lib.celerylib import run_task, locked_task
10 from rhodecode.lib.helpers import person
10 from rhodecode.lib.helpers import person
11 from rhodecode.lib.smtp_mailer import SmtpMailer
11 from rhodecode.lib.smtp_mailer import SmtpMailer
12 from rhodecode.lib.utils import OrderedDict
12 from rhodecode.lib.utils import OrderedDict
13 from vcs.backends import get_repo
13 from vcs.backends import get_repo
14 from rhodecode.model.db import RhodeCodeUi
14 from rhodecode.model.db import RhodeCodeUi
15
15
16 try:
16 try:
17 import json
17 import json
18 except ImportError:
18 except ImportError:
19 #python 2.5 compatibility
19 #python 2.5 compatibility
20 import simplejson as json
20 import simplejson as json
21
21
22 try:
22 try:
23 from celeryconfig import PYLONS_CONFIG as config
23 from celeryconfig import PYLONS_CONFIG as config
24 celery_on = True
24 celery_on = True
25 except ImportError:
25 except ImportError:
26 #if celeryconfig is not present let's just load our pylons
26 #if celeryconfig is not present let's just load our pylons
27 #config instead
27 #config instead
28 from pylons import config
28 from pylons import config
29 celery_on = False
29 celery_on = False
30
30
31
31
32 __all__ = ['whoosh_index', 'get_commits_stats',
32 __all__ = ['whoosh_index', 'get_commits_stats',
33 'reset_user_password', 'send_email']
33 'reset_user_password', 'send_email']
34
34
35 def get_session():
35 def get_session():
36 if celery_on:
36 if celery_on:
37 from sqlalchemy import engine_from_config
37 from sqlalchemy import engine_from_config
38 from sqlalchemy.orm import sessionmaker, scoped_session
38 from sqlalchemy.orm import sessionmaker, scoped_session
39 engine = engine_from_config(dict(config.items('app:main')),
39 engine = engine_from_config(dict(config.items('app:main')),
40 'sqlalchemy.db1.')
40 'sqlalchemy.db1.')
41 sa = scoped_session(sessionmaker(bind=engine))
41 sa = scoped_session(sessionmaker(bind=engine))
42 else:
42 else:
43 #If we don't use celery reuse our current application Session
43 #If we don't use celery reuse our current application Session
44 from rhodecode.model.meta import Session
44 from rhodecode.model.meta import Session
45 sa = Session()
45 sa = Session()
46
46
47 return sa
47 return sa
48
48
49 def get_repos_path():
49 def get_repos_path():
50 sa = get_session()
50 sa = get_session()
51 q = sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
51 q = sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
52 return q.ui_value
52 return q.ui_value
53
53
54 @task
54 @task
55 @locked_task
55 @locked_task
56 def whoosh_index(repo_location, full_index):
56 def whoosh_index(repo_location, full_index):
57 log = whoosh_index.get_logger()
57 log = whoosh_index.get_logger()
58 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
58 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
59 index_location = dict(config.items('app:main'))['index_dir']
59 index_location = dict(config.items('app:main'))['index_dir']
60 WhooshIndexingDaemon(index_location=index_location,
60 WhooshIndexingDaemon(index_location=index_location,
61 repo_location=repo_location).run(full_index=full_index)
61 repo_location=repo_location).run(full_index=full_index)
62
62
63 @task
63 @task
64 @locked_task
64 @locked_task
65 def get_commits_stats(repo_name, ts_min_y, ts_max_y):
65 def get_commits_stats(repo_name, ts_min_y, ts_max_y):
66 from rhodecode.model.db import Statistics, Repository
66 from rhodecode.model.db import Statistics, Repository
67 log = get_commits_stats.get_logger()
67 log = get_commits_stats.get_logger()
68
68
69 #for js data compatibilty
69 #for js data compatibilty
70 author_key_cleaner = lambda k: person(k).replace('"', "")
70 author_key_cleaner = lambda k: person(k).replace('"', "")
71
71
72 commits_by_day_author_aggregate = {}
72 commits_by_day_author_aggregate = {}
73 commits_by_day_aggregate = {}
73 commits_by_day_aggregate = {}
74 repos_path = get_repos_path()
74 repos_path = get_repos_path()
75 p = os.path.join(repos_path, repo_name)
75 p = os.path.join(repos_path, repo_name)
76 repo = get_repo(p)
76 repo = get_repo(p)
77
77
78 skip_date_limit = True
78 skip_date_limit = True
79 parse_limit = 250 #limit for single task changeset parsing optimal for
79 parse_limit = 250 #limit for single task changeset parsing optimal for
80 last_rev = 0
80 last_rev = 0
81 last_cs = None
81 last_cs = None
82 timegetter = itemgetter('time')
82 timegetter = itemgetter('time')
83
83
84 sa = get_session()
84 sa = get_session()
85
85
86 dbrepo = sa.query(Repository)\
86 dbrepo = sa.query(Repository)\
87 .filter(Repository.repo_name == repo_name).scalar()
87 .filter(Repository.repo_name == repo_name).scalar()
88 cur_stats = sa.query(Statistics)\
88 cur_stats = sa.query(Statistics)\
89 .filter(Statistics.repository == dbrepo).scalar()
89 .filter(Statistics.repository == dbrepo).scalar()
90 if cur_stats:
90 if cur_stats:
91 last_rev = cur_stats.stat_on_revision
91 last_rev = cur_stats.stat_on_revision
92 if not repo.revisions:
92 if not repo.revisions:
93 return True
93 return True
94
94
95 if last_rev == repo.revisions[-1] and len(repo.revisions) > 1:
95 if last_rev == repo.revisions[-1] and len(repo.revisions) > 1:
96 #pass silently without any work if we're not on first revision or
96 #pass silently without any work if we're not on first revision or
97 #current state of parsing revision(from db marker) is the last revision
97 #current state of parsing revision(from db marker) is the last revision
98 return True
98 return True
99
99
100 if cur_stats:
100 if cur_stats:
101 commits_by_day_aggregate = OrderedDict(
101 commits_by_day_aggregate = OrderedDict(
102 json.loads(
102 json.loads(
103 cur_stats.commit_activity_combined))
103 cur_stats.commit_activity_combined))
104 commits_by_day_author_aggregate = json.loads(cur_stats.commit_activity)
104 commits_by_day_author_aggregate = json.loads(cur_stats.commit_activity)
105
105
106 log.debug('starting parsing %s', parse_limit)
106 log.debug('starting parsing %s', parse_limit)
107 lmktime = mktime
107 lmktime = mktime
108
108
109 for cnt, rev in enumerate(repo.revisions[last_rev:]):
109 for cnt, rev in enumerate(repo.revisions[last_rev:]):
110 last_cs = cs = repo.get_changeset(rev)
110 last_cs = cs = repo.get_changeset(rev)
111 k = '%s-%s-%s' % (cs.date.timetuple()[0], cs.date.timetuple()[1],
111 k = '%s-%s-%s' % (cs.date.timetuple()[0], cs.date.timetuple()[1],
112 cs.date.timetuple()[2])
112 cs.date.timetuple()[2])
113 timetupple = [int(x) for x in k.split('-')]
113 timetupple = [int(x) for x in k.split('-')]
114 timetupple.extend([0 for _ in xrange(6)])
114 timetupple.extend([0 for _ in xrange(6)])
115 k = lmktime(timetupple)
115 k = lmktime(timetupple)
116 if commits_by_day_author_aggregate.has_key(author_key_cleaner(cs.author)):
116 if commits_by_day_author_aggregate.has_key(author_key_cleaner(cs.author)):
117 try:
117 try:
118 l = [timegetter(x) for x in commits_by_day_author_aggregate\
118 l = [timegetter(x) for x in commits_by_day_author_aggregate\
119 [author_key_cleaner(cs.author)]['data']]
119 [author_key_cleaner(cs.author)]['data']]
120 time_pos = l.index(k)
120 time_pos = l.index(k)
121 except ValueError:
121 except ValueError:
122 time_pos = False
122 time_pos = False
123
123
124 if time_pos >= 0 and time_pos is not False:
124 if time_pos >= 0 and time_pos is not False:
125
125
126 datadict = commits_by_day_author_aggregate\
126 datadict = commits_by_day_author_aggregate\
127 [author_key_cleaner(cs.author)]['data'][time_pos]
127 [author_key_cleaner(cs.author)]['data'][time_pos]
128
128
129 datadict["commits"] += 1
129 datadict["commits"] += 1
130 datadict["added"] += len(cs.added)
130 datadict["added"] += len(cs.added)
131 datadict["changed"] += len(cs.changed)
131 datadict["changed"] += len(cs.changed)
132 datadict["removed"] += len(cs.removed)
132 datadict["removed"] += len(cs.removed)
133
133
134 else:
134 else:
135 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
135 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
136
136
137 datadict = {"time":k,
137 datadict = {"time":k,
138 "commits":1,
138 "commits":1,
139 "added":len(cs.added),
139 "added":len(cs.added),
140 "changed":len(cs.changed),
140 "changed":len(cs.changed),
141 "removed":len(cs.removed),
141 "removed":len(cs.removed),
142 }
142 }
143 commits_by_day_author_aggregate\
143 commits_by_day_author_aggregate\
144 [author_key_cleaner(cs.author)]['data'].append(datadict)
144 [author_key_cleaner(cs.author)]['data'].append(datadict)
145
145
146 else:
146 else:
147 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
147 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
148 commits_by_day_author_aggregate[author_key_cleaner(cs.author)] = {
148 commits_by_day_author_aggregate[author_key_cleaner(cs.author)] = {
149 "label":author_key_cleaner(cs.author),
149 "label":author_key_cleaner(cs.author),
150 "data":[{"time":k,
150 "data":[{"time":k,
151 "commits":1,
151 "commits":1,
152 "added":len(cs.added),
152 "added":len(cs.added),
153 "changed":len(cs.changed),
153 "changed":len(cs.changed),
154 "removed":len(cs.removed),
154 "removed":len(cs.removed),
155 }],
155 }],
156 "schema":["commits"],
156 "schema":["commits"],
157 }
157 }
158
158
159 #gather all data by day
159 #gather all data by day
160 if commits_by_day_aggregate.has_key(k):
160 if commits_by_day_aggregate.has_key(k):
161 commits_by_day_aggregate[k] += 1
161 commits_by_day_aggregate[k] += 1
162 else:
162 else:
163 commits_by_day_aggregate[k] = 1
163 commits_by_day_aggregate[k] = 1
164
164
165 if cnt >= parse_limit:
165 if cnt >= parse_limit:
166 #don't fetch to much data since we can freeze application
166 #don't fetch to much data since we can freeze application
167 break
167 break
168 overview_data = []
168 overview_data = []
169 for k, v in commits_by_day_aggregate.items():
169 for k, v in commits_by_day_aggregate.items():
170 overview_data.append([k, v])
170 overview_data.append([k, v])
171 overview_data = sorted(overview_data, key=itemgetter(0))
171 overview_data = sorted(overview_data, key=itemgetter(0))
172 if not commits_by_day_author_aggregate:
172 if not commits_by_day_author_aggregate:
173 commits_by_day_author_aggregate[author_key_cleaner(repo.contact)] = {
173 commits_by_day_author_aggregate[author_key_cleaner(repo.contact)] = {
174 "label":author_key_cleaner(repo.contact),
174 "label":author_key_cleaner(repo.contact),
175 "data":[0, 1],
175 "data":[0, 1],
176 "schema":["commits"],
176 "schema":["commits"],
177 }
177 }
178
178
179 stats = cur_stats if cur_stats else Statistics()
179 stats = cur_stats if cur_stats else Statistics()
180 stats.commit_activity = json.dumps(commits_by_day_author_aggregate)
180 stats.commit_activity = json.dumps(commits_by_day_author_aggregate)
181 stats.commit_activity_combined = json.dumps(overview_data)
181 stats.commit_activity_combined = json.dumps(overview_data)
182
182
183 log.debug('last revison %s', last_rev)
183 log.debug('last revison %s', last_rev)
184 leftovers = len(repo.revisions[last_rev:])
184 leftovers = len(repo.revisions[last_rev:])
185 log.debug('revisions to parse %s', leftovers)
185 log.debug('revisions to parse %s', leftovers)
186
186
187 if last_rev == 0 or leftovers < parse_limit:
187 if last_rev == 0 or leftovers < parse_limit:
188 stats.languages = json.dumps(__get_codes_stats(repo_name))
188 stats.languages = json.dumps(__get_codes_stats(repo_name))
189
189
190 stats.repository = dbrepo
190 stats.repository = dbrepo
191 stats.stat_on_revision = last_cs.revision
191 stats.stat_on_revision = last_cs.revision
192
192
193 try:
193 try:
194 sa.add(stats)
194 sa.add(stats)
195 sa.commit()
195 sa.commit()
196 except:
196 except:
197 log.error(traceback.format_exc())
197 log.error(traceback.format_exc())
198 sa.rollback()
198 sa.rollback()
199 return False
199 return False
200 if len(repo.revisions) > 1:
200 if len(repo.revisions) > 1:
201 run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y)
201 run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y)
202
202
203 return True
203 return True
204
204
205 @task
205 @task
206 def reset_user_password(user_email):
206 def reset_user_password(user_email):
207 log = reset_user_password.get_logger()
207 log = reset_user_password.get_logger()
208 from rhodecode.lib import auth
208 from rhodecode.lib import auth
209 from rhodecode.model.db import User
209 from rhodecode.model.db import User
210
210
211 try:
211 try:
212 try:
212 try:
213 sa = get_session()
213 sa = get_session()
214 user = sa.query(User).filter(User.email == user_email).scalar()
214 user = sa.query(User).filter(User.email == user_email).scalar()
215 new_passwd = auth.PasswordGenerator().gen_password(8,
215 new_passwd = auth.PasswordGenerator().gen_password(8,
216 auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
216 auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
217 if user:
217 if user:
218 user.password = auth.get_crypt_password(new_passwd)
218 user.password = auth.get_crypt_password(new_passwd)
219 sa.add(user)
219 sa.add(user)
220 sa.commit()
220 sa.commit()
221 log.info('change password for %s', user_email)
221 log.info('change password for %s', user_email)
222 if new_passwd is None:
222 if new_passwd is None:
223 raise Exception('unable to generate new password')
223 raise Exception('unable to generate new password')
224
224
225 except:
225 except:
226 log.error(traceback.format_exc())
226 log.error(traceback.format_exc())
227 sa.rollback()
227 sa.rollback()
228
228
229 run_task(send_email, user_email,
229 run_task(send_email, user_email,
230 "Your new rhodecode password",
230 "Your new rhodecode password",
231 'Your new rhodecode password:%s' % (new_passwd))
231 'Your new rhodecode password:%s' % (new_passwd))
232 log.info('send new password mail to %s', user_email)
232 log.info('send new password mail to %s', user_email)
233
233
234
234
235 except:
235 except:
236 log.error('Failed to update user password')
236 log.error('Failed to update user password')
237 log.error(traceback.format_exc())
237 log.error(traceback.format_exc())
238 return True
238 return True
239
239
240 @task
240 @task
241 def send_email(recipients, subject, body):
241 def send_email(recipients, subject, body):
242 """
242 """
243 Sends an email with defined parameters from the .ini files.
243 Sends an email with defined parameters from the .ini files.
244
244
245
245
246 :param recipients: list of recipients, it this is empty the defined email
246 :param recipients: list of recipients, it this is empty the defined email
247 address from field 'email_to' is used instead
247 address from field 'email_to' is used instead
248 :param subject: subject of the mail
248 :param subject: subject of the mail
249 :param body: body of the mail
249 :param body: body of the mail
250 """
250 """
251 log = send_email.get_logger()
251 log = send_email.get_logger()
252 email_config = dict(config.items('DEFAULT'))
252 email_config = dict(config.items('DEFAULT'))
253
253
254 if not recipients:
254 if not recipients:
255 recipients = [email_config.get('email_to')]
255 recipients = [email_config.get('email_to')]
256
256
257 def str2bool(v):
257 def str2bool(v):
258 return v.lower() in ["yes", "true", "t", "1"] if v else None
258 return v.lower() in ["yes", "true", "t", "1"] if v else None
259
259
260 mail_from = email_config.get('app_email_from')
260 mail_from = email_config.get('app_email_from')
261 user = email_config.get('smtp_username')
261 user = email_config.get('smtp_username')
262 passwd = email_config.get('smtp_password')
262 passwd = email_config.get('smtp_password')
263 mail_server = email_config.get('smtp_server')
263 mail_server = email_config.get('smtp_server')
264 mail_port = email_config.get('smtp_port')
264 mail_port = email_config.get('smtp_port')
265 tls = str2bool(email_config.get('smtp_use_tls'))
265 tls = str2bool(email_config.get('smtp_use_tls'))
266 ssl = str2bool(email_config.get('smtp_use_ssl'))
266 ssl = str2bool(email_config.get('smtp_use_ssl'))
267
267
268 try:
268 try:
269 m = SmtpMailer(mail_from, user, passwd, mail_server,
269 m = SmtpMailer(mail_from, user, passwd, mail_server,
270 mail_port, ssl, tls)
270 mail_port, ssl, tls)
271 m.send(recipients, subject, body)
271 m.send(recipients, subject, body)
272 except:
272 except:
273 log.error('Mail sending failed')
273 log.error('Mail sending failed')
274 log.error(traceback.format_exc())
274 log.error(traceback.format_exc())
275 return False
275 return False
276 return True
276 return True
277
277
278 @task
278 @task
279 def create_repo_fork(form_data, cur_user):
279 def create_repo_fork(form_data, cur_user):
280 from rhodecode.model.repo import RepoModel
280 from rhodecode.model.repo import RepoModel
281 from vcs import get_backend
281 from vcs import get_backend
282 log = create_repo_fork.get_logger()
282 log = create_repo_fork.get_logger()
283 repo_model = RepoModel()
283 repo_model = RepoModel(get_session())
284 repo_model.create(form_data, cur_user, just_db=True, fork=True)
284 repo_model.create(form_data, cur_user, just_db=True, fork=True)
285 repo_name = form_data['repo_name']
285 repo_name = form_data['repo_name']
286 repos_path = get_repos_path()
286 repos_path = get_repos_path()
287 repo_path = os.path.join(repos_path, repo_name)
287 repo_path = os.path.join(repos_path, repo_name)
288 repo_fork_path = os.path.join(repos_path, form_data['fork_name'])
288 repo_fork_path = os.path.join(repos_path, form_data['fork_name'])
289 alias = form_data['repo_type']
289 alias = form_data['repo_type']
290
290
291 log.info('creating repo fork %s as %s', repo_name, repo_path)
291 log.info('creating repo fork %s as %s', repo_name, repo_path)
292 backend = get_backend(alias)
292 backend = get_backend(alias)
293 backend(str(repo_fork_path), create=True, src_url=str(repo_path))
293 backend(str(repo_fork_path), create=True, src_url=str(repo_path))
294
294
295 def __get_codes_stats(repo_name):
295 def __get_codes_stats(repo_name):
296 LANGUAGES_EXTENSIONS = ['action', 'adp', 'ashx', 'asmx',
296 LANGUAGES_EXTENSIONS = ['action', 'adp', 'ashx', 'asmx',
297 'aspx', 'asx', 'axd', 'c', 'cfg', 'cfm', 'cpp', 'cs', 'diff', 'do', 'el',
297 'aspx', 'asx', 'axd', 'c', 'cfg', 'cfm', 'cpp', 'cs', 'diff', 'do', 'el',
298 'erl', 'h', 'java', 'js', 'jsp', 'jspx', 'lisp', 'lua', 'm', 'mako', 'ml',
298 'erl', 'h', 'java', 'js', 'jsp', 'jspx', 'lisp', 'lua', 'm', 'mako', 'ml',
299 'pas', 'patch', 'php', 'php3', 'php4', 'phtml', 'pm', 'py', 'rb', 'rst',
299 'pas', 'patch', 'php', 'php3', 'php4', 'phtml', 'pm', 'py', 'rb', 'rst',
300 's', 'sh', 'tpl', 'txt', 'vim', 'wss', 'xhtml', 'xml', 'xsl', 'xslt', 'yaws']
300 's', 'sh', 'tpl', 'txt', 'vim', 'wss', 'xhtml', 'xml', 'xsl', 'xslt', 'yaws']
301
301
302
302
303 repos_path = get_repos_path()
303 repos_path = get_repos_path()
304 p = os.path.join(repos_path, repo_name)
304 p = os.path.join(repos_path, repo_name)
305 repo = get_repo(p)
305 repo = get_repo(p)
306 tip = repo.get_changeset()
306 tip = repo.get_changeset()
307 code_stats = {}
307 code_stats = {}
308
308
309 def aggregate(cs):
309 def aggregate(cs):
310 for f in cs[2]:
310 for f in cs[2]:
311 k = f.mimetype
311 k = f.mimetype
312 if f.extension in LANGUAGES_EXTENSIONS:
312 if f.extension in LANGUAGES_EXTENSIONS:
313 if code_stats.has_key(k):
313 if code_stats.has_key(k):
314 code_stats[k] += 1
314 code_stats[k] += 1
315 else:
315 else:
316 code_stats[k] = 1
316 code_stats[k] = 1
317
317
318 map(aggregate, tip.walk('/'))
318 map(aggregate, tip.walk('/'))
319
319
320 return code_stats or {}
320 return code_stats or {}
321
321
322
322
323
323
324
324
@@ -1,23 +1,32
1 """The application's model objects"""
1 """The application's model objects"""
2 import logging
2 import logging
3 from rhodecode.model import meta
3 from rhodecode.model import meta
4 log = logging.getLogger(__name__)
4 log = logging.getLogger(__name__)
5
5
6 def init_model(engine):
6 def init_model(engine):
7 """Call me before using any of the tables or classes in the model"""
7 """Call me before using any of the tables or classes in the model"""
8 log.info("INITIALIZING DB MODELS")
8 log.info("INITIALIZING DB MODELS")
9 meta.Base.metadata.bind = engine
9 meta.Base.metadata.bind = engine
10 #meta.Base2.metadata.bind = engine2
10 #meta.Base2.metadata.bind = engine2
11
11
12 #THIS IS A TEST FOR EXECUTING SCRIPT AND LOAD PYLONS APPLICATION GLOBALS
12 #THIS IS A TEST FOR EXECUTING SCRIPT AND LOAD PYLONS APPLICATION GLOBALS
13 #from paste.deploy import appconfig
13 #from paste.deploy import appconfig
14 #from pylons import config
14 #from pylons import config
15 #from sqlalchemy import engine_from_config
15 #from sqlalchemy import engine_from_config
16 #from rhodecode.config.environment import load_environment
16 #from rhodecode.config.environment import load_environment
17 #
17 #
18 #conf = appconfig('config:development.ini', relative_to = './../../')
18 #conf = appconfig('config:development.ini', relative_to = './../../')
19 #load_environment(conf.global_conf, conf.local_conf)
19 #load_environment(conf.global_conf, conf.local_conf)
20 #
20 #
21 #engine = engine_from_config(config, 'sqlalchemy.')
21 #engine = engine_from_config(config, 'sqlalchemy.')
22 #init_model(engine)
22 #init_model(engine)
23 # DO SOMETHING
23 # DO SOMETHING
24
25
26 class BaseModel(object):
27
28 def __init__(self, sa=None):
29 if sa is not None:
30 self.sa = sa
31 else:
32 self.sa = meta.Session()
@@ -1,99 +1,96
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # Model for permissions
3 # Model for permissions
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5
5
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on Aug 20, 2010
21 Created on Aug 20, 2010
22 Model for permissions
22 Model for permissions
23 @author: marcink
23 :author: marcink
24 """
24 """
25
25
26 from rhodecode.model import BaseModel
26 from rhodecode.model.db import User, Permission, UserToPerm, RepoToPerm
27 from rhodecode.model.db import User, Permission, UserToPerm, RepoToPerm
27 from rhodecode.model.caching_query import FromCache
28 from rhodecode.model.caching_query import FromCache
28 from rhodecode.model.meta import Session
29 import logging
29 import logging
30 import traceback
30 import traceback
31 log = logging.getLogger(__name__)
31 log = logging.getLogger(__name__)
32
32
33
33
34 class PermissionModel(object):
34 class PermissionModel(BaseModel):
35
36 def __init__(self):
37 self.sa = Session()
38
35
39 def get_permission(self, permission_id, cache=False):
36 def get_permission(self, permission_id, cache=False):
40 perm = self.sa.query(Permission)
37 perm = self.sa.query(Permission)
41 if cache:
38 if cache:
42 perm = perm.options(FromCache("sql_cache_short",
39 perm = perm.options(FromCache("sql_cache_short",
43 "get_permission_%s" % permission_id))
40 "get_permission_%s" % permission_id))
44 return perm.get(permission_id)
41 return perm.get(permission_id)
45
42
46 def get_permission_by_name(self, name, cache=False):
43 def get_permission_by_name(self, name, cache=False):
47 perm = self.sa.query(Permission)\
44 perm = self.sa.query(Permission)\
48 .filter(Permission.permission_name == name)
45 .filter(Permission.permission_name == name)
49 if cache:
46 if cache:
50 perm = perm.options(FromCache("sql_cache_short",
47 perm = perm.options(FromCache("sql_cache_short",
51 "get_permission_%s" % name))
48 "get_permission_%s" % name))
52 return perm.scalar()
49 return perm.scalar()
53
50
54 def update(self, form_result):
51 def update(self, form_result):
55 perm_user = self.sa.query(User)\
52 perm_user = self.sa.query(User)\
56 .filter(User.username == form_result['perm_user_name']).scalar()
53 .filter(User.username == form_result['perm_user_name']).scalar()
57 u2p = self.sa.query(UserToPerm).filter(UserToPerm.user == perm_user).all()
54 u2p = self.sa.query(UserToPerm).filter(UserToPerm.user == perm_user).all()
58 if len(u2p) != 3:
55 if len(u2p) != 3:
59 raise Exception('Defined: %s should be 3 permissions for default'
56 raise Exception('Defined: %s should be 3 permissions for default'
60 ' user. This should not happen please verify'
57 ' user. This should not happen please verify'
61 ' your database' % len(u2p))
58 ' your database' % len(u2p))
62
59
63 try:
60 try:
64 #stage 1 change defaults
61 #stage 1 change defaults
65 for p in u2p:
62 for p in u2p:
66 if p.permission.permission_name.startswith('repository.'):
63 if p.permission.permission_name.startswith('repository.'):
67 p.permission = self.get_permission_by_name(
64 p.permission = self.get_permission_by_name(
68 form_result['default_perm'])
65 form_result['default_perm'])
69 self.sa.add(p)
66 self.sa.add(p)
70
67
71 if p.permission.permission_name.startswith('hg.register.'):
68 if p.permission.permission_name.startswith('hg.register.'):
72 p.permission = self.get_permission_by_name(
69 p.permission = self.get_permission_by_name(
73 form_result['default_register'])
70 form_result['default_register'])
74 self.sa.add(p)
71 self.sa.add(p)
75
72
76 if p.permission.permission_name.startswith('hg.create.'):
73 if p.permission.permission_name.startswith('hg.create.'):
77 p.permission = self.get_permission_by_name(
74 p.permission = self.get_permission_by_name(
78 form_result['default_create'])
75 form_result['default_create'])
79 self.sa.add(p)
76 self.sa.add(p)
80
77
81 #stage 2 update all default permissions for repos if checked
78 #stage 2 update all default permissions for repos if checked
82 if form_result['overwrite_default'] == True:
79 if form_result['overwrite_default'] == True:
83 for r2p in self.sa.query(RepoToPerm)\
80 for r2p in self.sa.query(RepoToPerm)\
84 .filter(RepoToPerm.user == perm_user).all():
81 .filter(RepoToPerm.user == perm_user).all():
85 r2p.permission = self.get_permission_by_name(
82 r2p.permission = self.get_permission_by_name(
86 form_result['default_perm'])
83 form_result['default_perm'])
87 self.sa.add(r2p)
84 self.sa.add(r2p)
88
85
89 #stage 3 set anonymous access
86 #stage 3 set anonymous access
90 if perm_user.username == 'default':
87 if perm_user.username == 'default':
91 perm_user.active = bool(form_result['anonymous'])
88 perm_user.active = bool(form_result['anonymous'])
92 self.sa.add(perm_user)
89 self.sa.add(perm_user)
93
90
94
91
95 self.sa.commit()
92 self.sa.commit()
96 except:
93 except:
97 log.error(traceback.format_exc())
94 log.error(traceback.format_exc())
98 self.sa.rollback()
95 self.sa.rollback()
99 raise
96 raise
@@ -1,235 +1,233
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # model for handling repositories actions
3 # model for handling repositories actions
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 # This program is free software; you can redistribute it and/or
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; version 2
7 # as published by the Free Software Foundation; version 2
8 # of the License or (at your opinion) any later version of the license.
8 # of the License or (at your opinion) any later version of the license.
9 #
9 #
10 # This program is distributed in the hope that it will be useful,
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
13 # GNU General Public License for more details.
14 #
14 #
15 # You should have received a copy of the GNU General Public License
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # MA 02110-1301, USA.
18 # MA 02110-1301, USA.
19 """
19 """
20 Created on Jun 5, 2010
20 Created on Jun 5, 2010
21 model for handling repositories actions
21 model for handling repositories actions
22 :author: marcink
22 :author: marcink
23 """
23 """
24 from vcs.backends import get_repo, get_backend
24 from vcs.backends import get_backend
25 from datetime import datetime
25 from datetime import datetime
26 from pylons import app_globals as g
26 from pylons import app_globals as g
27 from rhodecode.model.db import Repository, RepoToPerm, User, Permission, \
27 from rhodecode.model.db import Repository, RepoToPerm, User, Permission, \
28 Statistics
28 Statistics
29 from rhodecode.model.meta import Session
29 from rhodecode.model import BaseModel
30 from rhodecode.model.user import UserModel
30 from rhodecode.model.user import UserModel
31 from rhodecode.model.caching_query import FromCache
31 from rhodecode.model.caching_query import FromCache
32 import logging
32 import logging
33 import os
33 import os
34 import shutil
34 import shutil
35 import traceback
35 import traceback
36 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
37
37
38 class RepoModel(object):
38 class RepoModel(BaseModel):
39
40 def __init__(self):
41 self.sa = Session()
42
39
43 def get(self, repo_id, cache=False):
40 def get(self, repo_id, cache=False):
44 repo = self.sa.query(Repository)\
41 repo = self.sa.query(Repository)\
45 .filter(Repository.repo_id == repo_id)
42 .filter(Repository.repo_id == repo_id)
46
43
47 if cache:
44 if cache:
48 repo = repo.options(FromCache("sql_cache_short",
45 repo = repo.options(FromCache("sql_cache_short",
49 "get_repo_%s" % repo_id))
46 "get_repo_%s" % repo_id))
50 return repo.scalar()
47 return repo.scalar()
51
48
52
49
53 def get_by_repo_name(self, repo_name, cache=False):
50 def get_by_repo_name(self, repo_name, cache=False):
54 repo = self.sa.query(Repository)\
51 repo = self.sa.query(Repository)\
55 .filter(Repository.repo_name == repo_name)
52 .filter(Repository.repo_name == repo_name)
56
53
57 if cache:
54 if cache:
58 repo = repo.options(FromCache("sql_cache_short",
55 repo = repo.options(FromCache("sql_cache_short",
59 "get_repo_%s" % repo_name))
56 "get_repo_%s" % repo_name))
60 return repo.scalar()
57 return repo.scalar()
61
58
62 def get_users_js(self):
59 def get_users_js(self):
63
60
64 users = self.sa.query(User).filter(User.active == True).all()
61 users = self.sa.query(User).filter(User.active == True).all()
65 u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},'''
62 u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},'''
66 users_array = '[%s];' % '\n'.join([u_tmpl % (u.user_id, u.name,
63 users_array = '[%s];' % '\n'.join([u_tmpl % (u.user_id, u.name,
67 u.lastname, u.username)
64 u.lastname, u.username)
68 for u in users])
65 for u in users])
69 return users_array
66 return users_array
70
67
71
68
72 def update(self, repo_name, form_data):
69 def update(self, repo_name, form_data):
73 try:
70 try:
74
71
75 #update permissions
72 #update permissions
76 for username, perm in form_data['perms_updates']:
73 for username, perm in form_data['perms_updates']:
77 r2p = self.sa.query(RepoToPerm)\
74 r2p = self.sa.query(RepoToPerm)\
78 .filter(RepoToPerm.user == UserModel()\
75 .filter(RepoToPerm.user == UserModel(self.sa)\
79 .get_by_username(username, cache=False))\
76 .get_by_username(username, cache=False))\
80 .filter(RepoToPerm.repository == \
77 .filter(RepoToPerm.repository == \
81 self.get_by_repo_name(repo_name))\
78 self.get_by_repo_name(repo_name))\
82 .one()
79 .one()
83
80
84 r2p.permission_id = self.sa.query(Permission).filter(
81 r2p.permission_id = self.sa.query(Permission).filter(
85 Permission.permission_name ==
82 Permission.permission_name ==
86 perm).one().permission_id
83 perm).one().permission_id
87 self.sa.add(r2p)
84 self.sa.add(r2p)
88
85
89 #set new permissions
86 #set new permissions
90 for username, perm in form_data['perms_new']:
87 for username, perm in form_data['perms_new']:
91 r2p = RepoToPerm()
88 r2p = RepoToPerm()
92 r2p.repository = self.get_by_repo_name(repo_name)
89 r2p.repository = self.get_by_repo_name(repo_name)
93 r2p.user = UserModel().get_by_username(username, cache=False)
90 r2p.user = UserModel(self.sa).get_by_username(username, cache=False)
94
91
95 r2p.permission_id = self.sa.query(Permission).filter(
92 r2p.permission_id = self.sa.query(Permission).filter(
96 Permission.permission_name == perm)\
93 Permission.permission_name == perm)\
97 .one().permission_id
94 .one().permission_id
98 self.sa.add(r2p)
95 self.sa.add(r2p)
99
96
100 #update current repo
97 #update current repo
101 cur_repo = self.get_by_repo_name(repo_name, cache=False)
98 cur_repo = self.get_by_repo_name(repo_name, cache=False)
102
99
103 for k, v in form_data.items():
100 for k, v in form_data.items():
104 if k == 'user':
101 if k == 'user':
105 cur_repo.user_id = v
102 cur_repo.user_id = v
106 else:
103 else:
107 setattr(cur_repo, k, v)
104 setattr(cur_repo, k, v)
108
105
109 self.sa.add(cur_repo)
106 self.sa.add(cur_repo)
110
107
111 if repo_name != form_data['repo_name']:
108 if repo_name != form_data['repo_name']:
112 #rename our data
109 #rename our data
113 self.__rename_repo(repo_name, form_data['repo_name'])
110 self.__rename_repo(repo_name, form_data['repo_name'])
114
111
115 self.sa.commit()
112 self.sa.commit()
116 except:
113 except:
117 log.error(traceback.format_exc())
114 log.error(traceback.format_exc())
118 self.sa.rollback()
115 self.sa.rollback()
119 raise
116 raise
120
117
121 def create(self, form_data, cur_user, just_db=False, fork=False):
118 def create(self, form_data, cur_user, just_db=False, fork=False):
122 try:
119 try:
123 if fork:
120 if fork:
124 #force str since hg doesn't go with unicode
121 #force str since hg doesn't go with unicode
125 repo_name = str(form_data['fork_name'])
122 repo_name = str(form_data['fork_name'])
126 org_name = str(form_data['repo_name'])
123 org_name = str(form_data['repo_name'])
127
124
128 else:
125 else:
129 org_name = repo_name = str(form_data['repo_name'])
126 org_name = repo_name = str(form_data['repo_name'])
130 new_repo = Repository()
127 new_repo = Repository()
131 for k, v in form_data.items():
128 for k, v in form_data.items():
132 if k == 'repo_name':
129 if k == 'repo_name':
133 v = repo_name
130 v = repo_name
134 setattr(new_repo, k, v)
131 setattr(new_repo, k, v)
135
132
136 if fork:
133 if fork:
137 parent_repo = self.sa.query(Repository)\
134 parent_repo = self.sa.query(Repository)\
138 .filter(Repository.repo_name == org_name).scalar()
135 .filter(Repository.repo_name == org_name).scalar()
139 new_repo.fork = parent_repo
136 new_repo.fork = parent_repo
140
137
141 new_repo.user_id = cur_user.user_id
138 new_repo.user_id = cur_user.user_id
142 self.sa.add(new_repo)
139 self.sa.add(new_repo)
143
140
144 #create default permission
141 #create default permission
145 repo_to_perm = RepoToPerm()
142 repo_to_perm = RepoToPerm()
146 default = 'repository.read'
143 default = 'repository.read'
147 for p in UserModel().get_by_username('default', cache=False).user_perms:
144 for p in UserModel(self.sa).get_by_username('default', cache=False).user_perms:
148 if p.permission.permission_name.startswith('repository.'):
145 if p.permission.permission_name.startswith('repository.'):
149 default = p.permission.permission_name
146 default = p.permission.permission_name
150 break
147 break
151
148
152 default_perm = 'repository.none' if form_data['private'] else default
149 default_perm = 'repository.none' if form_data['private'] else default
153
150
154 repo_to_perm.permission_id = self.sa.query(Permission)\
151 repo_to_perm.permission_id = self.sa.query(Permission)\
155 .filter(Permission.permission_name == default_perm)\
152 .filter(Permission.permission_name == default_perm)\
156 .one().permission_id
153 .one().permission_id
157
154
158 repo_to_perm.repository_id = new_repo.repo_id
155 repo_to_perm.repository_id = new_repo.repo_id
159 repo_to_perm.user_id = UserModel().get_by_username('default', cache=False).user_id
156 repo_to_perm.user_id = UserModel(self.sa)\
157 .get_by_username('default', cache=False).user_id
160
158
161 self.sa.add(repo_to_perm)
159 self.sa.add(repo_to_perm)
162 self.sa.commit()
160 self.sa.commit()
163 if not just_db:
161 if not just_db:
164 self.__create_repo(repo_name, form_data['repo_type'])
162 self.__create_repo(repo_name, form_data['repo_type'])
165 except:
163 except:
166 log.error(traceback.format_exc())
164 log.error(traceback.format_exc())
167 self.sa.rollback()
165 self.sa.rollback()
168 raise
166 raise
169
167
170 def create_fork(self, form_data, cur_user):
168 def create_fork(self, form_data, cur_user):
171 from rhodecode.lib.celerylib import tasks, run_task
169 from rhodecode.lib.celerylib import tasks, run_task
172 run_task(tasks.create_repo_fork, form_data, cur_user)
170 run_task(tasks.create_repo_fork, form_data, cur_user)
173
171
174 def delete(self, repo):
172 def delete(self, repo):
175 try:
173 try:
176 self.sa.delete(repo)
174 self.sa.delete(repo)
177 self.__delete_repo(repo)
175 self.__delete_repo(repo)
178 self.sa.commit()
176 self.sa.commit()
179 except:
177 except:
180 log.error(traceback.format_exc())
178 log.error(traceback.format_exc())
181 self.sa.rollback()
179 self.sa.rollback()
182 raise
180 raise
183
181
184 def delete_perm_user(self, form_data, repo_name):
182 def delete_perm_user(self, form_data, repo_name):
185 try:
183 try:
186 self.sa.query(RepoToPerm)\
184 self.sa.query(RepoToPerm)\
187 .filter(RepoToPerm.repository \
185 .filter(RepoToPerm.repository \
188 == self.get_by_repo_name(repo_name))\
186 == self.get_by_repo_name(repo_name))\
189 .filter(RepoToPerm.user_id == form_data['user_id']).delete()
187 .filter(RepoToPerm.user_id == form_data['user_id']).delete()
190 self.sa.commit()
188 self.sa.commit()
191 except:
189 except:
192 log.error(traceback.format_exc())
190 log.error(traceback.format_exc())
193 self.sa.rollback()
191 self.sa.rollback()
194 raise
192 raise
195
193
196 def delete_stats(self, repo_name):
194 def delete_stats(self, repo_name):
197 try:
195 try:
198 self.sa.query(Statistics)\
196 self.sa.query(Statistics)\
199 .filter(Statistics.repository == \
197 .filter(Statistics.repository == \
200 self.get_by_repo_name(repo_name)).delete()
198 self.get_by_repo_name(repo_name)).delete()
201 self.sa.commit()
199 self.sa.commit()
202 except:
200 except:
203 log.error(traceback.format_exc())
201 log.error(traceback.format_exc())
204 self.sa.rollback()
202 self.sa.rollback()
205 raise
203 raise
206
204
207
205
208 def __create_repo(self, repo_name, alias):
206 def __create_repo(self, repo_name, alias):
209 from rhodecode.lib.utils import check_repo
207 from rhodecode.lib.utils import check_repo
210 repo_path = os.path.join(g.base_path, repo_name)
208 repo_path = os.path.join(g.base_path, repo_name)
211 if check_repo(repo_name, g.base_path):
209 if check_repo(repo_name, g.base_path):
212 log.info('creating repo %s in %s', repo_name, repo_path)
210 log.info('creating repo %s in %s', repo_name, repo_path)
213 backend = get_backend(alias)
211 backend = get_backend(alias)
214 backend(repo_path, create=True)
212 backend(repo_path, create=True)
215
213
216 def __rename_repo(self, old, new):
214 def __rename_repo(self, old, new):
217 log.info('renaming repo from %s to %s', old, new)
215 log.info('renaming repo from %s to %s', old, new)
218
216
219 old_path = os.path.join(g.base_path, old)
217 old_path = os.path.join(g.base_path, old)
220 new_path = os.path.join(g.base_path, new)
218 new_path = os.path.join(g.base_path, new)
221 if os.path.isdir(new_path):
219 if os.path.isdir(new_path):
222 raise Exception('Was trying to rename to already existing dir %s',
220 raise Exception('Was trying to rename to already existing dir %s',
223 new_path)
221 new_path)
224 shutil.move(old_path, new_path)
222 shutil.move(old_path, new_path)
225
223
226 def __delete_repo(self, repo):
224 def __delete_repo(self, repo):
227 rm_path = os.path.join(g.base_path, repo.repo_name)
225 rm_path = os.path.join(g.base_path, repo.repo_name)
228 log.info("Removing %s", rm_path)
226 log.info("Removing %s", rm_path)
229 #disable hg/git
227 #disable hg/git
230 alias = repo.repo_type
228 alias = repo.repo_type
231 shutil.move(os.path.join(rm_path, '.%s' % alias),
229 shutil.move(os.path.join(rm_path, '.%s' % alias),
232 os.path.join(rm_path, 'rm__.%s' % alias))
230 os.path.join(rm_path, 'rm__.%s' % alias))
233 #disable repo
231 #disable repo
234 shutil.move(rm_path, os.path.join(g.base_path, 'rm__%s__%s' \
232 shutil.move(rm_path, os.path.join(g.base_path, 'rm__%s__%s' \
235 % (datetime.today(), repo.repo_name)))
233 % (datetime.today(), repo.repo_name)))
@@ -1,350 +1,347
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # Model for RhodeCode
3 # Model for RhodeCode
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on April 9, 2010
21 Created on April 9, 2010
22 Model for RhodeCode
22 Model for RhodeCode
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from beaker.cache import cache_region, region_invalidate
25 from beaker.cache import cache_region, region_invalidate
26 from mercurial import ui
26 from mercurial import ui
27 from rhodecode import BACKENDS
27 from rhodecode import BACKENDS
28 from rhodecode.lib import helpers as h
28 from rhodecode.lib import helpers as h
29 from rhodecode.lib.auth import HasRepoPermissionAny
29 from rhodecode.lib.auth import HasRepoPermissionAny
30 from rhodecode.lib.utils import get_repos, make_ui, action_logger
30 from rhodecode.lib.utils import get_repos, make_ui, action_logger
31 from rhodecode.model import meta
31 from rhodecode.model import BaseModel
32 from rhodecode.model.db import Repository, User, RhodeCodeUi, CacheInvalidation, \
32 from rhodecode.model.db import Repository, User, RhodeCodeUi, CacheInvalidation, \
33 UserFollowing
33 UserFollowing
34 from rhodecode.model.caching_query import FromCache
34 from rhodecode.model.caching_query import FromCache
35 from sqlalchemy.orm import joinedload
35 from sqlalchemy.orm import joinedload
36 from sqlalchemy.orm.session import make_transient
36 from sqlalchemy.orm.session import make_transient
37 from vcs import get_backend
37 from vcs import get_backend
38 from vcs.utils.helpers import get_scm
38 from vcs.utils.helpers import get_scm
39 from vcs.exceptions import RepositoryError, VCSError
39 from vcs.exceptions import RepositoryError, VCSError
40 from vcs.utils.lazy import LazyProperty
40 from vcs.utils.lazy import LazyProperty
41 import traceback
41 import traceback
42 import logging
42 import logging
43 import os
43 import os
44 import time
44 import time
45
45
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
48 class UserTemp(object):
48 class UserTemp(object):
49 def __init__(self, user_id):
49 def __init__(self, user_id):
50 self.user_id = user_id
50 self.user_id = user_id
51
51
52 class RepoTemp(object):
52 class RepoTemp(object):
53 def __init__(self, repo_id):
53 def __init__(self, repo_id):
54 self.repo_id = repo_id
54 self.repo_id = repo_id
55
55
56
56
57 class ScmModel(object):
57 class ScmModel(BaseModel):
58 """
58 """
59 Mercurial Model
59 Mercurial Model
60 """
60 """
61
61
62 def __init__(self):
63 self.sa = meta.Session()
64
65 @LazyProperty
62 @LazyProperty
66 def repos_path(self):
63 def repos_path(self):
67 """
64 """
68 Get's the repositories root path from database
65 Get's the repositories root path from database
69 """
66 """
70 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
67 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
71
68
72 return q.ui_value
69 return q.ui_value
73
70
74 def repo_scan(self, repos_path, baseui, initial=False):
71 def repo_scan(self, repos_path, baseui, initial=False):
75 """
72 """
76 Listing of repositories in given path. This path should not be a
73 Listing of repositories in given path. This path should not be a
77 repository itself. Return a dictionary of repository objects
74 repository itself. Return a dictionary of repository objects
78
75
79 :param repos_path: path to directory containing repositories
76 :param repos_path: path to directory containing repositories
80 :param baseui
77 :param baseui
81 :param initial: initial scan
78 :param initial: initial scan
82 """
79 """
83 log.info('scanning for repositories in %s', repos_path)
80 log.info('scanning for repositories in %s', repos_path)
84
81
85 if not isinstance(baseui, ui.ui):
82 if not isinstance(baseui, ui.ui):
86 baseui = make_ui('db')
83 baseui = make_ui('db')
87 repos_list = {}
84 repos_list = {}
88
85
89 for name, path in get_repos(repos_path):
86 for name, path in get_repos(repos_path):
90 try:
87 try:
91 if repos_list.has_key(name):
88 if repos_list.has_key(name):
92 raise RepositoryError('Duplicate repository name %s '
89 raise RepositoryError('Duplicate repository name %s '
93 'found in %s' % (name, path))
90 'found in %s' % (name, path))
94 else:
91 else:
95
92
96 klass = get_backend(path[0])
93 klass = get_backend(path[0])
97
94
98 if path[0] == 'hg' and path[0] in BACKENDS.keys():
95 if path[0] == 'hg' and path[0] in BACKENDS.keys():
99 repos_list[name] = klass(path[1], baseui=baseui)
96 repos_list[name] = klass(path[1], baseui=baseui)
100
97
101 if path[0] == 'git' and path[0] in BACKENDS.keys():
98 if path[0] == 'git' and path[0] in BACKENDS.keys():
102 repos_list[name] = klass(path[1])
99 repos_list[name] = klass(path[1])
103 except OSError:
100 except OSError:
104 continue
101 continue
105
102
106 return repos_list
103 return repos_list
107
104
108 def get_repos(self, all_repos=None):
105 def get_repos(self, all_repos=None):
109 """
106 """
110 Get all repos from db and for each repo create it's backend instance.
107 Get all repos from db and for each repo create it's backend instance.
111 and fill that backed with information from database
108 and fill that backed with information from database
112
109
113 :param all_repos: give specific repositories list, good for filtering
110 :param all_repos: give specific repositories list, good for filtering
114 """
111 """
115 if not all_repos:
112 if not all_repos:
116 all_repos = self.sa.query(Repository)\
113 all_repos = self.sa.query(Repository)\
117 .order_by(Repository.repo_name).all()
114 .order_by(Repository.repo_name).all()
118
115
119 invalidation_list = [str(x.cache_key) for x in \
116 invalidation_list = [str(x.cache_key) for x in \
120 self.sa.query(CacheInvalidation.cache_key)\
117 self.sa.query(CacheInvalidation.cache_key)\
121 .filter(CacheInvalidation.cache_active == False)\
118 .filter(CacheInvalidation.cache_active == False)\
122 .all()]
119 .all()]
123
120
124 for r in all_repos:
121 for r in all_repos:
125
122
126 repo = self.get(r.repo_name, invalidation_list)
123 repo = self.get(r.repo_name, invalidation_list)
127
124
128 if repo is not None:
125 if repo is not None:
129 last_change = repo.last_change
126 last_change = repo.last_change
130 tip = h.get_changeset_safe(repo, 'tip')
127 tip = h.get_changeset_safe(repo, 'tip')
131
128
132 tmp_d = {}
129 tmp_d = {}
133 tmp_d['name'] = repo.name
130 tmp_d['name'] = repo.name
134 tmp_d['name_sort'] = tmp_d['name'].lower()
131 tmp_d['name_sort'] = tmp_d['name'].lower()
135 tmp_d['description'] = repo.dbrepo.description
132 tmp_d['description'] = repo.dbrepo.description
136 tmp_d['description_sort'] = tmp_d['description']
133 tmp_d['description_sort'] = tmp_d['description']
137 tmp_d['last_change'] = last_change
134 tmp_d['last_change'] = last_change
138 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
135 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
139 tmp_d['tip'] = tip.raw_id
136 tmp_d['tip'] = tip.raw_id
140 tmp_d['tip_sort'] = tip.revision
137 tmp_d['tip_sort'] = tip.revision
141 tmp_d['rev'] = tip.revision
138 tmp_d['rev'] = tip.revision
142 tmp_d['contact'] = repo.dbrepo.user.full_contact
139 tmp_d['contact'] = repo.dbrepo.user.full_contact
143 tmp_d['contact_sort'] = tmp_d['contact']
140 tmp_d['contact_sort'] = tmp_d['contact']
144 tmp_d['repo_archives'] = list(repo._get_archives())
141 tmp_d['repo_archives'] = list(repo._get_archives())
145 tmp_d['last_msg'] = tip.message
142 tmp_d['last_msg'] = tip.message
146 tmp_d['repo'] = repo
143 tmp_d['repo'] = repo
147 yield tmp_d
144 yield tmp_d
148
145
149 def get_repo(self, repo_name):
146 def get_repo(self, repo_name):
150 return self.get(repo_name)
147 return self.get(repo_name)
151
148
152 def get(self, repo_name, invalidation_list=None):
149 def get(self, repo_name, invalidation_list=None):
153 """
150 """
154 Get's repository from given name, creates BackendInstance and
151 Get's repository from given name, creates BackendInstance and
155 propagates it's data from database with all additional information
152 propagates it's data from database with all additional information
156 :param repo_name:
153 :param repo_name:
157 """
154 """
158 if not HasRepoPermissionAny('repository.read', 'repository.write',
155 if not HasRepoPermissionAny('repository.read', 'repository.write',
159 'repository.admin')(repo_name, 'get repo check'):
156 'repository.admin')(repo_name, 'get repo check'):
160 return
157 return
161
158
162 @cache_region('long_term')
159 @cache_region('long_term')
163 def _get_repo(repo_name):
160 def _get_repo(repo_name):
164
161
165 repo_path = os.path.join(self.repos_path, repo_name)
162 repo_path = os.path.join(self.repos_path, repo_name)
166 alias = get_scm(repo_path)[0]
163 alias = get_scm(repo_path)[0]
167
164
168 log.debug('Creating instance of %s repository', alias)
165 log.debug('Creating instance of %s repository', alias)
169 backend = get_backend(alias)
166 backend = get_backend(alias)
170
167
171 #TODO: get the baseui from somewhere for this
168 #TODO: get the baseui from somewhere for this
172 if alias == 'hg':
169 if alias == 'hg':
173 from pylons import app_globals as g
170 from pylons import app_globals as g
174 repo = backend(repo_path, create=False, baseui=g.baseui)
171 repo = backend(repo_path, create=False, baseui=g.baseui)
175 #skip hidden web repository
172 #skip hidden web repository
176 if repo._get_hidden():
173 if repo._get_hidden():
177 return
174 return
178 else:
175 else:
179 repo = backend(repo_path, create=False)
176 repo = backend(repo_path, create=False)
180
177
181 dbrepo = self.sa.query(Repository)\
178 dbrepo = self.sa.query(Repository)\
182 .options(joinedload(Repository.fork))\
179 .options(joinedload(Repository.fork))\
183 .options(joinedload(Repository.user))\
180 .options(joinedload(Repository.user))\
184 .filter(Repository.repo_name == repo_name)\
181 .filter(Repository.repo_name == repo_name)\
185 .scalar()
182 .scalar()
186 make_transient(dbrepo)
183 make_transient(dbrepo)
187 repo.dbrepo = dbrepo
184 repo.dbrepo = dbrepo
188 return repo
185 return repo
189
186
190 pre_invalidate = True
187 pre_invalidate = True
191 if invalidation_list:
188 if invalidation_list:
192 pre_invalidate = repo_name in invalidation_list
189 pre_invalidate = repo_name in invalidation_list
193
190
194 if pre_invalidate:
191 if pre_invalidate:
195 invalidate = self._should_invalidate(repo_name)
192 invalidate = self._should_invalidate(repo_name)
196
193
197 if invalidate:
194 if invalidate:
198 log.info('invalidating cache for repository %s', repo_name)
195 log.info('invalidating cache for repository %s', repo_name)
199 region_invalidate(_get_repo, None, repo_name)
196 region_invalidate(_get_repo, None, repo_name)
200 self._mark_invalidated(invalidate)
197 self._mark_invalidated(invalidate)
201
198
202 return _get_repo(repo_name)
199 return _get_repo(repo_name)
203
200
204
201
205
202
206 def mark_for_invalidation(self, repo_name):
203 def mark_for_invalidation(self, repo_name):
207 """
204 """
208 Puts cache invalidation task into db for
205 Puts cache invalidation task into db for
209 further global cache invalidation
206 further global cache invalidation
210
207
211 :param repo_name: this repo that should invalidation take place
208 :param repo_name: this repo that should invalidation take place
212 """
209 """
213 log.debug('marking %s for invalidation', repo_name)
210 log.debug('marking %s for invalidation', repo_name)
214 cache = self.sa.query(CacheInvalidation)\
211 cache = self.sa.query(CacheInvalidation)\
215 .filter(CacheInvalidation.cache_key == repo_name).scalar()
212 .filter(CacheInvalidation.cache_key == repo_name).scalar()
216
213
217 if cache:
214 if cache:
218 #mark this cache as inactive
215 #mark this cache as inactive
219 cache.cache_active = False
216 cache.cache_active = False
220 else:
217 else:
221 log.debug('cache key not found in invalidation db -> creating one')
218 log.debug('cache key not found in invalidation db -> creating one')
222 cache = CacheInvalidation(repo_name)
219 cache = CacheInvalidation(repo_name)
223
220
224 try:
221 try:
225 self.sa.add(cache)
222 self.sa.add(cache)
226 self.sa.commit()
223 self.sa.commit()
227 except:
224 except:
228 log.error(traceback.format_exc())
225 log.error(traceback.format_exc())
229 self.sa.rollback()
226 self.sa.rollback()
230
227
231
228
232 def toggle_following_repo(self, follow_repo_id, user_id):
229 def toggle_following_repo(self, follow_repo_id, user_id):
233
230
234 f = self.sa.query(UserFollowing)\
231 f = self.sa.query(UserFollowing)\
235 .filter(UserFollowing.follows_repo_id == follow_repo_id)\
232 .filter(UserFollowing.follows_repo_id == follow_repo_id)\
236 .filter(UserFollowing.user_id == user_id).scalar()
233 .filter(UserFollowing.user_id == user_id).scalar()
237
234
238 if f is not None:
235 if f is not None:
239
236
240 try:
237 try:
241 self.sa.delete(f)
238 self.sa.delete(f)
242 self.sa.commit()
239 self.sa.commit()
243 action_logger(UserTemp(user_id),
240 action_logger(UserTemp(user_id),
244 'stopped_following_repo',
241 'stopped_following_repo',
245 RepoTemp(follow_repo_id))
242 RepoTemp(follow_repo_id))
246 return
243 return
247 except:
244 except:
248 log.error(traceback.format_exc())
245 log.error(traceback.format_exc())
249 self.sa.rollback()
246 self.sa.rollback()
250 raise
247 raise
251
248
252
249
253 try:
250 try:
254 f = UserFollowing()
251 f = UserFollowing()
255 f.user_id = user_id
252 f.user_id = user_id
256 f.follows_repo_id = follow_repo_id
253 f.follows_repo_id = follow_repo_id
257 self.sa.add(f)
254 self.sa.add(f)
258 self.sa.commit()
255 self.sa.commit()
259 action_logger(UserTemp(user_id),
256 action_logger(UserTemp(user_id),
260 'started_following_repo',
257 'started_following_repo',
261 RepoTemp(follow_repo_id))
258 RepoTemp(follow_repo_id))
262 except:
259 except:
263 log.error(traceback.format_exc())
260 log.error(traceback.format_exc())
264 self.sa.rollback()
261 self.sa.rollback()
265 raise
262 raise
266
263
267 def toggle_following_user(self, follow_user_id , user_id):
264 def toggle_following_user(self, follow_user_id , user_id):
268 f = self.sa.query(UserFollowing)\
265 f = self.sa.query(UserFollowing)\
269 .filter(UserFollowing.follows_user_id == follow_user_id)\
266 .filter(UserFollowing.follows_user_id == follow_user_id)\
270 .filter(UserFollowing.user_id == user_id).scalar()
267 .filter(UserFollowing.user_id == user_id).scalar()
271
268
272 if f is not None:
269 if f is not None:
273 try:
270 try:
274 self.sa.delete(f)
271 self.sa.delete(f)
275 self.sa.commit()
272 self.sa.commit()
276 return
273 return
277 except:
274 except:
278 log.error(traceback.format_exc())
275 log.error(traceback.format_exc())
279 self.sa.rollback()
276 self.sa.rollback()
280 raise
277 raise
281
278
282 try:
279 try:
283 f = UserFollowing()
280 f = UserFollowing()
284 f.user_id = user_id
281 f.user_id = user_id
285 f.follows_user_id = follow_user_id
282 f.follows_user_id = follow_user_id
286 self.sa.add(f)
283 self.sa.add(f)
287 self.sa.commit()
284 self.sa.commit()
288 except:
285 except:
289 log.error(traceback.format_exc())
286 log.error(traceback.format_exc())
290 self.sa.rollback()
287 self.sa.rollback()
291 raise
288 raise
292
289
293 def is_following_repo(self, repo_name, user_id):
290 def is_following_repo(self, repo_name, user_id):
294 r = self.sa.query(Repository)\
291 r = self.sa.query(Repository)\
295 .filter(Repository.repo_name == repo_name).scalar()
292 .filter(Repository.repo_name == repo_name).scalar()
296
293
297 f = self.sa.query(UserFollowing)\
294 f = self.sa.query(UserFollowing)\
298 .filter(UserFollowing.follows_repository == r)\
295 .filter(UserFollowing.follows_repository == r)\
299 .filter(UserFollowing.user_id == user_id).scalar()
296 .filter(UserFollowing.user_id == user_id).scalar()
300
297
301 return f is not None
298 return f is not None
302
299
303 def is_following_user(self, username, user_id):
300 def is_following_user(self, username, user_id):
304 u = self.sa.query(User)\
301 u = self.sa.query(User)\
305 .filter(User.username == username).scalar()
302 .filter(User.username == username).scalar()
306
303
307 f = self.sa.query(UserFollowing)\
304 f = self.sa.query(UserFollowing)\
308 .filter(UserFollowing.follows_user == u)\
305 .filter(UserFollowing.follows_user == u)\
309 .filter(UserFollowing.user_id == user_id).scalar()
306 .filter(UserFollowing.user_id == user_id).scalar()
310
307
311 return f is not None
308 return f is not None
312
309
313 def get_followers(self, repo_id):
310 def get_followers(self, repo_id):
314 return self.sa.query(UserFollowing)\
311 return self.sa.query(UserFollowing)\
315 .filter(UserFollowing.follows_repo_id == repo_id).count()
312 .filter(UserFollowing.follows_repo_id == repo_id).count()
316
313
317 def get_forks(self, repo_id):
314 def get_forks(self, repo_id):
318 return self.sa.query(Repository)\
315 return self.sa.query(Repository)\
319 .filter(Repository.fork_id == repo_id).count()
316 .filter(Repository.fork_id == repo_id).count()
320
317
321 def _should_invalidate(self, repo_name):
318 def _should_invalidate(self, repo_name):
322 """
319 """
323 Looks up database for invalidation signals for this repo_name
320 Looks up database for invalidation signals for this repo_name
324 :param repo_name:
321 :param repo_name:
325 """
322 """
326
323
327 ret = self.sa.query(CacheInvalidation)\
324 ret = self.sa.query(CacheInvalidation)\
328 .options(FromCache('sql_cache_short',
325 .options(FromCache('sql_cache_short',
329 'get_invalidation_%s' % repo_name))\
326 'get_invalidation_%s' % repo_name))\
330 .filter(CacheInvalidation.cache_key == repo_name)\
327 .filter(CacheInvalidation.cache_key == repo_name)\
331 .filter(CacheInvalidation.cache_active == False)\
328 .filter(CacheInvalidation.cache_active == False)\
332 .scalar()
329 .scalar()
333
330
334 return ret
331 return ret
335
332
336 def _mark_invalidated(self, cache_key):
333 def _mark_invalidated(self, cache_key):
337 """
334 """
338 Marks all occurences of cache to invaldation as already invalidated
335 Marks all occurences of cache to invaldation as already invalidated
339 @param repo_name:
336 @param repo_name:
340 """
337 """
341 if cache_key:
338 if cache_key:
342 log.debug('marking %s as already invalidated', cache_key)
339 log.debug('marking %s as already invalidated', cache_key)
343 try:
340 try:
344 cache_key.cache_active = True
341 cache_key.cache_active = True
345 self.sa.add(cache_key)
342 self.sa.add(cache_key)
346 self.sa.commit()
343 self.sa.commit()
347 except:
344 except:
348 log.error(traceback.format_exc())
345 log.error(traceback.format_exc())
349 self.sa.rollback()
346 self.sa.rollback()
350
347
@@ -1,79 +1,76
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # Model for RhodeCode settings
3 # Model for RhodeCode settings
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on Nov 17, 2010
21 Created on Nov 17, 2010
22 Model for RhodeCode
22 Model for RhodeCode
23 @author: marcink
23 :author: marcink
24 """
24 """
25
25 from rhodecode.lib import helpers as h
26 from rhodecode.lib import helpers as h
26 from rhodecode.model import meta
27 from rhodecode.model import BaseModel
27 from rhodecode.model.caching_query import FromCache
28 from rhodecode.model.caching_query import FromCache
28 from rhodecode.model.db import RhodeCodeSettings
29 from rhodecode.model.db import RhodeCodeSettings
29 from sqlalchemy.orm import joinedload
30 from sqlalchemy.orm import joinedload
30 from sqlalchemy.orm.session import make_transient
31 from sqlalchemy.orm.session import make_transient
31 import logging
32 import logging
32
33
33 log = logging.getLogger(__name__)
34 log = logging.getLogger(__name__)
34
35
35 class SettingsModel(object):
36 class SettingsModel(BaseModel):
36 """
37 """
37 Settings model
38 Settings model
38 """
39 """
39
40
40 def __init__(self):
41 self.sa = meta.Session()
42
43
44 def get(self, settings_key, cache=False):
41 def get(self, settings_key, cache=False):
45 r = self.sa.query(RhodeCodeSettings)\
42 r = self.sa.query(RhodeCodeSettings)\
46 .filter(RhodeCodeSettings.app_settings_name == settings_key).scalar()
43 .filter(RhodeCodeSettings.app_settings_name == settings_key).scalar()
47 if cache:
44 if cache:
48 r = r.options(FromCache("sql_cache_short",
45 r = r.options(FromCache("sql_cache_short",
49 "get_setting_%s" % settings_key))
46 "get_setting_%s" % settings_key))
50 return r
47 return r
51
48
52
49
53 def get_ldap_settings(self):
50 def get_ldap_settings(self):
54 """
51 """
55 Returns ldap settings from database
52 Returns ldap settings from database
56 :returns:
53 :returns:
57 ldap_active
54 ldap_active
58 ldap_host
55 ldap_host
59 ldap_port
56 ldap_port
60 ldap_ldaps
57 ldap_ldaps
61 ldap_dn_user
58 ldap_dn_user
62 ldap_dn_pass
59 ldap_dn_pass
63 ldap_base_dn
60 ldap_base_dn
64 """
61 """
65
62
66 r = self.sa.query(RhodeCodeSettings)\
63 r = self.sa.query(RhodeCodeSettings)\
67 .filter(RhodeCodeSettings.app_settings_name\
64 .filter(RhodeCodeSettings.app_settings_name\
68 .startswith('ldap_'))\
65 .startswith('ldap_'))\
69 .all()
66 .all()
70
67
71 fd = {}
68 fd = {}
72
69
73 for row in r:
70 for row in r:
74 v = row.app_settings_value
71 v = row.app_settings_value
75 if v in ['0', '1']:
72 if v in ['0', '1']:
76 v = v == '1'
73 v = v == '1'
77 fd.update({row.app_settings_name:v})
74 fd.update({row.app_settings_name:v})
78
75
79 return fd
76 return fd
@@ -1,220 +1,217
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # Model for users
3 # Model for users
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on April 9, 2010
21 Created on April 9, 2010
22 Model for users
22 Model for users
23 :author: marcink
23 :author: marcink
24 """
24 """
25
25
26 from pylons.i18n.translation import _
26 from pylons.i18n.translation import _
27 from rhodecode.model import BaseModel
27 from rhodecode.model.caching_query import FromCache
28 from rhodecode.model.caching_query import FromCache
28 from rhodecode.model.db import User
29 from rhodecode.model.db import User
29 from rhodecode.model.meta import Session
30 from rhodecode.lib.exceptions import *
30 from rhodecode.lib.exceptions import *
31
31
32 import logging
32 import logging
33 import traceback
33 import traceback
34
34
35 log = logging.getLogger(__name__)
35 log = logging.getLogger(__name__)
36
36
37
37
38
38
39 class UserModel(object):
39 class UserModel(BaseModel):
40
41 def __init__(self):
42 self.sa = Session()
43
40
44 def get(self, user_id, cache=False):
41 def get(self, user_id, cache=False):
45 user = self.sa.query(User)
42 user = self.sa.query(User)
46 if cache:
43 if cache:
47 user = user.options(FromCache("sql_cache_short",
44 user = user.options(FromCache("sql_cache_short",
48 "get_user_%s" % user_id))
45 "get_user_%s" % user_id))
49 return user.get(user_id)
46 return user.get(user_id)
50
47
51
48
52 def get_by_username(self, username, cache=False, case_insensitive=False):
49 def get_by_username(self, username, cache=False, case_insensitive=False):
53
50
54 if case_insensitive:
51 if case_insensitive:
55 user = self.sa.query(User).filter(User.username.ilike(username))
52 user = self.sa.query(User).filter(User.username.ilike(username))
56 else:
53 else:
57 user = self.sa.query(User)\
54 user = self.sa.query(User)\
58 .filter(User.username == username)
55 .filter(User.username == username)
59 if cache:
56 if cache:
60 user = user.options(FromCache("sql_cache_short",
57 user = user.options(FromCache("sql_cache_short",
61 "get_user_%s" % username))
58 "get_user_%s" % username))
62 return user.scalar()
59 return user.scalar()
63
60
64 def create(self, form_data):
61 def create(self, form_data):
65 try:
62 try:
66 new_user = User()
63 new_user = User()
67 for k, v in form_data.items():
64 for k, v in form_data.items():
68 setattr(new_user, k, v)
65 setattr(new_user, k, v)
69
66
70 self.sa.add(new_user)
67 self.sa.add(new_user)
71 self.sa.commit()
68 self.sa.commit()
72 except:
69 except:
73 log.error(traceback.format_exc())
70 log.error(traceback.format_exc())
74 self.sa.rollback()
71 self.sa.rollback()
75 raise
72 raise
76
73
77 def create_ldap(self, username, password):
74 def create_ldap(self, username, password):
78 """
75 """
79 Checks if user is in database, if not creates this user marked
76 Checks if user is in database, if not creates this user marked
80 as ldap user
77 as ldap user
81 :param username:
78 :param username:
82 :param password:
79 :param password:
83 """
80 """
84 from rhodecode.lib.auth import get_crypt_password
81 from rhodecode.lib.auth import get_crypt_password
85 if self.get_by_username(username) is None:
82 if self.get_by_username(username) is None:
86 try:
83 try:
87 new_user = User()
84 new_user = User()
88 new_user.username = username
85 new_user.username = username
89 new_user.password = get_crypt_password(password)
86 new_user.password = get_crypt_password(password)
90 new_user.email = '%s@ldap.server' % username
87 new_user.email = '%s@ldap.server' % username
91 new_user.active = True
88 new_user.active = True
92 new_user.is_ldap = True
89 new_user.is_ldap = True
93 new_user.name = '%s@ldap' % username
90 new_user.name = '%s@ldap' % username
94 new_user.lastname = ''
91 new_user.lastname = ''
95
92
96
93
97 self.sa.add(new_user)
94 self.sa.add(new_user)
98 self.sa.commit()
95 self.sa.commit()
99 return True
96 return True
100 except:
97 except:
101 log.error(traceback.format_exc())
98 log.error(traceback.format_exc())
102 self.sa.rollback()
99 self.sa.rollback()
103 raise
100 raise
104
101
105 return False
102 return False
106
103
107 def create_registration(self, form_data):
104 def create_registration(self, form_data):
108 from rhodecode.lib.celerylib import tasks, run_task
105 from rhodecode.lib.celerylib import tasks, run_task
109 try:
106 try:
110 new_user = User()
107 new_user = User()
111 for k, v in form_data.items():
108 for k, v in form_data.items():
112 if k != 'admin':
109 if k != 'admin':
113 setattr(new_user, k, v)
110 setattr(new_user, k, v)
114
111
115 self.sa.add(new_user)
112 self.sa.add(new_user)
116 self.sa.commit()
113 self.sa.commit()
117 body = ('New user registration\n'
114 body = ('New user registration\n'
118 'username: %s\n'
115 'username: %s\n'
119 'email: %s\n')
116 'email: %s\n')
120 body = body % (form_data['username'], form_data['email'])
117 body = body % (form_data['username'], form_data['email'])
121
118
122 run_task(tasks.send_email, None,
119 run_task(tasks.send_email, None,
123 _('[RhodeCode] New User registration'),
120 _('[RhodeCode] New User registration'),
124 body)
121 body)
125 except:
122 except:
126 log.error(traceback.format_exc())
123 log.error(traceback.format_exc())
127 self.sa.rollback()
124 self.sa.rollback()
128 raise
125 raise
129
126
130 def update(self, user_id, form_data):
127 def update(self, user_id, form_data):
131 try:
128 try:
132 new_user = self.get(user_id, cache=False)
129 new_user = self.get(user_id, cache=False)
133 if new_user.username == 'default':
130 if new_user.username == 'default':
134 raise DefaultUserException(
131 raise DefaultUserException(
135 _("You can't Edit this user since it's"
132 _("You can't Edit this user since it's"
136 " crucial for entire application"))
133 " crucial for entire application"))
137
134
138 for k, v in form_data.items():
135 for k, v in form_data.items():
139 if k == 'new_password' and v != '':
136 if k == 'new_password' and v != '':
140 new_user.password = v
137 new_user.password = v
141 else:
138 else:
142 setattr(new_user, k, v)
139 setattr(new_user, k, v)
143
140
144 self.sa.add(new_user)
141 self.sa.add(new_user)
145 self.sa.commit()
142 self.sa.commit()
146 except:
143 except:
147 log.error(traceback.format_exc())
144 log.error(traceback.format_exc())
148 self.sa.rollback()
145 self.sa.rollback()
149 raise
146 raise
150
147
151 def update_my_account(self, user_id, form_data):
148 def update_my_account(self, user_id, form_data):
152 try:
149 try:
153 new_user = self.get(user_id, cache=False)
150 new_user = self.get(user_id, cache=False)
154 if new_user.username == 'default':
151 if new_user.username == 'default':
155 raise DefaultUserException(
152 raise DefaultUserException(
156 _("You can't Edit this user since it's"
153 _("You can't Edit this user since it's"
157 " crucial for entire application"))
154 " crucial for entire application"))
158 for k, v in form_data.items():
155 for k, v in form_data.items():
159 if k == 'new_password' and v != '':
156 if k == 'new_password' and v != '':
160 new_user.password = v
157 new_user.password = v
161 else:
158 else:
162 if k not in ['admin', 'active']:
159 if k not in ['admin', 'active']:
163 setattr(new_user, k, v)
160 setattr(new_user, k, v)
164
161
165 self.sa.add(new_user)
162 self.sa.add(new_user)
166 self.sa.commit()
163 self.sa.commit()
167 except:
164 except:
168 log.error(traceback.format_exc())
165 log.error(traceback.format_exc())
169 self.sa.rollback()
166 self.sa.rollback()
170 raise
167 raise
171
168
172 def delete(self, user_id):
169 def delete(self, user_id):
173 try:
170 try:
174 user = self.get(user_id, cache=False)
171 user = self.get(user_id, cache=False)
175 if user.username == 'default':
172 if user.username == 'default':
176 raise DefaultUserException(
173 raise DefaultUserException(
177 _("You can't remove this user since it's"
174 _("You can't remove this user since it's"
178 " crucial for entire application"))
175 " crucial for entire application"))
179 if user.repositories:
176 if user.repositories:
180 raise UserOwnsReposException(_('This user still owns %s '
177 raise UserOwnsReposException(_('This user still owns %s '
181 'repositories and cannot be '
178 'repositories and cannot be '
182 'removed. Switch owners or '
179 'removed. Switch owners or '
183 'remove those repositories') \
180 'remove those repositories') \
184 % user.repositories)
181 % user.repositories)
185 self.sa.delete(user)
182 self.sa.delete(user)
186 self.sa.commit()
183 self.sa.commit()
187 except:
184 except:
188 log.error(traceback.format_exc())
185 log.error(traceback.format_exc())
189 self.sa.rollback()
186 self.sa.rollback()
190 raise
187 raise
191
188
192 def reset_password(self, data):
189 def reset_password(self, data):
193 from rhodecode.lib.celerylib import tasks, run_task
190 from rhodecode.lib.celerylib import tasks, run_task
194 run_task(tasks.reset_user_password, data['email'])
191 run_task(tasks.reset_user_password, data['email'])
195
192
196
193
197 def fill_data(self, user):
194 def fill_data(self, user):
198 """
195 """
199 Fills user data with those from database and log out user if not
196 Fills user data with those from database and log out user if not
200 present in database
197 present in database
201 :param user:
198 :param user:
202 """
199 """
203
200
204 if not hasattr(user, 'user_id') or user.user_id is None:
201 if not hasattr(user, 'user_id') or user.user_id is None:
205 raise Exception('passed in user has to have the user_id attribute')
202 raise Exception('passed in user has to have the user_id attribute')
206
203
207
204
208 log.debug('filling auth user data')
205 log.debug('filling auth user data')
209 try:
206 try:
210 dbuser = self.get(user.user_id)
207 dbuser = self.get(user.user_id)
211 user.username = dbuser.username
208 user.username = dbuser.username
212 user.is_admin = dbuser.admin
209 user.is_admin = dbuser.admin
213 user.name = dbuser.name
210 user.name = dbuser.name
214 user.lastname = dbuser.lastname
211 user.lastname = dbuser.lastname
215 user.email = dbuser.email
212 user.email = dbuser.email
216 except:
213 except:
217 log.error(traceback.format_exc())
214 log.error(traceback.format_exc())
218 user.is_authenticated = False
215 user.is_authenticated = False
219
216
220 return user
217 return user
General Comments 0
You need to be logged in to leave comments. Login now