def slot_deletedb(self, arg):
        """This is a dangerous one! It will completely delete a database.
        """
        if not confirmationDialog(_("Delete Database?"),
                argSub(_("Do you really want to delete database '%1'?"),
                        (self.dbname,)), False):
            return
        if not self.master:
            return
        self.deletedb(self.dbname)

        # adjust display, select new db
        self.initDBlist()
Example #2
0
    def slot_deletedb(self, arg):
        """This is a dangerous one! It will completely delete a database.
        """
        if not confirmationDialog(
                _("Delete Database?"),
                argSub(_("Do you really want to delete database '%1'?"),
                       (self.dbname, )), False):
            return
        if not self.master:
            return
        self.deletedb(self.dbname)

        # adjust display, select new db
        self.initDBlist()
    def newRole(self, name, properties):
        """Create a new role (user) with the given properties.
        If the user exists already, try to delete it. If that
        doesn't work, ask if its properties should be altered.
        If even that fails (or is rejected) raise an exception.
        """
        try:
            self.send(u"DROP ROLE IF EXISTS %s" % name)
        except:
            pass
        if self.userExists(name) and confirmationDialog(
            _("Problem removing user"), _("Couldn't drop user '%s'.\n" "Alter its properties?") % name, True
        ):
            com = u"ALTER"
        else:
            com = u"CREATE"

        self.send(com + u" ROLE " + name + u" WITH " + properties)
Example #4
0
def recreate(dbm, filepath, user, gui):
    """Recreate the user database, taking master update lock
    into consideration. NOTE that this 'lock' is not 100%
    effective, but it is a simple method which I hope will be
    adequate for the envisaged application.
    """
    dir = os.path.dirname(filepath)
    while True:
        udt = getudtime(dbm)
        if not mUnstable(dbm):
            break
        gui.report(_("Master database is in unstable state.\n  Waiting ..."))
        sleep(10)

    # Dump the master database to the selected file
    while True:
        dump = Dump(dbm, dir, user)
        if dump.filepath:
            break
        warning(_("Couldn't create database file in folder %1,"
                " select new folder"), (dir,))
        dir = getDirectory(dir)
        if not dir:
            if confirmationDialog(_("Abandon?"),
                    _("User database not regenerated,"
                    " do you really want to abandon this operation?"), False):
                break

    if dump.filepath:
        dump.run(gui)

    fp = dump.filepath
    dump = None
    if fp:
        # Check master database hasn't been updated
        if (udt == getudtime(dbm)):
            gui.report(_("\nSUCCESS! - User database regenerated"))
        else:
            gui.report(_("Master has been updated,"
                    " need to repeat...\n"))
            recreate(dbm, filepath, user, gui)
    else:
        gui.report(_("\nFAILED! Couldn't regenerate user database.\n"
                " --- Please contact administrator!"))
Example #5
0
def checkOverwrite(path, force):
    """If the file exists, ask whether to delete it and return the
    answer. If the answer was affirmative, delete the file.
    If the end result is that there is now no file of that name,
    return True, else False.
    """
    if os.path.exists(path):
        if force or confirmationDialog(_("Overwrite?"),
                _("File '%s' exists already. Delete it?") % path):

            try:
                os.remove(path)
            except:
                warning(_("Couldn't delete file '%s'") % path)
                return False

        else:
            return False
    return True
    def addUser(self, login):
        """Add a new 'normal' user, with limited rights.
        """
        if self.db.userExists(login):

            if confirmationDialog(_("User name problem"),
                    argSub(_("User '%1' already exists. Try to recreate?"),
                    (login,)), True):

                if not self.removeUser(login):
                    raise

        try:
            self.db.createRole(login, USERROLE)
        except:
            #print_exc()
            message(_("Database Problem: Couldn't create user '%1'"),
                    (login,))
            raise
Example #7
0
def checkOverwrite(path, force):
    """If the file exists, ask whether to delete it and return the
    answer. If the answer was affirmative, delete the file.
    If the end result is that there is now no file of that name,
    return True, else False.
    """
    if os.path.exists(path):
        if force or confirmationDialog(
                _("Overwrite?"),
                _("File '%s' exists already. Delete it?") % path):

            try:
                os.remove(path)
            except:
                warning(_("Couldn't delete file '%s'") % path)
                return False

        else:
            return False
    return True
Example #8
0
    def addUser(self, login):
        """Add a new 'normal' user, with limited rights.
        """
        if self.db.userExists(login):

            if confirmationDialog(
                    _("User name problem"),
                    argSub(_("User '%1' already exists. Try to recreate?"),
                           (login, )), True):

                if not self.removeUser(login):
                    raise

        try:
            self.db.createRole(login, USERROLE)
        except:
            #print_exc()
            message(_("Database Problem: Couldn't create user '%1'"),
                    (login, ))
            raise
    def slot_finalize(self, on):
        """'Finalize' the database.
        Set the 'finalized' item in the 'config' table and revoke
        update privelege from teachers.
        """
        if (not self.master) or (on == self.finalized):
            return

        if on:
            if not confirmationDialog(_("Finalize Database?"),
                argSub(_("Finalizing stops teachers' access to the database.\n"
                        "It may also clear their passwords.\n  Continue?"),
                        (self.dbname,)), False):
                return
            val = u"1"
        else:
            val = u""
        self.master.send(u"""UPDATE config SET value= ?
                WHERE id = 'finalized'""", (val,))
        self.showFinalized(on)
        self.usersPrivileges(self.master)
Example #10
0
    def slot_finalize(self, on):
        """'Finalize' the database.
        Set the 'finalized' item in the 'config' table and revoke
        update privelege from teachers.
        """
        if (not self.master) or (on == self.finalized):
            return

        if on:
            if not confirmationDialog(
                    _("Finalize Database?"),
                    argSub(
                        _("Finalizing stops teachers' access to the database.\n"
                          "It may also clear their passwords.\n  Continue?"),
                        (self.dbname, )), False):
                return
            val = u"1"
        else:
            val = u""
        self.master.send(
            u"""UPDATE config SET value= ?
                WHERE id = 'finalized'""", (val, ))
        self.showFinalized(on)
        self.usersPrivileges(self.master)
Example #11
0
    def run(self, ui):
        minCols = 0
        for v in self.columns.values():
            if (v > minCols):
                minCols = v
        self.ui = ui
        for f in os.listdir(self.idir):
            if not f.endswith('.csv'):
                self.report(_("Ignoring '%s'") % f)
                continue

            classTag = f[:-4]   # cut off the ending
            classPath = "classes/" + classTag
            if not self.configEd.pathExists(classPath + '/'):
                self.report(_("ERROR: There is no class with tag '%s'")
                        % classTag)
                continue


            lastId = self.configEd.getField(classPath + "/info", "lastId")
            if (lastId > 0):
                if not confirmationDialog(_("Warning"),
                        _("Reloading pupil information can lead to loss"
                        " or mixing up of reports. Continue?"),
                        False):
                    continue

            self.report(_("Removing all pupils from class '%s'") % classTag)
            pupilPath = classPath + "/pupils"
            self.configEd.emptyDir(pupilPath)

            # Open the input file
            fi = os.path.join(self.idir, f)
            fih = open(fi, "rb")
            self.report(_("Fetching pupils from file '%s'") % fi)

            ln = 0
            id = 0      # counter for automatic id
            for line in fih:
                ln += 1
                line = line.strip()
                if (not line) or (line[0] == '#'):
                    continue

                # 'Strip' the individual columns
                cols = []
                for cv in [c.strip() for c in line.split(self.colSep)]:
                    r = quoteStrip.match(cv)
                    if r:
                        cv = r.group(1)
                    cols.append(cv)

                if (len(cols) < minCols):
                    self.report(_("ERROR: Insufficient columns at line %d")
                            % ln)
                    continue

                # Write out the file for this pupil
                if (self.idcol == 0 ):
                    id += 1
                    pfile = "%03d" % id
                else:
                    id -= 1
                    pfile = cols[self.idcol]
                opstring = ''
                for field, ix in self.columns.items():
                    if ix:
                        value = cols[ix - 1]
                    else:
                        value = ''
                    if (field != "id"):
                        opstring += "%s = %s\n" % (field, value)

                self.configEd.addPupil(pupilPath, pfile, opstring)

            self.report(_("Imported %d pupils\n") % abs(id))
            self.configEd.endPupils(classPath, id)
Example #12
0
    def slot_restore(self, arg):
        """Restore a dumped database.
        It can be either an existing one, or one which has been deleted.
        """
        # Get source file:
        dbpath = self.getBDbPath()
        if not dbpath: return None

        restore = Restore(dbpath)
        dbname = restore.getDbName()
        if not dbname:
            message(_("Couldn't open database file '%1'"), (dbpath, ))
            return

        state = 0
        try:

            if dbname in self.dbList:
                if not confirmationDialog(
                        _("Replace Database?"),
                        argSub(
                            _("Are you sure you want to replace database '%1'?"
                              ), (dbname, )), False):
                    restore.close()
                    return
                self.deletedb(dbname)

            self.db.send(u"""CREATE DATABASE %s
                    OWNER %s ENCODING 'UTF8'""" % (dbname, ADMIN))
            state = 1
            # Add to 'databases' table
            self.db.send(u"INSERT INTO databases VALUES (?, ?, ?, ?)",
                         (self.db.getTime(), dbname, u'', u''))
            state = 2

            newmaster = self.connect(dbname)
            state = 3

            guimessage = argSub(
                _("New database '%1' created, now read in the data"),
                (dbname, ))
            restore.setMaster(newmaster)
            guiReport(_("Restore Database"), restore, guimessage)
            #message(_("New database now set up"))

            self.usersPrivileges(newmaster)

            # Ensure connection is closed
            restore = None
            newmaster.close()
            newmaster = None

        except:
            print_exc()

            message(_("Couldn't create new database (%1)"), (dbname, ))
            if (state >= 3):
                newmaster.close()
            if (state >= 2):
                self.db.send(u"DELETE FROM databases WHERE name = ?",
                             (dbname, ))
            if (state >= 1):
                self.db.send(u"DROP DATABASE %s" % dbname)

        # adjust display, select new db
        self.initDBlist()
Example #13
0
def go():
    gui.report("  ------------------------------------\n")
    # Connect to control database
    connectData = getConnectInfo(app.settings, "postgres")
    if not connectData:
        return False

    gui.report(_("Connecting to postgres@%s") % connectData[u"host"])

    dbzc = connectData[u"db"]
    connectData[u"db"] = u"postgres"
    dbp = DB(connectData)
    if not dbp.isOpen():
        error(_("Couldn't open 'postgres' database"))
        return False

    gui.report(_("Checking existing databases"))

    if dbp.read1(u"SELECT datname FROM pg_database WHERE datname = ?",
            (dbzc,)):
        if not confirmationDialog(_("Remove Control Database?"),
                _("The control database (%s) already exists."
                  " Should it be removed, with everything it contains?")
                        % dbzc, False):
            dbp.close()
            return False

        connectData[u"db"] = dbzc
        userset = set()
        try:
            # Remove all databases and users
            db = DB(connectData)
            try:
                info = db.read(u"SELECT * FROM databases")
            except:
                info = None
            db.close()
            if info:
                for id, name, finalized, users in info:
                    gui.report(_("Removing database '%s'") % name)
                    dbp.send(u"DROP DATABASE IF EXISTS %s" % name)
                    userset |= set(users.split())

            gui.report(_("Removing database '%s'") % dbzc)
            dbp.send(u"DROP DATABASE %s" % dbzc)

        except:
            #print_exc()

            error(_("Couldn't remove old data -"
                    " summon a PostgreSQL expert:\n%s") % format_exc())

        gui.report(_("Trying to remove users ..."))
        try:
            dbp.send(u"DROP ROLE IF EXISTS %s" % USERROLE)
        except:
            gui.report(_("  ... couldn't remove user '%s'") % USERROLE)
        try:
            dbp.send(u"DROP ROLE IF EXISTS %s" % ADMIN)
        except:
            gui.report(_("  ... couldn't remove user '%s'") % ADMIN)
        for u in userset:
            try:
                dbp.send(u"DROP ROLE IF EXISTS %s" % u)
            except:
                gui.report(_("  ... couldn't remove user '%s'") % u)

    gui.report(_("\nCreating control database"))
    dbp.send(u"CREATE DATABASE %s ENCODING 'UTF8'" % dbzc)
    dbp.close()
    dbp = None

    connectData[u"db"] = dbzc
    db = DB(connectData)
    if not db.isOpen():
        error(_("Couldn't open control database"))
        return False

    try:
        setupCDB(db)
    except:
        db.close()
        error(_("Couldn't set up the '%s' database."
                " Please try again:\n%s") % (dbzc, format_exc()))
        return False
    gui.report(_("\nSuccess! The control database is ready."))
    gui.report(_("  Now use the control panel (zgcp) to set up"
            " report databases."))

    db.close()
    return True
    def slot_restore(self, arg):
        """Restore a dumped database.
        It can be either an existing one, or one which has been deleted.
        """
        # Get source file:
        dbpath = self.getBDbPath()
        if not dbpath: return None

        restore = Restore(dbpath)
        dbname = restore.getDbName()
        if not dbname:
            message(_("Couldn't open database file '%1'"), (dbpath,))
            return

        state = 0
        try:

            if dbname in self.dbList:
                if not confirmationDialog(_("Replace Database?"),
                        argSub(_("Are you sure you want to replace database '%1'?"),
                        (dbname,)), False):
                    restore.close()
                    return
                self.deletedb(dbname)

            self.db.send(u"""CREATE DATABASE %s
                    OWNER %s ENCODING 'UTF8'""" % (dbname, ADMIN))
            state = 1
            # Add to 'databases' table
            self.db.send(u"INSERT INTO databases VALUES (?, ?, ?, ?)",
                    (self.db.getTime(), dbname, u'', u''))
            state = 2

            newmaster = self.connect(dbname)
            state = 3

            guimessage = argSub(_("New database '%1' created, now read in the data"),
                    (dbname,))
            restore.setMaster(newmaster)
            guiReport(_("Restore Database"), restore, guimessage)
            #message(_("New database now set up"))

            self.usersPrivileges(newmaster)

            # Ensure connection is closed
            restore = None
            newmaster.close()
            newmaster = None

        except:
            print_exc()

            message(_("Couldn't create new database (%1)"), (dbname,))
            if (state >= 3):
                newmaster.close()
            if (state >= 2):
                self.db.send(u"DELETE FROM databases WHERE name = ?",
                        (dbname,))
            if (state >= 1):
                self.db.send(u"DROP DATABASE %s" % dbname)

        # adjust display, select new db
        self.initDBlist()
Example #15
0
    def save(self, onlytemp=False, force=False, imageX=None):
        """Save the data to a temporary file, close it and then ask if
        the original file should be replaced by it.
        If onlytemp is True, stop after saving the data to the
        temporary file, leaving the source file open, and fail if that
        didn't work first time. Otherwise the possibility of entering
        an alternative save path will be given.
        If force is True, don't ask, just do everything.
        If imageX is a directory path, get the images from there
        instead of from the source file
        """
        if not self.baseFolder:
            return
        cfgFile = os.path.join(self.baseFolder, self.source.cfgName + '.zip')
        tmpsave = cfgFile + '_'
        backup = cfgFile + '~'

        while True:
            try:
                if os.path.exists(tmpsave):
                    os.remove(tmpsave)
                self.saveData(tmpsave, imageX)
                if onlytemp:
                    messageDialog(_("Information"),
                            _("Saved as '%s'") % tmpsave)
                    return
                self.source.close()
                break

            except:
                traceback.print_exc()
                warning(_("Could not save data to '%s'") % tmpsave)
                if onlytemp:
                    return
                tmpsave = getFile(_("Save file to"),
                        startDir=os.path.dirname(tmpsave),
                        defaultSuffix="zip",
                        filter=(_("zip Files"), ("*.zip",)),
                        create=True)
                if isinstance(tmpsave, unicode):
                    tmpsave = tmpsave.encode('utf8')
            if not tmpsave:
                return


        if (not force) and (not confirmationDialog(_("Replace existing file?"),
                _("The changes have been saved to '%s'.\n"
                "Should this now replace the previous data?") % tmpsave)):
            return

        try:
            if os.path.exists(backup):
                os.remove(backup)
            if os.path.exists(cfgFile):
                os.rename(cfgFile, backup)
            os.rename(tmpsave, cfgFile)
            if imageX:
                self.baseFolder = None
                self.slot_openConfig(False)
            else:
                # For the control panel, to indicate that the file has
                # been saved:
                self.sourcePath = cfgFile
                self.validationObject.validateAll()
                self.errorCount = self.validationObject.errorCount
        except:
            traceback.print_exc()
            warning(_("Couldn't update configuration file '%s'") % cfgFile)
Example #16
0
def synchronize(dbm, filepath, gui):
    """Synchronize the given file with the given (open) master database.
    """
    # Current master time
    mtime = dbm.getTime()
    # Move the user database file to backup location
    dir = os.path.dirname(filepath)
    bfile = re.sub(".zga$", "_%s.zga" % mtime, filepath)
    if (os.name == 'posix'):
        try:
            if Popen(["lsof", filepath],
                    stdout=PIPE).communicate()[0]:
                warning(_("The database file (%1) is being used"
                        " by another application"), (filepath,))
                return
        except:
            warning(_("You should install 'lsof' so that usage"
                    " of the file can be tested"))
    try:
        os.rename(filepath, bfile)
    except:
        # This trap only works on Windows. Linux will happily
        # allow you to delete a file while another program is
        # working on it! 'lsof filename' (see above) should be
        # a way to avoid that.
        warning(_("Couldn't rename the database file (%1).\n"
                "Is it being used by another application?"),
                (filepath,))
        return

    gui.report(_("Database file renamed to %s") % bfile)

    dbs = DBs(bfile)
    if not dbs.isOpen():
        os.rename(bfile, filepath)
        return

    # Teacher's report table
    teacher = dbs.getConfig(u"me")
    mtb = teacher2user(teacher)
    if mtb not in dbm.getTeacherTables():
        warning(_("%1: Owning teacher (%2) not known to master database"),
                (filepath, teacher))
        return

    gui.report(_("Copying reports from user database to master"))
    # Counter for transferred reports
    rcount = 0
    # Creation time of slave db, i.e. last sync time
    ctime = dbs.getConfig(u"createtime")
    # Get all updated reports
    for id, data in dbs.read(u"SELECT * FROM reports"):
        # Split off the version data
        dver, drep = data.split(u"\n", 1)
        # Get the master version data
        try:
            mver = dbm.readValue(mtb, id).split(u"\n", 1)[0]
        except:
            gui.report(_("Invalid report, not updated : %s") % id)

        if (mver > ctime):
            if confirmationDialog(_("Report update problem"),
                    _("Master version of report has been updated"
                    " since this client was last synchronized.\n"
                    "   Replace that version of '%s'?") % id, False):
                gui.report(_("Revised master version of report '%s'"
                        " will be overwritten") % id)
            else:
                gui.report(_("Revised master version of report '%s'"
                        " not overwritten") % id)
                continue

        elif (dver <= mver):
            # Only do anything if the local version is newer than the
            # the master version
            continue

        if (dver > mtime):
            # The new version has a time stamp later than the
            # current time on the master, adjust it
            if dver.endswith(u"$"):
                dver = mtime + u"$"
            else:
                dver = mtime

        try:
            sqlupd = u"UPDATE %s SET value = ? WHERE id = ?" % mtb
            dbm.send(sqlupd, (dver + u"\n" + drep, id))
            rcount += 1
        except:
            gui.report(_("Couldn't update report '%s'") % id)

    gui.report(_("Transferred %d reports") % rcount)

    # Close the user database
    dbs.close()

    # Remember the latest sync time
    if rcount:
        dbm.send(u"""UPDATE interface SET value = ?
                    WHERE id = 'lastsynctime'""", (mtime,))

    # Recreate the user database
    gui.report(_("Recreating the user database"))
    recreate(dbm, filepath, teacher, gui)
Example #17
0
    def run(self, ui):
        minCols = 0
        for v in self.columns.values():
            if (v > minCols):
                minCols = v
        self.ui = ui
        for f in os.listdir(self.idir):
            if not f.endswith('.csv'):
                self.report(_("Ignoring '%s'") % f)
                continue

            classTag = f[:-4]  # cut off the ending
            classPath = "classes/" + classTag
            if not self.configEd.pathExists(classPath + '/'):
                self.report(
                    _("ERROR: There is no class with tag '%s'") % classTag)
                continue

            lastId = self.configEd.getField(classPath + "/info", "lastId")
            if (lastId > 0):
                if not confirmationDialog(
                        _("Warning"),
                        _("Reloading pupil information can lead to loss"
                          " or mixing up of reports. Continue?"), False):
                    continue

            self.report(_("Removing all pupils from class '%s'") % classTag)
            pupilPath = classPath + "/pupils"
            self.configEd.emptyDir(pupilPath)

            # Open the input file
            fi = os.path.join(self.idir, f)
            fih = open(fi, "rb")
            self.report(_("Fetching pupils from file '%s'") % fi)

            ln = 0
            id = 0  # counter for automatic id
            for line in fih:
                ln += 1
                line = line.strip()
                if (not line) or (line[0] == '#'):
                    continue

                # 'Strip' the individual columns
                cols = []
                for cv in [c.strip() for c in line.split(self.colSep)]:
                    r = quoteStrip.match(cv)
                    if r:
                        cv = r.group(1)
                    cols.append(cv)

                if (len(cols) < minCols):
                    self.report(
                        _("ERROR: Insufficient columns at line %d") % ln)
                    continue

                # Write out the file for this pupil
                if (self.idcol == 0):
                    id += 1
                    pfile = "%03d" % id
                else:
                    id -= 1
                    pfile = cols[self.idcol]
                opstring = ''
                for field, ix in self.columns.items():
                    if ix:
                        value = cols[ix - 1]
                    else:
                        value = ''
                    if (field != "id"):
                        opstring += "%s = %s\n" % (field, value)

                self.configEd.addPupil(pupilPath, pfile, opstring)

            self.report(_("Imported %d pupils\n") % abs(id))
            self.configEd.endPupils(classPath, id)
Example #18
0
def go():
    gui.report("  ------------------------------------\n")
    # Connect to control database
    connectData = getConnectInfo(app.settings, "postgres")
    if not connectData:
        return False

    gui.report(_("Connecting to postgres@%s") % connectData[u"host"])

    dbzc = connectData[u"db"]
    connectData[u"db"] = u"postgres"
    dbp = DB(connectData)
    if not dbp.isOpen():
        error(_("Couldn't open 'postgres' database"))
        return False

    gui.report(_("Checking existing databases"))

    if dbp.read1(u"SELECT datname FROM pg_database WHERE datname = ?",
                 (dbzc, )):
        if not confirmationDialog(
                _("Remove Control Database?"),
                _("The control database (%s) already exists."
                  " Should it be removed, with everything it contains?") %
                dbzc, False):
            dbp.close()
            return False

        connectData[u"db"] = dbzc
        userset = set()
        try:
            # Remove all databases and users
            db = DB(connectData)
            try:
                info = db.read(u"SELECT * FROM databases")
            except:
                info = None
            db.close()
            if info:
                for id, name, finalized, users in info:
                    gui.report(_("Removing database '%s'") % name)
                    dbp.send(u"DROP DATABASE IF EXISTS %s" % name)
                    userset |= set(users.split())

            gui.report(_("Removing database '%s'") % dbzc)
            dbp.send(u"DROP DATABASE %s" % dbzc)

        except:
            #print_exc()

            error(
                _("Couldn't remove old data -"
                  " summon a PostgreSQL expert:\n%s") % format_exc())

        gui.report(_("Trying to remove users ..."))
        try:
            dbp.send(u"DROP ROLE IF EXISTS %s" % USERROLE)
        except:
            gui.report(_("  ... couldn't remove user '%s'") % USERROLE)
        try:
            dbp.send(u"DROP ROLE IF EXISTS %s" % ADMIN)
        except:
            gui.report(_("  ... couldn't remove user '%s'") % ADMIN)
        for u in userset:
            try:
                dbp.send(u"DROP ROLE IF EXISTS %s" % u)
            except:
                gui.report(_("  ... couldn't remove user '%s'") % u)

    gui.report(_("\nCreating control database"))
    dbp.send(u"CREATE DATABASE %s ENCODING 'UTF8'" % dbzc)
    dbp.close()
    dbp = None

    connectData[u"db"] = dbzc
    db = DB(connectData)
    if not db.isOpen():
        error(_("Couldn't open control database"))
        return False

    try:
        setupCDB(db)
    except:
        db.close()
        error(
            _("Couldn't set up the '%s' database."
              " Please try again:\n%s") % (dbzc, format_exc()))
        return False
    gui.report(_("\nSuccess! The control database is ready."))
    gui.report(
        _("  Now use the control panel (zgcp) to set up"
          " report databases."))

    db.close()
    return True