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

« back to all changes in this revision

Viewing changes to ivle/makeuser.py

  • Committer: David Coles
  • Date: 2010-08-30 03:26:13 UTC
  • Revision ID: coles.david@gmail.com-20100830032613-d14vng0jkelniu3l
python-console: Fix globals broken with new JSON library.

simplejson always returns unicode strings. cJSON would return ordinary strings 
if possible. cPickle.loads() only accepts strings. At present we use pickle 
version 0 so they should all works as ASCII strings. Higher versions of pickle 
are not plain ASCII and are likely to break this and so this should be fixed 
at some point.

Also replaced unconditional exception with one that catches Pickle errors. Not 
sure the best way to report failures of these functions.

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.
69
72
        f.write("""
70
73
[%(login)s:/]
71
74
%(login)s = rw
72
 
""" % {'login': u.login})
 
75
""" % {'login': u.login.encode('utf-8')})
 
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.offering_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
                    Enrolment.active == True,
 
107
                )
 
108
            )
 
109
 
 
110
        f.write("""
 
111
# Submission %(id)d
 
112
[%(login)s:%(path)s]
 
113
""" % {'login': login.encode('utf-8'), 'id': psid,
 
114
       'path': pspath.encode('utf-8')})
 
115
 
 
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'))
73
121
 
74
122
    f.close()
75
123
    os.rename(temp_name, conf_name)
90
138
 
91
139
""" % {'time': time.asctime()})
92
140
 
 
141
    group_members_cache = {}
93
142
    for group in store.find(ProjectGroup):
94
143
        offering = group.project_set.offering
95
144
        reponame = "_".join([offering.subject.short_name,
96
145
                             offering.semester.year,
97
 
                             offering.semester.semester,
 
146
                             offering.semester.url_name,
98
147
                             group.name])
99
148
 
100
 
        f.write("[%s:/]\n" % reponame)
 
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()
101
152
        for user in group.members:
102
 
            f.write("%s = rw\n" % user.login)
 
153
            group_members_cache[group.id].add(user.login)
 
154
            f.write("%s = rw\n" % user.login.encode('utf-8'))
103
155
        f.write("\n")
104
156
 
 
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.url_name,
 
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
 
178
            )
 
179
        ):
 
180
 
 
181
        reponame = "_".join([ssn, year, sem, name])
 
182
 
 
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(
 
187
                    User.login,
 
188
                    User.id == Enrolment.user_id,
 
189
                    Enrolment.offering_id == offeringid,
 
190
                    Enrolment.role.is_in((u'tutor', u'lecturer')),
 
191
                    Enrolment.active == True,
 
192
                )
 
193
            )
 
194
 
 
195
        f.write("""
 
196
# Submission %(id)d
 
197
[%(repo)s:%(path)s]
 
198
""" % {'repo': reponame.encode('utf-8'), 'id': psid,
 
199
       'path': pspath.encode('utf-8')})
 
200
 
 
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)
 
205
 
105
206
    f.close()
106
207
    os.rename(temp_name, conf_name)
107
208
    chown_to_webserver(conf_name)
114
215
    """
115
216
    # filename is, eg, /var/lib/ivle/svn/ivle.auth
116
217
    filename = config['paths']['svn']['auth_ivle']
117
 
    passwd = hashlib.md5(uuid.uuid4().bytes).hexdigest()
118
218
    if os.path.exists(filename):
119
219
        create = ""
120
220
    else:
121
221
        create = "c"
122
222
 
123
223
    user = User.get_by_login(store, login)
124
 
    user.svn_pass = unicode(passwd)
 
224
 
 
225
    if user.svn_pass is None:
 
226
        passwd = hashlib.md5(uuid.uuid4().bytes).hexdigest()
 
227
        user.svn_pass = unicode(passwd)
125
228
 
126
229
    res = subprocess.call(['htpasswd', '-%smb' % create,
127
 
                           filename, login, passwd])
 
230
                           filename, login, user.svn_pass])
128
231
    if res != 0 and throw_on_error:
129
232
        raise Exception("Unable to create ivle-auth for %s" % login)
130
233
 
132
235
    if create == "c":
133
236
        chown_to_webserver(filename)
134
237
 
135
 
    return passwd
 
238
    return user.svn_pass
136
239
 
137
240
def make_jail(user, config, force=True):
138
241
    """Create or update a user's jail.
161
264
        os.mkdir(tempdir)
162
265
    userdir = os.path.join(jail_src_base, user.login)
163
266
    homedir = os.path.join(userdir, 'home')
 
267
    tmpdir = os.path.join(userdir, 'tmp')
164
268
    userhomedir = os.path.join(homedir, user.login)   # Return value
165
269
 
166
270
    if os.path.exists(userdir):
169
273
        # User jail already exists. Blow it away but preserve their home
170
274
        # directory. It should be all that is there anyway, but you never
171
275
        # know!
172
 
        # Ignore warnings about the use of tmpnam
 
276
        # Ignore warnings about the use of tempnam
173
277
        warnings.simplefilter('ignore')
174
278
        homebackup = os.tempnam(tempdir)
175
279
        warnings.resetwarnings()
178
282
        # NOTE that shutil.move changed in Python 2.6, it now moves a
179
283
        # directory INTO the target (like `mv`), which it didn't use to do.
180
284
        # This code works regardless.
181
 
        shutil.move(homedir, homebackup)
 
285
        shutil.move(userhomedir, homebackup)
182
286
        shutil.rmtree(userdir)
183
 
        os.makedirs(userdir)
184
 
        shutil.move(homebackup, homedir)
 
287
        os.makedirs(homedir)
 
288
        shutil.move(homebackup, userhomedir)
185
289
        # Change the ownership of all the files to the right unixid
186
290
        logging.debug("chown %s's home directory files to uid %d"
187
291
            %(user.login, user.unixid))
199
303
    make_ivle_conf(user.login, userdir, user.svn_pass, config)
200
304
    make_etc_passwd(user.login, userdir, config['paths']['jails']['template'],
201
305
                    user.unixid)
 
306
    os.makedirs(tmpdir)
 
307
    os.chmod(tmpdir, 01777)
202
308
 
203
309
    return userhomedir
204
310
 
213
319
    @param svn_pass: User's SVN password.
214
320
    @param sys_config: An ivle.config.Config object (the system-wide config).
215
321
    """
216
 
    conf_path = os.path.join(user_jail_dir, "etc/ivle/ivle.conf")
217
 
    os.makedirs(os.path.dirname(conf_path))
 
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))
218
325
 
219
326
    # In the "in-jail" version of conf, we don't need MOST of the details
220
327
    # (it would be a security risk to have them here).
221
328
    # So we just write root_dir.
222
329
    conf_obj = ivle.config.Config(blank=True)
223
330
    conf_obj.filename = conf_path
 
331
    conf_obj['urls'] = {}
224
332
    conf_obj['urls']['root'] = sys_config['urls']['root']
225
333
    conf_obj['urls']['public_host'] = sys_config['urls']['public_host']
226
334
    conf_obj['urls']['svn_addr'] = sys_config['urls']['svn_addr']
 
335
    conf_obj['user_info'] = {}
227
336
    conf_obj['user_info']['login'] = username
228
337
    conf_obj['user_info']['svn_pass'] = svn_pass
229
338
    conf_obj.write()
239
348
    Creates /etc/passwd in the given user's jail. This will be identical to
240
349
    that in the template jail, except for the added entry for this user.
241
350
    """
242
 
    template_passwd_path = os.path.join(template_dir, "etc/passwd")
243
 
    passwd_path = os.path.join(user_jail_dir, "etc/passwd")
 
351
    template_passwd_path = os.path.join(template_dir, "home/.passwd")
 
352
    passwd_path = os.path.join(user_jail_dir, "home/.passwd")
244
353
    passwd_dir = os.path.dirname(passwd_path)
245
354
    if not os.path.exists(passwd_dir):
246
355
        os.makedirs(passwd_dir)