30
from storm.expr import Select, Max
33
from ivle.database import (User, ProjectGroup, Assessed, ProjectSubmission,
34
Project, ProjectSet, Offering, Enrolment, Subject, Semester)
31
from ivle.database import ProjectGroup, User
36
33
def chown_to_webserver(filename):
37
34
"""chown a directory and its contents to the web server.
75
""" % {'login': u.login.encode('utf-8')})
77
# Now we need to grant offering tutors and lecturers access to the latest
78
# submissions in their offerings. There are much prettier ways to do this,
79
# but a lot of browser requests call this function, so it needs to be
80
# fast. We can grab all of the paths needing authorisation directives with
81
# a single query, and we cache the list of viewers for each offering.
82
offering_viewers_cache = {}
83
for (login, psid, pspath, offeringid) in store.find(
84
(User.login, ProjectSubmission.id, ProjectSubmission.path,
86
Assessed.id == ProjectSubmission.assessed_id,
87
User.id == Assessed.user_id,
88
Project.id == Assessed.project_id,
89
ProjectSet.id == Project.project_set_id,
90
Offering.id == ProjectSet.offering_id,
91
ProjectSubmission.date_submitted == Select(
92
Max(ProjectSubmission.date_submitted),
93
ProjectSubmission.assessed_id == Assessed.id,
94
tables=ProjectSubmission
98
# Do we already have the list of logins authorised for this offering
99
# cached? If not, get it.
100
if offeringid not in offering_viewers_cache:
101
offering_viewers_cache[offeringid] = list(store.find(
103
User.id == Enrolment.user_id,
104
Enrolment.offering_id == offeringid,
105
Enrolment.role.is_in((u'tutor', u'lecturer')),
106
Enrolment.active == True,
113
""" % {'login': login.encode('utf-8'), 'id': psid,
114
'path': pspath.encode('utf-8')})
116
for viewer_login in offering_viewers_cache[offeringid]:
117
# We don't want to override the owner's write privilege,
118
# so we don't add them to the read-only ACL.
119
if login != viewer_login:
120
f.write("%s = r\n" % viewer_login.encode('utf-8'))
72
""" % {'login': u.login})
123
75
os.rename(temp_name, conf_name)
146
97
offering.semester.semester,
149
f.write("[%s:/]\n" % reponame.encode('utf-8'))
150
if group.id not in group_members_cache:
151
group_members_cache[group.id] = set()
100
f.write("[%s:/]\n" % reponame)
152
101
for user in group.members:
153
group_members_cache[group.id].add(user.login)
154
f.write("%s = rw\n" % user.login.encode('utf-8'))
102
f.write("%s = rw\n" % user.login)
157
# Now we need to grant offering tutors and lecturers access to the latest
158
# submissions in their offerings. There are much prettier ways to do this,
159
# but a lot of browser requests call this function, so it needs to be
160
# fast. We can grab all of the paths needing authorisation directives with
161
# a single query, and we cache the list of viewers for each offering.
162
offering_viewers_cache = {}
163
for (ssn, year, sem, name, psid, pspath, gid, offeringid) in store.find(
164
(Subject.short_name, Semester.year, Semester.semester,
165
ProjectGroup.name, ProjectSubmission.id, ProjectSubmission.path,
166
ProjectGroup.id, Offering.id),
167
Assessed.id == ProjectSubmission.assessed_id,
168
ProjectGroup.id == Assessed.project_group_id,
169
Project.id == Assessed.project_id,
170
ProjectSet.id == Project.project_set_id,
171
Offering.id == ProjectSet.offering_id,
172
Subject.id == Offering.subject_id,
173
Semester.id == Offering.semester_id,
174
ProjectSubmission.date_submitted == Select(
175
Max(ProjectSubmission.date_submitted),
176
ProjectSubmission.assessed_id == Assessed.id,
177
tables=ProjectSubmission
181
reponame = "_".join([ssn, year, sem, name])
183
# Do we already have the list of logins authorised for this offering
184
# cached? If not, get it.
185
if offeringid not in offering_viewers_cache:
186
offering_viewers_cache[offeringid] = list(store.find(
188
User.id == Enrolment.user_id,
189
Enrolment.offering_id == offeringid,
190
Enrolment.role.is_in((u'tutor', u'lecturer')),
191
Enrolment.active == True,
198
""" % {'repo': reponame.encode('utf-8'), 'id': psid,
199
'path': pspath.encode('utf-8')})
201
for viewer_login in offering_viewers_cache[offeringid]:
202
# Skip existing group members, or they can't write to it any more.
203
if viewer_login not in group_members_cache[gid]:
204
f.write("%s = r\n" % viewer_login)
207
106
os.rename(temp_name, conf_name)
208
107
chown_to_webserver(conf_name)
216
115
# filename is, eg, /var/lib/ivle/svn/ivle.auth
217
116
filename = config['paths']['svn']['auth_ivle']
117
passwd = hashlib.md5(uuid.uuid4().bytes).hexdigest()
218
118
if os.path.exists(filename):
223
123
user = User.get_by_login(store, login)
225
if user.svn_pass is None:
226
passwd = hashlib.md5(uuid.uuid4().bytes).hexdigest()
227
user.svn_pass = unicode(passwd)
124
user.svn_pass = unicode(passwd)
229
126
res = subprocess.call(['htpasswd', '-%smb' % create,
230
filename, login, user.svn_pass])
127
filename, login, passwd])
231
128
if res != 0 and throw_on_error:
232
129
raise Exception("Unable to create ivle-auth for %s" % login)
282
178
# NOTE that shutil.move changed in Python 2.6, it now moves a
283
179
# directory INTO the target (like `mv`), which it didn't use to do.
284
180
# This code works regardless.
285
shutil.move(userhomedir, homebackup)
181
shutil.move(homedir, homebackup)
286
182
shutil.rmtree(userdir)
288
shutil.move(homebackup, userhomedir)
184
shutil.move(homebackup, homedir)
289
185
# Change the ownership of all the files to the right unixid
290
186
logging.debug("chown %s's home directory files to uid %d"
291
187
%(user.login, user.unixid))
319
213
@param svn_pass: User's SVN password.
320
214
@param sys_config: An ivle.config.Config object (the system-wide config).
322
conf_path = os.path.join(user_jail_dir, "home/.ivle.conf")
323
if not os.path.exists(os.path.dirname(conf_path)):
324
os.makedirs(os.path.dirname(conf_path))
216
conf_path = os.path.join(user_jail_dir, "etc/ivle/ivle.conf")
217
os.makedirs(os.path.dirname(conf_path))
326
219
# In the "in-jail" version of conf, we don't need MOST of the details
327
220
# (it would be a security risk to have them here).
328
221
# So we just write root_dir.
329
222
conf_obj = ivle.config.Config(blank=True)
330
223
conf_obj.filename = conf_path
331
conf_obj['urls'] = {}
332
224
conf_obj['urls']['root'] = sys_config['urls']['root']
333
225
conf_obj['urls']['public_host'] = sys_config['urls']['public_host']
334
226
conf_obj['urls']['svn_addr'] = sys_config['urls']['svn_addr']
335
conf_obj['user_info'] = {}
336
227
conf_obj['user_info']['login'] = username
337
228
conf_obj['user_info']['svn_pass'] = svn_pass
348
239
Creates /etc/passwd in the given user's jail. This will be identical to
349
240
that in the template jail, except for the added entry for this user.
351
template_passwd_path = os.path.join(template_dir, "home/.passwd")
352
passwd_path = os.path.join(user_jail_dir, "home/.passwd")
242
template_passwd_path = os.path.join(template_dir, "etc/passwd")
243
passwd_path = os.path.join(user_jail_dir, "etc/passwd")
353
244
passwd_dir = os.path.dirname(passwd_path)
354
245
if not os.path.exists(passwd_dir):
355
246
os.makedirs(passwd_dir)