def set_default_language(request, lang_code, global_set=False):
    """
    global_set has different meanings for different users.
    For students, it means their personal default language
    For teachers, it means their personal default language
    For django users, it means the server language.
    """

    # Get lang packs directly, to force reloading, as they may have changed.
    lang_packs = get_installed_language_packs(force=True).keys()
    lang_code = select_best_available_language(lang_code, available_codes=lang_packs)  # Make sure to reload available languages; output is in django_lang format

    if lang_code != request.session.get("default_language"):
        logging.debug("setting session language to %s" % lang_code)
        request.session["default_language"] = lang_code

    if global_set:
        if request.is_django_user and lang_code != Settings.get("default_language"):
            logging.debug("setting server default language to %s" % lang_code)
            Settings.set("default_language", lang_code)
        elif not request.is_django_user and request.is_logged_in and lang_code != request.session["facility_user"].default_language:
            logging.debug("setting user default language to %s" % lang_code)
            request.session["facility_user"].default_language = lang_code
            request.session["facility_user"].save()

    set_request_language(request, lang_code)
Exemple #2
0
 def setUp_fake_device(self):
     """
     Fake the install process, to (quickly) make a key and set up the own_device()
     """
     # Could be a fixture, but safer to simply hard-code.
     Settings.set("public_key", u'MIIBCgKCAQEAlbIPLnQH2dORFBK8i9x7/3E0DR571S01aP7M0TJD8vJf8OrgL8pnru3o2Jaoni1XasCZgizvM4GNImk9geqPP/sFkj0cf/MXSLr1VDKo1SoflST9yTbOi7tzVuhTeL4P3LJL6PO6iNiWkjAdqp9QX3mE/DHh/Q40G68meRw6dPDI4z8pyUcshOpxAHTSh2YQ39LJAxP7YS26yjDX/+9UNhetFxemMrBZO0UKtJYggPYRlMZmlTZLBU4ODMmK6MT26fB4DC4ChA3BD4OFiGDHI/iSy+iYJlcWaldbZtc+YfZlGhvsLnJlrp4WYykJSH5qeBuI7nZLWjYWWvMrDepXowIDAQAB')
     Settings.set("private_key", u'-----BEGIN RSA PRIVATE KEY-----\nMIIEqQIBAAKCAQEAlbIPLnQH2dORFBK8i9x7/3E0DR571S01aP7M0TJD8vJf8Org\nL8pnru3o2Jaoni1XasCZgizvM4GNImk9geqPP/sFkj0cf/MXSLr1VDKo1SoflST9\nyTbOi7tzVuhTeL4P3LJL6PO6iNiWkjAdqp9QX3mE/DHh/Q40G68meRw6dPDI4z8p\nyUcshOpxAHTSh2YQ39LJAxP7YS26yjDX/+9UNhetFxemMrBZO0UKtJYggPYRlMZm\nlTZLBU4ODMmK6MT26fB4DC4ChA3BD4OFiGDHI/iSy+iYJlcWaldbZtc+YfZlGhvs\nLnJlrp4WYykJSH5qeBuI7nZLWjYWWvMrDepXowIDAQABAoIBAD8S/a6XGU/BA1ov\n4t4TkvO44TO96nOSTvTkl6x1v4e4dJBwhvHcGP/uIrRQFtA/TpwedxAQmuFa7vrW\n2SHKkX1l6Z0Kvt1yshblH8XQaq8WxqPzKDQGMdVSsHCoB7PScaCOR8nqGGjcyeTi\n/T0NT7JK46vX4N7dgttrE+WixOrtDOUJLX92tGSp8bZgg284fV053nJqYHHROpmZ\nCibM5HK8B/19ULCpglGQCUVmJPtRzNK1bE9OlB8P5aZzdEd82oC8TKfSGmByO1TI\nCat6x8e0hYVIDElYGdcW5CDAr6rbU0CXOxxQAz3gJFDe1/RbbGJEdjO3IulYbR4H\nBK+nGxECgYkA424wFuQGRAwig//SNasv5aIqz2qnczL5ob3MXCFR4aOMowS94qvd\neRG9McxgRwbEApOTMVMAUYlBMkKE//sBM9XWQ4q8igJ+TUlV8RRQ8AP6hMUhSXX0\nNeEECcauP4vI6hhsnTsG/OQ4pr/4bEewsyXFwPSGkh2v3O+fuc6A8RywQ3u6icc+\n9wJ5AKiACZmpSskyJgp+3X0jpYixb7pQ9gU6QpJmP9Z2DdUNnm0Y5tDjnaCd/Bvy\nmNuCWqNbYdlEYH32B3sCshzFCqQwkgSMOa84cHQHx4Nx7SG2fUp9w1ExvnMRzrnw\n3sjB3ptbNhk1yrkzhFbd6ZG4fsL5Mb0EurAFtQKBiFCUVc2GdQHfGsuR9DS3tnyx\n/GEI9NNIGFJKIQHzfENp4wZPQ8fwBMREmLfwJZyEtSYEi35KXi6FZugb0WuwzzhC\nZ2v+19Y+E+nmNeD4xcSEZFpuTeDtPd1pIDkmf85cBI+Mn88FfvBTHA9YrPgQXnba\nxzoaaSOUCR9Kd1kp5V2IQJtoVytBwPkCeFIDD6kkxuuqZu2Q1gkEgptHkZPjt/rP\nYnuTHNsrVowuNr/u8NkXEC+O9Zg8ub2NcsQzxCpVp4lnaDitFTf/h7Bmm4tvHNx1\n4fX3m1oU51ATXGQXVit8xK+JKU9DN4wLIGgJOwmGLwd5VZ5aIEb2v2vykgzn8l2e\nSQKBiQC7CJVToYSUWnDGwCRsF+fY9jUculveAQpVWj03nYBtBdTh2EWcvfoSjjfl\nmpzrraojpQlUhrbUf5MU1fD9+i6swrCCvfjXITG3c1bkkB5AaQW7NiPHvDRMuDpc\nHIQ+vqzdn4iUlt7KB5ChpnZMmgiOdCBM0vQsZlVCbp0ZNLqVYhFASQnWl6V9\n-----END RSA PRIVATE KEY-----\n')
     Device.initialize_own_device()
Exemple #3
0
def load_keys():
    private_key_string = Settings.get("private_key")
    public_key_string = Settings.get("public_key")
    if private_key_string and public_key_string:
        sys.modules[__name__]._own_key = Key(
            public_key_string=public_key_string,
            private_key_string=private_key_string)
    else:
        reset_keys()
Exemple #4
0
def load_keys():
    private_key_string = Settings.get("private_key")
    public_key_string = Settings.get("public_key")
    if private_key_string and public_key_string:
        sys.modules[__name__]._own_key = Key(
            public_key_string=public_key_string,
            private_key_string=private_key_string)
    else:
        reset_keys()
    def initialize_default_facility(cls, facility_name=None):
        facility_name = facility_name or settings.INSTALL_FACILITY_NAME

        # Finally, install a facility--would help users get off the ground
        if facility_name:
            facility = get_object_or_None(cls, name=facility_name)
            if not facility:
                facility = Facility(name=facility_name)
                facility.save()
            Settings.set("default_facility", facility.id)
Exemple #6
0
    def setup_fake_device(cls, **kwargs):
        fields = FakeDeviceMixin.DEFAULTS.copy()
        fields.update(kwargs)

        Device.own_device = None

        Settings.set("public_key", fields.get('public_key'))
        Settings.set("private_key", fields.get('private_key'))

        Device.initialize_own_device()
Exemple #7
0
    def setup_fake_device(cls, **kwargs):
        fields = FakeDeviceMixin.DEFAULTS.copy()
        fields.update(kwargs)

        Device.own_device = None

        Settings.set("public_key", fields.get('public_key'))
        Settings.set("private_key", fields.get('private_key'))

        Device.initialize_own_device()
Exemple #8
0
    def setup_server_if_needed(self):
        """Run the setup command, if necessary."""

        try: # Ensure that the database has been synced and a Device has been created
            assert Settings.get("private_key") and Device.objects.count()
        except (DatabaseError, AssertionError): # Otherwise, run the setup command
            self.stdout.write("Setting up KA Lite; this may take a few minutes; please wait!\n")
            call_command("setup", interactive=False)
        # Double check that the setup process successfully created a Device
        assert Settings.get("private_key") and Device.objects.count(), "There was an error configuring the server. Please report the output of this command to Learning Equality."
 def setup_fake_device(cls):
     Device.own_device = None
     Settings.set(
         "public_key",
         u'MIIBCgKCAQEAlbIPLnQH2dORFBK8i9x7/3E0DR571S01aP7M0TJD8vJf8OrgL8pnru3o2Jaoni1XasCZgizvM4GNImk9geqPP/sFkj0cf/MXSLr1VDKo1SoflST9yTbOi7tzVuhTeL4P3LJL6PO6iNiWkjAdqp9QX3mE/DHh/Q40G68meRw6dPDI4z8pyUcshOpxAHTSh2YQ39LJAxP7YS26yjDX/+9UNhetFxemMrBZO0UKtJYggPYRlMZmlTZLBU4ODMmK6MT26fB4DC4ChA3BD4OFiGDHI/iSy+iYJlcWaldbZtc+YfZlGhvsLnJlrp4WYykJSH5qeBuI7nZLWjYWWvMrDepXowIDAQAB'
     )
     Settings.set(
         "private_key",
         u'-----BEGIN RSA PRIVATE KEY-----\nMIIEqQIBAAKCAQEAlbIPLnQH2dORFBK8i9x7/3E0DR571S01aP7M0TJD8vJf8Org\nL8pnru3o2Jaoni1XasCZgizvM4GNImk9geqPP/sFkj0cf/MXSLr1VDKo1SoflST9\nyTbOi7tzVuhTeL4P3LJL6PO6iNiWkjAdqp9QX3mE/DHh/Q40G68meRw6dPDI4z8p\nyUcshOpxAHTSh2YQ39LJAxP7YS26yjDX/+9UNhetFxemMrBZO0UKtJYggPYRlMZm\nlTZLBU4ODMmK6MT26fB4DC4ChA3BD4OFiGDHI/iSy+iYJlcWaldbZtc+YfZlGhvs\nLnJlrp4WYykJSH5qeBuI7nZLWjYWWvMrDepXowIDAQABAoIBAD8S/a6XGU/BA1ov\n4t4TkvO44TO96nOSTvTkl6x1v4e4dJBwhvHcGP/uIrRQFtA/TpwedxAQmuFa7vrW\n2SHKkX1l6Z0Kvt1yshblH8XQaq8WxqPzKDQGMdVSsHCoB7PScaCOR8nqGGjcyeTi\n/T0NT7JK46vX4N7dgttrE+WixOrtDOUJLX92tGSp8bZgg284fV053nJqYHHROpmZ\nCibM5HK8B/19ULCpglGQCUVmJPtRzNK1bE9OlB8P5aZzdEd82oC8TKfSGmByO1TI\nCat6x8e0hYVIDElYGdcW5CDAr6rbU0CXOxxQAz3gJFDe1/RbbGJEdjO3IulYbR4H\nBK+nGxECgYkA424wFuQGRAwig//SNasv5aIqz2qnczL5ob3MXCFR4aOMowS94qvd\neRG9McxgRwbEApOTMVMAUYlBMkKE//sBM9XWQ4q8igJ+TUlV8RRQ8AP6hMUhSXX0\nNeEECcauP4vI6hhsnTsG/OQ4pr/4bEewsyXFwPSGkh2v3O+fuc6A8RywQ3u6icc+\n9wJ5AKiACZmpSskyJgp+3X0jpYixb7pQ9gU6QpJmP9Z2DdUNnm0Y5tDjnaCd/Bvy\nmNuCWqNbYdlEYH32B3sCshzFCqQwkgSMOa84cHQHx4Nx7SG2fUp9w1ExvnMRzrnw\n3sjB3ptbNhk1yrkzhFbd6ZG4fsL5Mb0EurAFtQKBiFCUVc2GdQHfGsuR9DS3tnyx\n/GEI9NNIGFJKIQHzfENp4wZPQ8fwBMREmLfwJZyEtSYEi35KXi6FZugb0WuwzzhC\nZ2v+19Y+E+nmNeD4xcSEZFpuTeDtPd1pIDkmf85cBI+Mn88FfvBTHA9YrPgQXnba\nxzoaaSOUCR9Kd1kp5V2IQJtoVytBwPkCeFIDD6kkxuuqZu2Q1gkEgptHkZPjt/rP\nYnuTHNsrVowuNr/u8NkXEC+O9Zg8ub2NcsQzxCpVp4lnaDitFTf/h7Bmm4tvHNx1\n4fX3m1oU51ATXGQXVit8xK+JKU9DN4wLIGgJOwmGLwd5VZ5aIEb2v2vykgzn8l2e\nSQKBiQC7CJVToYSUWnDGwCRsF+fY9jUculveAQpVWj03nYBtBdTh2EWcvfoSjjfl\nmpzrraojpQlUhrbUf5MU1fD9+i6swrCCvfjXITG3c1bkkB5AaQW7NiPHvDRMuDpc\nHIQ+vqzdn4iUlt7KB5ChpnZMmgiOdCBM0vQsZlVCbp0ZNLqVYhFASQnWl6V9\n-----END RSA PRIVATE KEY-----\n'
     )
     Device.initialize_own_device()
Exemple #10
0
    def handle(self, *args, **options):
        # Eliminate irrelevant settings
        for opt in BaseCommand.option_list:
            del options[opt.dest]

        # Parse the crappy way that runcherrypy takes args,
        #   or the host/port
        for arg in args:
            if "=" in arg:
                (key,val) = arg.split("=")
                options[key] = val
            elif ":" in arg:
                (options["host"], options["port"]) = arg.split(":")
            elif isnumeric(arg):
                options["port"] = arg
            else:
                raise CommandError("Unexpected argument format: %s" % arg)

        # In order to avoid doing this twice when the autoreloader
        #   loads this process again, only execute the initialization
        #   code if autoreloader won't be run (daemonize), or if
        #   RUN_MAIN is set (autoreloader has started)
        if options["daemonize"] or os.environ.get("RUN_MAIN"):
            self.setup_server_if_needed()

            # we do this on every server request,
            # as we don't know what happens when we're not looking.
            self.reinitialize_server()

        # In case any chronograph threads were interrupted the last time
        # the server was stopped, clear their is_running flags to allow
        # them to be started up again as needed.
        Job.objects.update(is_running=False)


        call_command("collectstatic", interactive=False)

        # set the BUILD_HASH to the current time, so assets get refreshed to their newest versions
        build_hash = str(time.mktime(time.gmtime()))
        logging.debug("Writing %s as BUILD_HASH" % build_hash)
        Settings.set('BUILD_HASH', build_hash)

        if options['startuplock']:
            os.unlink(options['startuplock'])
        
        # Now call the proper command
        if not options["production"]:
            call_command("runserver", "%s:%s" % (options["host"], options["port"]))
        else:
            del options["production"]
            sys.stdout.write("To access KA Lite from another connected computer, try the following address(es):\n")
            for addr in get_ip_addresses():
                sys.stdout.write("\thttp://%s:%s/\n" % (addr, settings.USER_FACING_PORT()))
            call_command("runcherrypyserver", *["%s=%s" % (key,val) for key, val in options.iteritems()])
Exemple #11
0
    def wrapper_fn(request, *args, **kwargs):
        facility = None

        if kwargs.get("facility_id", None):  # avoid using blank
            # Facility passed in directly
            facility = get_object_or_None(Facility, pk=kwargs["facility_id"])
            del kwargs["facility_id"]

        if not facility and "facility" in request.GET:
            # Facility from querystring
            facility = get_object_or_None(Facility, pk=request.GET["facility"])

        if facility:
            pass

        elif settings.CENTRAL_SERVER:  # following options are distributed-only
            facility = None

        elif "facility_user" in request.session:
            # Facility from currently logged-in facility user
            facility = request.session["facility_user"].facility

        elif request.session["facility_count"] == 1:
            # There's only one facility
            facility = Facility.objects.all()[0]

        elif request.session["facility_count"] > 0:
            if Settings.get("default_facility"):
                # There are multiple facilities--try to grab the default
                facility = get_object_or_None(
                    Facility, pk=Settings.get("default_facility"))

            elif Facility.objects.filter(
                    Q(signed_by__isnull=True)
                    | Q(signed_by=Device.get_own_device())).count() == 1:
                # Default to a locally created facility (if there are multiple, and none are specified)
                facility = Facility.objects.filter(
                    Q(signed_by__isnull=True)
                    | Q(signed_by=Device.get_own_device()))[0]

            else:
                facility = None
        else:
            # There's nothing; don't bother even hitting the DB
            facility = None

        if "set_default" in request.GET and request.is_admin and facility:
            Settings.set("default_facility", facility.id)

        if facility or "facility" not in kwargs:  # this syntax allows passed in facility param to work.
            kwargs["facility"] = facility
        return handler(request, *args, **kwargs)
Exemple #12
0
def get_current_unit_settings_value(facility_id):
    """
    Get value of current unit based on facility id.  If none, defaults to 1 and creates an
    entry on the Settings.
    """
    name = get_current_unit_settings_name(facility_id)
    value = Settings.get(name, UNITS[0])
    if value == 0:
        # This may be the first time this facility`s current unit is queried so
        # make sure it has a value at Settings so we can either change it on
        # the admin page or at front-end code later.
        value = 1
        Settings.set(name, value)
    return value
Exemple #13
0
def get_current_unit_settings_value(facility_id):
    """
    Get value of current unit based on facility id.  If none, defaults to 1 and creates an
    entry on the Settings.
    """
    name = get_current_unit_settings_name(facility_id)
    value = Settings.get(name, UNITS[0])
    if value == 0:
        # This may be the first time this facility`s current unit is queried so
        # make sure it has a value at Settings so we can either change it on
        # the admin page or at front-end code later.
        value = 1
        Settings.set(name, value)
    return value
Exemple #14
0
    def setup_server_if_needed(self):
        """Run the setup command, if necessary."""

        try:  # Ensure that the database has been synced and a Device has been created
            assert Settings.get("private_key") and Device.objects.count()
        except (DatabaseError,
                AssertionError):  # Otherwise, run the setup command
            self.stdout.write(
                "Setting up KA Lite; this may take a few minutes; please wait!\n"
            )
            call_command("setup", interactive=False)
        # Double check that the setup process successfully created a Device
        assert Settings.get("private_key") and Device.objects.count(
        ), "There was an error configuring the server. Please report the output of this command to Learning Equality."
Exemple #15
0
    def initialize_default_facility(cls, facility_name=None):
        facility_name = facility_name or getattr(settings, "INSTALL_FACILITY_NAME", None) or unicode(_("Default Facility"))

        # Finally, install a facility--would help users get off the ground
        facilities = Facility.objects.filter(name=facility_name)
        if facilities.count() == 0:
            # Create a facility, set it as the default.
            facility = Facility(name=facility_name)
            facility.save()
            Settings.set("default_facility", facility.id)

        elif Settings.get("default_facility") not in [fac.id for fac in facilities.all()]:
            # Use an existing facility as the default, if one of them isn't the default already.
            Settings.set("default_facility", facilities[0].id)
    def setup_server_if_needed(self):
        """Run the setup command, if necessary.
            It's necessary if the Settings model doesn't have a "database_version" or if that version doesn't match
            kalite.version.VERSION, indicating the source has been changed. Then setup is run to create/migrate the db.
        """

        try:
            from kalite.version import VERSION
            assert Settings.get("database_version") == VERSION
        except (DatabaseError, AssertionError):
            logging.info("Setting up KA Lite; this may take a few minutes; please wait!\n")
            call_command("setup", interactive=False)
            # Double check the setup process worked ok.
            assert Settings.get("database_version") == VERSION, "There was an error configuring the server. Please report the output of this command to Learning Equality."
Exemple #17
0
    def setup_server_if_needed(self):
        """Run the setup command, if necessary."""

        # Now, validate the server.
        try:
            if Settings.get("private_key") and Device.objects.count():
                # The only success case
                pass

            elif not Device.objects.count():
                # Nothing we can do to recover
                raise CommandError(
                    "You are screwed, buddy--you went through setup but you have no devices defined!  Call for help!"
                )

            else:
                # Force hitting recovery code, by raising a generic error
                #   that gets us to the "except" clause
                raise DatabaseError

        except DatabaseError:
            self.stdout.write(
                "Setting up KA Lite; this may take a few minutes; please wait!\n"
            )

            call_command("setup", interactive=False)  # show output to the user
Exemple #18
0
 def handle(self, *args, **options):
     if Settings.get("private_key"):
         self.stderr.write("Error: This device already has an encryption key generated for it; aborting.\n")
         return
     self.stdout.write("Generating 2048-bit RSA encryption key (may take a few minutes; please wait)...\n")
     reset_keys()
     self.stdout.write("Done!\n")
Exemple #19
0
    def facility_from_request_wrapper_fn(request, *args, **kwargs):
        facility = None

        if kwargs.get("facility_id", None):  # avoid using blank
            # Facility passed in directly
            facility = get_object_or_None(Facility, pk=kwargs["facility_id"])
            del kwargs["facility_id"]

        if not facility and "facility" in request.GET:
            # Facility from querystring
            facility = get_object_or_None(Facility, pk=request.GET["facility"])

        if facility:
            pass

        elif settings.CENTRAL_SERVER:  # following options are distributed-only
            facility = None

        elif "facility_user" in request.session:
            # Facility from currently logged-in facility user
            facility = request.session["facility_user"].facility

        elif request.session["facility_count"] == 1:
            # There's only one facility
            facility = Facility.objects.all()[0]

        elif request.session["facility_count"] > 0:
            if Settings.get("default_facility"):
                # There are multiple facilities--try to grab the default
                facility = get_object_or_None(Facility, pk=Settings.get("default_facility"))

            elif Facility.objects.filter(Q(signed_by__isnull=True) | Q(signed_by=Device.get_own_device())).count() == 1:
                # Default to a locally created facility (if there are multiple, and none are specified)
                facility = Facility.objects.filter(Q(signed_by__isnull=True) | Q(signed_by=Device.get_own_device()))[0]

            else:
                facility = None
        else:
            # There's nothing; don't bother even hitting the DB
            facility = None

        if "set_default" in request.GET and request.is_admin and facility:
            Settings.set("default_facility", facility.id)

        if facility or "facility" not in kwargs:  # this syntax allows passed in facility param to work.
            kwargs["facility"] = facility
        return handler(request, *args, **kwargs)
Exemple #20
0
def set_exam_mode_on(test_object):
    """
    Sets the value of the EXAM_MODE_ON.
    TODO(cpauya): check if user is admin/teacher
    """

    # Figure out what the previous exam was, and then turn off exam mode
    # (to make sure we trigger any exam unsetting events)
    old_test_id = get_exam_mode_on()
    set_exam_mode_off()

    new_test_id = getattr(test_object, 'test_id', test_object)

    # only enable exam if it isn't the same one previously enabled
    # (since we for some reason just call the same method to toggle off)
    if old_test_id != new_test_id:
        Settings.set(SETTINGS_KEY_EXAM_MODE, new_test_id)
Exemple #21
0
def set_exam_mode_on(test_object):
    """
    Sets the value of the EXAM_MODE_ON.
    TODO(cpauya): check if user is admin/teacher
    """

    # Figure out what the previous exam was, and then turn off exam mode
    # (to make sure we trigger any exam unsetting events)
    old_test_id = get_exam_mode_on()
    set_exam_mode_off()

    new_test_id = getattr(test_object, "test_id", test_object)

    # only enable exam if it isn't the same one previously enabled
    # (since we for some reason just call the same method to toggle off)
    if old_test_id != new_test_id:
        Settings.set(SETTINGS_KEY_EXAM_MODE, new_test_id)
Exemple #22
0
    def setup_server_if_needed(self):
        """Run the setup command, if necessary."""

        try: # Ensure that the database has been synced and a Device has been created
            assert Settings.get("private_key") and Device.objects.count()
        except (DatabaseError, AssertionError): # Otherwise, run the setup command
            self.stdout.write("Setting up KA Lite; this may take a few minutes; please wait!\n")
            call_command("setup", interactive=False)
Exemple #23
0
    def initialize_default_facility(cls, facility_name=None):
        facility_name = facility_name or getattr(
            settings, "INSTALL_FACILITY_NAME", None) or unicode(
                _("Default Facility"))

        # Finally, install a facility--would help users get off the ground
        facilities = Facility.objects.filter(name=facility_name)
        if facilities.count() == 0:
            # Create a facility, set it as the default.
            facility = Facility(name=facility_name)
            facility.save()
            Settings.set("default_facility", facility.id)

        elif Settings.get("default_facility") not in [
                fac.id for fac in facilities.all()
        ]:
            # Use an existing facility as the default, if one of them isn't the default already.
            Settings.set("default_facility", facilities[0].id)
Exemple #24
0
def set_current_unit_settings_value(facility_id, value):
    """
    Set the value of the current unit on Settings based on the facility id.
    """
    old_unit = get_current_unit_settings_value(facility_id)
    name = get_current_unit_settings_name(facility_id)
    s = Settings.set(name, value)
    unit_switch.send(sender="None", old_unit=old_unit, new_unit=value, facility_id=facility_id)
    return s
Exemple #25
0
def set_exam_mode_off():
    """Switch off exam mode if it is on, do nothing if already off"""

    current_test_id = get_exam_mode_on()
    if not current_test_id:
        return

    # do the import here to prevent circular import
    from .models import Test

    test = Test.all().get(current_test_id, None)

    if test and test.practice:
        exam_unset.send(sender="None", test_id=current_test_id)

    Settings.set(SETTINGS_KEY_EXAM_MODE, "")

    return
Exemple #26
0
    def setup_server_if_needed(self):
        """Run the setup command, if necessary.
            It's necessary if the Settings model doesn't have a "database_version" or if that version doesn't match
            kalite.version.VERSION, indicating the source has been changed. Then setup is run to create/migrate the db.
        """

        try:
            from kalite.version import VERSION
            assert Settings.get("database_version") == VERSION
        except (DatabaseError, AssertionError):
            logging.info(
                "Setting up KA Lite; this may take a few minutes; please wait!\n"
            )
            call_command("setup", interactive=False)
            # Double check the setup process worked ok.
            assert Settings.get(
                "database_version"
            ) == VERSION, "There was an error configuring the server. Please report the output of this command to Learning Equality."
Exemple #27
0
def set_exam_mode_off():
    """Switch off exam mode if it is on, do nothing if already off"""

    current_test_id = get_exam_mode_on()
    if not current_test_id:
        return

    # do the import here to prevent circular import
    from .models import Test

    test = Test.all().get(current_test_id, None)

    if test and test.practice:
        exam_unset.send(sender="None", test_id=current_test_id)

    Settings.set(SETTINGS_KEY_EXAM_MODE, '')

    return
 def handle(self, *args, **options):
     if Settings.get("private_key"):
         self.stderr.write(
             "Error: This device already has an encryption key generated for it; aborting.\n"
         )
         return
     self.stdout.write(
         "Generating 2048-bit RSA encryption key (may take a few minutes; please wait)...\n"
     )
     reset_keys()
     self.stdout.write("Done!\n")
Exemple #29
0
    def setup_server_if_needed(self):
        """Run the setup command, if necessary."""

        try:  # Ensure that the database has been synced and a Device has been created
            assert Settings.get("private_key") and Device.objects.count()
        except (DatabaseError,
                AssertionError):  # Otherwise, run the setup command
            self.stdout.write(
                "Setting up KA Lite; this may take a few minutes; please wait!\n"
            )
            call_command("setup", interactive=False)
Exemple #30
0
def load_keys():
    global _own_key

    # load key strings from the Settings models
    private_key_string = Settings.get("private_key")
    public_key_string = Settings.get("public_key")

    # check whether the keys have been overridden in the settings.py file, and ensure they match any existing keys
    if hasattr(settings, "OWN_DEVICE_PUBLIC_KEY") and hasattr(settings, "OWN_DEVICE_PRIVATE_KEY"):
        assert public_key_string == "" or public_key_string == settings.OWN_DEVICE_PUBLIC_KEY, "OWN_DEVICE_PUBLIC_KEY does not match public_key in Settings"
        assert private_key_string == "" or private_key_string == settings.OWN_DEVICE_PRIVATE_KEY, "OWN_DEVICE_PRIVATE_KEY does not match private_key in Settings"
        public_key_string = settings.OWN_DEVICE_PUBLIC_KEY
        private_key_string = settings.OWN_DEVICE_PRIVATE_KEY

    # instantiate from key strings or generate new key if needed
    if private_key_string and public_key_string:
        _own_key = Key(
            public_key_string=public_key_string,
            private_key_string=private_key_string)
    else:
        reset_keys()
Exemple #31
0
def set_current_unit_settings_value(facility_id, value):
    """
    Set the value of the current unit on Settings based on the facility id.
    """
    old_unit = get_current_unit_settings_value(facility_id)
    name = get_current_unit_settings_name(facility_id)
    s = Settings.set(name, value)
    unit_switch.send(sender="None",
                     old_unit=old_unit,
                     new_unit=value,
                     facility_id=facility_id)
    return s
def set_language_data(request):
    """
    Process requests to set language, redirect to the same URL to continue processing
    without leaving the "set" in the browser history.
    """
    if "set_server_language" in request.GET:
        # Set the current server default language, and redirect (to clean browser history)
        if not request.is_admin:
            raise PermissionDenied(_("You don't have permissions to set the server's default language."))

        set_default_language(request, lang_code=request.GET["set_server_language"], global_set=True)

        # Redirect to the same URL, but without the GET param,
        #   to remove the language setting from the browser history.
        redirect_url = set_query_params(request.get_full_path(), {"set_server_language": None})
        return HttpResponseRedirect(redirect_url)

    elif "set_user_language" in request.GET:
        # Set the current user's session language, and redirect (to clean browser history)
        set_default_language(request, request.GET["set_user_language"], global_set=(request.is_logged_in and not request.is_django_user))

        # Redirect to the same URL, but without the GET param,
        #   to remove the language setting from the browser history.
        redirect_url = set_query_params(request.get_full_path(), {"set_user_language": None})
        return HttpResponseRedirect(redirect_url)

    if not "default_language" in request.session:
        # default_language has the following priority:
        #   facility user's individual setting
        #   config.Settings object's value
        #   settings' value
        request.session["default_language"] = select_best_available_language( \
            getattr(request.session.get("facility_user"), "default_language", None) \
            or Settings.get("default_language") \
            or settings.LANGUAGE_CODE
        )

    # Set this request's language based on the listed priority
    cur_lang = request.GET.get("lang") \
        or request.session.get("default_language")

    set_request_language(request, lang_code=cur_lang)
    def setup_server_if_needed(self):
        """Run the setup command, if necessary."""

        # Now, validate the server.
        try:
            if Settings.get("private_key") and Device.objects.count():
                # The only success case
                pass

            elif not Device.objects.count():
                # Nothing we can do to recover
                raise CommandError("You are screwed, buddy--you went through setup but you have no devices defined!  Call for help!")

            else:
                # Force hitting recovery code, by raising a generic error
                #   that gets us to the "except" clause
                raise DatabaseError

        except DatabaseError:
            self.stdout.write("Setting up KA Lite; this may take a few minutes; please wait!\n")

            call_command("setup", interactive=False)  # show output to the user
Exemple #34
0
 def register_device(self):
     z = Zone.objects.create(name='test_zone')
     DeviceZone.objects.create(zone=z, device=Device.get_own_device())
     Settings.set("registered", True)
def static_with_build(path, with_build=True):
    """
    We need a way for the client browser to load the newly updated static
        files because some browsers cache the static files and does not
        load them up automatically when we release new versions but with
        the same name.

    REF: https://github.com/learningequality/ka-lite/issues/1161

    One way is to add a Get paramater to the static file's path so it becomes
        unique and the browser invalidates it's cached version.

    We re-use django's `{% static <path> %}` template tag to add build version
        to the filenames of static files.

    REF: https://www.quora.com/What-are-the-best-practices-for-versioning-CSS-and-JS-files

    Option 1: Use the `fle_utils.config.models.Settings`
        Pros: It works and more flexible.
        Cons: Requires us to update the BUILD_ID key at admin page.

    Option 2: Use the BUILD as Get parameter.
        Pros: It works.
        Cons: We need to maintain the `kalite/version.py` hard-coded values
            every time we make a release.

    Option 3: Use the SHA hash of the file's bytes as querystring.
        Pros: It works and more reliable.
        Cons: Requires us to open the static files to generate the hash.
                TODO(cpauya): Benchmark this!
                TODO(cpauya): Inefficient!  This is called everytime the static file is used.

    We try all options which does not throw exception.
    """
    global BUILD_HASH_CACHE

    new_path = static_lib(path)
    if with_build:
        build_id = ''

        # try fle_utils`s Settings
        try:
            if BUILD_HASH_CACHE:
                build_id = BUILD_HASH_CACHE
            else:
                build_id = BUILD_HASH_CACHE = Settings.get(BUILD_HASH, '')
        except Exception:
            pass

        # try the BUILD data from `version.py`
        if not build_id:
            try:
                build_id = BUILD_HASH_CACHE = version.VERSION_INFO[
                    version.VERSION]["git_commit"][0:8]
            except:
                pass

        # attempt to use hash
        if not build_id:
            try:
                # REF: http://stackoverflow.com/questions/16874598/how-do-i-calculate-the-md5-checksum-of-a-file-in-python
                file_path = os.path.realpath(
                    os.path.join(settings.STATIC_ROOT, path))
                with open(file_path, 'rb') as file_to_check:
                    # REF: http://stackoverflow.com/questions/1131220/get-md5-hash-of-big-files-in-python
                    filehash = hashlib.sha256()
                    while True:
                        data = file_to_check.read(8192)
                        if not data:
                            break
                        filehash.update(data)
                    build_id = filehash.hexdigest()
            except Exception:
                pass

        if build_id:
            new_path = '%s?%s' % (
                new_path,
                build_id,
            )
    return new_path
Exemple #36
0
def reset_keys():
    sys.modules[__name__]._own_key = Key()
    Settings.set("private_key", _own_key.get_private_key_string())
    Settings.set("public_key", _own_key.get_public_key_string())
Exemple #37
0
def get_exam_mode_on():
    """
    Returns the value of the EXAM_MODE_ON or else return an empty string.
    """
    ret = Settings.get(SETTINGS_KEY_EXAM_MODE, "")
    return ret
Exemple #38
0
def get_exam_mode_on():
    """
    Returns the value of the EXAM_MODE_ON or else return an empty string.
    """
    ret = Settings.get(SETTINGS_KEY_EXAM_MODE, '')
    return ret
Exemple #39
0
    def user_progress(cls, user_id, language=None):
        """
        Return a list of PlaylistProgress objects associated with the user.
        """

        if not language:
            language = Settings.get(
                "default_language") or settings.LANGUAGE_CODE

        user = FacilityUser.objects.get(id=user_id)

        # Retrieve video, exercise, and quiz logs that appear in this playlist
        user_vid_logs, user_ex_logs = cls.get_user_logs(user)

        exercise_ids = list(
            set([ex_log["exercise_id"] for ex_log in user_ex_logs]))
        video_ids = list(
            set([vid_log["video_id"] for vid_log in user_vid_logs]))

        # Build a list of playlists for which the user has at least one data point
        user_playlists = get_content_parents(ids=exercise_ids + video_ids,
                                             language=language)

        # Store stats for each playlist
        user_progress = list()
        for i, p in enumerate(user_playlists):
            # Playlist entry totals
            pl_video_ids, pl_exercise_ids = cls.get_playlist_entry_ids(p)
            n_pl_videos = float(len(pl_video_ids))
            n_pl_exercises = float(len(pl_exercise_ids))

            # Vid & exercise logs in this playlist
            pl_ex_logs = [
                ex_log for ex_log in user_ex_logs
                if ex_log["exercise_id"] in pl_exercise_ids
            ]
            pl_vid_logs = [
                vid_log for vid_log in user_vid_logs
                if vid_log["video_id"] in pl_video_ids
            ]

            # Compute video stats
            n_vid_complete = len(
                [vid for vid in pl_vid_logs if vid["complete"]])
            n_vid_started = len([
                vid for vid in pl_vid_logs
                if (vid["total_seconds_watched"] > 0) and (not vid["complete"])
            ])
            vid_pct_complete = int(float(n_vid_complete) / n_pl_videos *
                                   100) if n_pl_videos else 0
            vid_pct_started = int(float(n_vid_started) / n_pl_videos *
                                  100) if n_pl_videos else 0
            if vid_pct_complete == 100:
                vid_status = "complete"
            elif n_vid_started > 0:
                vid_status = "inprogress"
            else:
                vid_status = "notstarted"

            # Compute exercise stats
            n_ex_mastered = len([ex for ex in pl_ex_logs if ex["complete"]])
            n_ex_started = len([ex for ex in pl_ex_logs if ex["attempts"] > 0])
            n_ex_incomplete = len([
                ex for ex in pl_ex_logs
                if (ex["attempts"] > 0 and not ex["complete"])
            ])
            n_ex_struggling = len(
                [ex for ex in pl_ex_logs if ex["struggling"]])
            ex_pct_mastered = int(
                float(n_ex_mastered) / (n_pl_exercises or 1) * 100)
            ex_pct_incomplete = int(
                float(n_ex_incomplete) / (n_pl_exercises or 1) * 100)
            ex_pct_struggling = int(
                float(n_ex_struggling) / (n_pl_exercises or 1) * 100)
            if not n_ex_started:
                ex_status = "notstarted"
            elif ex_pct_struggling > 0:
                # note: we want to help students prioritize areas they need to focus on
                # therefore if they are struggling in this exercise group, we highlight it for them
                ex_status = "struggling"
            elif ex_pct_mastered < 99:
                ex_status = "inprogress"
            else:
                ex_status = "complete"

            progress = {
                "title": p.get("title"),
                "id": p.get("id"),
                "tag": p.get("tag"),
                "vid_pct_complete": vid_pct_complete,
                "vid_pct_started": vid_pct_started,
                "vid_status": vid_status,
                "ex_pct_mastered": ex_pct_mastered,
                "ex_pct_incomplete": ex_pct_incomplete,
                "ex_pct_struggling": ex_pct_struggling,
                "ex_status": ex_status,
                "n_pl_videos": n_pl_videos,
                "n_pl_exercises": n_pl_exercises,
            }

            try:
                progress["url"] = reverse("view_playlist",
                                          kwargs={"playlist_id": p.get("id")})
            except NoReverseMatch:
                progress["url"] = reverse("learn") + p.get("path")

            user_progress.append(cls(**progress))

        return user_progress
Exemple #40
0
    def handle(self, *args, **options):
        if not options["interactive"]:
            options["hostname"] = options["hostname"] or get_host_name()

        # blank allows ansible scripts to dump errors cleanly.
        print("                                     ")
        print("   _   __  ___    _     _ _          ")
        print("  | | / / / _ \  | |   (_) |         ")
        print("  | |/ / / /_\ \ | |    _| |_ ___    ")
        print("  |    \ |  _  | | |   | | __/ _ \   ")
        print("  | |\  \| | | | | |___| | ||  __/   ")
        print("  \_| \_/\_| |_/ \_____/_|\__\___|   ")
        print("                                     ")
        print("https://learningequality.org/ka-lite/")
        print("                                     ")
        print("         version %s" % VERSION)
        print("                                     ")

        if sys.version_info < (2, 7):
            raise CommandError(
                "Support for Python version 2.6 and below had been discontinued, please upgrade."
            )
        elif sys.version_info >= (2, 8):
            raise CommandError(
                "Your Python version is: %d.%d.%d -- which is not supported. Please use the Python 2.7 series or wait for Learning Equality to release Kolibri.\n"
                % sys.version_info[:3])
        elif sys.version_info < (2, 7, 6):
            logging.warning(
                "It's recommended that you install Python version 2.7.6. Your version is: %d.%d.%d\n"
                % sys.version_info[:3])

        if options["interactive"]:
            print(
                "--------------------------------------------------------------------------------"
            )
            print(
                "This script will configure the database and prepare it for use."
            )
            print(
                "--------------------------------------------------------------------------------"
            )
            raw_input("Press [enter] to continue...")

        # Tried not to be os-specific, but ... hey. :-/
        # benjaoming: This doesn't work, why is 502 hard coded!? Root is normally
        # '0' And let's not care about stuff like this, people can be free to
        # run this as root if they want :)
        if not is_windows() and hasattr(os, "getuid") and os.getuid() == 502:
            print(
                "-------------------------------------------------------------------"
            )
            print("WARNING: You are installing KA-Lite as root user!")
            print(
                "\tInstalling as root may cause some permission problems while running"
            )
            print("\tas a normal user in the future.")
            print(
                "-------------------------------------------------------------------"
            )
            if options["interactive"]:
                if not raw_input_yn(
                        "Do you wish to continue and install it as root?"):
                    raise CommandError("Aborting script.\n")

        git_migrate_path = options["git_migrate_path"]

        if git_migrate_path:
            call_command("gitmigrate",
                         path=git_migrate_path,
                         interactive=options["interactive"])

        database_kind = settings.DATABASES["default"]["ENGINE"]
        if "sqlite" in database_kind:
            database_file = settings.DATABASES["default"]["NAME"]
        else:
            database_file = None

        database_exists = database_file and os.path.isfile(database_file)

        # An empty file is created automatically even when the database dosn't
        # exist. But if it's empty, it's safe to overwrite.
        database_exists = database_exists and os.path.getsize(
            database_file) > 0

        install_clean = not database_exists

        if database_file:
            if not database_exists:
                install_clean = True
            else:
                # We found an existing database file.  By default,
                #   we will upgrade it; users really need to work hard
                #   to delete the file (but it's possible, which is nice).
                print(
                    "-------------------------------------------------------------------"
                )
                print("WARNING: Database file already exists!")
                print(
                    "-------------------------------------------------------------------"
                )
                if not options["interactive"] \
                   or raw_input_yn("Keep database file and upgrade to KA Lite version %s? " % VERSION) \
                   or not raw_input_yn("Remove database file '%s' now? " % database_file) \
                   or not raw_input_yn("WARNING: all data will be lost!  Are you sure? "):
                    install_clean = False
                    print("Upgrading database to KA Lite version %s" % VERSION)
                else:
                    install_clean = True
                    print("OK.  We will run a clean install; ")
                    # After all, don't delete--just move.
                    print(
                        "the database file will be moved to a deletable location."
                    )

        if not install_clean and not database_file:
            # Make sure that, for non-sqlite installs, the database exists.
            raise Exception(
                "For databases not using SQLite, you must set up your database before running setup."
            )

        # Do all input at once, at the beginning
        if install_clean and options["interactive"]:
            if not options["username"] or not options["password"]:
                print(
                    "Please choose a username and password for the admin account on this device."
                )
                print(
                    "\tYou must remember this login information, as you will need"
                )
                print(
                    "\tto enter it to administer this installation of KA Lite."
                )
            (username,
             password) = get_username_password(options["username"],
                                               options["password"])
            email = options["email"]
            (hostname, description) = get_hostname_and_description(
                options["hostname"], options["description"])
        else:
            username = options["username"] = (options["username"] or getattr(
                settings, "INSTALL_ADMIN_USERNAME", None)
                                              or get_clean_default_username())
            password = options["password"] or getattr(
                settings, "INSTALL_ADMIN_PASSWORD", None)
            email = options["email"]  # default is non-empty
            hostname = options["hostname"]
            description = options["description"]

        if username and not validate_username(username):
            raise CommandError(
                "Username must contain only letters, digits, and underscores, and start with a letter.\n"
            )

        ########################
        # Now do stuff
        ########################

        # Clean *pyc files if we are in a git repo
        if settings.IS_SOURCE:
            clean_pyc(settings.SOURCE_DIR)
        else:
            # Because we install dependencies as data_files, we run into problems,
            # namely that the pyc files are left dangling.
            distributed_packages = [
                os.path.join(kalite.ROOT_DATA_PATH, 'dist-packages'),
                os.path.join(kalite.ROOT_DATA_PATH, 'python-packages'),
            ]
            # Try locating django
            for dir_to_clean in distributed_packages:
                clean_pyc(dir_to_clean)

        # Move database file (if exists)
        if install_clean and database_file and os.path.exists(database_file):
            if not settings.DB_TEMPLATE_DEFAULT or database_file != settings.DB_TEMPLATE_DEFAULT:
                # This is an overwrite install; destroy the old db
                dest_file = tempfile.mkstemp()[1]
                print(
                    "(Re)moving database file to temp location, starting clean install. Recovery location: %s"
                    % dest_file)
                shutil.move(database_file, dest_file)

        if settings.DB_TEMPLATE_DEFAULT and not database_exists and os.path.exists(
                settings.DB_TEMPLATE_DEFAULT):
            print("Copying database file from {0} to {1}".format(
                settings.DB_TEMPLATE_DEFAULT, settings.DEFAULT_DATABASE_PATH))
            shutil.copy(settings.DB_TEMPLATE_DEFAULT,
                        settings.DEFAULT_DATABASE_PATH)
        else:
            print(
                "Baking a fresh database from scratch or upgrading existing database."
            )
            call_command("syncdb",
                         interactive=False,
                         verbosity=options.get("verbosity"))
            call_command("migrate",
                         merge=True,
                         verbosity=options.get("verbosity"))
        Settings.set("database_version", VERSION)

        # Copy all content item db templates
        if os.path.exists(settings.DB_CONTENT_ITEM_TEMPLATE_DIR):
            for file_name in os.listdir(settings.DB_CONTENT_ITEM_TEMPLATE_DIR):
                if file_name.endswith("sqlite"):
                    template_path = os.path.join(
                        settings.DB_CONTENT_ITEM_TEMPLATE_DIR, file_name)
                    dest_database = os.path.join(settings.DEFAULT_DATABASE_DIR,
                                                 file_name)
                    if install_clean or not os.path.exists(dest_database):
                        print("Copying {} to {}".format(
                            template_path, dest_database))
                        shutil.copy(template_path, dest_database)
                    else:
                        print("Skipping {}".format(template_path))

        # download the english content pack
        # This can take a long time and lead to Travis stalling. None of this
        # is required for tests, and does not apply to the central server.
        if options.get("no-assessment-items", False):

            logging.warning(
                "Skipping content pack downloading and configuration.")

        else:

            # Outdated location of assessment items - move assessment items from their
            # old location (CONTENT_ROOT/khan where they were mixed with other content
            # items)

            # TODO(benjaoming) for 0.15, remove the "move assessment items"
            # mechanism
            writable_assessment_items = os.access(KHAN_ASSESSMENT_ITEM_ROOT,
                                                  os.W_OK)

            # Remove old assessment items
            if os.path.exists(OLD_ASSESSMENT_ITEMS_LOCATION) and os.access(
                    OLD_ASSESSMENT_ITEMS_LOCATION, os.W_OK):
                logging.info("Deleting old assessment items")
                shutil.rmtree(OLD_ASSESSMENT_ITEMS_LOCATION)

            if writable_assessment_items and options[
                    'force-assessment-item-dl']:
                call_command("retrievecontentpack", "download", "en")
            elif options['force-assessment-item-dl']:
                raise RuntimeError(
                    "Got force-assessment-item-dl but directory not writable")
            elif not settings.RUNNING_IN_TRAVIS and options['interactive']:
                print(
                    "\nStarting in version 0.13, you will need an assessment items package in order to access many of the available exercises."
                )
                print(
                    "If you have an internet connection, you can download the needed package. Warning: this may take a long time!"
                )
                print(
                    "If you have already downloaded the assessment items package, you can specify the file in the next step."
                )
                print("Otherwise, we will download it from {url}.".format(
                    url=CONTENTPACK_URL))

                if raw_input_yn(
                        "Do you wish to download the content pack now?"):
                    ass_item_filename = CONTENTPACK_URL
                    retrieval_method = "download"
                elif raw_input_yn(
                        "Have you already downloaded the content pack?"):
                    ass_item_filename = get_assessment_items_filename()
                    retrieval_method = "local"
                else:
                    ass_item_filename = None
                    retrieval_method = "local"

                if not ass_item_filename:
                    logging.warning(
                        "No content pack given. You will need to download and unpack it later."
                    )
                else:
                    call_command("retrievecontentpack",
                                 retrieval_method,
                                 "en",
                                 ass_item_filename,
                                 foreground=True)

            elif options['interactive']:
                logging.warning(
                    "Assessment item directory not writable, skipping download."
                )
            else:
                print("Found bundled assessment items")

        # Individually generate any prerequisite models/state that is missing
        if not Settings.get("private_key"):
            call_command("generatekeys", verbosity=options.get("verbosity"))
        if not Device.objects.count():
            call_command("initdevice",
                         hostname,
                         description,
                         verbosity=options.get("verbosity"))
        if not Facility.objects.count():
            Facility.initialize_default_facility()

        # Create the admin user
        # blank password (non-interactive) means don't create a superuser
        if password:
            admin = get_object_or_None(User, username=username)
            if not admin:
                call_command("createsuperuser",
                             username=username,
                             email=email,
                             interactive=False,
                             verbosity=options.get("verbosity"))
                admin = User.objects.get(username=username)
            admin.set_password(password)
            admin.save()

        # Now deploy the static files
        logging.info("Copying static media...")
        call_command("collectstatic",
                     interactive=False,
                     verbosity=0,
                     ignore_patterns=['vtt', 'html', 'srt'],
                     clear=True)
        call_command("collectstatic_js_reverse", interactive=False)

        # This is not possible in a distributed env
        if not settings.CENTRAL_SERVER:

            kalite_executable = 'kalite'
            if not spawn.find_executable('kalite'):
                if os.name == 'posix':
                    start_script_path = os.path.realpath(
                        os.path.join(settings.PROJECT_PATH, "..", "bin",
                                     kalite_executable))
                else:
                    start_script_path = os.path.realpath(
                        os.path.join(settings.PROJECT_PATH, "..", "bin",
                                     "windows", "kalite.bat"))
            else:
                start_script_path = kalite_executable

            # Run annotate_content_items, on the distributed server.
            print(
                "Annotating availability of all content, checking for content in this directory: (%s)"
                % settings.CONTENT_ROOT)
            try:
                call_command("annotate_content_items")
            except OperationalError:
                pass

            # done; notify the user.
            print(
                "\nCONGRATULATIONS! You've finished setting up the KA Lite server software."
            )
            print(
                "You can now start KA Lite with the following command:\n\n\t%s start\n\n"
                % start_script_path)

            if options['interactive']:
                if raw_input_yn("Do you wish to start the server now?"):
                    print("Running {0} start".format(start_script_path))
                    p = subprocess.Popen([start_script_path, "start"],
                                         env=os.environ)
                    p.wait()
Exemple #41
0
def get_default_language():
    """Returns: the default language (ietf-formatted language code)"""
    return Settings.get("default_language") or settings.LANGUAGE_CODE or "en"
Exemple #42
0
    def handle(self, *args, **options):
        if not options["interactive"]:
            options["hostname"] = options["hostname"] or get_host_name()

        # blank allows ansible scripts to dump errors cleanly.
        logger.info(
            "                                     \n"
            "   _   __  ___    _     _ _          \n"
            "  | | / / / _ \  | |   (_) |         \n"
            "  | |/ / / /_\ \ | |    _| |_ ___    \n"
            "  |    \ |  _  | | |   | | __/ _ \   \n"
            "  | |\  \| | | | | |___| | ||  __/   \n"
            "  \_| \_/\_| |_/ \_____/_|\__\___|   \n"
            "                                     \n"
            "https://learningequality.org/ka-lite/\n"
            "                                     \n"
            "         version {version:s}\n"
            "                                     ".format(
                version=VERSION
            )
        )

        if sys.version_info < (2, 7):
            raise CommandError(
                "Support for Python version 2.6 and below had been discontinued, please upgrade.")
        elif sys.version_info >= (2, 8):
            raise CommandError(
                "Your Python version is: %d.%d.%d -- which is not supported. Please use the Python 2.7 series or wait for Learning Equality to release Kolibri.\n" % sys.version_info[:3])
        elif sys.version_info < (2, 7, 6):
            logger.warning(
                "It's recommended that you install Python version 2.7.6. Your version is: %d.%d.%d\n" % sys.version_info[:3])

        if options["interactive"]:
            logger.info(
                "--------------------------------------------------------------------------------\n"
                "This script will configure the database and prepare it for use.\n"
                "--------------------------------------------------------------------------------\n"
            )
            raw_input("Press [enter] to continue...")

        # Assuming uid '0' is always root
        if not is_windows() and hasattr(os, "getuid") and os.getuid() == 0:
            logger.info(
                "-------------------------------------------------------------------\n"
                "WARNING: You are installing KA-Lite as root user!\n"
                "    Installing as root may cause some permission problems while running\n"
                "    as a normal user in the future.\n"
                "-------------------------------------------------------------------\n"
            )
            if options["interactive"]:
                if not raw_input_yn("Do you wish to continue and install it as root?"):
                    raise CommandError("Aborting script.\n")

        database_kind = settings.DATABASES["default"]["ENGINE"]
        if "sqlite" in database_kind:
            database_file = settings.DATABASES["default"]["NAME"]
        else:
            database_file = None

        database_exists = database_file and os.path.isfile(database_file)

        # An empty file is created automatically even when the database dosn't
        # exist. But if it's empty, it's safe to overwrite.
        database_exists = database_exists and os.path.getsize(
            database_file) > 0

        install_clean = not database_exists

        if database_file:
            if not database_exists:
                install_clean = True
            else:
                # We found an existing database file.  By default,
                #   we will upgrade it; users really need to work hard
                #   to delete the file (but it's possible, which is nice).
                logger.info(
                    "-------------------------------------------------------------------\n"
                    "WARNING: Database file already exists!\n"
                    "-------------------------------------------------------------------"
                )
                if not options["interactive"] \
                   or raw_input_yn("Keep database file and upgrade to KA Lite version %s? " % VERSION) \
                   or not raw_input_yn("Remove database file '%s' now? " % database_file) \
                   or not raw_input_yn("WARNING: all data will be lost!  Are you sure? "):
                    install_clean = False
                    logger.info("Upgrading database to KA Lite version %s" % VERSION)
                else:
                    install_clean = True
                    logger.info("OK.  We will run a clean install; ")
                    # After all, don't delete--just move.
                    logger.info(
                        "the database file will be moved to a deletable "
                        "location."
                    )

        if not install_clean and not database_file:
            # Make sure that, for non-sqlite installs, the database exists.
            raise Exception(
                "For databases not using SQLite, you must set up your database before running setup.")

        # Do all input at once, at the beginning
        if install_clean and options["interactive"]:
            if not options["username"] or not options["password"]:
                logger.info(
                    "Please choose a username and password for the admin account on this device.\n"
                    "    You must remember this login information, as you will need\n"
                    "    to enter it to administer this installation of KA Lite."
                )
            (username, password) = get_username_password(
                options["username"], options["password"])
            email = options["email"]
            (hostname, description) = get_hostname_and_description(
                options["hostname"], options["description"])
        else:
            username = options["username"] = (
                options["username"] or
                getattr(settings, "INSTALL_ADMIN_USERNAME", None) or
                get_clean_default_username()
            )
            password = options["password"] or getattr(
                settings, "INSTALL_ADMIN_PASSWORD", None)
            email = options["email"]  # default is non-empty
            hostname = options["hostname"]
            description = options["description"]

        if username and not validate_username(username):
            raise CommandError(
                "Username must contain only letters, digits, and underscores, and start with a letter.\n")

        ########################
        # Now do stuff
        ########################

        # Move database file (if exists)
        if install_clean and database_file and os.path.exists(database_file):
            if not settings.DB_TEMPLATE_DEFAULT or database_file != settings.DB_TEMPLATE_DEFAULT:
                # This is an overwrite install; destroy the old db
                dest_file = tempfile.mkstemp()[1]
                logger.info(
                    "(Re)moving database file to temp location, starting "
                    "clean install. Recovery location: {recovery:s}".format(
                        recovery=dest_file
                    )
                )
                shutil.move(database_file, dest_file)

        if settings.DB_TEMPLATE_DEFAULT and not database_exists and os.path.exists(settings.DB_TEMPLATE_DEFAULT):
            logger.info(
                "Copying database file from {0} to {1}".format(
                    settings.DB_TEMPLATE_DEFAULT,
                    settings.DEFAULT_DATABASE_PATH
                )
            )
            shutil.copy(
                settings.DB_TEMPLATE_DEFAULT, settings.DEFAULT_DATABASE_PATH)
        else:
            logger.info(
                "Baking a fresh database from scratch or upgrading existing "
                "database."
            )
            call_command(
                "syncdb", interactive=False, verbosity=options.get("verbosity"))
            call_command(
                "migrate", merge=True, verbosity=options.get("verbosity"))
        Settings.set("database_version", VERSION)

        # Copy all content item db templates
        reset_content_db(force=install_clean)

        # download the english content pack
        # This can take a long time and lead to Travis stalling. None of this
        # is required for tests, and does not apply to the central server.
        if options.get("no-assessment-items", False):

            logger.warning(
                "Skipping content pack downloading and configuration.")

        else:

            # user wants to force a new download; do it if we can, else error
            if options['force-assessment-item-dl']:
                call_command("retrievecontentpack", "download", "en")
            else:
                detect_content_packs(options)

        # Individually generate any prerequisite models/state that is missing
        if not Settings.get("private_key"):
            call_command("generatekeys", verbosity=options.get("verbosity"))
        if not Device.objects.count():
            call_command(
                "initdevice", hostname, description, verbosity=options.get("verbosity"))
        if not Facility.objects.count():
            Facility.initialize_default_facility()

        # Create the admin user
        # blank password (non-interactive) means don't create a superuser
        if password:
            admin = get_object_or_None(User, username=username)
            if not admin:
                call_command("createsuperuser", username=username, email=email,
                             interactive=False, verbosity=options.get("verbosity"))
                admin = User.objects.get(username=username)
            admin.set_password(password)
            admin.save()

        # Now deploy the static files
        logger.info("Copying static media...")
        ensure_dir(settings.STATIC_ROOT)

        call_command("collectstatic", interactive=False, verbosity=0, clear=True)
        call_command("collectstatic_js_reverse", interactive=False)

        # This is not possible in a distributed env
        if not settings.CENTRAL_SERVER:

            kalite_executable = 'kalite'
            if spawn.find_executable(kalite_executable):
                start_script_path = kalite_executable
            else:
                start_script_path = None

            # Run annotate_content_items, on the distributed server.
            logger.info(
                "Annotating availability of all content, checking for content "
                "in this directory: {content_root:s}".format(
                    content_root=settings.CONTENT_ROOT
                )
            )
            try:
                call_command("annotate_content_items")
            except OperationalError:
                pass

            # done; notify the user.
            logger.info(
                "\nCONGRATULATIONS! You've finished setting up the KA Lite "
                "server software."
            )
            logger.info(
                "You can now start KA Lite with the following command:"
                "\n\n"
                "    {kalite_cmd} start"
                "\n\n".format(
                    kalite_cmd=start_script_path
                )
            )

            if options['interactive'] and start_script_path:
                if raw_input_yn("Do you wish to start the server now?"):
                    logger.info("Running {0} start".format(start_script_path))
                    p = subprocess.Popen(
                        [start_script_path, "start"], env=os.environ)
                    p.wait()
Exemple #43
0
def get_default_language():
    """Returns: the default language (ietf-formatted language code)"""
    return Settings.get("default_language") or settings.LANGUAGE_CODE or "en"
Exemple #44
0
    def user_progress_detail(cls, user_id, playlist_id, language=None):
        """
        Return a list of video, exercise, and quiz log PlaylistProgressDetail
        objects associated with a specific user and playlist ID.
        """
        if not language:
            language = Settings.get(
                "default_language") or settings.LANGUAGE_CODE

        user = FacilityUser.objects.get(id=user_id)
        playlist = next(
            (pl for pl in get_leafed_topics() if pl.get("id") == playlist_id),
            None)

        pl_video_ids, pl_exercise_ids = cls.get_playlist_entry_ids(playlist)

        # Retrieve video, exercise, and quiz logs that appear in this playlist
        user_vid_logs, user_ex_logs = cls.get_user_logs(
            user, pl_video_ids, pl_exercise_ids)

        # Format & append quiz the quiz log, if it exists
        # quiz_exists, quiz_log, quiz_pct_score = cls.get_quiz_log(user, (playlist.get("entries") or playlist.get("children")), playlist.get("id"))

        # Finally, sort an ordered list of the playlist entries, with user progress
        # injected where it exists.
        progress_details = list()
        for entity_id in playlist.get("children"):
            entry = {}
            leaf_node = get_content_cache(
                language=language).get(entity_id) or get_exercise_cache(
                    language=language).get(entity_id) or {}
            kind = leaf_node.get("kind")

            status = "notstarted"
            score = 0

            if kind == "Video":
                vid_log = next((vid_log for vid_log in user_vid_logs
                                if vid_log["video_id"] == entity_id), None)
                if vid_log:
                    if vid_log.get("complete"):
                        status = "complete"
                    elif vid_log.get("total_seconds_watched"):
                        status = "inprogress"

                    score = int(
                        float(vid_log.get("points")) / float(750) * 100)

            elif kind == "Exercise":
                ex_log = next((ex_log for ex_log in user_ex_logs
                               if ex_log["exercise_id"] == entity_id), None)
                if ex_log:
                    if ex_log.get("struggling"):
                        status = "struggling"
                    elif ex_log.get("complete"):
                        status = "complete"
                    elif ex_log.get("attempts"):
                        status = "inprogress"

                    score = ex_log.get('streak_progress')

            entry = {
                "id": entity_id,
                "kind": kind,
                "status": status,
                "score": score,
                "title": leaf_node["title"],
                "path": leaf_node["path"],
            }

            progress_details.append(cls(**entry))

        return progress_details
Exemple #45
0
    def user_progress(cls, user_id, language=None):
        """
        Return a list of PlaylistProgress objects associated with the user.
        """

        if not language:
            language = Settings.get("default_language") or settings.LANGUAGE_CODE

        user = FacilityUser.objects.get(id=user_id)
        all_playlists = get_leafed_topics(language=language)

        # Retrieve video, exercise, and quiz logs that appear in this playlist
        user_vid_logs, user_ex_logs = cls.get_user_logs(user)

        exercise_ids = set([ex_log["exercise_id"] for ex_log in user_ex_logs])
        video_ids = set([get_id2slug_map().get(vid_log["video_id"]) for vid_log in user_vid_logs])
        # quiz_log_ids = [ql_id["quiz"] for ql_id in QuizLog.objects.filter(user=user).values("quiz")]
        # Build a list of playlists for which the user has at least one data point
        user_playlists = list()
        for p in all_playlists:
            for e_id in p.get("children"):

                if e_id in exercise_ids or e_id in video_ids:
                    user_playlists.append(p)
                    break

        # Store stats for each playlist
        user_progress = list()
        for i, p in enumerate(user_playlists):
            # Playlist entry totals
            pl_video_ids, pl_exercise_ids = cls.get_playlist_entry_ids(p)
            n_pl_videos = float(len(pl_video_ids))
            n_pl_exercises = float(len(pl_exercise_ids))

            # Vid & exercise logs in this playlist
            pl_ex_logs = [ex_log for ex_log in user_ex_logs if ex_log["exercise_id"] in pl_exercise_ids]
            pl_vid_logs = [vid_log for vid_log in user_vid_logs if vid_log["video_id"] in pl_video_ids]

            # Compute video stats
            n_vid_complete = len([vid for vid in pl_vid_logs if vid["complete"]])
            n_vid_started = len([vid for vid in pl_vid_logs if (vid["total_seconds_watched"] > 0) and (not vid["complete"])])
            vid_pct_complete = int(float(n_vid_complete) / n_pl_videos * 100) if n_pl_videos else 0
            vid_pct_started = int(float(n_vid_started) / n_pl_videos * 100) if n_pl_videos else 0
            if vid_pct_complete == 100:
                vid_status = "complete"
            elif n_vid_started > 0:
                vid_status = "inprogress"
            else:
                vid_status = "notstarted"

            # Compute exercise stats
            n_ex_mastered = len([ex for ex in pl_ex_logs if ex["complete"]])
            n_ex_started = len([ex for ex in pl_ex_logs if ex["attempts"] > 0])
            n_ex_incomplete = len([ex for ex in pl_ex_logs if (ex["attempts"] > 0 and not ex["complete"])])
            n_ex_struggling = len([ex for ex in pl_ex_logs if ex["struggling"]])
            ex_pct_mastered = int(float(n_ex_mastered) / (n_pl_exercises or 1) * 100)
            ex_pct_incomplete = int(float(n_ex_incomplete) / (n_pl_exercises or 1) * 100)
            ex_pct_struggling = int(float(n_ex_struggling) / (n_pl_exercises or 1) * 100)
            if not n_ex_started:
                ex_status = "notstarted"
            elif ex_pct_struggling > 0:
                # note: we want to help students prioritize areas they need to focus on
                # therefore if they are struggling in this exercise group, we highlight it for them
                ex_status = "struggling"
            elif ex_pct_mastered < 99:
                ex_status = "inprogress"
            else:
                ex_status = "complete"

            # Oh Quizzes, we hardly knew ye!
            # TODO (rtibbles): Sort out the status of Quizzes, and either reinstate them or remove them.
            # Compute quiz stats
            # quiz_exists, quiz_log, quiz_pct_score = cls.get_quiz_log(user, (p.get("entries") or p.get("children")), p.get("id"))
            # if quiz_log:
            #     if quiz_pct_score <= 50:
            #         quiz_status = "struggling"
            #     elif quiz_pct_score <= 79:
            #         quiz_status = "borderline"
            #     else:
            #         quiz_status = "complete"
            # else:
            #     quiz_status = "notstarted"

            progress = {
                "title": p.get("title"),
                "id": p.get("id"),
                "tag": p.get("tag"),
                "vid_pct_complete": vid_pct_complete,
                "vid_pct_started": vid_pct_started,
                "vid_status": vid_status,
                "ex_pct_mastered": ex_pct_mastered,
                "ex_pct_incomplete": ex_pct_incomplete,
                "ex_pct_struggling": ex_pct_struggling,
                "ex_status": ex_status,
                # "quiz_status": quiz_status,
                # "quiz_exists": quiz_exists,
                # "quiz_pct_score": quiz_pct_score,
                "n_pl_videos": n_pl_videos,
                "n_pl_exercises": n_pl_exercises,
            }

            try:
                progress["url"] = reverse("view_playlist", kwargs={"playlist_id": p.get("id")})
            except NoReverseMatch:
                progress["url"] = reverse("learn") + p.get("path")

            user_progress.append(cls(**progress))

        return user_progress
Exemple #46
0
    def handle(self, *args, **options):
        if not options["interactive"]:
            options["hostname"] = options["hostname"] or get_host_name()

        # blank allows ansible scripts to dump errors cleanly.
        print("                                  ")
        print("  _   __  ___    _     _ _        ")
        print(" | | / / / _ \  | |   (_) |       ")
        print(" | |/ / / /_\ \ | |    _| |_ ___  ")
        print(" |    \ |  _  | | |   | | __/ _ \ ")
        print(" | |\  \| | | | | |___| | ||  __/ ")
        print(" \_| \_/\_| |_/ \_____/_|\__\___| ")
        print("                                  ")
        print("http://kalite.learningequality.org")
        print("                                  ")
        print("         version %s" % VERSION)
        print("                                  ")

        if sys.version_info >= (2, 8) or sys.version_info < (2, 6):
            raise CommandError(
                "You must have Python version 2.6.x or 2.7.x installed. Your version is: %s\n" % str(sys.version_info))
        if sys.version_info < (2, 7, 9):
            logging.warning(
                "It's recommended that you install Python version 2.7.9. Your version is: %s\n" % str(sys.version_info))

        if options["interactive"]:
            print(
                "--------------------------------------------------------------------------------")
            print(
                "This script will configure the database and prepare it for use.")
            print(
                "--------------------------------------------------------------------------------")
            raw_input("Press [enter] to continue...")

        # Tried not to be os-specific, but ... hey. :-/
        # benjaoming: This doesn't work, why is 502 hard coded!? Root is normally
        # '0' And let's not care about stuff like this, people can be free to
        # run this as root if they want :)
        if not is_windows() and hasattr(os, "getuid") and os.getuid() == 502:
            print(
                "-------------------------------------------------------------------")
            print("WARNING: You are installing KA-Lite as root user!")
            print(
                "\tInstalling as root may cause some permission problems while running")
            print("\tas a normal user in the future.")
            print(
                "-------------------------------------------------------------------")
            if options["interactive"]:
                if not raw_input_yn("Do you wish to continue and install it as root?"):
                    raise CommandError("Aborting script.\n")

        git_migrate_path = options["git_migrate_path"]

        if git_migrate_path:
            call_command("gitmigrate", path=git_migrate_path)
        
        # TODO(benjaoming): This is used very loosely, what does it mean?
        # Does it mean that the installation path is clean or does it mean
        # that we should remove (clean) items from a previous installation?
        install_clean = not kalite.is_installed()
        
        database_kind = settings.DATABASES["default"]["ENGINE"]
        database_file = (
            "sqlite" in database_kind and settings.DATABASES["default"]["NAME"]) or None

        if database_file and os.path.exists(database_file):
            # We found an existing database file.  By default,
            #   we will upgrade it; users really need to work hard
            #   to delete the file (but it's possible, which is nice).
            print(
                "-------------------------------------------------------------------")
            print("WARNING: Database file already exists!")
            print(
                "-------------------------------------------------------------------")
            if not options["interactive"] \
               or raw_input_yn("Keep database file and upgrade to KA Lite version %s? " % VERSION) \
               or not raw_input_yn("Remove database file '%s' now? " % database_file) \
               or not raw_input_yn("WARNING: all data will be lost!  Are you sure? "):
                install_clean = False
                print("Upgrading database to KA Lite version %s" % VERSION)
            else:
                install_clean = True
                print("OK.  We will run a clean install; ")
                # After all, don't delete--just move.
                print(
                    "the database file will be moved to a deletable location.")

        if not install_clean and not database_file and not kalite.is_installed():
            # Make sure that, for non-sqlite installs, the database exists.
            raise Exception(
                "For databases not using SQLite, you must set up your database before running setup.")

        # Do all input at once, at the beginning
        if install_clean and options["interactive"]:
            if not options["username"] or not options["password"]:
                print(
                    "Please choose a username and password for the admin account on this device.")
                print(
                    "\tYou must remember this login information, as you will need")
                print(
                    "\tto enter it to administer this installation of KA Lite.")
            (username, password) = get_username_password(
                options["username"], options["password"])
            email = options["email"]
            (hostname, description) = get_hostname_and_description(
                options["hostname"], options["description"])
        else:
            username = options["username"] = options["username"] or \
                                             getattr(settings, "INSTALL_ADMIN_USERNAME", None) or \
                                             get_clean_default_username()
            password = options["password"] or getattr(settings, "INSTALL_ADMIN_PASSWORD", None)
            email = options["email"]  # default is non-empty
            hostname = options["hostname"]
            description = options["description"]

        if username and not validate_username(username):
            raise CommandError(
                "Username must contain only letters, digits, and underscores, and start with a letter.\n")

        ########################
        # Now do stuff
        ########################

        # Clean *pyc files if we are in a git repo
        if settings.IS_SOURCE:
            clean_pyc(settings.SOURCE_DIR)
        else:
            # Because we install dependencies as data_files, we run into problems,
            # namely that the pyc files are left dangling.
            distributed_packages = [
                os.path.join(kalite.ROOT_DATA_PATH, 'dist-packages'),
                os.path.join(kalite.ROOT_DATA_PATH, 'python-packages'),
            ]
            # Try locating django
            for dir_to_clean in distributed_packages:
                clean_pyc(dir_to_clean)
            
        # Move database file (if exists)
        if install_clean and database_file and os.path.exists(database_file):
            # This is an overwrite install; destroy the old db
            dest_file = tempfile.mkstemp()[1]
            print(
                "(Re)moving database file to temp location, starting clean install. Recovery location: %s" % dest_file)
            shutil.move(database_file, dest_file)

        # benjaoming: Commented out, this hits the wrong directories currently
        # and should not be necessary.
        # If we have problems with pyc files, we're doing something else wrong.
        # See https://github.com/learningequality/ka-lite/issues/3487

        # Should clean_pyc for (clean) reinstall purposes
        # call_command("clean_pyc", interactive=False, verbosity=options.get("verbosity"), path=os.path.join(settings.PROJECT_PATH, ".."))

        # Migrate the database
        call_command(
            "syncdb", interactive=False, verbosity=options.get("verbosity"))
        call_command("migrate", merge=True, verbosity=options.get("verbosity"))
        # Create *.json and friends database
        call_command("syncdb", interactive=False, verbosity=options.get(
            "verbosity"), database="assessment_items")

        # download assessment items
        # This can take a long time and lead to Travis stalling. None of this
        # is required for tests.

        # Outdated location of assessment items
        # TODO(benjaoming) for 0.15, remove this
        writable_assessment_items = os.access(
            settings.KHAN_ASSESSMENT_ITEM_ROOT, os.W_OK)

        def _move_to_new_location(old, new):
            if not writable_assessment_items:
                return
            if os.path.exists(old):
                if os.access(settings.KHAN_CONTENT_PATH, os.W_OK):
                    os.rename(old, new)
        _move_to_new_location(
            os.path.join(settings.KHAN_CONTENT_PATH, 'assessmentitems.sqlite'),
            settings.KHAN_ASSESSMENT_ITEM_DATABASE_PATH
        )
        _move_to_new_location(
            os.path.join(
                settings.KHAN_CONTENT_PATH, 'assessmentitems.version'),
            settings.KHAN_ASSESSMENT_ITEM_VERSION_PATH
        )
        _move_to_new_location(
            os.path.join(
                settings.USER_DATA_ROOT, "data", "khan", "assessmentitems.json"),
            settings.KHAN_ASSESSMENT_ITEM_JSON_PATH
        )
        if writable_assessment_items and options['force-assessment-item-dl']:
            call_command(
                "unpack_assessment_zip", settings.ASSESSMENT_ITEMS_ZIP_URL)
        elif options['force-assessment-item-dl']:
            raise RuntimeError(
                "Got force-assessment-item-dl but directory not writable")
        elif writable_assessment_items and not settings.RUNNING_IN_TRAVIS and options['interactive']:
            print(
                "\nStarting in version 0.13, you will need an assessment items package in order to access many of the available exercises.")
            print(
                "If you have an internet connection, you can download the needed package. Warning: this may take a long time!")
            print(
                "If you have already downloaded the assessment items package, you can specify the file in the next step.")
            print("Otherwise, we will download it from {url}.".format(
                url=settings.ASSESSMENT_ITEMS_ZIP_URL))

            if raw_input_yn("Do you wish to download the assessment items package now?"):
                ass_item_filename = settings.ASSESSMENT_ITEMS_ZIP_URL
            elif raw_input_yn("Have you already downloaded the assessment items package?"):
                ass_item_filename = get_assessment_items_filename()
            else:
                ass_item_filename = None

            if not ass_item_filename:
                logging.warning(
                    "No assessment items package file given. You will need to download and unpack it later.")
            else:
                call_command("unpack_assessment_zip", ass_item_filename)
        elif options['interactive']:
            logging.warning(
                "Assessment item directory not writable, skipping download.")
        else:
            logging.warning(
                "No assessment items package file given. You will need to download and unpack it later.")

        # Individually generate any prerequisite models/state that is missing
        if not Settings.get("private_key"):
            call_command("generatekeys", verbosity=options.get("verbosity"))
        if not Device.objects.count():
            call_command(
                "initdevice", hostname, description, verbosity=options.get("verbosity"))
        if not Facility.objects.count():
            Facility.initialize_default_facility()

        # Create the admin user
        # blank password (non-interactive) means don't create a superuser
        if password:
            admin = get_object_or_None(User, username=username)
            if not admin:
                call_command("createsuperuser", username=username, email=email,
                             interactive=False, verbosity=options.get("verbosity"))
                admin = User.objects.get(username=username)
            admin.set_password(password)
            admin.save()

        # Now deploy the static files
        logging.info("Copying static media...")
        call_command("collectstatic", interactive=False, verbosity=0)

        # This is not possible in a distributed env
        if not settings.CENTRAL_SERVER:

            kalite_executable = 'kalite'
            if not spawn.find_executable('kalite'):
                if os.name == 'posix':
                    start_script_path = os.path.realpath(
                        os.path.join(settings.PROJECT_PATH, "..", "bin", kalite_executable))
                else:
                    start_script_path = os.path.realpath(
                        os.path.join(settings.PROJECT_PATH, "..", "bin", "windows", "kalite.bat"))
            else:
                start_script_path = kalite_executable

            # Run videoscan, on the distributed server.
            print("Scanning for video files in the content directory (%s)" %
                  settings.CONTENT_ROOT)
            call_command("videoscan")

            # done; notify the user.
            print(
                "CONGRATULATIONS! You've finished setting up the KA Lite server software.")
            print(
                "You can now start KA Lite with the following command:\n\n\t%s start\n\n" % start_script_path)
Exemple #47
0
    def handle(self, *args, **options):
        if not options["interactive"]:
            options["username"] = options["username"] or getattr(settings, "INSTALL_ADMIN_USERNAME", None) or get_clean_default_username()
            options["hostname"] = options["hostname"] or get_host_name()

        sys.stdout.write("                                  \n")  # blank allows ansible scripts to dump errors cleanly.
        sys.stdout.write("  _   __  ___    _     _ _        \n")
        sys.stdout.write(" | | / / / _ \  | |   (_) |       \n")
        sys.stdout.write(" | |/ / / /_\ \ | |    _| |_ ___  \n")
        sys.stdout.write(" |    \ |  _  | | |   | | __/ _ \ \n")
        sys.stdout.write(" | |\  \| | | | | |___| | ||  __/ \n")
        sys.stdout.write(" \_| \_/\_| |_/ \_____/_|\__\___| \n")
        sys.stdout.write("                                  \n")
        sys.stdout.write("http://kalite.learningequality.org\n")
        sys.stdout.write("                                  \n")
        sys.stdout.write("         version %s\n" % VERSION)
        sys.stdout.write("                                  \n")

        if sys.version_info >= (2,8) or sys.version_info < (2,6):
            raise CommandError("You must have Python version 2.6.x or 2.7.x installed. Your version is: %s\n" % sys.version_info)

        if options["interactive"]:
            sys.stdout.write("--------------------------------------------------------------------------------\n")
            sys.stdout.write("\n")
            sys.stdout.write("This script will configure the database and prepare it for use.\n")
            sys.stdout.write("\n")
            sys.stdout.write("--------------------------------------------------------------------------------\n")
            sys.stdout.write("\n")
            raw_input("Press [enter] to continue...")
            sys.stdout.write("\n")

        # Tried not to be os-specific, but ... hey. :-/
        if not is_windows() and hasattr(os, "getuid") and os.getuid() == 502:
            sys.stdout.write("-------------------------------------------------------------------\n")
            sys.stdout.write("WARNING: You are installing KA-Lite as root user!\n")
            sys.stdout.write("\tInstalling as root may cause some permission problems while running\n")
            sys.stdout.write("\tas a normal user in the future.\n")
            sys.stdout.write("-------------------------------------------------------------------\n")
            if options["interactive"]:
                if not raw_input_yn("Do you wish to continue and install it as root?"):
                    raise CommandError("Aborting script.\n")
                sys.stdout.write("\n")

        # Check to see if the current user is the owner of the install directory
        if not os.access(BASE_DIR, os.W_OK):
            raise CommandError("You do not have permission to write to this directory!")

        install_clean = not kalite.is_installed()
        database_kind = settings.DATABASES["default"]["ENGINE"]
        database_file = ("sqlite" in database_kind and settings.DATABASES["default"]["NAME"]) or None

        if database_file and os.path.exists(database_file):
            # We found an existing database file.  By default,
            #   we will upgrade it; users really need to work hard
            #   to delete the file (but it's possible, which is nice).
            sys.stdout.write("-------------------------------------------------------------------\n")
            sys.stdout.write("WARNING: Database file already exists! \n")
            sys.stdout.write("-------------------------------------------------------------------\n")
            if not options["interactive"] \
               or raw_input_yn("Keep database file and upgrade to KA Lite version %s? " % VERSION) \
               or not raw_input_yn("Remove database file '%s' now? " % database_file) \
               or not raw_input_yn("WARNING: all data will be lost!  Are you sure? "):
                install_clean = False
                sys.stdout.write("Upgrading database to KA Lite version %s\n" % VERSION)
            else:
                install_clean = True
                sys.stdout.write("OK.  We will run a clean install; \n")
                sys.stdout.write("the database file will be moved to a deletable location.\n")  # After all, don't delete--just move.

        if not install_clean and not database_file and not kalite.is_installed():
            # Make sure that, for non-sqlite installs, the database exists.
            raise Exception("For databases not using SQLite, you must set up your database before running setup.")

        # Do all input at once, at the beginning
        if install_clean and options["interactive"]:
            if not options["username"] or not options["password"]:
                sys.stdout.write("\n")
                sys.stdout.write("Please choose a username and password for the admin account on this device.\n")
                sys.stdout.write("\tYou must remember this login information, as you will need\n")
                sys.stdout.write("\tto enter it to administer this installation of KA Lite.\n")
                sys.stdout.write("\n")
            (username, password) = get_username_password(options["username"], options["password"])
            email = options["email"]
            (hostname, description) = get_hostname_and_description(options["hostname"], options["description"])
        else:
            username = options["username"] or getattr(settings, "INSTALL_ADMIN_USERNAME", None)
            password = options["password"] or getattr(settings, "INSTALL_ADMIN_PASSWORD", None)
            email = options["email"]  # default is non-empty
            hostname = options["hostname"]
            description = options["description"]

        if username and not validate_username(username):
            raise CommandError("Username must contain only letters, digits, and underscores, and start with a letter.\n")


        ########################
        # Now do stuff
        ########################

        # Move database file (if exists)
        if install_clean and database_file and os.path.exists(database_file):
            # This is an overwrite install; destroy the old db
            dest_file = tempfile.mkstemp()[1]
            sys.stdout.write("(Re)moving database file to temp location, starting clean install.  Recovery location: %s\n" % dest_file)
            shutil.move(database_file, dest_file)

        # Should clean_pyc for (clean) reinstall purposes
        call_command("clean_pyc", interactive=False, verbosity=options.get("verbosity"), path=os.path.join(settings.PROJECT_PATH, ".."))

        # Migrate the database
        call_command("syncdb", interactive=False, verbosity=options.get("verbosity"))
        call_command("migrate", merge=True, verbosity=options.get("verbosity"))

        # Individually generate any prerequisite models/state that is missing
        if not Settings.get("private_key"):
            call_command("generatekeys", verbosity=options.get("verbosity"))
        if not Device.objects.count():
            call_command("initdevice", hostname, description, verbosity=options.get("verbosity"))
        if not Facility.objects.count():
            Facility.initialize_default_facility()

        # Install data
        # if install_clean:
        #     # Create device, load on any zone data
        #     call_command("generatekeys", verbosity=options.get("verbosity"))
        #     call_command("initdevice", hostname, description, verbosity=options.get("verbosity"))
        #     Facility.initialize_default_facility()

        #else:
            # Device exists; load data if required.
            #
            # Hackish, as this duplicates code from initdevice.
            #
            #if os.path.exists(InitCommand.data_json_file):
            #    # This is a pathway to install zone-based data on a software upgrade.
            #    sys.stdout.write("Loading zone data from '%s'\n" % InitCommand.data_json_file)
            #    load_data_for_offline_install(in_file=InitCommand.data_json_file)

        #    confirm_or_generate_zone()

        # Create the admin user
        if password:  # blank password (non-interactive) means don't create a superuser
            admin = get_object_or_None(User, username=username)
            if not admin:
                call_command("createsuperuser", username=username, email=email, interactive=False, verbosity=options.get("verbosity"))
                admin = User.objects.get(username=username)
            admin.set_password(password)
            admin.save()

        # Now deploy the static files
        call_command("collectstatic", interactive=False)

        if not settings.CENTRAL_SERVER:
            # Move scripts
            for script_name in ["start", "stop", "run_command"]:
                script_file = script_name + system_script_extension()
                dest_dir = os.path.join(settings.PROJECT_PATH, "..")
                src_dir = os.path.join(dest_dir, "scripts")
                shutil.copyfile(os.path.join(src_dir, script_file), os.path.join(dest_dir, script_file))
                try:
                    shutil.copystat(os.path.join(src_dir, script_file), os.path.join(dest_dir, script_file))
                except OSError: # even if we have write permission, we might not have permission to change file mode
                    sys.stdout.write("WARNING: Unable to set file permissions on %s! \n" % script_file)

            start_script_path = os.path.realpath(os.path.join(settings.PROJECT_PATH, "..", "start%s" % system_script_extension()))

            # Run videoscan, on the distributed server.
            sys.stdout.write("Scanning for video files in the content directory (%s)\n" % settings.CONTENT_ROOT)
            call_command("videoscan")

            # done; notify the user.
            sys.stdout.write("\n")
            if install_clean:
                sys.stdout.write("CONGRATULATIONS! You've finished setting up the KA Lite server software.\n")
                sys.stdout.write("\tPlease run '%s' to start the server,\n" % start_script_path)
                sys.stdout.write("\tthen load one of the following addresses in your browser to complete the configuration:\n")
                for ip in get_ip_addresses():
                    sys.stdout.write("\t\thttp://%s:%d/\n" % (ip, settings.USER_FACING_PORT()))

            else:
                sys.stdout.write("CONGRATULATIONS! You've finished updating the KA Lite server software.\n")
                sys.stdout.write("\tPlease run '%s' to start the server.\n" % start_script_path)
            sys.stdout.write("\n")
Exemple #48
0
 def is_default(self):
     return self.id == Settings.get("default_facility")
def static_with_build(path, with_build=True):
    """
    We need a way for the client browser to load the newly updated static
        files because some browsers cache the static files and does not
        load them up automatically when we release new versions but with
        the same name.

    REF: https://github.com/learningequality/ka-lite/issues/1161

    One way is to add a Get paramater to the static file's path so it becomes
        unique and the browser invalidates it's cached version.

    We re-use django's `{% static <path> %}` template tag to add build version
        to the filenames of static files.

    REF: https://www.quora.com/What-are-the-best-practices-for-versioning-CSS-and-JS-files

    Option 1: Use the `fle_utils.config.models.Settings`
        Pros: It works and more flexible.
        Cons: Requires us to update the BUILD_ID key at admin page.

    Option 2: Use the BUILD as Get parameter.
        Pros: It works.
        Cons: We need to maintain the `kalite/version.py` hard-coded values
            every time we make a release.

    Option 3: Use the SHA hash of the file's bytes as querystring.
        Pros: It works and more reliable.
        Cons: Requires us to open the static files to generate the hash.
                TODO(cpauya): Benchmark this!
                TODO(cpauya): Inefficient!  This is called everytime the static file is used.

    We try all options which does not throw exception.
    """
    global BUILD_HASH_CACHE

    new_path = static_lib(path)
    if with_build:
        build_id = ''

        # try fle_utils`s Settings
        try:
            if BUILD_HASH_CACHE:
                build_id = BUILD_HASH_CACHE
            else:
                build_id = BUILD_HASH_CACHE = Settings.get(BUILD_HASH, '')
        except Exception:
            pass

        # try the BUILD data from `version.py`
        if not build_id:
            try:
                build_id = BUILD_HASH_CACHE = version.VERSION_INFO[version.VERSION]["git_commit"][0:8]
            except:
                pass

        # attempt to use hash
        if not build_id:
            try:
                # REF: http://stackoverflow.com/questions/16874598/how-do-i-calculate-the-md5-checksum-of-a-file-in-python
                file_path = os.path.realpath(os.path.join(settings.STATIC_ROOT, path))
                with open(file_path, 'rb') as file_to_check:
                    # REF: http://stackoverflow.com/questions/1131220/get-md5-hash-of-big-files-in-python
                    filehash = hashlib.sha256()
                    while True:
                        data = file_to_check.read(8192)
                        if not data:
                            break
                        filehash.update(data)
                    build_id = filehash.hexdigest()
            except Exception:
                pass

        if build_id:
            new_path = '%s?%s' % (new_path, build_id,)
    return new_path
Exemple #50
0
    def user_progress(cls, user_id, language=None):
        """
        Return a list of PlaylistProgress objects associated with the user.
        """

        if not language:
            language = Settings.get(
                "default_language") or settings.LANGUAGE_CODE

        user = FacilityUser.objects.get(id=user_id)
        all_playlists = get_leafed_topics(language=language)

        # Retrieve video, exercise, and quiz logs that appear in this playlist
        user_vid_logs, user_ex_logs = cls.get_user_logs(user)

        exercise_ids = set([ex_log["exercise_id"] for ex_log in user_ex_logs])
        video_ids = set([
            get_id2slug_map().get(vid_log["video_id"])
            for vid_log in user_vid_logs
        ])
        # quiz_log_ids = [ql_id["quiz"] for ql_id in QuizLog.objects.filter(user=user).values("quiz")]
        # Build a list of playlists for which the user has at least one data point
        user_playlists = list()
        for p in all_playlists:
            for e_id in p.get("children"):

                if e_id in exercise_ids or e_id in video_ids:
                    user_playlists.append(p)
                    break

        # Store stats for each playlist
        user_progress = list()
        for i, p in enumerate(user_playlists):
            # Playlist entry totals
            pl_video_ids, pl_exercise_ids = cls.get_playlist_entry_ids(p)
            n_pl_videos = float(len(pl_video_ids))
            n_pl_exercises = float(len(pl_exercise_ids))

            # Vid & exercise logs in this playlist
            pl_ex_logs = [
                ex_log for ex_log in user_ex_logs
                if ex_log["exercise_id"] in pl_exercise_ids
            ]
            pl_vid_logs = [
                vid_log for vid_log in user_vid_logs
                if vid_log["video_id"] in pl_video_ids
            ]

            # Compute video stats
            n_vid_complete = len(
                [vid for vid in pl_vid_logs if vid["complete"]])
            n_vid_started = len([
                vid for vid in pl_vid_logs
                if (vid["total_seconds_watched"] > 0) and (not vid["complete"])
            ])
            vid_pct_complete = int(float(n_vid_complete) / n_pl_videos *
                                   100) if n_pl_videos else 0
            vid_pct_started = int(float(n_vid_started) / n_pl_videos *
                                  100) if n_pl_videos else 0
            if vid_pct_complete == 100:
                vid_status = "complete"
            elif n_vid_started > 0:
                vid_status = "inprogress"
            else:
                vid_status = "notstarted"

            # Compute exercise stats
            n_ex_mastered = len([ex for ex in pl_ex_logs if ex["complete"]])
            n_ex_started = len([ex for ex in pl_ex_logs if ex["attempts"] > 0])
            n_ex_incomplete = len([
                ex for ex in pl_ex_logs
                if (ex["attempts"] > 0 and not ex["complete"])
            ])
            n_ex_struggling = len(
                [ex for ex in pl_ex_logs if ex["struggling"]])
            ex_pct_mastered = int(
                float(n_ex_mastered) / (n_pl_exercises or 1) * 100)
            ex_pct_incomplete = int(
                float(n_ex_incomplete) / (n_pl_exercises or 1) * 100)
            ex_pct_struggling = int(
                float(n_ex_struggling) / (n_pl_exercises or 1) * 100)
            if not n_ex_started:
                ex_status = "notstarted"
            elif ex_pct_struggling > 0:
                # note: we want to help students prioritize areas they need to focus on
                # therefore if they are struggling in this exercise group, we highlight it for them
                ex_status = "struggling"
            elif ex_pct_mastered < 99:
                ex_status = "inprogress"
            else:
                ex_status = "complete"

            # Oh Quizzes, we hardly knew ye!
            # TODO (rtibbles): Sort out the status of Quizzes, and either reinstate them or remove them.
            # Compute quiz stats
            # quiz_exists, quiz_log, quiz_pct_score = cls.get_quiz_log(user, (p.get("entries") or p.get("children")), p.get("id"))
            # if quiz_log:
            #     if quiz_pct_score <= 50:
            #         quiz_status = "struggling"
            #     elif quiz_pct_score <= 79:
            #         quiz_status = "borderline"
            #     else:
            #         quiz_status = "complete"
            # else:
            #     quiz_status = "notstarted"

            progress = {
                "title": p.get("title"),
                "id": p.get("id"),
                "tag": p.get("tag"),
                "vid_pct_complete": vid_pct_complete,
                "vid_pct_started": vid_pct_started,
                "vid_status": vid_status,
                "ex_pct_mastered": ex_pct_mastered,
                "ex_pct_incomplete": ex_pct_incomplete,
                "ex_pct_struggling": ex_pct_struggling,
                "ex_status": ex_status,
                # "quiz_status": quiz_status,
                # "quiz_exists": quiz_exists,
                # "quiz_pct_score": quiz_pct_score,
                "n_pl_videos": n_pl_videos,
                "n_pl_exercises": n_pl_exercises,
            }

            try:
                progress["url"] = reverse("view_playlist",
                                          kwargs={"playlist_id": p.get("id")})
            except NoReverseMatch:
                progress["url"] = reverse("learn") + p.get("path")

            user_progress.append(cls(**progress))

        return user_progress
Exemple #51
0
    def handle(self, *args, **options):
        if not options["interactive"]:
            options["hostname"] = options["hostname"] or get_host_name()

        # blank allows ansible scripts to dump errors cleanly.
        print("                                     ")
        print("   _   __  ___    _     _ _          ")
        print("  | | / / / _ \  | |   (_) |         ")
        print("  | |/ / / /_\ \ | |    _| |_ ___    ")
        print("  |    \ |  _  | | |   | | __/ _ \   ")
        print("  | |\  \| | | | | |___| | ||  __/   ")
        print("  \_| \_/\_| |_/ \_____/_|\__\___|   ")
        print("                                     ")
        print("https://learningequality.org/ka-lite/")
        print("                                     ")
        print("         version %s" % VERSION)
        print("                                     ")

        if sys.version_info < (2, 7):
            raise CommandError("Support for Python version 2.6 and below had been discontinued, please upgrade.")
        elif sys.version_info >= (2, 8):
            raise CommandError(
                "Your Python version is: %d.%d.%d -- which is not supported. Please use the Python 2.7 series or wait for Learning Equality to release Kolibri.\n" % sys.version_info[:3])
        elif sys.version_info < (2, 7, 6):
            logging.warning(
                "It's recommended that you install Python version 2.7.6. Your version is: %d.%d.%d\n" % sys.version_info[:3])

        if options["interactive"]:
            print(
                "--------------------------------------------------------------------------------")
            print(
                "This script will configure the database and prepare it for use.")
            print(
                "--------------------------------------------------------------------------------")
            raw_input("Press [enter] to continue...")

        # Tried not to be os-specific, but ... hey. :-/
        # benjaoming: This doesn't work, why is 502 hard coded!? Root is normally
        # '0' And let's not care about stuff like this, people can be free to
        # run this as root if they want :)
        if not is_windows() and hasattr(os, "getuid") and os.getuid() == 502:
            print(
                "-------------------------------------------------------------------")
            print("WARNING: You are installing KA-Lite as root user!")
            print(
                "\tInstalling as root may cause some permission problems while running")
            print("\tas a normal user in the future.")
            print(
                "-------------------------------------------------------------------")
            if options["interactive"]:
                if not raw_input_yn("Do you wish to continue and install it as root?"):
                    raise CommandError("Aborting script.\n")

        git_migrate_path = options["git_migrate_path"]

        if git_migrate_path:
            call_command("gitmigrate", path=git_migrate_path, interactive=options["interactive"])

        database_kind = settings.DATABASES["default"]["ENGINE"]
        if "sqlite" in database_kind:
            database_file = settings.DATABASES["default"]["NAME"]
        else:
            database_file = None

        database_exists = database_file and os.path.isfile(database_file)

        # An empty file is created automatically even when the database dosn't
        # exist. But if it's empty, it's safe to overwrite.
        database_exists = database_exists and os.path.getsize(database_file) > 0

        install_clean = not database_exists

        if database_file:
            if not database_exists:
                install_clean = True
            else:
                # We found an existing database file.  By default,
                #   we will upgrade it; users really need to work hard
                #   to delete the file (but it's possible, which is nice).
                print(
                    "-------------------------------------------------------------------")
                print("WARNING: Database file already exists!")
                print(
                    "-------------------------------------------------------------------")
                if not options["interactive"] \
                   or raw_input_yn("Keep database file and upgrade to KA Lite version %s? " % VERSION) \
                   or not raw_input_yn("Remove database file '%s' now? " % database_file) \
                   or not raw_input_yn("WARNING: all data will be lost!  Are you sure? "):
                    install_clean = False
                    print("Upgrading database to KA Lite version %s" % VERSION)
                else:
                    install_clean = True
                    print("OK.  We will run a clean install; ")
                    # After all, don't delete--just move.
                    print(
                        "the database file will be moved to a deletable location.")

        if not install_clean and not database_file:
            # Make sure that, for non-sqlite installs, the database exists.
            raise Exception(
                "For databases not using SQLite, you must set up your database before running setup.")

        # Do all input at once, at the beginning
        if install_clean and options["interactive"]:
            if not options["username"] or not options["password"]:
                print(
                    "Please choose a username and password for the admin account on this device.")
                print(
                    "\tYou must remember this login information, as you will need")
                print(
                    "\tto enter it to administer this installation of KA Lite.")
            (username, password) = get_username_password(
                options["username"], options["password"])
            email = options["email"]
            (hostname, description) = get_hostname_and_description(
                options["hostname"], options["description"])
        else:
            username = options["username"] = (
                options["username"] or
                getattr(settings, "INSTALL_ADMIN_USERNAME", None) or
                get_clean_default_username()
            )
            password = options["password"] or getattr(settings, "INSTALL_ADMIN_PASSWORD", None)
            email = options["email"]  # default is non-empty
            hostname = options["hostname"]
            description = options["description"]

        if username and not validate_username(username):
            raise CommandError(
                "Username must contain only letters, digits, and underscores, and start with a letter.\n")

        ########################
        # Now do stuff
        ########################

        # Clean *pyc files if we are in a git repo
        if settings.IS_SOURCE:
            clean_pyc(settings.SOURCE_DIR)
        else:
            # Because we install dependencies as data_files, we run into problems,
            # namely that the pyc files are left dangling.
            distributed_packages = [
                os.path.join(kalite.ROOT_DATA_PATH, 'dist-packages'),
                os.path.join(kalite.ROOT_DATA_PATH, 'python-packages'),
            ]
            # Try locating django
            for dir_to_clean in distributed_packages:
                clean_pyc(dir_to_clean)

        # Move database file (if exists)
        if install_clean and database_file and os.path.exists(database_file):
            if not settings.DB_TEMPLATE_DEFAULT or database_file != settings.DB_TEMPLATE_DEFAULT:
                # This is an overwrite install; destroy the old db
                dest_file = tempfile.mkstemp()[1]
                print(
                    "(Re)moving database file to temp location, starting clean install. Recovery location: %s" % dest_file)
                shutil.move(database_file, dest_file)

        if settings.DB_TEMPLATE_DEFAULT and not database_exists and os.path.exists(settings.DB_TEMPLATE_DEFAULT):
            print("Copying database file from {0} to {1}".format(settings.DB_TEMPLATE_DEFAULT, settings.DEFAULT_DATABASE_PATH))
            shutil.copy(settings.DB_TEMPLATE_DEFAULT, settings.DEFAULT_DATABASE_PATH)
        else:
            print("Baking a fresh database from scratch or upgrading existing database.")
            call_command("syncdb", interactive=False, verbosity=options.get("verbosity"))
            call_command("migrate", merge=True, verbosity=options.get("verbosity"))
        Settings.set("database_version", VERSION)

        # Copy all content item db templates
        if os.path.exists(settings.DB_CONTENT_ITEM_TEMPLATE_DIR):
            for file_name in os.listdir(settings.DB_CONTENT_ITEM_TEMPLATE_DIR):
                if file_name.endswith("sqlite"):
                    template_path = os.path.join(settings.DB_CONTENT_ITEM_TEMPLATE_DIR, file_name)
                    dest_database = os.path.join(settings.DEFAULT_DATABASE_DIR, file_name)
                    if install_clean or not os.path.exists(dest_database):
                        print("Copying {} to {}".format(template_path, dest_database))
                        shutil.copy(template_path, dest_database)
                    else:
                        print("Skipping {}".format(template_path))

        # download the english content pack
        # This can take a long time and lead to Travis stalling. None of this
        # is required for tests, and does not apply to the central server.
        if options.get("no-assessment-items", False):

            logging.warning("Skipping content pack downloading and configuration.")

        else:

            # Outdated location of assessment items - move assessment items from their
            # old location (CONTENT_ROOT/khan where they were mixed with other content
            # items)

            # TODO(benjaoming) for 0.15, remove the "move assessment items"
            # mechanism
            writable_assessment_items = os.access(KHAN_ASSESSMENT_ITEM_ROOT, os.W_OK)

            # Remove old assessment items
            if os.path.exists(OLD_ASSESSMENT_ITEMS_LOCATION) and os.access(OLD_ASSESSMENT_ITEMS_LOCATION, os.W_OK):
                logging.info("Deleting old assessment items")
                shutil.rmtree(OLD_ASSESSMENT_ITEMS_LOCATION)

            if options['force-assessment-item-dl']:  # user wants to force a new download; do it if we can, else error
                if writable_assessment_items:
                    call_command("retrievecontentpack", "download", "en")
                else:
                    raise RuntimeError("Got force-assessment-item-dl but directory not writable")
            elif english_content_pack_and_assessment_resources_are_current():
                logging.warning("English content pack is already up-to-date; skipping download and configuration.")
            elif not writable_assessment_items:  # skip if we're not going to be able to unpack it anyway
                logging.warning("Assessment item directory not writable; skipping content pack download.")
            elif settings.RUNNING_IN_TRAVIS:  # skip if we're running on Travis
                logging.warning("Running in Travis; skipping content pack download.")
            elif not options['interactive']:  # skip if we're not running in interactive mode (and it wasn't forced)
                logging.warning("Not running in interactive mode; skipping content pack download.")
            else:  # if we get this far, then we need to ask the user whether/how they want to get the content pack
                print(
                    "\nIn order to access many of the available exercises, you need to load a content pack for the latest version.")
                print(
                    "If you have an Internet connection, you can download the needed package. Warning: this may take a long time!")
                print(
                    "If you have already downloaded the content pack, you can specify the location of the file in the next step.")
                print("Otherwise, we will download it from {url}.".format(url=CONTENTPACK_URL))

                if raw_input_yn("Do you wish to download and install the content pack now?"):
                    ass_item_filename = CONTENTPACK_URL
                    retrieval_method = "download"
                elif raw_input_yn("Do you have a local copy of the content pack already downloaded that you want to install?"):
                    ass_item_filename = get_assessment_items_filename()
                    retrieval_method = "local"
                else:
                    ass_item_filename = None
                    retrieval_method = "local"

                if not ass_item_filename:
                    logging.warning(
                        "No content pack given. You will need to download and install it later.")
                else:
                    call_command("retrievecontentpack", retrieval_method, "en", ass_item_filename, foreground=True)

        # Individually generate any prerequisite models/state that is missing
        if not Settings.get("private_key"):
            call_command("generatekeys", verbosity=options.get("verbosity"))
        if not Device.objects.count():
            call_command(
                "initdevice", hostname, description, verbosity=options.get("verbosity"))
        if not Facility.objects.count():
            Facility.initialize_default_facility()

        # Create the admin user
        # blank password (non-interactive) means don't create a superuser
        if password:
            admin = get_object_or_None(User, username=username)
            if not admin:
                call_command("createsuperuser", username=username, email=email,
                             interactive=False, verbosity=options.get("verbosity"))
                admin = User.objects.get(username=username)
            admin.set_password(password)
            admin.save()

        # Now deploy the static files
        logging.info("Copying static media...")
        ensure_dir(settings.STATIC_ROOT)

        # The following file ignores have to be preserved from a
        # collectstatic(clear=True), due to being bundled with content packs,
        # and we thus have now way of getting them back.
        collectstatic_ignores = [
            "*.vtt", "*.srt",  # subtitle files come with language packs -- don't delete
            "*/perseus/ke/exercises/*",  # exercises come with language packs, and we have no way to replicate
        ]
        call_command("collectstatic", interactive=False, verbosity=0, ignore_patterns=collectstatic_ignores,
                     clear=True)
        call_command("collectstatic_js_reverse", interactive=False)

        # This is not possible in a distributed env
        if not settings.CENTRAL_SERVER:

            kalite_executable = 'kalite'
            if not spawn.find_executable('kalite'):
                if os.name == 'posix':
                    start_script_path = os.path.realpath(
                        os.path.join(settings.PROJECT_PATH, "..", "bin", kalite_executable))
                else:
                    start_script_path = os.path.realpath(
                        os.path.join(settings.PROJECT_PATH, "..", "bin", "windows", "kalite.bat"))
            else:
                start_script_path = kalite_executable

            # Run annotate_content_items, on the distributed server.
            print("Annotating availability of all content, checking for content in this directory: (%s)" %
                  settings.CONTENT_ROOT)
            try:
                call_command("annotate_content_items")
            except OperationalError:
                pass

            # done; notify the user.
            print("\nCONGRATULATIONS! You've finished setting up the KA Lite server software.")
            print("You can now start KA Lite with the following command:\n\n\t%s start\n\n" % start_script_path)

            if options['interactive']:
                if raw_input_yn("Do you wish to start the server now?"):
                    print("Running {0} start".format(start_script_path))
                    p = subprocess.Popen([start_script_path, "start"], env=os.environ)
                    p.wait()
Exemple #52
0
def set_default_language(lang_code):
    """Sets the default language"""
    Settings.set("default_language", lcode_to_ietf(lang_code))
Exemple #53
0
    def handle(self, *args, **options):
        if not options["interactive"]:
            options["hostname"] = options["hostname"] or get_host_name()

        # blank allows ansible scripts to dump errors cleanly.
        print("                                     ")
        print("   _   __  ___    _     _ _          ")
        print("  | | / / / _ \  | |   (_) |         ")
        print("  | |/ / / /_\ \ | |    _| |_ ___    ")
        print("  |    \ |  _  | | |   | | __/ _ \   ")
        print("  | |\  \| | | | | |___| | ||  __/   ")
        print("  \_| \_/\_| |_/ \_____/_|\__\___|   ")
        print("                                     ")
        print("https://learningequality.org/ka-lite/")
        print("                                     ")
        print("         version %s" % VERSION)
        print("                                     ")

        if sys.version_info < (2, 7):
            raise CommandError(
                "Support for Python version 2.6 and below had been discontinued, please upgrade."
            )
        elif sys.version_info >= (2, 8):
            raise CommandError(
                "Your Python version is: %d.%d.%d -- which is not supported. Please use the Python 2.7 series or wait for Learning Equality to release Kolibri.\n"
                % sys.version_info[:3])
        elif sys.version_info < (2, 7, 6):
            logging.warning(
                "It's recommended that you install Python version 2.7.6. Your version is: %d.%d.%d\n"
                % sys.version_info[:3])

        if options["interactive"]:
            print(
                "--------------------------------------------------------------------------------"
            )
            print(
                "This script will configure the database and prepare it for use."
            )
            print(
                "--------------------------------------------------------------------------------"
            )
            raw_input("Press [enter] to continue...")

        # Assuming uid '0' is always root
        if not is_windows() and hasattr(os, "getuid") and os.getuid() == 0:
            print(
                "-------------------------------------------------------------------"
            )
            print("WARNING: You are installing KA-Lite as root user!")
            print(
                "\tInstalling as root may cause some permission problems while running"
            )
            print("\tas a normal user in the future.")
            print(
                "-------------------------------------------------------------------"
            )
            if options["interactive"]:
                if not raw_input_yn(
                        "Do you wish to continue and install it as root?"):
                    raise CommandError("Aborting script.\n")

        database_kind = settings.DATABASES["default"]["ENGINE"]
        if "sqlite" in database_kind:
            database_file = settings.DATABASES["default"]["NAME"]
        else:
            database_file = None

        database_exists = database_file and os.path.isfile(database_file)

        # An empty file is created automatically even when the database dosn't
        # exist. But if it's empty, it's safe to overwrite.
        database_exists = database_exists and os.path.getsize(
            database_file) > 0

        install_clean = not database_exists

        if database_file:
            if not database_exists:
                install_clean = True
            else:
                # We found an existing database file.  By default,
                #   we will upgrade it; users really need to work hard
                #   to delete the file (but it's possible, which is nice).
                print(
                    "-------------------------------------------------------------------"
                )
                print("WARNING: Database file already exists!")
                print(
                    "-------------------------------------------------------------------"
                )
                if not options["interactive"] \
                   or raw_input_yn("Keep database file and upgrade to KA Lite version %s? " % VERSION) \
                   or not raw_input_yn("Remove database file '%s' now? " % database_file) \
                   or not raw_input_yn("WARNING: all data will be lost!  Are you sure? "):
                    install_clean = False
                    print("Upgrading database to KA Lite version %s" % VERSION)
                else:
                    install_clean = True
                    print("OK.  We will run a clean install; ")
                    # After all, don't delete--just move.
                    print(
                        "the database file will be moved to a deletable location."
                    )

        if not install_clean and not database_file:
            # Make sure that, for non-sqlite installs, the database exists.
            raise Exception(
                "For databases not using SQLite, you must set up your database before running setup."
            )

        # Do all input at once, at the beginning
        if install_clean and options["interactive"]:
            if not options["username"] or not options["password"]:
                print(
                    "Please choose a username and password for the admin account on this device."
                )
                print(
                    "\tYou must remember this login information, as you will need"
                )
                print(
                    "\tto enter it to administer this installation of KA Lite."
                )
            (username,
             password) = get_username_password(options["username"],
                                               options["password"])
            email = options["email"]
            (hostname, description) = get_hostname_and_description(
                options["hostname"], options["description"])
        else:
            username = options["username"] = (options["username"] or getattr(
                settings, "INSTALL_ADMIN_USERNAME", None)
                                              or get_clean_default_username())
            password = options["password"] or getattr(
                settings, "INSTALL_ADMIN_PASSWORD", None)
            email = options["email"]  # default is non-empty
            hostname = options["hostname"]
            description = options["description"]

        if username and not validate_username(username):
            raise CommandError(
                "Username must contain only letters, digits, and underscores, and start with a letter.\n"
            )

        ########################
        # Now do stuff
        ########################

        # Move database file (if exists)
        if install_clean and database_file and os.path.exists(database_file):
            if not settings.DB_TEMPLATE_DEFAULT or database_file != settings.DB_TEMPLATE_DEFAULT:
                # This is an overwrite install; destroy the old db
                dest_file = tempfile.mkstemp()[1]
                print(
                    "(Re)moving database file to temp location, starting clean install. Recovery location: %s"
                    % dest_file)
                shutil.move(database_file, dest_file)

        if settings.DB_TEMPLATE_DEFAULT and not database_exists and os.path.exists(
                settings.DB_TEMPLATE_DEFAULT):
            print("Copying database file from {0} to {1}".format(
                settings.DB_TEMPLATE_DEFAULT, settings.DEFAULT_DATABASE_PATH))
            shutil.copy(settings.DB_TEMPLATE_DEFAULT,
                        settings.DEFAULT_DATABASE_PATH)
        else:
            print(
                "Baking a fresh database from scratch or upgrading existing database."
            )
            call_command("syncdb",
                         interactive=False,
                         verbosity=options.get("verbosity"))
            call_command("migrate",
                         merge=True,
                         verbosity=options.get("verbosity"))
        Settings.set("database_version", VERSION)

        # Copy all content item db templates
        reset_content_db(force=install_clean)

        # download the english content pack
        # This can take a long time and lead to Travis stalling. None of this
        # is required for tests, and does not apply to the central server.
        if options.get("no-assessment-items", False):

            logging.warning(
                "Skipping content pack downloading and configuration.")

        else:

            # user wants to force a new download; do it if we can, else error
            if options['force-assessment-item-dl']:
                call_command("retrievecontentpack", "download", "en")
            else:
                detect_content_packs(options)

        # Individually generate any prerequisite models/state that is missing
        if not Settings.get("private_key"):
            call_command("generatekeys", verbosity=options.get("verbosity"))
        if not Device.objects.count():
            call_command("initdevice",
                         hostname,
                         description,
                         verbosity=options.get("verbosity"))
        if not Facility.objects.count():
            Facility.initialize_default_facility()

        # Create the admin user
        # blank password (non-interactive) means don't create a superuser
        if password:
            admin = get_object_or_None(User, username=username)
            if not admin:
                call_command("createsuperuser",
                             username=username,
                             email=email,
                             interactive=False,
                             verbosity=options.get("verbosity"))
                admin = User.objects.get(username=username)
            admin.set_password(password)
            admin.save()

        # Now deploy the static files
        logging.info("Copying static media...")
        ensure_dir(settings.STATIC_ROOT)

        call_command("collectstatic",
                     interactive=False,
                     verbosity=0,
                     clear=True)
        call_command("collectstatic_js_reverse", interactive=False)

        # This is not possible in a distributed env
        if not settings.CENTRAL_SERVER:

            kalite_executable = 'kalite'
            if not spawn.find_executable('kalite'):
                if os.name == 'posix':
                    start_script_path = os.path.realpath(
                        os.path.join(settings.PROJECT_PATH, "..", "bin",
                                     kalite_executable))
                else:
                    start_script_path = os.path.realpath(
                        os.path.join(settings.PROJECT_PATH, "..", "bin",
                                     "windows", "kalite.bat"))
            else:
                start_script_path = kalite_executable

            # Run annotate_content_items, on the distributed server.
            print(
                "Annotating availability of all content, checking for content in this directory: (%s)"
                % settings.CONTENT_ROOT)
            try:
                call_command("annotate_content_items")
            except OperationalError:
                pass

            # done; notify the user.
            print(
                "\nCONGRATULATIONS! You've finished setting up the KA Lite server software."
            )
            print(
                "You can now start KA Lite with the following command:\n\n\t%s start\n\n"
                % start_script_path)

            if options['interactive']:
                if raw_input_yn("Do you wish to start the server now?"):
                    print("Running {0} start".format(start_script_path))
                    p = subprocess.Popen([start_script_path, "start"],
                                         env=os.environ)
                    p.wait()
Exemple #54
0
def set_default_language(lang_code):
    """Sets the default language"""
    Settings.set("default_language", lcode_to_ietf(lang_code))
Exemple #55
0
    def user_progress(cls, user_id, language=None):
        """
        Return a list of PlaylistProgress objects associated with the user.
        """

        if not language:
            language = Settings.get("default_language") or settings.LANGUAGE_CODE

        user = FacilityUser.objects.get(id=user_id)

        # Retrieve video, exercise, and quiz logs that appear in this playlist
        user_vid_logs, user_ex_logs = cls.get_user_logs(user)

        exercise_ids = list(set([ex_log["exercise_id"] for ex_log in user_ex_logs]))
        video_ids = list(set([vid_log["video_id"] for vid_log in user_vid_logs]))

        # Build a list of playlists for which the user has at least one data point
        user_playlists = get_content_parents(ids=exercise_ids+video_ids, language=language)

        # Store stats for each playlist
        user_progress = list()
        for i, p in enumerate(user_playlists):
            # Playlist entry totals
            pl_video_ids, pl_exercise_ids = cls.get_playlist_entry_ids(p)
            n_pl_videos = float(len(pl_video_ids))
            n_pl_exercises = float(len(pl_exercise_ids))

            # Vid & exercise logs in this playlist
            pl_ex_logs = [ex_log for ex_log in user_ex_logs if ex_log["exercise_id"] in pl_exercise_ids]
            pl_vid_logs = [vid_log for vid_log in user_vid_logs if vid_log["video_id"] in pl_video_ids]

            # Compute video stats
            n_vid_complete = len([vid for vid in pl_vid_logs if vid["complete"]])
            n_vid_started = len([vid for vid in pl_vid_logs if (vid["total_seconds_watched"] > 0) and (not vid["complete"])])
            vid_pct_complete = int(float(n_vid_complete) / n_pl_videos * 100) if n_pl_videos else 0
            vid_pct_started = int(float(n_vid_started) / n_pl_videos * 100) if n_pl_videos else 0
            if vid_pct_complete == 100:
                vid_status = "complete"
            elif n_vid_started > 0:
                vid_status = "inprogress"
            else:
                vid_status = "notstarted"

            # Compute exercise stats
            n_ex_mastered = len([ex for ex in pl_ex_logs if ex["complete"]])
            n_ex_started = len([ex for ex in pl_ex_logs if ex["attempts"] > 0])
            n_ex_incomplete = len([ex for ex in pl_ex_logs if (ex["attempts"] > 0 and not ex["complete"])])
            n_ex_struggling = len([ex for ex in pl_ex_logs if ex["struggling"]])
            ex_pct_mastered = int(float(n_ex_mastered) / (n_pl_exercises or 1) * 100)
            ex_pct_incomplete = int(float(n_ex_incomplete) / (n_pl_exercises or 1) * 100)
            ex_pct_struggling = int(float(n_ex_struggling) / (n_pl_exercises or 1) * 100)
            if not n_ex_started:
                ex_status = "notstarted"
            elif ex_pct_struggling > 0:
                # note: we want to help students prioritize areas they need to focus on
                # therefore if they are struggling in this exercise group, we highlight it for them
                ex_status = "struggling"
            elif ex_pct_mastered < 99:
                ex_status = "inprogress"
            else:
                ex_status = "complete"

            progress = {
                "title": p.get("title"),
                "id": p.get("id"),
                "tag": p.get("tag"),
                "vid_pct_complete": vid_pct_complete,
                "vid_pct_started": vid_pct_started,
                "vid_status": vid_status,
                "ex_pct_mastered": ex_pct_mastered,
                "ex_pct_incomplete": ex_pct_incomplete,
                "ex_pct_struggling": ex_pct_struggling,
                "ex_status": ex_status,
                "n_pl_videos": n_pl_videos,
                "n_pl_exercises": n_pl_exercises,
            }

            try:
                progress["url"] = reverse("view_playlist", kwargs={"playlist_id": p.get("id")})
            except NoReverseMatch:
                progress["url"] = reverse("learn") + p.get("path")

            user_progress.append(cls(**progress))

        return user_progress
Exemple #56
0
 def is_default(self):
     return self.id == Settings.get("default_facility")
Exemple #57
0
    def handle(self, *args, **options):
        if not options["interactive"]:
            options["username"] = options["username"] or getattr(settings, "INSTALL_ADMIN_USERNAME", None) or get_clean_default_username()
            options["hostname"] = options["hostname"] or get_host_name()

        print("                                  ")  # blank allows ansible scripts to dump errors cleanly.
        print("  _   __  ___    _     _ _        ")
        print(" | | / / / _ \  | |   (_) |       ")
        print(" | |/ / / /_\ \ | |    _| |_ ___  ")
        print(" |    \ |  _  | | |   | | __/ _ \ ")
        print(" | |\  \| | | | | |___| | ||  __/ ")
        print(" \_| \_/\_| |_/ \_____/_|\__\___| ")
        print("                                  ")
        print("http://kalite.learningequality.org")
        print("                                  ")
        print("         version %s" % VERSION)
        print("                                  ")

        if sys.version_info >= (2,8) or sys.version_info < (2,6):
            raise CommandError("You must have Python version 2.6.x or 2.7.x installed. Your version is: %s\n" % sys.version_info)

        if options["interactive"]:
            print("--------------------------------------------------------------------------------")
            print("This script will configure the database and prepare it for use.")
            print("--------------------------------------------------------------------------------")
            raw_input("Press [enter] to continue...")

        # Tried not to be os-specific, but ... hey. :-/
        # benjaoming: This doesn't work, why is 502 hard coded!? Root is normally
        # '0' And let's not care about stuff like this, people can be free to
        # run this as root if they want :)
        if not is_windows() and hasattr(os, "getuid") and os.getuid() == 502:
            print("-------------------------------------------------------------------")
            print("WARNING: You are installing KA-Lite as root user!")
            print("\tInstalling as root may cause some permission problems while running")
            print("\tas a normal user in the future.")
            print("-------------------------------------------------------------------")
            if options["interactive"]:
                if not raw_input_yn("Do you wish to continue and install it as root?"):
                    raise CommandError("Aborting script.\n")

        # Check to see if the current user is the owner of the install directory
        if not os.access(BASE_DIR, os.W_OK):
            raise CommandError("You do not have permission to write to this directory!")

        install_clean = not kalite.is_installed()
        database_kind = settings.DATABASES["default"]["ENGINE"]
        database_file = ("sqlite" in database_kind and settings.DATABASES["default"]["NAME"]) or None

        if database_file and os.path.exists(database_file):
            # We found an existing database file.  By default,
            #   we will upgrade it; users really need to work hard
            #   to delete the file (but it's possible, which is nice).
            print("-------------------------------------------------------------------")
            print("WARNING: Database file already exists!")
            print("-------------------------------------------------------------------")
            if not options["interactive"] \
               or raw_input_yn("Keep database file and upgrade to KA Lite version %s? " % VERSION) \
               or not raw_input_yn("Remove database file '%s' now? " % database_file) \
               or not raw_input_yn("WARNING: all data will be lost!  Are you sure? "):
                install_clean = False
                print("Upgrading database to KA Lite version %s" % VERSION)
            else:
                install_clean = True
                print("OK.  We will run a clean install; ")
                print("the database file will be moved to a deletable location.")  # After all, don't delete--just move.

        if not install_clean and not database_file and not kalite.is_installed():
            # Make sure that, for non-sqlite installs, the database exists.
            raise Exception("For databases not using SQLite, you must set up your database before running setup.")

        # Do all input at once, at the beginning
        if install_clean and options["interactive"]:
            if not options["username"] or not options["password"]:
                print("Please choose a username and password for the admin account on this device.")
                print("\tYou must remember this login information, as you will need")
                print("\tto enter it to administer this installation of KA Lite.")
            (username, password) = get_username_password(options["username"], options["password"])
            email = options["email"]
            (hostname, description) = get_hostname_and_description(options["hostname"], options["description"])
        else:
            username = options["username"] or getattr(settings, "INSTALL_ADMIN_USERNAME", None)
            password = options["password"] or getattr(settings, "INSTALL_ADMIN_PASSWORD", None)
            email = options["email"]  # default is non-empty
            hostname = options["hostname"]
            description = options["description"]

        if username and not validate_username(username):
            raise CommandError("Username must contain only letters, digits, and underscores, and start with a letter.\n")


        ########################
        # Now do stuff
        ########################

        # Move database file (if exists)
        if install_clean and database_file and os.path.exists(database_file):
            # This is an overwrite install; destroy the old db
            dest_file = tempfile.mkstemp()[1]
            print("(Re)moving database file to temp location, starting clean install.  Recovery location: %s" % dest_file)
            shutil.move(database_file, dest_file)

        # Should clean_pyc for (clean) reinstall purposes
        call_command("clean_pyc", interactive=False, verbosity=options.get("verbosity"), path=os.path.join(settings.PROJECT_PATH, ".."))

        # Migrate the database
        call_command("syncdb", interactive=False, verbosity=options.get("verbosity"))
        call_command("migrate", merge=True, verbosity=options.get("verbosity"))

        # download assessment items
        # This can take a long time and lead to Travis stalling. None of this is required for tests.
        if options['force-assessment-item-dl']:
            call_command("unpack_assessment_zip", settings.ASSESSMENT_ITEMS_ZIP_URL)
        elif not settings.RUNNING_IN_TRAVIS and options['interactive']:
            print("\nStarting in version 0.13, you will need an assessment items package in order to access many of the available exercises.")
            print("If you have an internet connection, you can download the needed package. Warning: this may take a long time!")
            print("If you have already downloaded the assessment items package, you can specify the file in the next step.")
            print("Otherwise, we will download it from {url}.".format(url=settings.ASSESSMENT_ITEMS_ZIP_URL))

            if raw_input_yn("Do you wish to download the assessment items package now?"):
                ass_item_filename = settings.ASSESSMENT_ITEMS_ZIP_URL
            elif raw_input_yn("Have you already downloaded the assessment items package?"):
                ass_item_filename = get_assessment_items_filename()
            else:
                ass_item_filename = None

            if not ass_item_filename:
                logging.warning("No assessment items package file given. You will need to download and unpack it later.")
            else:
                call_command("unpack_assessment_zip", ass_item_filename)
        else:
            logging.warning("No assessment items package file given. You will need to download and unpack it later.")


        # Individually generate any prerequisite models/state that is missing
        if not Settings.get("private_key"):
            call_command("generatekeys", verbosity=options.get("verbosity"))
        if not Device.objects.count():
            call_command("initdevice", hostname, description, verbosity=options.get("verbosity"))
        if not Facility.objects.count():
            Facility.initialize_default_facility()

        # Install data
        # if install_clean:
        #     # Create device, load on any zone data
        #     call_command("generatekeys", verbosity=options.get("verbosity"))
        #     call_command("initdevice", hostname, description, verbosity=options.get("verbosity"))
        #     Facility.initialize_default_facility()

        #else:
            # Device exists; load data if required.
            #
            # Hackish, as this duplicates code from initdevice.
            #
            #if os.path.exists(InitCommand.data_json_file):
            #    # This is a pathway to install zone-based data on a software upgrade.
            #    print("Loading zone data from '%s'\n" % InitCommand.data_json_file)
            #    load_data_for_offline_install(in_file=InitCommand.data_json_file)

        #    confirm_or_generate_zone()

        # Create the admin user
        if password:  # blank password (non-interactive) means don't create a superuser
            admin = get_object_or_None(User, username=username)
            if not admin:
                call_command("createsuperuser", username=username, email=email, interactive=False, verbosity=options.get("verbosity"))
                admin = User.objects.get(username=username)
            admin.set_password(password)
            admin.save()

        # Now deploy the static files
        call_command("collectstatic", interactive=False)

        if not settings.CENTRAL_SERVER:
            # Move scripts
            for script_name in ["start", "stop", "run_command"]:
                script_file = script_name + system_script_extension()
                dest_dir = os.path.join(settings.PROJECT_PATH, "..")
                src_dir = os.path.join(dest_dir, "scripts")
                shutil.copyfile(os.path.join(src_dir, script_file), os.path.join(dest_dir, script_file))
                try:
                    shutil.copystat(os.path.join(src_dir, script_file), os.path.join(dest_dir, script_file))
                except OSError:  # even if we have write permission, we might not have permission to change file mode
                    print("WARNING: Unable to set file permissions on %s! " % script_file)

            kalite_executable = 'kalite'
            if not spawn.find_executable('kalite'):
                if os.name == 'posix':
                    start_script_path = os.path.realpath(os.path.join(settings.PROJECT_PATH, "..", "bin", kalite_executable))
                else:
                    start_script_path = os.path.realpath(os.path.join(settings.PROJECT_PATH, "..", "bin", "windows", "kalite.bat"))
            else:
                start_script_path = kalite_executable

            # Run videoscan, on the distributed server.
            print("Scanning for video files in the content directory (%s)" % settings.CONTENT_ROOT)
            call_command("videoscan")

            # done; notify the user.
            print("CONGRATULATIONS! You've finished setting up the KA Lite server software.")
            print("You can now start KA Lite with the following command:\n\n\t%s start\n\n" % start_script_path)
Exemple #58
0
    def user_progress_detail(cls, user_id, playlist_id, language=None):
        """
        Return a list of video, exercise, and quiz log PlaylistProgressDetail
        objects associated with a specific user and playlist ID.
        """
        if not language:
            language = Settings.get("default_language") or settings.LANGUAGE_CODE

        user = FacilityUser.objects.get(id=user_id)
        playlist = next((pl for pl in get_leafed_topics() if pl.get("id") == playlist_id), None)

        pl_video_ids, pl_exercise_ids = cls.get_playlist_entry_ids(playlist)

        # Retrieve video, exercise, and quiz logs that appear in this playlist
        user_vid_logs, user_ex_logs = cls.get_user_logs(user, pl_video_ids, pl_exercise_ids)

        # Format & append quiz the quiz log, if it exists
        # quiz_exists, quiz_log, quiz_pct_score = cls.get_quiz_log(user, (playlist.get("entries") or playlist.get("children")), playlist.get("id"))

        # Finally, sort an ordered list of the playlist entries, with user progress
        # injected where it exists.
        progress_details = list()
        for entity_id in playlist.get("children"):
            entry = {}
            leaf_node = get_content_cache(language=language).get(entity_id) or get_exercise_cache(language=language).get(entity_id) or {}
            kind = leaf_node.get("kind")

            status = "notstarted"
            score = 0

            if kind == "Video":
                vid_log = next((vid_log for vid_log in user_vid_logs if vid_log["video_id"] == entity_id), None)
                if vid_log:
                    if vid_log.get("complete"):
                        status = "complete"
                    elif vid_log.get("total_seconds_watched"):
                        status = "inprogress"

                    score = int(float(vid_log.get("points")) / float(750) * 100)

            elif kind == "Exercise":
                ex_log = next((ex_log for ex_log in user_ex_logs if ex_log["exercise_id"] == entity_id), None)
                if ex_log:
                    if ex_log.get("struggling"):
                        status = "struggling"
                    elif ex_log.get("complete"):
                        status = "complete"
                    elif ex_log.get("attempts"):
                        status = "inprogress"

                    score = ex_log.get('streak_progress')

            entry = {
                "id": entity_id,
                "kind": kind,
                "status": status,
                "score": score,
                "title": leaf_node["title"],
                "path": leaf_node["path"],
            }

            progress_details.append(cls(**entry))

        return progress_details
Exemple #59
0
def reset_keys():
    global _own_key
    _own_key = Key()
    Settings.set("private_key", _own_key.get_private_key_string())
    Settings.set("public_key", _own_key.get_public_key_string())