~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/makeuser.py

Unbreak TestFramework's exception reporting mechanism, and report TestCreationErrors in test mode.

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
import logging
28
28
import subprocess
29
29
 
 
30
from storm.expr import Select, Max
 
31
 
30
32
import ivle.config
31
 
from ivle.database import ProjectGroup, User
 
33
from ivle.database import (User, ProjectGroup, Assessed, ProjectSubmission,
 
34
        Project, ProjectSet, Offering, Enrolment, Subject, Semester)
32
35
 
33
36
def chown_to_webserver(filename):
34
37
    """chown a directory and its contents to the web server.
71
74
%(login)s = rw
72
75
""" % {'login': u.login})
73
76
 
 
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,
 
85
         Offering.id),
 
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.id,
 
91
            ProjectSubmission.date_submitted == Select(
 
92
                    Max(ProjectSubmission.date_submitted),
 
93
                    ProjectSubmission.assessed_id == Assessed.id,
 
94
                    tables=ProjectSubmission
 
95
            )
 
96
        ):
 
97
 
 
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(
 
102
                    User.login,
 
103
                    User.id == Enrolment.user_id,
 
104
                    Enrolment.offering_id == offeringid,
 
105
                    Enrolment.role.is_in((u'tutor', u'lecturer'))
 
106
                )
 
107
            )
 
108
 
 
109
        f.write("""
 
110
# Submission %(id)d
 
111
[%(login)s:%(path)s]
 
112
""" % {'login': login, 'id': psid, 'path': pspath})
 
113
 
 
114
        for viewer_login in offering_viewers_cache[offeringid]:
 
115
            # We don't want to override the owner's write privilege,
 
116
            # so we don't add them to the read-only ACL.
 
117
            if login != viewer_login:
 
118
                f.write("%s = r\n" % viewer_login)
 
119
 
74
120
    f.close()
75
121
    os.rename(temp_name, conf_name)
76
122
    chown_to_webserver(conf_name)
90
136
 
91
137
""" % {'time': time.asctime()})
92
138
 
 
139
    group_members_cache = {}
93
140
    for group in store.find(ProjectGroup):
94
141
        offering = group.project_set.offering
95
142
        reponame = "_".join([offering.subject.short_name,
98
145
                             group.name])
99
146
 
100
147
        f.write("[%s:/]\n" % reponame)
 
148
        if group.id not in group_members_cache:
 
149
            group_members_cache[group.id] = set()
101
150
        for user in group.members:
 
151
            group_members_cache[group.id].add(user.login)
102
152
            f.write("%s = rw\n" % user.login)
103
153
        f.write("\n")
104
154
 
 
155
    # Now we need to grant offering tutors and lecturers access to the latest
 
156
    # submissions in their offerings. There are much prettier ways to do this,
 
157
    # but a lot of browser requests call this function, so it needs to be
 
158
    # fast. We can grab all of the paths needing authorisation directives with
 
159
    # a single query, and we cache the list of viewers for each offering.
 
160
    offering_viewers_cache = {}
 
161
    for (ssn, year, sem, name, psid, pspath, gid, offeringid) in store.find(
 
162
        (Subject.short_name, Semester.year, Semester.semester,
 
163
         ProjectGroup.name, ProjectSubmission.id, ProjectSubmission.path,
 
164
         ProjectGroup.id, Offering.id),
 
165
            Assessed.id == ProjectSubmission.assessed_id,
 
166
            ProjectGroup.id == Assessed.project_group_id,
 
167
            Project.id == Assessed.project_id,
 
168
            ProjectSet.id == Project.project_set_id,
 
169
            Offering.id == ProjectSet.offering_id,
 
170
            Subject.id == Offering.subject_id,
 
171
            Semester.id == Offering.semester_id,
 
172
            ProjectSubmission.date_submitted == Select(
 
173
                    Max(ProjectSubmission.date_submitted),
 
174
                    ProjectSubmission.assessed_id == Assessed.id,
 
175
                    tables=ProjectSubmission
 
176
            )
 
177
        ):
 
178
 
 
179
        reponame = "_".join([ssn, year, sem, name])
 
180
 
 
181
        # Do we already have the list of logins authorised for this offering
 
182
        # cached? If not, get it.
 
183
        if offeringid not in offering_viewers_cache:
 
184
            offering_viewers_cache[offeringid] = list(store.find(
 
185
                    User.login,
 
186
                    User.id == Enrolment.user_id,
 
187
                    Enrolment.offering_id == offeringid,
 
188
                    Enrolment.role.is_in((u'tutor', u'lecturer'))
 
189
                )
 
190
            )
 
191
 
 
192
        f.write("""
 
193
# Submission %(id)d
 
194
[%(repo)s:%(path)s]
 
195
""" % {'repo': reponame, 'id': psid, 'path': pspath})
 
196
 
 
197
        for viewer_login in offering_viewers_cache[offeringid]:
 
198
            # Skip existing group members, or they can't write to it any more.
 
199
            if viewer_login not in group_members_cache[gid]:
 
200
                f.write("%s = r\n" % viewer_login)
 
201
 
105
202
    f.close()
106
203
    os.rename(temp_name, conf_name)
107
204
    chown_to_webserver(conf_name)
114
211
    """
115
212
    # filename is, eg, /var/lib/ivle/svn/ivle.auth
116
213
    filename = config['paths']['svn']['auth_ivle']
117
 
    passwd = hashlib.md5(uuid.uuid4().bytes).hexdigest()
118
214
    if os.path.exists(filename):
119
215
        create = ""
120
216
    else:
121
217
        create = "c"
122
218
 
123
219
    user = User.get_by_login(store, login)
124
 
    user.svn_pass = unicode(passwd)
 
220
 
 
221
    if user.svn_pass is None:
 
222
        passwd = hashlib.md5(uuid.uuid4().bytes).hexdigest()
 
223
        user.svn_pass = unicode(passwd)
125
224
 
126
225
    res = subprocess.call(['htpasswd', '-%smb' % create,
127
 
                           filename, login, passwd])
 
226
                           filename, login, user.svn_pass])
128
227
    if res != 0 and throw_on_error:
129
228
        raise Exception("Unable to create ivle-auth for %s" % login)
130
229
 
132
231
    if create == "c":
133
232
        chown_to_webserver(filename)
134
233
 
135
 
    return passwd
 
234
    return user.svn_pass
136
235
 
137
236
def make_jail(user, config, force=True):
138
237
    """Create or update a user's jail.
161
260
        os.mkdir(tempdir)
162
261
    userdir = os.path.join(jail_src_base, user.login)
163
262
    homedir = os.path.join(userdir, 'home')
 
263
    tmpdir = os.path.join(userdir, 'tmp')
164
264
    userhomedir = os.path.join(homedir, user.login)   # Return value
165
265
 
166
266
    if os.path.exists(userdir):
178
278
        # NOTE that shutil.move changed in Python 2.6, it now moves a
179
279
        # directory INTO the target (like `mv`), which it didn't use to do.
180
280
        # This code works regardless.
181
 
        shutil.move(homedir, homebackup)
 
281
        shutil.move(userhomedir, homebackup)
182
282
        shutil.rmtree(userdir)
183
 
        os.makedirs(userdir)
184
 
        shutil.move(homebackup, homedir)
 
283
        os.makedirs(homedir)
 
284
        shutil.move(homebackup, userhomedir)
185
285
        # Change the ownership of all the files to the right unixid
186
286
        logging.debug("chown %s's home directory files to uid %d"
187
287
            %(user.login, user.unixid))
199
299
    make_ivle_conf(user.login, userdir, user.svn_pass, config)
200
300
    make_etc_passwd(user.login, userdir, config['paths']['jails']['template'],
201
301
                    user.unixid)
 
302
    os.makedirs(tmpdir)
 
303
    os.chmod(tmpdir, 01777)
202
304
 
203
305
    return userhomedir
204
306
 
213
315
    @param svn_pass: User's SVN password.
214
316
    @param sys_config: An ivle.config.Config object (the system-wide config).
215
317
    """
216
 
    conf_path = os.path.join(user_jail_dir, "etc/ivle/ivle.conf")
217
 
    os.makedirs(os.path.dirname(conf_path))
 
318
    conf_path = os.path.join(user_jail_dir, "home/.ivle.conf")
 
319
    if not os.path.exists(os.path.dirname(conf_path)):
 
320
        os.makedirs(os.path.dirname(conf_path))
218
321
 
219
322
    # In the "in-jail" version of conf, we don't need MOST of the details
220
323
    # (it would be a security risk to have them here).
239
342
    Creates /etc/passwd in the given user's jail. This will be identical to
240
343
    that in the template jail, except for the added entry for this user.
241
344
    """
242
 
    template_passwd_path = os.path.join(template_dir, "etc/passwd")
243
 
    passwd_path = os.path.join(user_jail_dir, "etc/passwd")
 
345
    template_passwd_path = os.path.join(template_dir, "home/.passwd")
 
346
    passwd_path = os.path.join(user_jail_dir, "home/.passwd")
244
347
    passwd_dir = os.path.dirname(passwd_path)
245
348
    if not os.path.exists(passwd_dir):
246
349
        os.makedirs(passwd_dir)