Skip to content
content.py 36.8 KiB
Newer Older
    except ObjectDoesNotExist:
        if vctx is not None:
            vctx.add_warning(
                    location,
                    _("unrecognized date/time specification: '%s' "
                    "(interpreted as 'now')")
                    % orig_datespec)
        return now()
    if is_end:
        if event_obj.end_time is not None:
            result = event_obj.end_time
        else:
            result = event_obj.time
            if vctx is not None:
                vctx.add_warning(
                        location,
                        _("event '%s' has no end time, using start time instead")
                        % orig_datespec)

    else:
        result = event_obj.time

    return apply_postprocs(result)


def compute_chunk_weight_and_shown(course, chunk, role, now_datetime,
    if not hasattr(chunk, "rules"):
        return 0, True

    for rule in chunk.rules:
        if hasattr(rule, "if_has_role"):
            if role not in rule.if_has_role:
                continue
        if hasattr(rule, "if_after"):
            start_date = parse_date_spec(course, rule.if_after)
            if now_datetime < start_date:
                continue

        if hasattr(rule, "if_before"):
            end_date = parse_date_spec(course, rule.if_before)
            if end_date < now_datetime:
                continue

        if hasattr(rule, "if_in_facility"):
            if rule.if_in_facility not in facilities:
        if hasattr(rule, "roles"):
            if role not in rule.roles:
                continue

        if hasattr(rule, "start"):
            start_date = parse_date_spec(course, rule.start)
            if now_datetime < start_date:
Andreas Klöckner's avatar
Andreas Klöckner committed
                continue
        if hasattr(rule, "end"):
            end_date = parse_date_spec(course, rule.end)
            if end_date < now_datetime:
Andreas Klöckner's avatar
Andreas Klöckner committed
                continue
        shown = True
        if hasattr(rule, "shown"):
            shown = rule.shown

        return rule.weight, shown
def get_processed_page_chunks(course, repo, commit_sha,
        page_desc, role, now_datetime, facilities):
    for chunk in page_desc.chunks:
        chunk.weight, chunk.shown = \
                compute_chunk_weight_and_shown(
                        course, chunk, role, now_datetime,
        chunk.html_content = markup_to_html(course, repo, commit_sha, chunk.content)
        if not hasattr(chunk, "title"):
            from course.content import extract_title_from_markup
            chunk.title = extract_title_from_markup(chunk.content)
    page_desc.chunks.sort(key=lambda chunk: chunk.weight, reverse=True)
    return [chunk for chunk in page_desc.chunks
            if chunk.shown]
def normalize_page_desc(page_desc):
    if hasattr(page_desc, "content"):
        content = page_desc.content
        from relate.utils import struct_to_dict, Struct
        d = struct_to_dict(page_desc)
        del d["content"]
        d["chunks"] = [Struct({"id": "main", "content": content})]
        return Struct(d)

    return page_desc


def get_staticpage_desc(repo, course, commit_sha, filename):
    page_desc = get_yaml_from_repo(repo, filename, commit_sha)
    page_desc = normalize_page_desc(page_desc)
    return page_desc


def get_course_desc(repo, course, commit_sha):
    return get_staticpage_desc(repo, course, commit_sha, course.course_file)
def normalize_flow_desc(flow_desc):
    if hasattr(flow_desc, "pages"):
        pages = flow_desc.pages
        from relate.utils import struct_to_dict, Struct
        d = struct_to_dict(flow_desc)
        del d["pages"]
        d["groups"] = [Struct({"id": "main", "pages": pages})]
        return Struct(d)

    if hasattr(flow_desc, "rules"):
        rules = flow_desc.rules
        if not hasattr(rules, "grade_identifier"):
            # Legacy content with grade_identifier in grading rule,
            # move first found grade_identifier up to rules.

            rules.grade_identifier = None
            rules.grade_aggregation_strategy = None

            for grule in rules.grading:
                if grule.grade_identifier is not None:
                    rules.grade_identifier = grule.grade_identifier
                    rules.grade_aggregation_strategy = \
                            grule.grade_aggregation_strategy
                    break

def get_flow_desc(repo, course, flow_id, commit_sha):
    flow_desc = get_yaml_from_repo(repo, "flows/%s.yml" % flow_id, commit_sha)

    flow_desc = normalize_flow_desc(flow_desc)
    flow_desc.description_html = markup_to_html(
            course, repo, commit_sha, getattr(flow_desc, "description", None))
    return flow_desc
def get_flow_page_desc(flow_id, flow_desc, group_id, page_id):
    for grp in flow_desc.groups:
        if grp.id == group_id:
            for page in grp.pages:
                if page.id == page_id:
                    return page

    raise ObjectDoesNotExist(
            _("page '%(group_id)s/%(page_id)s' in flow '%(flow_id)s'") % {
                'group_id': group_id,
                'page_id': page_id,
                'flow_id': flow_id
                })
class ClassNotFoundError(RuntimeError):
def import_class(name):
    components = name.split('.')
    if len(components) < 2:
        # need at least one module plus class name
        raise ClassNotFoundError(name)
    module_name = ".".join(components[:-1])
    try:
        mod = __import__(module_name)
    except ImportError:
        raise ClassNotFoundError(name)
    for comp in components[1:]:
        try:
            mod = getattr(mod, comp)
        except AttributeError:
            raise ClassNotFoundError(name)
def get_flow_page_class(repo, typename, commit_sha):
    # look among default page types
    import course.page
    try:
        return getattr(course.page, typename)
    except AttributeError:
        pass
    # try a global dotted-name import
    try:
        return import_class(typename)
    except ClassNotFoundError:
        pass
    if typename.startswith("repo:"):
        stripped_typename = typename[5:]
        components = stripped_typename.split(".")
        if len(components) != 2:
            raise ClassNotFoundError(
                    _("repo page class must conist of two "
                    "dotted components (invalid: '%s')")
        module, classname = components
Andreas Klöckner's avatar
Andreas Klöckner committed
        module_code = get_repo_blob(repo, module_name, commit_sha,
                allow_tree=False).data
        module_dict = {}
        exec(compile(module_code, module_name, 'exec'), module_dict)
        try:
            return module_dict[classname]
        except AttributeError:
            raise ClassNotFoundError(typename)
    else:
        raise ClassNotFoundError(typename)
def instantiate_flow_page(location, repo, page_desc, commit_sha):
    class_ = get_flow_page_class(repo, page_desc.type, commit_sha)
    return class_(None, location, page_desc)
def get_course_commit_sha(course, participation):
    # logic duplicated in course.utils.CoursePageContext

    sha = course.active_git_commit_sha

    if participation is not None and participation.preview_git_commit_sha:
        preview_sha = participation.preview_git_commit_sha

        repo = get_course_repo(course)
        if isinstance(repo, SubdirRepoWrapper):
            repo = repo.repo

        try:
            repo[preview_sha.encode()]
        except KeyError:
            preview_sha = None

        if preview_sha is not None:
            sha = preview_sha
def list_flow_ids(repo, commit_sha):
    flow_ids = []
    try:
        flows_tree = get_repo_blob(repo, "flows", commit_sha)
    except ObjectDoesNotExist:
        # That's OK--no flows yet.
        pass
    else:
        for entry in flows_tree.items():
            if entry.path.endswith(b".yml"):
                flow_ids.append(entry.path[:-4])

    return sorted(flow_ids)

# vim: foldmethod=marker