Giter VIP home page Giter VIP logo

riyaz's Introduction

riyaz

Riyaz is a light-weight, self-hostable learning platform.

How to use

This software requires sqlite 3.38.0 or higher.

Step 1: Setup database

$ sqlite3 riyaz.db < riyaz/schema.sql

Step 2: install python dependencies

$ pip install -r requirements.txt dev-requirements.txt

Step 3: load sample data

$ python run.py --load-sample-data

Step 4: run the app

$ python run.py

riyaz's People

Contributors

nikochiko avatar anandology avatar

Stargazers

 avatar Suraj Kamath avatar

Watchers

 avatar vikrant avatar Amit Kapoor avatar  avatar

riyaz's Issues

enable foreign keys in sqlite

foreign keys support is disabled by default in sqlite. From the client, it can be abled by running:

PRAGMA foreign_keys = ON;

Find how to do this from the python client and make sure foreign key constrains are respected. Write a test case to ensure this.

Discussion: `riyaz serve` command

riyaz serve command is already merged in the codebase.

It works like this:

  1. Create a riyaz.db in the current directory (if it doesnt exist)
  2. Run schema.sql migrations on it (if table document doesn't exist)
  3. Load sample data from sample_data/ directory (using code in sample_data.py)
  4. Read course from current directory, push it to database
  5. Start a Flask server

More features that we want:

move to simple SQL

We are using a document database created on top of sqlite. It feels a bit limiting and unnecessary abstration. It may be a lot simpler and effective in the long run to use SQL and simple abstractions.

Approach

I propose using web.py database for this. web.py makes it easier to write SQL without adding complex abstractions.

For migrations, we can have a simple migrate.py with all the migration steps.

The Document class in the db module will be replaced by a BaseModel that will continue to support the find, find_all and save methods.

Home page

Create a simple homepage listing all courses.

Mockup

image

Course development API

Part of #4

REST API

Resources:
courses, assets, lessons, authors

Base prefix: /api

Endpoints:

  1. /courses
    Methods:
    * GET - Get all courses
    * POST - Create a new course
  2. /courses/:course_name
    Methods:
    * GET - Get a course by its name (like joy-of-programming)
    * PUT - Update course details
    * DELETE - Delete a course
  3. /courses/:course_name/assets
    Methods:
    * GET - Get list of assets in a course
    * POST / PUT - Add a new asset
  4. /courses/:course_name/lessons
    Methods:
    * GET - Get list of lessons in a course
    * POST / PUT - Add a new lesson
  5. /courses/:course_name/authors
    Methods:
    * GET - Get list of authors in a course
    * POST / PUT - Add a new author
  6. /assets/:course_name/:path_to_asset
    Methods:
    * GET - Get asset at the specified path
    * PUT - Update asset at the specified path
    * DELETE - Delete the asset
  7. /lessons/:course_name/:path_to_lesson
    :path_to_lesson can have at most 1 level of hierarchy. Either,
    :path_to_lesson = lesson-name or module-name/lesson-name
    Methods:
    * GET - Get lesson at the specified path
    * PUT - Update lesson at the specified path
    * DELETE - Delete lesson at the specified path
  8. /author/:course_name/:author_name xor /author/:author_name
    Methods:
    * GET - Get lesson at the specified path
    * PUT - Update lesson at the specified path
    * DELETE - Delete lesson at the specified path

The problem with this is that we don't have endpoints that will take static IDs. Paths may change with a PUT request.
A few solutions could be:

  • More endpoints that will work with an ID instead of a name. GitHub does this with endpoints like /users/:username and /user/:id.
  • An RPC-like API that can take either ID or path/name.

@anandology what do you think?

Code coverage tools

While writing tests, it would be helpful to know which lines were covered and which were missed.

Design plugin system for riyaz

Design a plugin system for riyaz to support extensions. The following are examples of some of the features that we would like a plugin to be able to do:

  • add support for live code execution
  • add support for creating and presenting quizs
  • support for projects
  • discussions

This means, a plugin should be able to add:

  • css and javascript to be included globally
  • css and javascript to be included on select pages
  • add a markdown extension
  • add custom routes

Please feel free to suggest any other things that a plugin should be able to do.

Implement simple db module

Implement a db module with a simple interface.

API

db.get(doctype, key) -> Document
db.get_many(doctype, keys) -> List[Document]
db.query(doctype, field1='a', field2='b') -> List[Document]

It also supports defining classes for each doctype.

@db.register_model("course")
class Course(db.Document):
    def get_authors(self):
        ...

Tasks

...

Lesson Page

The lesson page will have show the lesson title followed by the lesson contents. It will also have breadcrumbs in the top to go back the course.

Mockup

image

Course page

The course page will have a header and three sections: about the course, course outline and instructor.

Mockup

image

New command: `riyaz new`

It should:

  • help the course developer to understand where each file goes, and how the settings need to be specified
  • give user a project template to fill in the blanks or swap out pieces

Approach:

  • Add a template/ folder in sample-data/ that has files for chapters, lessons, authors, and course.yml
  • When user runs riyaz new {course-dir}:
    1. Create directory {course-dir}, copy contents of template/ into {course-dir}/. If directory exists, an error should be raised.
    2. Load {course-dir}/course.yml into memory, change value of course: {course-dir} to the title-fied version of {course-dir}.

The sample data loaded should have some demonstration of how to use the features provided by riyaz.

Schema for models

We have the database and the schema for it in place, but we need to finalise some of schema of how we connect between documents and what fields each has.

Some unknowns:

  • Do we need a doctype for "Module"?
  • How do we keep track of index of lessons within a module (as per the outline)? Do we keep an index or idx field or refer back to outline each time?
    ...

refactor: Multiple model types are increasing code complexity

We have models for doctypes, models (parsed-representations of disk courses), and on-disk format.
I feel there is room for some refactoring: models.py and doctypes.py don't have very different purposes.
Doctypes also don't have the attributes exposed in doctypes.py, but it is mostly the same as models.py.

Course Development Flow

This issue outlines the flow for developing a course.

The course creator will start a new course by calling the following commands:

$ pip install riyaz

$ riyaz new course_directory

That would create a course structure with a couple of sample lessons and a course.yml file.

You can start a dev server using:

$ riyaz serve
http://localhost:5000/

The dev server would serve the course and any changes made to the lessons will be reloaded live. The behavior is similar to mkdocs.

Serving from assets directory

From code review in #28

While #28 will work fine, I feel this deserves more consideration at some point.

Member
@anandology anandology 3 days ago

Why do we need to make an assets directory in the tmp folder? Why can't you serve the assets from where they are?

nikochiko reacted with thumbs up emoji
Member
Author
@nikochiko nikochiko 3 days ago

This directory is like the assets directory on a hosted server with multiple courses.

Users may want to keep their own assets in the local assets/ organized differently.
If we load the assets from their paths into local assets/ that would cause spam.

Member
Author
@nikochiko nikochiko 3 days ago

Our URLs and paths would be like /assets/instructor/1/kitten.png, but that might not make sense for the course creator.

db: AttributeError on 'super' object after `document._id`

>>> course._id
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/.../riyaz/riyaz/db.py", line 79, in __getattr__
    return super().__getattr__(key)
AttributeError: 'super' object has no attribute '__getattr__'

Management of course assets

Course will have assets like instructor photo, and other custom assets that are loaded into markdown by user.

We need to save that in a separate directory that can be served by Flask or another file server.

On disk format for courses

Propose and finalize on disk for authoring courses.

Format for course.yml:

name: sample-course # required
title: Sample Course # required

short_description: This is a sample course for use to clarify the course.yml format # optional
description: | # required, markdown
    This is a longer description in markdown format. The course instructor can use codeblocks and italics to highlight
    the ideas in the course. 

authors:
    - alfa # we'll find an authors/alfa.md
    - bravo # authors/bravo.md

outline: # could be called 'chapters' ?
    - name: getting-started
      title: Getting started
      lessons:
        - getting-started/how-to-use-sample.md
        - getting-started/more-about-sample.md
    - name: intermediate-sample:
      title: Intermediate Sample
      lessons:
        - intermediate-sample/more-use-cases-of-sample.md
        - intermediate-sample/more-reading-about-sample.md

New command: `riyaz import-course`

This command should import a course from Git.

Example usage:

$ ls
riyaz.yml riyaz.db
$ riyaz import-course ../path/to/course/directory

Course Deployment Flow

The applciation configuration will have a place to specify a secret token and that token is specified to push a course.

$ riyaz push --token $token

or

$ export RIYAZ_TOKEN=abcd1234
$ riyaz push

Fix tests

Tests are failing / error-ing.

  • Fix tests
  • Add new tests for db
  • Add tests for CLI

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.