diff --git a/404.html b/404.html index 4c1aa35d69..5cf36e2d14 100644 --- a/404.html +++ b/404.html @@ -4,13 +4,13 @@ Page Not Found | Richie - - + +
-
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- - +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

+ + \ No newline at end of file diff --git a/assets/js/02aff391.2c57ca34.js b/assets/js/02aff391.2c57ca34.js deleted file mode 100644 index 5f26309e31..0000000000 --- a/assets/js/02aff391.2c57ca34.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[27128],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var r=n(67294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=c(n),h=i,f=p["".concat(s,".").concat(h)]||p[h]||d[h]||o;return n?r.createElement(f,a(a({ref:t},u),{},{components:n})):r.createElement(f,a({ref:t},u))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,a=new Array(o);a[0]=p;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:i,a[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>s,default:()=>h,frontMatter:()=>l,metadata:()=>c,toc:()=>d});var r=n(83117),i=n(80102),o=(n(67294),n(3905)),a=["components"],l={id:"building-the-frontend",title:"Building Richie's frontend in your own project",sidebar_label:"Building the frontend"},s=void 0,c={unversionedId:"building-the-frontend",id:"version-2.21.0/building-the-frontend",title:"Building Richie's frontend in your own project",description:"Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.",source:"@site/versioned_docs/version-2.21.0/building-the-frontend.md",sourceDirName:".",slug:"/building-the-frontend",permalink:"/docs/building-the-frontend",draft:!1,tags:[],version:"2.21.0",lastUpdatedBy:"jbpenrath",lastUpdatedAt:1679473023,formattedLastUpdatedAt:"Mar 22, 2023",frontMatter:{id:"building-the-frontend",title:"Building Richie's frontend in your own project",sidebar_label:"Building the frontend"},sidebar:"docs",previous:{title:"Django & React",permalink:"/docs/django-react-interop"},next:{title:"Frontend overrides",permalink:"/docs/frontend-overrides"}},u={},d=[{value:"Installing richie-education",id:"installing-richie-education",level:2},{value:"Building the Javascript bundle",id:"building-the-javascript-bundle",level:2},{value:"Building the CSS",id:"building-the-css",level:2}],p={toc:d};function h(e){var t=e.components,n=(0,i.Z)(e,a);return(0,o.kt)("wrapper",(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings."),(0,o.kt)("p",null,"Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend."),(0,o.kt)("h2",{id:"installing-richie-education"},"Installing ",(0,o.kt)("inlineCode",{parentName:"h2"},"richie-education")),(0,o.kt)("p",null,"If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir -p src/frontend\n")),(0,o.kt)("p",null,"Then, you need to bootstrap your own frontend project in this new directory."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cd src/frontend\nyarn init\n")),(0,o.kt)("p",null,"With each version of Richie, we build and publish an ",(0,o.kt)("inlineCode",{parentName:"p"},"NPM")," package to enable Richie users to build their own Javascript and CSS. You're now ready to install it."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"yarn add richie-education\n")),(0,o.kt)("p",null,"In your ",(0,o.kt)("inlineCode",{parentName:"p"},"package.json")," file, you should see it in the list of dependencies. Also, there's a ",(0,o.kt)("inlineCode",{parentName:"p"},"node_modules")," directory where the package and its dependencies are actually installed."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'"dependencies": {\n "richie-education": "1.12.0"\n},\n')),(0,o.kt)("h2",{id:"building-the-javascript-bundle"},"Building the Javascript bundle"),(0,o.kt)("p",null,"You are now ready to run your own frontend build. We'll just be using webpack directly."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build\n")),(0,o.kt)("p",null,"Here is everything that is happening:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"yarn webpack")," \u2014 run the webpack CLI;"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"--config node_modules/richie-education/webpack.config.js")," \u2014 point webpack to ",(0,o.kt)("inlineCode",{parentName:"li"},"richie-education"),"'s webpack config file;"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"--output-path ./build")," \u2014 make sure we get our output where we need it to be;"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"--richie-dependent-build")," \u2014 enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.")),(0,o.kt)("p",null,"You can now run your build to change frontend settings or override frontend components with your own."),(0,o.kt)("h2",{id:"building-the-css"},"Building the CSS"),(0,o.kt)("p",null,"If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself."),(0,o.kt)("p",null,"Start by creating your own ",(0,o.kt)("inlineCode",{parentName:"p"},"main")," file. The ",(0,o.kt)("inlineCode",{parentName:"p"},"_")," underscore at the beginning is there to prevent sass from auto-compiling the file."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir -p src/frontend/scss\ntouch src/frontend/scss/_mains.scss\n")),(0,o.kt)("p",null,"Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include \u2014 in effect re-doing Richie's ",(0,o.kt)("inlineCode",{parentName:"p"},"_main.scss")," on your own."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-sass"},'@import "richie-education/scss/main";\n')),(0,o.kt)("p",null,"You are now ready to run the CSS build:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"cd src/frontend\nyarn build-sass\n")),(0,o.kt)("p",null,"This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/02aff391.9a816351.js b/assets/js/02aff391.9a816351.js new file mode 100644 index 0000000000..8c6db108fa --- /dev/null +++ b/assets/js/02aff391.9a816351.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[27128],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var r=n(67294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=c(n),h=i,f=p["".concat(s,".").concat(h)]||p[h]||d[h]||o;return n?r.createElement(f,a(a({ref:t},u),{},{components:n})):r.createElement(f,a({ref:t},u))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,a=new Array(o);a[0]=p;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:i,a[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>s,default:()=>h,frontMatter:()=>l,metadata:()=>c,toc:()=>d});var r=n(83117),i=n(80102),o=(n(67294),n(3905)),a=["components"],l={id:"building-the-frontend",title:"Building Richie's frontend in your own project",sidebar_label:"Building the frontend"},s=void 0,c={unversionedId:"building-the-frontend",id:"version-2.21.0/building-the-frontend",title:"Building Richie's frontend in your own project",description:"Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.",source:"@site/versioned_docs/version-2.21.0/building-the-frontend.md",sourceDirName:".",slug:"/building-the-frontend",permalink:"/docs/2.21.0/building-the-frontend",draft:!1,tags:[],version:"2.21.0",lastUpdatedBy:"jbpenrath",lastUpdatedAt:1679473023,formattedLastUpdatedAt:"Mar 22, 2023",frontMatter:{id:"building-the-frontend",title:"Building Richie's frontend in your own project",sidebar_label:"Building the frontend"},sidebar:"docs",previous:{title:"Django & React",permalink:"/docs/2.21.0/django-react-interop"},next:{title:"Frontend overrides",permalink:"/docs/2.21.0/frontend-overrides"}},u={},d=[{value:"Installing richie-education",id:"installing-richie-education",level:2},{value:"Building the Javascript bundle",id:"building-the-javascript-bundle",level:2},{value:"Building the CSS",id:"building-the-css",level:2}],p={toc:d};function h(e){var t=e.components,n=(0,i.Z)(e,a);return(0,o.kt)("wrapper",(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings."),(0,o.kt)("p",null,"Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend."),(0,o.kt)("h2",{id:"installing-richie-education"},"Installing ",(0,o.kt)("inlineCode",{parentName:"h2"},"richie-education")),(0,o.kt)("p",null,"If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir -p src/frontend\n")),(0,o.kt)("p",null,"Then, you need to bootstrap your own frontend project in this new directory."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cd src/frontend\nyarn init\n")),(0,o.kt)("p",null,"With each version of Richie, we build and publish an ",(0,o.kt)("inlineCode",{parentName:"p"},"NPM")," package to enable Richie users to build their own Javascript and CSS. You're now ready to install it."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"yarn add richie-education\n")),(0,o.kt)("p",null,"In your ",(0,o.kt)("inlineCode",{parentName:"p"},"package.json")," file, you should see it in the list of dependencies. Also, there's a ",(0,o.kt)("inlineCode",{parentName:"p"},"node_modules")," directory where the package and its dependencies are actually installed."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'"dependencies": {\n "richie-education": "1.12.0"\n},\n')),(0,o.kt)("h2",{id:"building-the-javascript-bundle"},"Building the Javascript bundle"),(0,o.kt)("p",null,"You are now ready to run your own frontend build. We'll just be using webpack directly."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build\n")),(0,o.kt)("p",null,"Here is everything that is happening:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"yarn webpack")," \u2014 run the webpack CLI;"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"--config node_modules/richie-education/webpack.config.js")," \u2014 point webpack to ",(0,o.kt)("inlineCode",{parentName:"li"},"richie-education"),"'s webpack config file;"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"--output-path ./build")," \u2014 make sure we get our output where we need it to be;"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"--richie-dependent-build")," \u2014 enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.")),(0,o.kt)("p",null,"You can now run your build to change frontend settings or override frontend components with your own."),(0,o.kt)("h2",{id:"building-the-css"},"Building the CSS"),(0,o.kt)("p",null,"If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself."),(0,o.kt)("p",null,"Start by creating your own ",(0,o.kt)("inlineCode",{parentName:"p"},"main")," file. The ",(0,o.kt)("inlineCode",{parentName:"p"},"_")," underscore at the beginning is there to prevent sass from auto-compiling the file."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir -p src/frontend/scss\ntouch src/frontend/scss/_mains.scss\n")),(0,o.kt)("p",null,"Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include \u2014 in effect re-doing Richie's ",(0,o.kt)("inlineCode",{parentName:"p"},"_main.scss")," on your own."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-sass"},'@import "richie-education/scss/main";\n')),(0,o.kt)("p",null,"You are now ready to run the CSS build:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"cd src/frontend\nyarn build-sass\n")),(0,o.kt)("p",null,"This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/061b9ec0.9c3a0854.js b/assets/js/061b9ec0.9c3a0854.js new file mode 100644 index 0000000000..4fdc473150 --- /dev/null +++ b/assets/js/061b9ec0.9c3a0854.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[74685],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(67294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function s(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},u=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,s=e.originalType,l=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),d=c(r),m=o,f=d["".concat(l,".").concat(m)]||d[m]||p[m]||s;return r?n.createElement(f,a(a({ref:t},u),{},{components:r})):n.createElement(f,a({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var s=r.length,a=new Array(s);a[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i.mdxType="string"==typeof e?e:o,a[1]=i;for(var c=2;c{r.r(t),r.d(t,{assets:()=>u,contentTitle:()=>l,default:()=>m,frontMatter:()=>i,metadata:()=>c,toc:()=>p});var n=r(83117),o=r(80102),s=(r(67294),r(3905)),a=["components"],i={id:"css-guidelines",title:"CSS Guidelines",sidebar_label:"CSS Guidelines"},l=void 0,c={unversionedId:"css-guidelines",id:"version-2.21.1/css-guidelines",title:"CSS Guidelines",description:"The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.",source:"@site/versioned_docs/version-2.21.1/css-guidelines.md",sourceDirName:".",slug:"/css-guidelines",permalink:"/docs/css-guidelines",draft:!1,tags:[],version:"2.21.1",lastUpdatedBy:"jbpenrath",lastUpdatedAt:1680624606,formattedLastUpdatedAt:"Apr 4, 2023",frontMatter:{id:"css-guidelines",title:"CSS Guidelines",sidebar_label:"CSS Guidelines"},sidebar:"docs",previous:{title:"Accessibility testing",permalink:"/docs/accessibility-testing"}},u={},p=[{value:"File structuration",id:"file-structuration",level:2},{value:"Code structuration",id:"code-structuration",level:2},{value:"Quick pointers",id:"quick-pointers",level:2}],d={toc:p};function m(e){var t=e.components,r=(0,o.Z)(e,a);return(0,s.kt)("wrapper",(0,n.Z)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,s.kt)("p",null,"The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly."),(0,s.kt)("p",null,"Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations."),(0,s.kt)("h2",{id:"file-structuration"},"File structuration"),(0,s.kt)("p",null,"Rules should be placed where their purpose is most apparent, and where they are easiest to find."),(0,s.kt)("p",null,"Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a ",(0,s.kt)("inlineCode",{parentName:"p"},".scss")," file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are ",(0,s.kt)("strong",{parentName:"p"},"specific to this component/template and this one only")),(0,s.kt)("p",null,"Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central ",(0,s.kt)("inlineCode",{parentName:"p"},"app/static/scss")," folder."),(0,s.kt)("h2",{id:"code-structuration"},"Code structuration"),(0,s.kt)("p",null,"In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes."),(0,s.kt)("p",null,"Following the ",(0,s.kt)("a",{parentName:"p",href:"http://getbem.com/introduction/"},"BEM naming convention"),", we will write our classes as follows :"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"},".block {}\n.block__element {}\n.block--modifier {}\n")),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},".block")," represents the higher level of an abstraction or component."),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},".block__element")," represents a descendent of .block that helps form .block as a whole."),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},".block--modifier")," represents a different state or version of .block.")),(0,s.kt)("p",null,"We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. ",(0,s.kt)("inlineCode",{parentName:"p"},".site-search__field--full"),")."),(0,s.kt)("p",null,"Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup."),(0,s.kt)("h2",{id:"quick-pointers"},"Quick pointers"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},"In general, ",(0,s.kt)("strong",{parentName:"li"},"do not use IDs"),". ",(0,s.kt)("em",{parentName:"li"},"They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.")),(0,s.kt)("li",{parentName:"ul"},"Do not nest selectors unnecessarily. ",(0,s.kt)("em",{parentName:"li"},"It will increase specificity and affect where else you can use your styles.")),(0,s.kt)("li",{parentName:"ul"},"Do not qualify selectors unnecessarily. ",(0,s.kt)("em",{parentName:"li"},"It will impact the number of different elements you can apply styles to.")),(0,s.kt)("li",{parentName:"ul"},"Comment profusely, ",(0,s.kt)("em",{parentName:"li"},"whenever you think the CSS is getting complex or it would not be easy to understand its intent.")),(0,s.kt)("li",{parentName:"ul"},"Use !important proactively. ",(0,s.kt)("em",{parentName:"li"},"!important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively."))),(0,s.kt)("p",null,"(Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. ",(0,s.kt)("inlineCode",{parentName:"p"},"div > #example")," is A LOT more efficient than ",(0,s.kt)("inlineCode",{parentName:"p"},"#example > div")," although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See ",(0,s.kt)("a",{parentName:"p",href:"http://csswizardry.com/2011/09/writing-efficient-css-selectors/"},"CSS Wizardry")," for more details."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/0add6094.d6475b98.js b/assets/js/0add6094.d6475b98.js new file mode 100644 index 0000000000..e039c0e668 --- /dev/null +++ b/assets/js/0add6094.d6475b98.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[70005],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>m});var r=t(67294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function a(e){for(var n=1;n=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=r.createContext({}),c=function(e){var n=r.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):a(a({},n),e)),t},u=function(e){var n=c(e.components);return r.createElement(l.Provider,{value:n},e.children)},p={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},d=r.forwardRef((function(e,n){var t=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=c(t),m=o,h=d["".concat(l,".").concat(m)]||d[m]||p[m]||i;return t?r.createElement(h,a(a({ref:n},u),{},{components:t})):r.createElement(h,a({ref:n},u))}));function m(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var i=t.length,a=new Array(i);a[0]=d;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s.mdxType="string"==typeof e?e:o,a[1]=s;for(var c=2;c{t.r(n),t.d(n,{assets:()=>u,contentTitle:()=>l,default:()=>m,frontMatter:()=>s,metadata:()=>c,toc:()=>p});var r=t(83117),o=t(80102),i=(t(67294),t(3905)),a=["components"],s={id:"course-run-synchronization-api",title:"Course run synchronization API",sidebar_label:"course run sync"},l=void 0,c={unversionedId:"api/course-run-synchronization-api",id:"version-2.21.1/api/course-run-synchronization-api",title:"Course run synchronization API",description:"API endpoint allowing remote systems to synchronize their course runs with a Richie instance.",source:"@site/versioned_docs/version-2.21.1/api/course-run-synchronization-api.md",sourceDirName:"api",slug:"/api/course-run-synchronization-api",permalink:"/docs/api/course-run-synchronization-api",draft:!1,tags:[],version:"2.21.1",lastUpdatedBy:"jbpenrath",lastUpdatedAt:1680624606,formattedLastUpdatedAt:"Apr 4, 2023",frontMatter:{id:"course-run-synchronization-api",title:"Course run synchronization API",sidebar_label:"course run sync"}},u={},p=[{value:"Synchronization endpoint /api/1.0/course-runs-sync",id:"synchronization-endpoint-api10course-runs-sync",level:2},{value:"Synchronize a course run POST",id:"synchronize-a-course-run-post",level:3}],d={toc:p};function m(e){var n=e.components,t=(0,o.Z)(e,a);return(0,i.kt)("wrapper",(0,r.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"API endpoint allowing remote systems to synchronize their course runs with a Richie instance."),(0,i.kt)("h2",{id:"synchronization-endpoint-api10course-runs-sync"},"Synchronization endpoint ","[/api/1.0/course-runs-sync]"),(0,i.kt)("p",null,'This documentation describes version "1.0" of this API endpoint.'),(0,i.kt)("h3",{id:"synchronize-a-course-run-post"},"Synchronize a course run ","[POST]"),(0,i.kt)("p",null,"It takes a JSON object containing the course run details:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"resource_link: ",(0,i.kt)("inlineCode",{parentName:"li"},"https://lms.example.com/courses/course-v1:001+001+001/info")," (string, required) -\nurl of the course syllabus on the LMS from which a unique course identifier can be extracted"),(0,i.kt)("li",{parentName:"ul"},"start: ",(0,i.kt)("inlineCode",{parentName:"li"},"2018-02-01T06:00:00Z")," (string, optional) - ISO 8601 date, when this session of the\ncourse starts"),(0,i.kt)("li",{parentName:"ul"},"end: ",(0,i.kt)("inlineCode",{parentName:"li"},"2018-02-28T06:00:00Z")," (string, optional) - ISO 8601 date, when this session of the course\nends"),(0,i.kt)("li",{parentName:"ul"},"enrollment_start: ",(0,i.kt)("inlineCode",{parentName:"li"},"2018-01-01T06:00:00Z")," (string, optional) - ISO 8601 date, when enrollment\nfor this session of the course starts"),(0,i.kt)("li",{parentName:"ul"},"enrollment_end: ",(0,i.kt)("inlineCode",{parentName:"li"},"2018-01-31T06:00:00Z")," (string, optional) - ISO 8601 date, when enrollment for\nthis session of the course ends"),(0,i.kt)("li",{parentName:"ul"},"languages: ","['fr', 'en']"," (array","[string]",", required) - ISO 639-1 code (2 letters) for the course's\nlanguages")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"Request (application/json)"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"Headers"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Authorization: ",(0,i.kt)("inlineCode",{parentName:"li"},"SIG-HMAC-SHA256 xxxxxxx")," (string, required) - Authorization header\ncontaining the digest of the utf-8 encoded json representation of the submitted data\nfor the given secret key and SHA256 digest algorithm (see ","[synchronizing-course-runs]","\nfor an example)."))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"Body"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},' {\n "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",\n "start": "2021-02-01T00:00:00Z",\n "end": "2021-02-31T23:59:59Z",\n "enrollment_start": "2021-01-01T00:00:00Z",\n "enrollment_end": "2021-01-31T23:59:59Z",\n "languages": ["en", "fr"]\n }\n'))))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"Response 200 (application/json)"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"Body"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre"},' {\n "success": True\n }\n')))))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/0b704f48.a57f152d.js b/assets/js/0b704f48.a57f152d.js new file mode 100644 index 0000000000..1eb31f4bb0 --- /dev/null +++ b/assets/js/0b704f48.a57f152d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[43382],{3905:(e,t,o)=>{o.d(t,{Zo:()=>s,kt:()=>h});var r=o(67294);function n(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function i(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,r)}return o}function a(e){for(var t=1;t=0||(n[o]=e[o]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(n[o]=e[o])}return n}var l=r.createContext({}),u=function(e){var t=r.useContext(l),o=t;return e&&(o="function"==typeof e?e(t):a(a({},t),e)),o},s=function(e){var t=u(e.components);return r.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var o=e.components,n=e.mdxType,i=e.originalType,l=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),d=u(o),h=n,m=d["".concat(l,".").concat(h)]||d[h]||p[h]||i;return o?r.createElement(m,a(a({ref:t},s),{},{components:o})):r.createElement(m,a({ref:t},s))}));function h(e,t){var o=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=o.length,a=new Array(i);a[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:n,a[1]=c;for(var u=2;u{o.r(t),o.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>h,frontMatter:()=>c,metadata:()=>u,toc:()=>p});var r=o(83117),n=o(80102),i=(o(67294),o(3905)),a=["components"],c={id:"cookiecutter",title:"Start your own site",sidebar_label:"Start your own site"},l=void 0,u={unversionedId:"cookiecutter",id:"cookiecutter",title:"Start your own site",description:"We use Cookiecutter to help you",source:"@site/../docs/cookiecutter.md",sourceDirName:".",slug:"/cookiecutter",permalink:"/docs/next/cookiecutter",draft:!1,tags:[],version:"current",lastUpdatedBy:"jbpenrath",lastUpdatedAt:1680624606,formattedLastUpdatedAt:"Apr 4, 2023",frontMatter:{id:"cookiecutter",title:"Start your own site",sidebar_label:"Start your own site"},sidebar:"docs",previous:{title:"Discover Richie",permalink:"/docs/next/discover"},next:{title:"Search filters customization",permalink:"/docs/next/filters-customization"}},s={},p=[{value:"Run Cookiecutter",id:"run-cookiecutter",level:2},{value:"Bootstrap your project",id:"bootstrap-your-project",level:3},{value:"Theming",id:"theming",level:2},{value:"Update your Richie site factory",id:"update-your-richie-site-factory",level:2},{value:"Help us improve this project",id:"help-us-improve-this-project",level:2}],d={toc:p};function h(e){var t=e.components,o=(0,n.Z)(e,a);return(0,i.kt)("wrapper",(0,r.Z)({},d,o,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"We use ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/audreyr/cookiecutter"},"Cookiecutter")," to help you\nset up a production-ready learning portal website based on\n",(0,i.kt)("a",{parentName:"p",href:"https://github.com/openfun/richie"},"Richie")," in seconds."),(0,i.kt)("h2",{id:"run-cookiecutter"},"Run Cookiecutter"),(0,i.kt)("p",null,"There are 2 options to run Cookiecutter:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://cookiecutter.readthedocs.io/en/latest/installation.html"},"install it on your machine")),(0,i.kt)("li",{parentName:"ul"},"run it with Docker")),(0,i.kt)("p",null,"While you think of it, navigate to the directory in which you want to create\nyour site factory:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"cd /path/to/your/code/directory\n")),(0,i.kt)("p",null,"If you chose to install Cookiecutter, you can now run it against our\n",(0,i.kt)("a",{parentName:"p",href:"https://github.com/openfun/richie/tree/master/cookiecutter"},"template")," as follows:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"cookiecutter gh:openfun/richie --directory cookiecutter --checkout v2.21.1\n")),(0,i.kt)("p",null,"If you didn't want to install it on your machine, we provide a Docker image\nbuilt with our ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/openfun/dockerfiles"},"own repository")," that you can use as follows:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"docker run --rm -it -u $(id -u):$(id -g) -v $PWD:/app \\\nfundocker/cookiecutter gh:openfun/richie --directory cookiecutter --checkout v2.21.1\n")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"--directory")," option is to indicate that our Cookiecutter template is in\na ",(0,i.kt)("inlineCode",{parentName:"p"},"cookiecutter")," directory inside our git repository and not at the root."),(0,i.kt)("p",null,'You will be prompted to enter an organization name, which will determine the\nname of your repository. For example, if you choose "foo" as organization\nname, your repository will be named ',(0,i.kt)("inlineCode",{parentName:"p"},"foo-richie-site-factory"),". It's\nnice if you keep it that way so all richie site factories follow this\nconvention."),(0,i.kt)("p",null,"When you confirm the organization name, Cookiecutter will generate your\nproject from the Cookiecutter template and place it at the level where you\ncurrently are."),(0,i.kt)("h3",{id:"bootstrap-your-project"},"Bootstrap your project"),(0,i.kt)("p",null,"Enter the newly created project and add a new site to your site factory:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"cd foo-richie-site-factory\nmake add-site\n")),(0,i.kt)("p",null,"This script also uses Cookiecutter against our ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/openfun/richie/tree/master/cookiecutter/%7B%7Bcookiecutter.organization%7D%7D-richie-site-factory/template"},"site template"),"."),(0,i.kt)("p",null,"Once your new site is created, activate it:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"bin/activate\n")),(0,i.kt)("p",null,"Now bootstrap the site to build its docker image, create its media folder,\ndatabase, etc.:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"make bootstrap\n")),(0,i.kt)("p",null,"Once the bootstrap phase is finished, you should be able to view the site at\n",(0,i.kt)("a",{parentName:"p",href:"http://localhost:8070"},"localhost:8070"),"."),(0,i.kt)("p",null,"You can create a full fledge demo to test your site by running:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"make demo-site\n")),(0,i.kt)("p",null,"Note that the README of your newly created site factory contains detailed\ninformation about how to configure and run a site."),(0,i.kt)("p",null,"Once you're happy with your site, don't forget to backup your work e.g. by\ncommitting it and pushing it to a new git repository."),(0,i.kt)("h2",{id:"theming"},"Theming"),(0,i.kt)("p",null,"You probably want to change the default theme. The cookiecutter adds an extra scss frontend folder with a couple of templates that you can use to change the default styling of the site."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sites//src/frontend/scss/extras/colors/_palette.scss")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sites//src/frontend/scss/extras/colors/_theme.scss"))),(0,i.kt)("p",null,"To change the default logo of the site, you need to create the folder ",(0,i.kt)("inlineCode",{parentName:"p"},"sites//src/backend/base/static/richie/images")," and then override the new ",(0,i.kt)("inlineCode",{parentName:"p"},"logo.png")," picture."),(0,i.kt)("p",null,"For more advanced customization, refer to our recipes:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/docs/next/filters-customization"},"How to customize search filters")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/docs/next/frontend-overrides"},"How to override frontend components in Richie"))),(0,i.kt)("h2",{id:"update-your-richie-site-factory"},"Update your Richie site factory"),(0,i.kt)("p",null,"If we later improve our scripts, you will be able to update your own site\nfactory by replaying Cookiecutter. This will override your files in the\nproject's scaffolding but, don't worry, it will respect all the sites you\nwill have created in the ",(0,i.kt)("inlineCode",{parentName:"p"},"sites")," directory:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"cookiecutter --overwrite-if-exists gh:openfun/richie --directory=cookiecutter\n")),(0,i.kt)("h2",{id:"help-us-improve-this-project"},"Help us improve this project"),(0,i.kt)("p",null,"After starting your project, please submit an issue let us know how it went and\nwhat other features we should add to make it better."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/0b704f48.c856e92a.js b/assets/js/0b704f48.c856e92a.js deleted file mode 100644 index 2b40b4df10..0000000000 --- a/assets/js/0b704f48.c856e92a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[43382],{3905:(e,t,o)=>{o.d(t,{Zo:()=>s,kt:()=>h});var r=o(67294);function n(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function i(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,r)}return o}function a(e){for(var t=1;t=0||(n[o]=e[o]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(n[o]=e[o])}return n}var l=r.createContext({}),u=function(e){var t=r.useContext(l),o=t;return e&&(o="function"==typeof e?e(t):a(a({},t),e)),o},s=function(e){var t=u(e.components);return r.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var o=e.components,n=e.mdxType,i=e.originalType,l=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),d=u(o),h=n,m=d["".concat(l,".").concat(h)]||d[h]||p[h]||i;return o?r.createElement(m,a(a({ref:t},s),{},{components:o})):r.createElement(m,a({ref:t},s))}));function h(e,t){var o=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=o.length,a=new Array(i);a[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:n,a[1]=c;for(var u=2;u{o.r(t),o.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>h,frontMatter:()=>c,metadata:()=>u,toc:()=>p});var r=o(83117),n=o(80102),i=(o(67294),o(3905)),a=["components"],c={id:"cookiecutter",title:"Start your own site",sidebar_label:"Start your own site"},l=void 0,u={unversionedId:"cookiecutter",id:"cookiecutter",title:"Start your own site",description:"We use Cookiecutter to help you",source:"@site/../docs/cookiecutter.md",sourceDirName:".",slug:"/cookiecutter",permalink:"/docs/next/cookiecutter",draft:!1,tags:[],version:"current",lastUpdatedBy:"jbpenrath",lastUpdatedAt:1679473023,formattedLastUpdatedAt:"Mar 22, 2023",frontMatter:{id:"cookiecutter",title:"Start your own site",sidebar_label:"Start your own site"},sidebar:"docs",previous:{title:"Discover Richie",permalink:"/docs/next/discover"},next:{title:"Search filters customization",permalink:"/docs/next/filters-customization"}},s={},p=[{value:"Run Cookiecutter",id:"run-cookiecutter",level:2},{value:"Bootstrap your project",id:"bootstrap-your-project",level:3},{value:"Theming",id:"theming",level:2},{value:"Update your Richie site factory",id:"update-your-richie-site-factory",level:2},{value:"Help us improve this project",id:"help-us-improve-this-project",level:2}],d={toc:p};function h(e){var t=e.components,o=(0,n.Z)(e,a);return(0,i.kt)("wrapper",(0,r.Z)({},d,o,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"We use ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/audreyr/cookiecutter"},"Cookiecutter")," to help you\nset up a production-ready learning portal website based on\n",(0,i.kt)("a",{parentName:"p",href:"https://github.com/openfun/richie"},"Richie")," in seconds."),(0,i.kt)("h2",{id:"run-cookiecutter"},"Run Cookiecutter"),(0,i.kt)("p",null,"There are 2 options to run Cookiecutter:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://cookiecutter.readthedocs.io/en/latest/installation.html"},"install it on your machine")),(0,i.kt)("li",{parentName:"ul"},"run it with Docker")),(0,i.kt)("p",null,"While you think of it, navigate to the directory in which you want to create\nyour site factory:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"cd /path/to/your/code/directory\n")),(0,i.kt)("p",null,"If you chose to install Cookiecutter, you can now run it against our\n",(0,i.kt)("a",{parentName:"p",href:"https://github.com/openfun/richie/tree/master/cookiecutter"},"template")," as follows:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"cookiecutter gh:openfun/richie --directory cookiecutter --checkout v2.21.0\n")),(0,i.kt)("p",null,"If you didn't want to install it on your machine, we provide a Docker image\nbuilt with our ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/openfun/dockerfiles"},"own repository")," that you can use as follows:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"docker run --rm -it -u $(id -u):$(id -g) -v $PWD:/app \\\nfundocker/cookiecutter gh:openfun/richie --directory cookiecutter --checkout v2.21.0\n")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"--directory")," option is to indicate that our Cookiecutter template is in\na ",(0,i.kt)("inlineCode",{parentName:"p"},"cookiecutter")," directory inside our git repository and not at the root."),(0,i.kt)("p",null,'You will be prompted to enter an organization name, which will determine the\nname of your repository. For example, if you choose "foo" as organization\nname, your repository will be named ',(0,i.kt)("inlineCode",{parentName:"p"},"foo-richie-site-factory"),". It's\nnice if you keep it that way so all richie site factories follow this\nconvention."),(0,i.kt)("p",null,"When you confirm the organization name, Cookiecutter will generate your\nproject from the Cookiecutter template and place it at the level where you\ncurrently are."),(0,i.kt)("h3",{id:"bootstrap-your-project"},"Bootstrap your project"),(0,i.kt)("p",null,"Enter the newly created project and add a new site to your site factory:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"cd foo-richie-site-factory\nmake add-site\n")),(0,i.kt)("p",null,"This script also uses Cookiecutter against our ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/openfun/richie/tree/master/cookiecutter/%7B%7Bcookiecutter.organization%7D%7D-richie-site-factory/template"},"site template"),"."),(0,i.kt)("p",null,"Once your new site is created, activate it:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"bin/activate\n")),(0,i.kt)("p",null,"Now bootstrap the site to build its docker image, create its media folder,\ndatabase, etc.:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"make bootstrap\n")),(0,i.kt)("p",null,"Once the bootstrap phase is finished, you should be able to view the site at\n",(0,i.kt)("a",{parentName:"p",href:"http://localhost:8070"},"localhost:8070"),"."),(0,i.kt)("p",null,"You can create a full fledge demo to test your site by running:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"make demo-site\n")),(0,i.kt)("p",null,"Note that the README of your newly created site factory contains detailed\ninformation about how to configure and run a site."),(0,i.kt)("p",null,"Once you're happy with your site, don't forget to backup your work e.g. by\ncommitting it and pushing it to a new git repository."),(0,i.kt)("h2",{id:"theming"},"Theming"),(0,i.kt)("p",null,"You probably want to change the default theme. The cookiecutter adds an extra scss frontend folder with a couple of templates that you can use to change the default styling of the site."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sites//src/frontend/scss/extras/colors/_palette.scss")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sites//src/frontend/scss/extras/colors/_theme.scss"))),(0,i.kt)("p",null,"To change the default logo of the site, you need to create the folder ",(0,i.kt)("inlineCode",{parentName:"p"},"sites//src/backend/base/static/richie/images")," and then override the new ",(0,i.kt)("inlineCode",{parentName:"p"},"logo.png")," picture."),(0,i.kt)("p",null,"For more advanced customization, refer to our recipes:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/docs/next/filters-customization"},"How to customize search filters")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/docs/next/frontend-overrides"},"How to override frontend components in Richie"))),(0,i.kt)("h2",{id:"update-your-richie-site-factory"},"Update your Richie site factory"),(0,i.kt)("p",null,"If we later improve our scripts, you will be able to update your own site\nfactory by replaying Cookiecutter. This will override your files in the\nproject's scaffolding but, don't worry, it will respect all the sites you\nwill have created in the ",(0,i.kt)("inlineCode",{parentName:"p"},"sites")," directory:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"cookiecutter --overwrite-if-exists gh:openfun/richie --directory=cookiecutter\n")),(0,i.kt)("h2",{id:"help-us-improve-this-project"},"Help us improve this project"),(0,i.kt)("p",null,"After starting your project, please submit an issue let us know how it went and\nwhat other features we should add to make it better."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/0d621e61.cd820561.js b/assets/js/0d621e61.cd820561.js new file mode 100644 index 0000000000..a83528df8a --- /dev/null +++ b/assets/js/0d621e61.cd820561.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[33444],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>m});var a=n(67294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=p(n),m=r,k=d["".concat(s,".").concat(m)]||d[m]||u[m]||o;return n?a.createElement(k,i(i({ref:t},c),{},{components:n})):a.createElement(k,i({ref:t},c))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:r,i[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>m,frontMatter:()=>l,metadata:()=>p,toc:()=>u});var a=n(83117),r=n(80102),o=(n(67294),n(3905)),i=["components"],l={id:"installation",title:"Installing Richie for development",sidebar_label:"Installation"},s=void 0,p={unversionedId:"installation",id:"version-2.21.1/installation",title:"Installing Richie for development",description:"Richie is a container-native application but can also be installed",source:"@site/versioned_docs/version-2.21.1/installation.md",sourceDirName:".",slug:"/installation",permalink:"/docs/installation",draft:!1,tags:[],version:"2.21.1",lastUpdatedBy:"jbpenrath",lastUpdatedAt:1680624606,formattedLastUpdatedAt:"Apr 4, 2023",frontMatter:{id:"installation",title:"Installing Richie for development",sidebar_label:"Installation"},sidebar:"docs",previous:{title:"Web Analytics",permalink:"/docs/web-analytics"},next:{title:"Docker development",permalink:"/docs/docker-development"}},c={},u=[{value:"Docker",id:"docker",level:2},{value:"Project bootstrap",id:"project-bootstrap",level:3},{value:"Adding content",id:"adding-content",level:3},{value:"Connecting Richie to an LMS",id:"connecting-richie-to-an-lms",level:2}],d={toc:u};function m(e){var t=e.components,n=(0,r.Z)(e,i);return(0,o.kt)("wrapper",(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"Richie")," is a ",(0,o.kt)("strong",{parentName:"p"},"container-native application")," but can also be installed\n",(0,o.kt)("a",{parentName:"p",href:"/docs/native-installation"},"on your machine"),"."),(0,o.kt)("p",null,"For development, the project is defined using a\n",(0,o.kt)("a",{parentName:"p",href:"../docker-compose.yml"},"docker-compose file")," and consists of:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"3 running services:"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"database"),": ",(0,o.kt)("inlineCode",{parentName:"li"},"postgresql")," or ",(0,o.kt)("inlineCode",{parentName:"li"},"mysql")," at your preference,"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"elasticsearch"),": the search engine,"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"app"),": the actual ",(0,o.kt)("inlineCode",{parentName:"li"},"DjangoCMS")," project with all our application code."))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"2 containers for building purposes:"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"node"),": used for front-end related tasks, ",(0,o.kt)("em",{parentName:"li"},"i.e.")," transpiling\n",(0,o.kt)("inlineCode",{parentName:"li"},"TypeScript")," sources, bundling them into a JS package, and building the\nCSS files from Sass sources,"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"crowdin"),": used to upload and retrieve i18n files to and from the\n",(0,o.kt)("a",{parentName:"li",href:"https://crowdin.com/"},"Crowding")," service that we use to crowd source\ntranslations,")))),(0,o.kt)("p",null,'At "France Universit\xe9 Num\xe9rique", we deploy our applications on ',(0,o.kt)("inlineCode",{parentName:"p"},"Kubernetes"),"\nusing ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/openfun/arnold"},(0,o.kt)("inlineCode",{parentName:"a"},"Arnold")),"."),(0,o.kt)("h2",{id:"docker"},"Docker"),(0,o.kt)("p",null,"First, make sure you have a recent version of Docker and\n",(0,o.kt)("a",{parentName:"p",href:"https://docs.docker.com/compose/install"},"Docker Compose")," installed on your\nlaptop:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"$ docker -v\n Docker version 20.10.12, build e91ed57\n\n$ docker-compose --version\n docker-compose version 1.29.2, build 5becea4c\n")),(0,o.kt)("p",null,"\u26a0\ufe0f You may need to run the following commands with ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo")," but this can be\navoided by assigning your user to the ",(0,o.kt)("inlineCode",{parentName:"p"},"docker")," group."),(0,o.kt)("h3",{id:"project-bootstrap"},"Project bootstrap"),(0,o.kt)("p",null,"The easiest way to start working on the project is to use our ",(0,o.kt)("inlineCode",{parentName:"p"},"Makefile"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"$ make bootstrap\n")),(0,o.kt)("p",null,"This command builds the ",(0,o.kt)("inlineCode",{parentName:"p"},"app")," container, installs front-end and back-end\ndependencies, builds the front-end application and styles, and performs\ndatabase migrations. It's a good idea to use this command each time you are\npulling code from the project repository to avoid dependency-related or\nmigration-related issues."),(0,o.kt)("p",null,"Now that your ",(0,o.kt)("inlineCode",{parentName:"p"},"Docker")," services are ready to be used, start the full CMS by\nrunning:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"$ make run\n")),(0,o.kt)("h3",{id:"adding-content"},"Adding content"),(0,o.kt)("p",null,"Once the CMS is up and running, you can create a superuser account:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"$ make superuser\n")),(0,o.kt)("p",null,"You can create a basic demo site by running:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"$ make demo-site\n")),(0,o.kt)("p",null,"Note that if you don't create the demo site and start from a blank CMS, you\nwill get some errors requesting you to create some required root pages. So it\nis easier as a first approach to test the CMS with the demo site."),(0,o.kt)("p",null,"You should be able to view the site at ",(0,o.kt)("a",{parentName:"p",href:"http://localhost:8070"},"localhost:8070")),(0,o.kt)("h2",{id:"connecting-richie-to-an-lms"},"Connecting Richie to an LMS"),(0,o.kt)("p",null,"It is possible to use Richie as a catalogue aggregating courses from one or\nmore LMS without any specific connection. In this case, each course run in\nthe catalogue points to a course on the LMS, and the LMS points back to the\ncatalogue to browse courses."),(0,o.kt)("p",null,"This approach is used for example on ",(0,o.kt)("a",{parentName:"p",href:"https://www.fun-campus.fr"},"https://www.fun-campus.fr")," or\n",(0,o.kt)("a",{parentName:"p",href:"https://catalogue.edulib.org"},"https://catalogue.edulib.org"),"."),(0,o.kt)("p",null,"For a seamless user experience, it is possible to connect a Richie instance\nto an OpenEdX instance (or some other LMS like Moodle at the cost of minor\nadaptations), in several ways that we explain in the\n",(0,o.kt)("a",{parentName:"p",href:"lms-connection"},"LMS connection guide"),"."),(0,o.kt)("p",null,"This approach is used for example on ",(0,o.kt)("a",{parentName:"p",href:"https://www.fun-mooc.fr"},"https://www.fun-mooc.fr")," or\n",(0,o.kt)("a",{parentName:"p",href:"https://www.nau.edu.pt"},"https://www.nau.edu.pt"),"."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1681c897.04898a5f.js b/assets/js/1681c897.04898a5f.js new file mode 100644 index 0000000000..a537789571 --- /dev/null +++ b/assets/js/1681c897.04898a5f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[29228],{3905:(e,t,o)=>{o.d(t,{Zo:()=>s,kt:()=>h});var r=o(67294);function n(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function i(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,r)}return o}function a(e){for(var t=1;t=0||(n[o]=e[o]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(n[o]=e[o])}return n}var l=r.createContext({}),u=function(e){var t=r.useContext(l),o=t;return e&&(o="function"==typeof e?e(t):a(a({},t),e)),o},s=function(e){var t=u(e.components);return r.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var o=e.components,n=e.mdxType,i=e.originalType,l=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),d=u(o),h=n,m=d["".concat(l,".").concat(h)]||d[h]||p[h]||i;return o?r.createElement(m,a(a({ref:t},s),{},{components:o})):r.createElement(m,a({ref:t},s))}));function h(e,t){var o=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=o.length,a=new Array(i);a[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:n,a[1]=c;for(var u=2;u{o.r(t),o.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>h,frontMatter:()=>c,metadata:()=>u,toc:()=>p});var r=o(83117),n=o(80102),i=(o(67294),o(3905)),a=["components"],c={id:"cookiecutter",title:"Start your own site",sidebar_label:"Start your own site"},l=void 0,u={unversionedId:"cookiecutter",id:"version-2.21.1/cookiecutter",title:"Start your own site",description:"We use Cookiecutter to help you",source:"@site/versioned_docs/version-2.21.1/cookiecutter.md",sourceDirName:".",slug:"/cookiecutter",permalink:"/docs/cookiecutter",draft:!1,tags:[],version:"2.21.1",lastUpdatedBy:"jbpenrath",lastUpdatedAt:1680624606,formattedLastUpdatedAt:"Apr 4, 2023",frontMatter:{id:"cookiecutter",title:"Start your own site",sidebar_label:"Start your own site"},sidebar:"docs",previous:{title:"Discover Richie",permalink:"/docs/discover"},next:{title:"Search filters customization",permalink:"/docs/filters-customization"}},s={},p=[{value:"Run Cookiecutter",id:"run-cookiecutter",level:2},{value:"Bootstrap your project",id:"bootstrap-your-project",level:3},{value:"Theming",id:"theming",level:2},{value:"Update your Richie site factory",id:"update-your-richie-site-factory",level:2},{value:"Help us improve this project",id:"help-us-improve-this-project",level:2}],d={toc:p};function h(e){var t=e.components,o=(0,n.Z)(e,a);return(0,i.kt)("wrapper",(0,r.Z)({},d,o,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"We use ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/audreyr/cookiecutter"},"Cookiecutter")," to help you\nset up a production-ready learning portal website based on\n",(0,i.kt)("a",{parentName:"p",href:"https://github.com/openfun/richie"},"Richie")," in seconds."),(0,i.kt)("h2",{id:"run-cookiecutter"},"Run Cookiecutter"),(0,i.kt)("p",null,"There are 2 options to run Cookiecutter:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://cookiecutter.readthedocs.io/en/latest/installation.html"},"install it on your machine")),(0,i.kt)("li",{parentName:"ul"},"run it with Docker")),(0,i.kt)("p",null,"While you think of it, navigate to the directory in which you want to create\nyour site factory:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"cd /path/to/your/code/directory\n")),(0,i.kt)("p",null,"If you chose to install Cookiecutter, you can now run it against our\n",(0,i.kt)("a",{parentName:"p",href:"https://github.com/openfun/richie/tree/master/cookiecutter"},"template")," as follows:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"cookiecutter gh:openfun/richie --directory cookiecutter --checkout v2.21.1\n")),(0,i.kt)("p",null,"If you didn't want to install it on your machine, we provide a Docker image\nbuilt with our ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/openfun/dockerfiles"},"own repository")," that you can use as follows:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"docker run --rm -it -u $(id -u):$(id -g) -v $PWD:/app \\\nfundocker/cookiecutter gh:openfun/richie --directory cookiecutter --checkout v2.21.1\n")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"--directory")," option is to indicate that our Cookiecutter template is in\na ",(0,i.kt)("inlineCode",{parentName:"p"},"cookiecutter")," directory inside our git repository and not at the root."),(0,i.kt)("p",null,'You will be prompted to enter an organization name, which will determine the\nname of your repository. For example, if you choose "foo" as organization\nname, your repository will be named ',(0,i.kt)("inlineCode",{parentName:"p"},"foo-richie-site-factory"),". It's\nnice if you keep it that way so all richie site factories follow this\nconvention."),(0,i.kt)("p",null,"When you confirm the organization name, Cookiecutter will generate your\nproject from the Cookiecutter template and place it at the level where you\ncurrently are."),(0,i.kt)("h3",{id:"bootstrap-your-project"},"Bootstrap your project"),(0,i.kt)("p",null,"Enter the newly created project and add a new site to your site factory:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"cd foo-richie-site-factory\nmake add-site\n")),(0,i.kt)("p",null,"This script also uses Cookiecutter against our ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/openfun/richie/tree/master/cookiecutter/%7B%7Bcookiecutter.organization%7D%7D-richie-site-factory/template"},"site template"),"."),(0,i.kt)("p",null,"Once your new site is created, activate it:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"bin/activate\n")),(0,i.kt)("p",null,"Now bootstrap the site to build its docker image, create its media folder,\ndatabase, etc.:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"make bootstrap\n")),(0,i.kt)("p",null,"Once the bootstrap phase is finished, you should be able to view the site at\n",(0,i.kt)("a",{parentName:"p",href:"http://localhost:8070"},"localhost:8070"),"."),(0,i.kt)("p",null,"You can create a full fledge demo to test your site by running:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"make demo-site\n")),(0,i.kt)("p",null,"Note that the README of your newly created site factory contains detailed\ninformation about how to configure and run a site."),(0,i.kt)("p",null,"Once you're happy with your site, don't forget to backup your work e.g. by\ncommitting it and pushing it to a new git repository."),(0,i.kt)("h2",{id:"theming"},"Theming"),(0,i.kt)("p",null,"You probably want to change the default theme. The cookiecutter adds an extra scss frontend folder with a couple of templates that you can use to change the default styling of the site."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sites//src/frontend/scss/extras/colors/_palette.scss")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sites//src/frontend/scss/extras/colors/_theme.scss"))),(0,i.kt)("p",null,"To change the default logo of the site, you need to create the folder ",(0,i.kt)("inlineCode",{parentName:"p"},"sites//src/backend/base/static/richie/images")," and then override the new ",(0,i.kt)("inlineCode",{parentName:"p"},"logo.png")," picture."),(0,i.kt)("p",null,"For more advanced customization, refer to our recipes:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/docs/filters-customization"},"How to customize search filters")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/docs/frontend-overrides"},"How to override frontend components in Richie"))),(0,i.kt)("h2",{id:"update-your-richie-site-factory"},"Update your Richie site factory"),(0,i.kt)("p",null,"If we later improve our scripts, you will be able to update your own site\nfactory by replaying Cookiecutter. This will override your files in the\nproject's scaffolding but, don't worry, it will respect all the sites you\nwill have created in the ",(0,i.kt)("inlineCode",{parentName:"p"},"sites")," directory:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"cookiecutter --overwrite-if-exists gh:openfun/richie --directory=cookiecutter\n")),(0,i.kt)("h2",{id:"help-us-improve-this-project"},"Help us improve this project"),(0,i.kt)("p",null,"After starting your project, please submit an issue let us know how it went and\nwhat other features we should add to make it better."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/18b93cb3.95bb2857.js b/assets/js/18b93cb3.95bb2857.js deleted file mode 100644 index 89177eccde..0000000000 --- a/assets/js/18b93cb3.95bb2857.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[3042],{29732:(e,t,l)=>{l.r(t),l.d(t,{default:()=>o});var n=l(39960),r=l(52263),a=l(7961),c=l(67294);const s=JSON.parse('["2.21.0","2.20.1","2.20.0","2.19.0","2.18.0","2.17.0","2.16.0","2.15.1","2.15.0","2.14.1","2.14.0","2.13.0","2.12.0","2.11.0","2.10.0","2.9.1","2.9.0","2.8.2","2.8.1","2.8.0","2.7.1","2.7.0","2.6.0","2.5.0","2.4.0","2.3.3","2.3.2","2.3.1","2.3.0","2.2.0","2.1.0","2.0.1","2.0.0","1.17","1.16","1.15","1.14","1.13","1.12"]');const o=function(){var e=(0,r.Z)().siteConfig,t=s[0];return c.createElement(a.Z,null,c.createElement("section",null,c.createElement("div",{className:"container"},c.createElement("div",{className:"post"},c.createElement("header",{className:"postHeader"},c.createElement("h1",null,e.title," versions and documentation")),c.createElement("p",null,"New versions of this project are shipped regularly. Every new version includes its own version of the documentation."),c.createElement("p",null,"Versions below ",c.createElement("code",null,"1.12.0")," did not have a dedicated documentation website."),c.createElement("h3",{id:"latest"},"Current version (Stable)"),c.createElement("table",{className:"versions"},c.createElement("tbody",null,c.createElement("tr",null,c.createElement("th",null,t),c.createElement("td",null,c.createElement(n.Z,{to:"docs/discover"},"Documentation")),c.createElement("td",null,c.createElement(n.Z,{to:e.customFields.repoUrl+"/releases/tag/v"+t},"Release Notes"))))),c.createElement("h3",{id:"rc"},"Pre-release versions"),c.createElement("table",{className:"versions"},c.createElement("tbody",null,c.createElement("tr",null,c.createElement("th",null,"master"),c.createElement("td",null,c.createElement(n.Z,{to:"docs/next/discover"},"Documentation")),c.createElement("td",null,c.createElement(n.Z,{to:e.customFields.repoUrl},"Source Code"))))),c.createElement("h3",{id:"archive"},"Past Versions"),c.createElement("p",null,"Here you can find previous versions of the documentation."),c.createElement("table",{className:"versions"},c.createElement("tbody",null,s.map((function(l){return l!==t&&c.createElement("tr",{key:l},c.createElement("th",null,l),c.createElement("td",null,c.createElement(n.Z,{to:"docs/"+l+"/discover"},"Documentation")),c.createElement("td",null,c.createElement(n.Z,{to:e.customFields.repoUrl+"/releases/tag/v"+(3===l.split(".").length?l:l+".0")},"Release Notes")))})))),c.createElement("p",null,"You can find past versions of this project on"," ",c.createElement(n.Z,{to:e.customFields.repoUrl},"GitHub"),".")))))}}}]); \ No newline at end of file diff --git a/assets/js/18b93cb3.fd17dff1.js b/assets/js/18b93cb3.fd17dff1.js new file mode 100644 index 0000000000..84f91348ca --- /dev/null +++ b/assets/js/18b93cb3.fd17dff1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[3042],{29732:(e,t,l)=>{l.r(t),l.d(t,{default:()=>o});var n=l(39960),r=l(52263),a=l(7961),c=l(67294);const s=JSON.parse('["2.21.1","2.21.0","2.20.1","2.20.0","2.19.0","2.18.0","2.17.0","2.16.0","2.15.1","2.15.0","2.14.1","2.14.0","2.13.0","2.12.0","2.11.0","2.10.0","2.9.1","2.9.0","2.8.2","2.8.1","2.8.0","2.7.1","2.7.0","2.6.0","2.5.0","2.4.0","2.3.3","2.3.2","2.3.1","2.3.0","2.2.0","2.1.0","2.0.1","2.0.0","1.17","1.16","1.15","1.14","1.13","1.12"]');const o=function(){var e=(0,r.Z)().siteConfig,t=s[0];return c.createElement(a.Z,null,c.createElement("section",null,c.createElement("div",{className:"container"},c.createElement("div",{className:"post"},c.createElement("header",{className:"postHeader"},c.createElement("h1",null,e.title," versions and documentation")),c.createElement("p",null,"New versions of this project are shipped regularly. Every new version includes its own version of the documentation."),c.createElement("p",null,"Versions below ",c.createElement("code",null,"1.12.0")," did not have a dedicated documentation website."),c.createElement("h3",{id:"latest"},"Current version (Stable)"),c.createElement("table",{className:"versions"},c.createElement("tbody",null,c.createElement("tr",null,c.createElement("th",null,t),c.createElement("td",null,c.createElement(n.Z,{to:"docs/discover"},"Documentation")),c.createElement("td",null,c.createElement(n.Z,{to:e.customFields.repoUrl+"/releases/tag/v"+t},"Release Notes"))))),c.createElement("h3",{id:"rc"},"Pre-release versions"),c.createElement("table",{className:"versions"},c.createElement("tbody",null,c.createElement("tr",null,c.createElement("th",null,"master"),c.createElement("td",null,c.createElement(n.Z,{to:"docs/next/discover"},"Documentation")),c.createElement("td",null,c.createElement(n.Z,{to:e.customFields.repoUrl},"Source Code"))))),c.createElement("h3",{id:"archive"},"Past Versions"),c.createElement("p",null,"Here you can find previous versions of the documentation."),c.createElement("table",{className:"versions"},c.createElement("tbody",null,s.map((function(l){return l!==t&&c.createElement("tr",{key:l},c.createElement("th",null,l),c.createElement("td",null,c.createElement(n.Z,{to:"docs/"+l+"/discover"},"Documentation")),c.createElement("td",null,c.createElement(n.Z,{to:e.customFields.repoUrl+"/releases/tag/v"+(3===l.split(".").length?l:l+".0")},"Release Notes")))})))),c.createElement("p",null,"You can find past versions of this project on"," ",c.createElement(n.Z,{to:e.customFields.repoUrl},"GitHub"),".")))))}}}]); \ No newline at end of file diff --git a/assets/js/2411f77f.41e1ee0c.js b/assets/js/2411f77f.41e1ee0c.js new file mode 100644 index 0000000000..8443c8cec9 --- /dev/null +++ b/assets/js/2411f77f.41e1ee0c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[52076],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>h});var a=t(67294);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var s=a.createContext({}),p=function(e){var n=a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=p(e.components);return a.createElement(s.Provider,{value:n},e.children)},c={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},d=a.forwardRef((function(e,n){var t=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=p(t),h=i,m=d["".concat(s,".").concat(h)]||d[h]||c[h]||r;return t?a.createElement(m,o(o({ref:n},u),{},{components:t})):a.createElement(m,o({ref:n},u))}));function h(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var r=t.length,o=new Array(r);o[0]=d;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l.mdxType="string"==typeof e?e:i,o[1]=l;for(var p=2;p{t.r(n),t.d(n,{assets:()=>u,contentTitle:()=>s,default:()=>h,frontMatter:()=>l,metadata:()=>p,toc:()=>c});var a=t(83117),i=t(80102),r=(t(67294),t(3905)),o=["components"],l={id:"displaying-connection-status",title:"Displaying OpenEdX connection status in Richie",sidebar_label:"Displaying connection status"},s=void 0,p={unversionedId:"displaying-connection-status",id:"version-2.21.0/displaying-connection-status",title:"Displaying OpenEdX connection status in Richie",description:"This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status",source:"@site/versioned_docs/version-2.21.0/displaying-connection-status.md",sourceDirName:".",slug:"/displaying-connection-status",permalink:"/docs/2.21.0/displaying-connection-status",draft:!1,tags:[],version:"2.21.0",lastUpdatedBy:"jbpenrath",lastUpdatedAt:1679473023,formattedLastUpdatedAt:"Mar 22, 2023",frontMatter:{id:"displaying-connection-status",title:"Displaying OpenEdX connection status in Richie",sidebar_label:"Displaying connection status"}},u={},c=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Allow redirects",id:"allow-redirects",level:2},{value:"Configure authentication delegation",id:"configure-authentication-delegation",level:2},{value:"BASE_URL",id:"base_url",level:3},{value:"BACKEND",id:"backend",level:3},{value:"PROFILE_URLS",id:"profile_urls",level:3}],d={toc:c};function h(e){var n=e.components,t=(0,i.Z)(e,o);return(0,r.kt)("wrapper",(0,a.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status\nand display profile information for the logged-in user in Richie."),(0,r.kt)("p",null,"In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the\nsite, are editors and staff users. Your instructors and learners will not have user accounts on\nRichie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or\nyour own centralized identity management service."),(0,r.kt)("p",null,"In the following, we will explain how to use OpenEdX as your authentication delegation service."),(0,r.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,r.kt)("p",null,"Richie will need to make CORS requests to the OpenEdX instance. As a consequence, you need to\nactivate CORS requests on your OpenEdX instance:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python"},'FEATURES = {\n ...\n "ENABLE_CORS_HEADERS": True,\n}\n')),(0,r.kt)("p",null,"Then, make sure the following settings are set as follows on your OpenEdX instance:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python"},'CORS_ALLOW_CREDENTIALS = True\nCORS_ALLOW_INSECURE = False\nCORS_ORIGIN_ALLOW_ALL = False\nCORS_ORIGIN_WHITELIST: ["richie.example.com"] # The domain on which Richie is hosted\n')),(0,r.kt)("h2",{id:"allow-redirects"},"Allow redirects"),(0,r.kt)("p",null,"When Richie sends the user to the OpenEdX instance for authentication, and wants OpenEdX to\nredirect the user back to Richie after a successful login or signup, it prefixes the path with\n",(0,r.kt)("inlineCode",{parentName:"p"},"/richie"),". Adding the following rule to your Nginx server (or equivalent) and replacing the\nrichie host by yours will allow this redirect to follow through to your Richie instance:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"rewrite ^/richie/(.*)$ https://richie.example.com/$1 permanent;\n")),(0,r.kt)("h2",{id:"configure-authentication-delegation"},"Configure authentication delegation"),(0,r.kt)("p",null,"Now, on your Richie instance, you need to configure the service to which Richie will delegate\nauthentication using the ",(0,r.kt)("inlineCode",{parentName:"p"},"RICHIE_AUTHENTICATION_DELEGATION")," setting:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python"},'RICHIE_AUTHENTICATION_DELEGATION = {\n "BASE_URL": "https://lms.example.com",\n "BACKEND": "openedx-hawthorn",\n "PROFILE_URLS": {\n "dashboard": {\n "label": _("Dashboard"),\n "href": "{base_url:s}/dashboard",\n },\n },\n}\n')),(0,r.kt)("p",null,"The following should help you understand how to configure this setting:"),(0,r.kt)("h3",{id:"base_url"},"BASE_URL"),(0,r.kt)("p",null,"The base url on which the OpenEdX instance is hosted. This is used to construct the complete url\nof the login/signup pages to which the frontend application will send the user for authentication."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Type: string"),(0,r.kt)("li",{parentName:"ul"},"Required: Yes"),(0,r.kt)("li",{parentName:"ul"},"Value: for example ",(0,r.kt)("a",{parentName:"li",href:"https://lms.example.com"},"https://lms.example.com"))),(0,r.kt)("h3",{id:"backend"},"BACKEND"),(0,r.kt)("p",null,"The name of the ReactJS backend to use for the targeted LMS."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Type: string"),(0,r.kt)("li",{parentName:"ul"},"Required: Yes"),(0,r.kt)("li",{parentName:"ul"},"Value: Richie ships with the following Javascript backends:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"openedx-dogwood"),": backend for OpenEdX versions equal to ",(0,r.kt)("inlineCode",{parentName:"li"},"dogwood")," or ",(0,r.kt)("inlineCode",{parentName:"li"},"eucalyptus")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"openedx-hawthorn"),": backend for OpenEdX versions equal to ",(0,r.kt)("inlineCode",{parentName:"li"},"hawthorn")," or higher"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"openedx-fonzie"),": backend for OpenEdX via ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/openfun/fonzie"},"Fonzie"),"\n(extra user info and JWT tokens)"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"base"),": fake backend for development purposes")))),(0,r.kt)("h3",{id:"profile_urls"},"PROFILE_URLS"),(0,r.kt)("p",null,"Mapping definition of custom links presented to the logged-in user as a dropdown menu when he/she\nclicks on his/her username in Richie's page header."),(0,r.kt)("p",null,"Links order will be respected to build the dropdown menu."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Type: dictionary")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Required: No")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Value: For example, to emulate the links proposed in OpenEdX, you can configure this setting\nas follows:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-python"},' {\n "dashboard": {\n "label": _("Dashboard"),\n "href": "{base_url:s}/dashboard",\n },\n "profile": {\n "label": _("Profile"),\n "href": "{base_url:s}/u/(username)",\n },\n "account": {\n "label": _("Account"),\n "href": "{base_url:s}/account/settings",\n }\n }\n')),(0,r.kt)("p",{parentName:"li"}," The ",(0,r.kt)("inlineCode",{parentName:"p"},"base_url")," variable is used as a Python format parameter and will be replaced by the value\nset for the above authentication delegation ",(0,r.kt)("inlineCode",{parentName:"p"},"BASE_URL")," setting."),(0,r.kt)("p",{parentName:"li"}," If you need to bind user data into a url, wrap the property between brackets. For example, the\nlink configured above for the profile page ",(0,r.kt)("inlineCode",{parentName:"p"},"{base_url:s}/u/(username)")," would point to\n",(0,r.kt)("inlineCode",{parentName:"p"},"https://lms.example.com/u/johndoe")," for a user carrying the username ",(0,r.kt)("inlineCode",{parentName:"p"},"johndoe"),"."))))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2411f77f.97a76d0d.js b/assets/js/2411f77f.97a76d0d.js deleted file mode 100644 index faaf58bd3f..0000000000 --- a/assets/js/2411f77f.97a76d0d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[52076],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>h});var a=t(67294);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var s=a.createContext({}),p=function(e){var n=a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=p(e.components);return a.createElement(s.Provider,{value:n},e.children)},c={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},d=a.forwardRef((function(e,n){var t=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=p(t),h=i,m=d["".concat(s,".").concat(h)]||d[h]||c[h]||r;return t?a.createElement(m,o(o({ref:n},u),{},{components:t})):a.createElement(m,o({ref:n},u))}));function h(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var r=t.length,o=new Array(r);o[0]=d;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l.mdxType="string"==typeof e?e:i,o[1]=l;for(var p=2;p{t.r(n),t.d(n,{assets:()=>u,contentTitle:()=>s,default:()=>h,frontMatter:()=>l,metadata:()=>p,toc:()=>c});var a=t(83117),i=t(80102),r=(t(67294),t(3905)),o=["components"],l={id:"displaying-connection-status",title:"Displaying OpenEdX connection status in Richie",sidebar_label:"Displaying connection status"},s=void 0,p={unversionedId:"displaying-connection-status",id:"version-2.21.0/displaying-connection-status",title:"Displaying OpenEdX connection status in Richie",description:"This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status",source:"@site/versioned_docs/version-2.21.0/displaying-connection-status.md",sourceDirName:".",slug:"/displaying-connection-status",permalink:"/docs/displaying-connection-status",draft:!1,tags:[],version:"2.21.0",lastUpdatedBy:"jbpenrath",lastUpdatedAt:1679473023,formattedLastUpdatedAt:"Mar 22, 2023",frontMatter:{id:"displaying-connection-status",title:"Displaying OpenEdX connection status in Richie",sidebar_label:"Displaying connection status"}},u={},c=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Allow redirects",id:"allow-redirects",level:2},{value:"Configure authentication delegation",id:"configure-authentication-delegation",level:2},{value:"BASE_URL",id:"base_url",level:3},{value:"BACKEND",id:"backend",level:3},{value:"PROFILE_URLS",id:"profile_urls",level:3}],d={toc:c};function h(e){var n=e.components,t=(0,i.Z)(e,o);return(0,r.kt)("wrapper",(0,a.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status\nand display profile information for the logged-in user in Richie."),(0,r.kt)("p",null,"In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the\nsite, are editors and staff users. Your instructors and learners will not have user accounts on\nRichie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or\nyour own centralized identity management service."),(0,r.kt)("p",null,"In the following, we will explain how to use OpenEdX as your authentication delegation service."),(0,r.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,r.kt)("p",null,"Richie will need to make CORS requests to the OpenEdX instance. As a consequence, you need to\nactivate CORS requests on your OpenEdX instance:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python"},'FEATURES = {\n ...\n "ENABLE_CORS_HEADERS": True,\n}\n')),(0,r.kt)("p",null,"Then, make sure the following settings are set as follows on your OpenEdX instance:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python"},'CORS_ALLOW_CREDENTIALS = True\nCORS_ALLOW_INSECURE = False\nCORS_ORIGIN_ALLOW_ALL = False\nCORS_ORIGIN_WHITELIST: ["richie.example.com"] # The domain on which Richie is hosted\n')),(0,r.kt)("h2",{id:"allow-redirects"},"Allow redirects"),(0,r.kt)("p",null,"When Richie sends the user to the OpenEdX instance for authentication, and wants OpenEdX to\nredirect the user back to Richie after a successful login or signup, it prefixes the path with\n",(0,r.kt)("inlineCode",{parentName:"p"},"/richie"),". Adding the following rule to your Nginx server (or equivalent) and replacing the\nrichie host by yours will allow this redirect to follow through to your Richie instance:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"rewrite ^/richie/(.*)$ https://richie.example.com/$1 permanent;\n")),(0,r.kt)("h2",{id:"configure-authentication-delegation"},"Configure authentication delegation"),(0,r.kt)("p",null,"Now, on your Richie instance, you need to configure the service to which Richie will delegate\nauthentication using the ",(0,r.kt)("inlineCode",{parentName:"p"},"RICHIE_AUTHENTICATION_DELEGATION")," setting:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python"},'RICHIE_AUTHENTICATION_DELEGATION = {\n "BASE_URL": "https://lms.example.com",\n "BACKEND": "openedx-hawthorn",\n "PROFILE_URLS": {\n "dashboard": {\n "label": _("Dashboard"),\n "href": "{base_url:s}/dashboard",\n },\n },\n}\n')),(0,r.kt)("p",null,"The following should help you understand how to configure this setting:"),(0,r.kt)("h3",{id:"base_url"},"BASE_URL"),(0,r.kt)("p",null,"The base url on which the OpenEdX instance is hosted. This is used to construct the complete url\nof the login/signup pages to which the frontend application will send the user for authentication."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Type: string"),(0,r.kt)("li",{parentName:"ul"},"Required: Yes"),(0,r.kt)("li",{parentName:"ul"},"Value: for example ",(0,r.kt)("a",{parentName:"li",href:"https://lms.example.com"},"https://lms.example.com"))),(0,r.kt)("h3",{id:"backend"},"BACKEND"),(0,r.kt)("p",null,"The name of the ReactJS backend to use for the targeted LMS."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Type: string"),(0,r.kt)("li",{parentName:"ul"},"Required: Yes"),(0,r.kt)("li",{parentName:"ul"},"Value: Richie ships with the following Javascript backends:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"openedx-dogwood"),": backend for OpenEdX versions equal to ",(0,r.kt)("inlineCode",{parentName:"li"},"dogwood")," or ",(0,r.kt)("inlineCode",{parentName:"li"},"eucalyptus")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"openedx-hawthorn"),": backend for OpenEdX versions equal to ",(0,r.kt)("inlineCode",{parentName:"li"},"hawthorn")," or higher"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"openedx-fonzie"),": backend for OpenEdX via ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/openfun/fonzie"},"Fonzie"),"\n(extra user info and JWT tokens)"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"base"),": fake backend for development purposes")))),(0,r.kt)("h3",{id:"profile_urls"},"PROFILE_URLS"),(0,r.kt)("p",null,"Mapping definition of custom links presented to the logged-in user as a dropdown menu when he/she\nclicks on his/her username in Richie's page header."),(0,r.kt)("p",null,"Links order will be respected to build the dropdown menu."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Type: dictionary")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Required: No")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Value: For example, to emulate the links proposed in OpenEdX, you can configure this setting\nas follows:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-python"},' {\n "dashboard": {\n "label": _("Dashboard"),\n "href": "{base_url:s}/dashboard",\n },\n "profile": {\n "label": _("Profile"),\n "href": "{base_url:s}/u/(username)",\n },\n "account": {\n "label": _("Account"),\n "href": "{base_url:s}/account/settings",\n }\n }\n')),(0,r.kt)("p",{parentName:"li"}," The ",(0,r.kt)("inlineCode",{parentName:"p"},"base_url")," variable is used as a Python format parameter and will be replaced by the value\nset for the above authentication delegation ",(0,r.kt)("inlineCode",{parentName:"p"},"BASE_URL")," setting."),(0,r.kt)("p",{parentName:"li"}," If you need to bind user data into a url, wrap the property between brackets. For example, the\nlink configured above for the profile page ",(0,r.kt)("inlineCode",{parentName:"p"},"{base_url:s}/u/(username)")," would point to\n",(0,r.kt)("inlineCode",{parentName:"p"},"https://lms.example.com/u/johndoe")," for a user carrying the username ",(0,r.kt)("inlineCode",{parentName:"p"},"johndoe"),"."))))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/26e576cc.6a8ab89b.js b/assets/js/26e576cc.6a8ab89b.js new file mode 100644 index 0000000000..82b8a497d3 --- /dev/null +++ b/assets/js/26e576cc.6a8ab89b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[40043],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>h});var a=n(67294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=p(n),h=r,m=u["".concat(s,".").concat(h)]||u[h]||d[h]||o;return n?a.createElement(m,i(i({ref:t},c),{},{components:n})):a.createElement(m,i({ref:t},c))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:r,i[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>h,frontMatter:()=>l,metadata:()=>p,toc:()=>d});var a=n(83117),r=n(80102),o=(n(67294),n(3905)),i=["components"],l={id:"django-react-interop",title:"Connecting React components with Django",sidebar_label:"Django & React"},s=void 0,p={unversionedId:"django-react-interop",id:"version-2.21.1/django-react-interop",title:"Connecting React components with Django",description:"richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.",source:"@site/versioned_docs/version-2.21.1/django-react-interop.md",sourceDirName:".",slug:"/django-react-interop",permalink:"/docs/django-react-interop",draft:!1,tags:[],version:"2.21.1",lastUpdatedBy:"jbpenrath",lastUpdatedAt:1680624606,formattedLastUpdatedAt:"Apr 4, 2023",frontMatter:{id:"django-react-interop",title:"Connecting React components with Django",sidebar_label:"Django & React"},sidebar:"docs",previous:{title:"Search filters customization",permalink:"/docs/filters-customization"},next:{title:"Building the frontend",permalink:"/docs/building-the-frontend"}},c={},d=[{value:"Rendering components",id:"rendering-components",level:2},{value:"Example",id:"example",level:3},{value:"Passing properties to components",id:"passing-properties-to-components",level:2},{value:"Example",id:"example-1",level:3},{value:"Built-in components",id:"built-in-components",level:2},{value:"<RootSearchSuggestField />",id:"rootsearchsuggestfield-",level:3},{value:"<Search />",id:"search-",level:3},{value:"<SearchSuggestField />",id:"searchsuggestfield-",level:3},{value:"<UserLogin />",id:"userlogin-",level:3},{value:"Context",id:"context",level:2}],u={toc:d};function h(e){var t=e.components,n=(0,r.Z)(e,i);return(0,o.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"richie")," is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages."),(0,o.kt)("h2",{id:"rendering-components"},"Rendering components"),(0,o.kt)("p",null,"We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there."),(0,o.kt)("p",null,"We decided to use a specific CSS class name along with its modifiers. We reserve the ",(0,o.kt)("inlineCode",{parentName:"p"},"richie-react")," class and its modified children for this purpose."),(0,o.kt)("p",null,"Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the ",(0,o.kt)("inlineCode",{parentName:"p"},"lang")," attribute of the ",(0,o.kt)("inlineCode",{parentName:"p"},"")," element, which is a requirement to have an accessible page anyway."),(0,o.kt)("p",null,"They use the BCP47/RFC5646 format."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'\n')),(0,o.kt)("h3",{id:"example"},"Example"),(0,o.kt)("p",null,"Here is how we would call a ",(0,o.kt)("inlineCode",{parentName:"p"},"")," component from a template, a plugin or a snippet:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'\n')),(0,o.kt)("p",null,"When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element."),(0,o.kt)("h2",{id:"passing-properties-to-components"},"Passing properties to components"),(0,o.kt)("p",null,'Some of Richie\'s React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.'),(0,o.kt)("p",null,"Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM."),(0,o.kt)("p",null,"We can add a ",(0,o.kt)("inlineCode",{parentName:"p"},"data-props")," attribute on the element with the ",(0,o.kt)("inlineCode",{parentName:"p"},"richie-react")," class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a ",(0,o.kt)("inlineCode",{parentName:"p"},"propName={propValue}")," to the React component."),(0,o.kt)("h3",{id:"example-1"},"Example"),(0,o.kt)("p",null,"Here is how we would pass a ",(0,o.kt)("inlineCode",{parentName:"p"},'categories={[ "sociology", "anthropology" ]}')," prop to our ",(0,o.kt)("inlineCode",{parentName:"p"},"")," component:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'\n')),(0,o.kt)("p",null,"When the component is rendered, it will be passed a ",(0,o.kt)("inlineCode",{parentName:"p"},"categories")," prop with the relevant categories."),(0,o.kt)("h2",{id:"built-in-components"},"Built-in components"),(0,o.kt)("p",null,"Here are the React component that Richie comes with and uses out of the box."),(0,o.kt)("h3",{id:"rootsearchsuggestfield-"},"<","RootSearchSuggestField /",">"),(0,o.kt)("p",null,"Renders a course search bar, like the one that appears in the default ",(0,o.kt)("inlineCode",{parentName:"p"},"Search")," page."),(0,o.kt)("p",null,"Interactions will send the user to the ",(0,o.kt)("inlineCode",{parentName:"p"},"courseSearchPageUrl")," url passed in the props, including the selected filter and/or search terms."),(0,o.kt)("p",null,"It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results."),(0,o.kt)("p",null,"Props:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"courseSearchPageUrl")," ","[required]"," \u2014 URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"context")," ","[required]"," \u2014 see ",(0,o.kt)("a",{parentName:"li",href:"#context"},"context"),".")),(0,o.kt)("h3",{id:"search-"},"<","Search /",">"),(0,o.kt)("p",null,"Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with ",(0,o.kt)("inlineCode",{parentName:"p"},""),") nor the page title."),(0,o.kt)("p",null,"NB: the ",(0,o.kt)("inlineCode",{parentName:"p"},"Search")," Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake."),(0,o.kt)("p",null,"Props:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"context")," ","[required]"," \u2014 see ",(0,o.kt)("a",{parentName:"li",href:"#context"},"context"),".")),(0,o.kt)("h3",{id:"searchsuggestfield-"},"<","SearchSuggestField /",">"),(0,o.kt)("p",null,"Renders the course search bar that interacts directly with ",(0,o.kt)("inlineCode",{parentName:"p"},""),"."),(0,o.kt)("p",null,"It automatically communicates with ",(0,o.kt)("inlineCode",{parentName:"p"},"")," through browser history APIs and a shared React provider. This one, unlike ",(0,o.kt)("inlineCode",{parentName:"p"},""),", is meant to be used in combination with ",(0,o.kt)("inlineCode",{parentName:"p"},"")," (on the same page)."),(0,o.kt)("p",null,"Props:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"context")," ","[required]"," \u2014 see ",(0,o.kt)("a",{parentName:"li",href:"#context"},"context"),".")),(0,o.kt)("h3",{id:"userlogin-"},"<","UserLogin /",">"),(0,o.kt)("p",null,"Renders a component that uses the ",(0,o.kt)("inlineCode",{parentName:"p"},"/users/whoami")," endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button."),(0,o.kt)("p",null,"Props:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"loginUrl")," ","[required]",' \u2014 the URL where the user is sent when they click on "Log in";'),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"logoutUrl")," ","[required]"," \u2014 a link that logs the user out and redirects them (can be the standard django logout URL);"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"signupUrl")," ","[required]",' \u2014 the URL where the user is sent when they click on "Sign up".')),(0,o.kt)("h2",{id:"context"},"Context"),(0,o.kt)("p",null,"All built-in components for Richie accept a ",(0,o.kt)("inlineCode",{parentName:"p"},"context")," prop, that may be required or optional, depending on the component."),(0,o.kt)("p",null,"It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie."),(0,o.kt)("p",null,"Here is the expected shape for this object:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'{\n assets: {\n // SVG sprite used throughout Richie\n icons: "/path/to/icons/sprite.svg"\n }\n}\n')),(0,o.kt)("p",null,"Note that it might be expanded in further versions of Richie."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2bd76b34.8eea0d83.js b/assets/js/2bd76b34.8eea0d83.js new file mode 100644 index 0000000000..2974944ba8 --- /dev/null +++ b/assets/js/2bd76b34.8eea0d83.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[68572],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var r=n(67294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),s=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=s(e.components);return r.createElement(c.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),h=a,f=p["".concat(c,".").concat(h)]||p[h]||d[h]||o;return n?r.createElement(f,i(i({ref:t},u),{},{components:n})):r.createElement(f,i({ref:t},u))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=p;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l.mdxType="string"==typeof e?e:a,i[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>c,default:()=>h,frontMatter:()=>l,metadata:()=>s,toc:()=>d});var r=n(83117),a=n(80102),o=(n(67294),n(3905)),i=["components"],l={id:"internationalization",title:"Internationalization",sidebar_label:"I18n"},c=void 0,s={unversionedId:"internationalization",id:"version-2.21.1/internationalization",title:"Internationalization",description:"richie has built-in localization and internationalization:",source:"@site/versioned_docs/version-2.21.1/internationalization.md",sourceDirName:".",slug:"/internationalization",permalink:"/docs/internationalization",draft:!1,tags:[],version:"2.21.1",lastUpdatedBy:"jbpenrath",lastUpdatedAt:1680624606,formattedLastUpdatedAt:"Apr 4, 2023",frontMatter:{id:"internationalization",title:"Internationalization",sidebar_label:"I18n"},sidebar:"docs",previous:{title:"Frontend overrides",permalink:"/docs/frontend-overrides"},next:{title:"LMS connection",permalink:"/docs/lms-connection"}},u={},d=[{value:"Contributing as a translator or proof-reader",id:"contributing-as-a-translator-or-proof-reader",level:2},{value:"Sign-up on Crowdin",id:"sign-up-on-crowdin",level:3},{value:"Join the Richie project",id:"join-the-richie-project",level:3},{value:"Add a new language",id:"add-a-new-language",level:3}],p={toc:d};function h(e){var t=e.components,l=(0,a.Z)(e,i);return(0,o.kt)("wrapper",(0,r.Z)({},p,l,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"richie")," has built-in localization and internationalization:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,"),(0,o.kt)("li",{parentName:"ul"},"On the frontend, we use React Intl.")),(0,o.kt)("h2",{id:"contributing-as-a-translator-or-proof-reader"},"Contributing as a translator or proof-reader"),(0,o.kt)("p",null,"We use the ",(0,o.kt)("a",{parentName:"p",href:"https://crowdin.com"},"Crowdin")," web platform to translate Richie to different languages.\nAll translations are hosted at ",(0,o.kt)("a",{parentName:"p",href:"https://i18n.richie.education"},"https://i18n.richie.education"),", which allows translators and\nproof-readers to contribute on translations in the languages they master."),(0,o.kt)("h3",{id:"sign-up-on-crowdin"},"Sign-up on Crowdin"),(0,o.kt)("p",null,"If you don't have an account on Crowdin already, go to ",(0,o.kt)("a",{parentName:"p",href:"https://accounts.crowdin.com/register"},"https://accounts.crowdin.com/register")," and\nfill out the form to create a free account."),(0,o.kt)("h3",{id:"join-the-richie-project"},"Join the Richie project"),(0,o.kt)("p",null,"Now that you have an account on Crowdin,\n",(0,o.kt)("a",{parentName:"p",href:"https://crowdin.com/project/richie"},'look for the project called "Richie"'),', select the language\non which you wish to contribute and click the "Join" button as demonstrated below:'),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"How to join Richie on Crowdin",src:n(50792).Z,width:"2462",height:"1506"})),(0,o.kt)("p",null,"We will then review you application and you should soon start translating strings!"),(0,o.kt)("p",null,"For more information on how Crowdin works, you can refer to\n",(0,o.kt)("a",{parentName:"p",href:"https://support.crowdin.com"},"their documentation"),"."),(0,o.kt)("h3",{id:"add-a-new-language"},"Add a new language"),(0,o.kt)("p",null,'If Richie is not yet translated in the language you want, let us know by clicking the "contact"\nlink on ',(0,o.kt)("a",{parentName:"p",href:"https://i18n.richie.education"},"Richie's Crowdin profile page")," and we will consider adding\nit."),(0,o.kt)("p",null,"If you request a new language, the Richie community will expect you to keep this language\nup-to-date each time strings are modified or new strings are added, and this before each\nrelease."),(0,o.kt)("p",null,"Before asking for a new language, make sure it does not already exist. If your language already\nexists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider\ncontributing on the existing language if your resources to contribute are limited."))}h.isMDXComponent=!0},50792:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/crowdin-join-richie-fd505b1a132bafb2bdafc715649a7c0f.gif"}}]); \ No newline at end of file diff --git a/assets/js/2cb39df3.4fc5ddb5.js b/assets/js/2cb39df3.4fc5ddb5.js new file mode 100644 index 0000000000..2f09ef5b4f --- /dev/null +++ b/assets/js/2cb39df3.4fc5ddb5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[27815],{3905:(e,n,t)=>{t.d(n,{Zo:()=>d,kt:()=>m});var o=t(67294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,o)}return t}function a(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=o.createContext({}),p=function(e){var n=o.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):a(a({},n),e)),t},d=function(e){var n=p(e.components);return o.createElement(s.Provider,{value:n},e.children)},c={inlineCode:"code",wrapper:function(e){var n=e.children;return o.createElement(o.Fragment,{},n)}},u=o.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),u=p(t),m=r,h=u["".concat(s,".").concat(m)]||u[m]||c[m]||i;return t?o.createElement(h,a(a({ref:n},d),{},{components:t})):o.createElement(h,a({ref:n},d))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,a=new Array(i);a[0]=u;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l.mdxType="string"==typeof e?e:r,a[1]=l;for(var p=2;p{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>s,default:()=>m,frontMatter:()=>l,metadata:()=>p,toc:()=>c});var o=t(83117),r=t(80102),i=(t(67294),t(3905)),a=["components"],l={id:"frontend-overrides",title:"Overriding frontend components",sidebar_label:"Frontend overrides"},s=void 0,p={unversionedId:"frontend-overrides",id:"version-2.21.0/frontend-overrides",title:"Overriding frontend components",description:"Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.",source:"@site/versioned_docs/version-2.21.0/frontend-overrides.md",sourceDirName:".",slug:"/frontend-overrides",permalink:"/docs/2.21.0/frontend-overrides",draft:!1,tags:[],version:"2.21.0",lastUpdatedBy:"jbpenrath",lastUpdatedAt:1679473023,formattedLastUpdatedAt:"Mar 22, 2023",frontMatter:{id:"frontend-overrides",title:"Overriding frontend components",sidebar_label:"Frontend overrides"},sidebar:"docs",previous:{title:"Building the frontend",permalink:"/docs/2.21.0/building-the-frontend"},next:{title:"I18n",permalink:"/docs/2.21.0/internationalization"}},d={},c=[{value:"Defining your overrides",id:"defining-your-overrides",level:2},{value:"Building a component override",id:"building-a-component-override",level:2},{value:"Override translation",id:"override-translation",level:2},{value:"Create new translation keys",id:"create-new-translation-keys",level:3},{value:"Override an existing translation key",id:"override-an-existing-translation-key",level:3}],u={toc:c};function m(e){var n=e.components,t=(0,r.Z)(e,a);return(0,i.kt)("wrapper",(0,o.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself."),(0,i.kt)("p",null,"This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs."),(0,i.kt)("h2",{id:"defining-your-overrides"},"Defining your overrides"),(0,i.kt)("p",null,"Create a ",(0,i.kt)("inlineCode",{parentName:"p"},"json")," settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build."),(0,i.kt)("p",null,"Currently, it is only possible to override components. Richie's build is only set up to handle them."),(0,i.kt)("p",null,"Inside, create an object with only one key: ",(0,i.kt)("inlineCode",{parentName:"p"},'"overrides"'),". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "overrides": {\n "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"\n }\n}\n')),(0,i.kt)("h2",{id:"building-a-component-override"},"Building a component override"),(0,i.kt)("p",null,"As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API."),(0,i.kt)("p",null,"For example, if our component to override was the following:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-tsx"},"export interface CourseGlimpseProps {\n course: Course;\n context: { someProp: string };\n}\n\nexport const CourseGlimpse: React.FC = ({ course, context }) => {\n // Whatever happens in this component\n return

The glimpse

;\n};\n")),(0,i.kt)("p",null,"Then, your override needs to provide the same exports, explicitly a named ",(0,i.kt)("inlineCode",{parentName:"p"},"CourseGlimpseProps")," interface and a named ",(0,i.kt)("inlineCode",{parentName:"p"},"CourseGlimpse")," component."),(0,i.kt)("p",null,"You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component."),(0,i.kt)("p",null,"For example returning ",(0,i.kt)("inlineCode",{parentName:"p"},"null")," might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component."),(0,i.kt)("h2",{id:"override-translation"},"Override translation"),(0,i.kt)("p",null,"When you create an application based on richie, you can encounter two cases about translations:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"You created or overrode a react component and created new translation keys"),(0,i.kt)("li",{parentName:"ol"},"You just want to override a translation in an existing richie component")),(0,i.kt)("h3",{id:"create-new-translation-keys"},"Create new translation keys"),(0,i.kt)("p",null,"Once you created your new component with its translation keys, you have to extract them with the following command:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"}," formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin\n")),(0,i.kt)("p",null,"This command extracts all translations defined in your typescript files then generates a ",(0,i.kt)("inlineCode",{parentName:"p"},"frontend.json")," file in ",(0,i.kt)("inlineCode",{parentName:"p"},"i18n/")," directory. This file is like a pot file, this is the base to create your translations in any language you want."),(0,i.kt)("p",null,"As ",(0,i.kt)("inlineCode",{parentName:"p"},"--format")," option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the ",(0,i.kt)("a",{parentName:"p",href:"https://formatjs.io/docs/tooling/cli/"},"formatjs/cli documentation"),"."),(0,i.kt)("p",null,"Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for ",(0,i.kt)("inlineCode",{parentName:"p"},"react-intl"),". Below, here is an example of a compilation command:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"}," node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json\n")),(0,i.kt)("p",null,"This command looks for all translation files in ",(0,i.kt)("inlineCode",{parentName:"p"},"i18n/locales")," directory then merges files found with richie translation files. You can pass several path patterns. You can also use an ",(0,i.kt)("inlineCode",{parentName:"p"},"--ignore")," argument to ignore a particular path."),(0,i.kt)("h3",{id:"override-an-existing-translation-key"},"Override an existing translation key"),(0,i.kt)("p",null,"As explain above, the compilation process aggregates translations files then ",(0,i.kt)("strong",{parentName:"p"},"merges them according their filename"),". That means if you want override for example the english translation, you just have to create a ",(0,i.kt)("inlineCode",{parentName:"p"},"en-US.json")," file and redefine translation keys used by Richie."),(0,i.kt)("p",null,"Richie uses one file per language. Currently 4 languages supported:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"English: filename is ",(0,i.kt)("inlineCode",{parentName:"li"},"en-US.json")),(0,i.kt)("li",{parentName:"ul"},"French: filename is ",(0,i.kt)("inlineCode",{parentName:"li"},"fr-FR.json")),(0,i.kt)("li",{parentName:"ul"},"Canadian french: filename is ",(0,i.kt)("inlineCode",{parentName:"li"},"fr-CA.json")),(0,i.kt)("li",{parentName:"ul"},"Spanish: filename is ",(0,i.kt)("inlineCode",{parentName:"li"},"es-ES.json"))),(0,i.kt)("p",null,"For example, richie uses the translation key ",(0,i.kt)("inlineCode",{parentName:"p"},"components.UserLogin.logIn")," for the Log in button. If you want to change this label for the english translation, you just have to create a translation file ",(0,i.kt)("inlineCode",{parentName:"p"},"en-US.json")," which redefines this translation key:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "components.UserLogin.logIn": {\n "description": "Overriden text for the login button.",\n "message": "Authentication"\n },\n}\n')),(0,i.kt)("p",null,"Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"}," node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json\n")),(0,i.kt)("p",null,'In this way, "',(0,i.kt)("em",{parentName:"p"},"Authentication"),'" will be displayed as label for login button instead of "',(0,i.kt)("em",{parentName:"p"},"Sign in"),'".'))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2cb39df3.66b07728.js b/assets/js/2cb39df3.66b07728.js deleted file mode 100644 index 1b7c5cfb69..0000000000 --- a/assets/js/2cb39df3.66b07728.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[27815],{3905:(e,n,t)=>{t.d(n,{Zo:()=>d,kt:()=>m});var o=t(67294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,o)}return t}function a(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=o.createContext({}),p=function(e){var n=o.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):a(a({},n),e)),t},d=function(e){var n=p(e.components);return o.createElement(s.Provider,{value:n},e.children)},c={inlineCode:"code",wrapper:function(e){var n=e.children;return o.createElement(o.Fragment,{},n)}},u=o.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),u=p(t),m=r,h=u["".concat(s,".").concat(m)]||u[m]||c[m]||i;return t?o.createElement(h,a(a({ref:n},d),{},{components:t})):o.createElement(h,a({ref:n},d))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,a=new Array(i);a[0]=u;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l.mdxType="string"==typeof e?e:r,a[1]=l;for(var p=2;p{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>s,default:()=>m,frontMatter:()=>l,metadata:()=>p,toc:()=>c});var o=t(83117),r=t(80102),i=(t(67294),t(3905)),a=["components"],l={id:"frontend-overrides",title:"Overriding frontend components",sidebar_label:"Frontend overrides"},s=void 0,p={unversionedId:"frontend-overrides",id:"version-2.21.0/frontend-overrides",title:"Overriding frontend components",description:"Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.",source:"@site/versioned_docs/version-2.21.0/frontend-overrides.md",sourceDirName:".",slug:"/frontend-overrides",permalink:"/docs/frontend-overrides",draft:!1,tags:[],version:"2.21.0",lastUpdatedBy:"jbpenrath",lastUpdatedAt:1679473023,formattedLastUpdatedAt:"Mar 22, 2023",frontMatter:{id:"frontend-overrides",title:"Overriding frontend components",sidebar_label:"Frontend overrides"},sidebar:"docs",previous:{title:"Building the frontend",permalink:"/docs/building-the-frontend"},next:{title:"I18n",permalink:"/docs/internationalization"}},d={},c=[{value:"Defining your overrides",id:"defining-your-overrides",level:2},{value:"Building a component override",id:"building-a-component-override",level:2},{value:"Override translation",id:"override-translation",level:2},{value:"Create new translation keys",id:"create-new-translation-keys",level:3},{value:"Override an existing translation key",id:"override-an-existing-translation-key",level:3}],u={toc:c};function m(e){var n=e.components,t=(0,r.Z)(e,a);return(0,i.kt)("wrapper",(0,o.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself."),(0,i.kt)("p",null,"This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs."),(0,i.kt)("h2",{id:"defining-your-overrides"},"Defining your overrides"),(0,i.kt)("p",null,"Create a ",(0,i.kt)("inlineCode",{parentName:"p"},"json")," settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build."),(0,i.kt)("p",null,"Currently, it is only possible to override components. Richie's build is only set up to handle them."),(0,i.kt)("p",null,"Inside, create an object with only one key: ",(0,i.kt)("inlineCode",{parentName:"p"},'"overrides"'),". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "overrides": {\n "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"\n }\n}\n')),(0,i.kt)("h2",{id:"building-a-component-override"},"Building a component override"),(0,i.kt)("p",null,"As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API."),(0,i.kt)("p",null,"For example, if our component to override was the following:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-tsx"},"export interface CourseGlimpseProps {\n course: Course;\n context: { someProp: string };\n}\n\nexport const CourseGlimpse: React.FC = ({ course, context }) => {\n // Whatever happens in this component\n return

The glimpse

;\n};\n")),(0,i.kt)("p",null,"Then, your override needs to provide the same exports, explicitly a named ",(0,i.kt)("inlineCode",{parentName:"p"},"CourseGlimpseProps")," interface and a named ",(0,i.kt)("inlineCode",{parentName:"p"},"CourseGlimpse")," component."),(0,i.kt)("p",null,"You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component."),(0,i.kt)("p",null,"For example returning ",(0,i.kt)("inlineCode",{parentName:"p"},"null")," might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component."),(0,i.kt)("h2",{id:"override-translation"},"Override translation"),(0,i.kt)("p",null,"When you create an application based on richie, you can encounter two cases about translations:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"You created or overrode a react component and created new translation keys"),(0,i.kt)("li",{parentName:"ol"},"You just want to override a translation in an existing richie component")),(0,i.kt)("h3",{id:"create-new-translation-keys"},"Create new translation keys"),(0,i.kt)("p",null,"Once you created your new component with its translation keys, you have to extract them with the following command:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"}," formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin\n")),(0,i.kt)("p",null,"This command extracts all translations defined in your typescript files then generates a ",(0,i.kt)("inlineCode",{parentName:"p"},"frontend.json")," file in ",(0,i.kt)("inlineCode",{parentName:"p"},"i18n/")," directory. This file is like a pot file, this is the base to create your translations in any language you want."),(0,i.kt)("p",null,"As ",(0,i.kt)("inlineCode",{parentName:"p"},"--format")," option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the ",(0,i.kt)("a",{parentName:"p",href:"https://formatjs.io/docs/tooling/cli/"},"formatjs/cli documentation"),"."),(0,i.kt)("p",null,"Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for ",(0,i.kt)("inlineCode",{parentName:"p"},"react-intl"),". Below, here is an example of a compilation command:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"}," node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json\n")),(0,i.kt)("p",null,"This command looks for all translation files in ",(0,i.kt)("inlineCode",{parentName:"p"},"i18n/locales")," directory then merges files found with richie translation files. You can pass several path patterns. You can also use an ",(0,i.kt)("inlineCode",{parentName:"p"},"--ignore")," argument to ignore a particular path."),(0,i.kt)("h3",{id:"override-an-existing-translation-key"},"Override an existing translation key"),(0,i.kt)("p",null,"As explain above, the compilation process aggregates translations files then ",(0,i.kt)("strong",{parentName:"p"},"merges them according their filename"),". That means if you want override for example the english translation, you just have to create a ",(0,i.kt)("inlineCode",{parentName:"p"},"en-US.json")," file and redefine translation keys used by Richie."),(0,i.kt)("p",null,"Richie uses one file per language. Currently 4 languages supported:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"English: filename is ",(0,i.kt)("inlineCode",{parentName:"li"},"en-US.json")),(0,i.kt)("li",{parentName:"ul"},"French: filename is ",(0,i.kt)("inlineCode",{parentName:"li"},"fr-FR.json")),(0,i.kt)("li",{parentName:"ul"},"Canadian french: filename is ",(0,i.kt)("inlineCode",{parentName:"li"},"fr-CA.json")),(0,i.kt)("li",{parentName:"ul"},"Spanish: filename is ",(0,i.kt)("inlineCode",{parentName:"li"},"es-ES.json"))),(0,i.kt)("p",null,"For example, richie uses the translation key ",(0,i.kt)("inlineCode",{parentName:"p"},"components.UserLogin.logIn")," for the Log in button. If you want to change this label for the english translation, you just have to create a translation file ",(0,i.kt)("inlineCode",{parentName:"p"},"en-US.json")," which redefines this translation key:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "components.UserLogin.logIn": {\n "description": "Overriden text for the login button.",\n "message": "Authentication"\n },\n}\n')),(0,i.kt)("p",null,"Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"}," node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json\n")),(0,i.kt)("p",null,'In this way, "',(0,i.kt)("em",{parentName:"p"},"Authentication"),'" will be displayed as label for login button instead of "',(0,i.kt)("em",{parentName:"p"},"Sign in"),'".'))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2fbb3042.6321f6cb.js b/assets/js/2fbb3042.6321f6cb.js new file mode 100644 index 0000000000..4f82123412 --- /dev/null +++ b/assets/js/2fbb3042.6321f6cb.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[46333],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var a=n(67294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),c=p(n),h=r,m=c["".concat(s,".").concat(h)]||c[h]||d[h]||l;return n?a.createElement(m,i(i({ref:t},u),{},{components:n})):a.createElement(m,i({ref:t},u))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,i=new Array(l);i[0]=c;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o.mdxType="string"==typeof e?e:r,i[1]=o;for(var p=2;p{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>s,default:()=>h,frontMatter:()=>o,metadata:()=>p,toc:()=>d});var a=n(83117),r=n(80102),l=(n(67294),n(3905)),i=["components"],o={id:"native-installation",title:"Installing Richie on your machine",sidebar_label:"Native installation"},s=void 0,p={unversionedId:"native-installation",id:"version-2.21.1/native-installation",title:"Installing Richie on your machine",description:"This document aims to list all needed steps to have a working Richie",source:"@site/versioned_docs/version-2.21.1/native-installation.md",sourceDirName:".",slug:"/native-installation",permalink:"/docs/native-installation",draft:!1,tags:[],version:"2.21.1",lastUpdatedBy:"jbpenrath",lastUpdatedAt:1680624606,formattedLastUpdatedAt:"Apr 4, 2023",frontMatter:{id:"native-installation",title:"Installing Richie on your machine",sidebar_label:"Native installation"},sidebar:"docs",previous:{title:"Docker development",permalink:"/docs/docker-development"},next:{title:"Contributing guide",permalink:"/docs/contributing-guide"}},u={},d=[{value:"Installing a fresh server",id:"installing-a-fresh-server",level:2},{value:"Version",id:"version",level:3},{value:"System update",id:"system-update",level:3},{value:"Database part",id:"database-part",level:2},{value:"Elasticsearch",id:"elasticsearch",level:2},{value:"Ubuntu",id:"ubuntu",level:3},{value:"OS X",id:"os-x",level:3},{value:"Application part",id:"application-part",level:2},{value:"Python and other requirements",id:"python-and-other-requirements",level:3},{value:"The virtualenv",id:"the-virtualenv",level:3},{value:"Frontend build",id:"frontend-build",level:3},{value:"Run server",id:"run-server",level:3}],c={toc:d};function h(e){var t=e.components,n=(0,r.Z)(e,i);return(0,l.kt)("wrapper",(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"This document aims to list all needed steps to have a working ",(0,l.kt)("inlineCode",{parentName:"p"},"Richie"),"\ninstallation on your laptop."),(0,l.kt)("p",null,"A better approach is to use ",(0,l.kt)("a",{parentName:"p",href:"https://docs.docker.com"},(0,l.kt)("inlineCode",{parentName:"a"},"Docker"))," as explained in\nour guide for ",(0,l.kt)("a",{parentName:"p",href:"/docs/installation"},"container-native installation")," instructions."),(0,l.kt)("h2",{id:"installing-a-fresh-server"},"Installing a fresh server"),(0,l.kt)("h3",{id:"version"},"Version"),(0,l.kt)("p",null,"You need a ",(0,l.kt)("inlineCode",{parentName:"p"},"Ubuntu 18.04 Bionic Beaver")," (the latest LTS version) fresh\ninstallation."),(0,l.kt)("p",null,"If you are using another operating system or distribution, you can use\n",(0,l.kt)("a",{parentName:"p",href:"https://docs.vagrantup.com/v2/getting-started/index.html"},(0,l.kt)("inlineCode",{parentName:"a"},"Vagrant"))," to get a\nrunning Ubuntu 18.04 server in seconds."),(0,l.kt)("h3",{id:"system-update"},"System update"),(0,l.kt)("p",null,"Be sure to have fresh packages on the server (kernel, libc, ssl patches...):\npost"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-sh"},"sudo apt-get -y update\nsudo apt-get -y dist-upgrade\n")),(0,l.kt)("h2",{id:"database-part"},"Database part"),(0,l.kt)("p",null,"You must first install ",(0,l.kt)("inlineCode",{parentName:"p"},"postgresql"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-sh"},"// On Linux\nsudo apt-get -y install postgresql\n\n// On OS X\nbrew install postgresql@10\nbrew services start postgresql@10\n// don't forget to add your new postgres install to the $PATH\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"Postgresql")," is now running."),(0,l.kt)("p",null,"Then you can create the database owner and the database itself, using the\n",(0,l.kt)("inlineCode",{parentName:"p"},"postgres")," user:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-sh"},"sudo -u postgres -i // skip this on OS X as the default install will use your local user\ncreateuser fun -sP\n")),(0,l.kt)("p",null,"Note: we created the user as a superuser. This should only be done in dev/test\nenvironments."),(0,l.kt)("p",null,"Now, create the database with this user:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-sh"},"createdb richie -O fun -W\nexit\n")),(0,l.kt)("h2",{id:"elasticsearch"},"Elasticsearch"),(0,l.kt)("h3",{id:"ubuntu"},"Ubuntu"),(0,l.kt)("p",null,"Download and install the Public Signing Key"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"$ wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -\n")),(0,l.kt)("p",null,"You may need to install the apt-transport-https package on Debian before\nproceeding:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"$ sudo apt-get install apt-transport-https\n")),(0,l.kt)("p",null,"Save the repository definition to /etc/apt/sources.list.d/elastic-6.3.1.list:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},'$ echo "deb https://artifacts.elastic.co/packages/6.3.1/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-6.3.1.list\n')),(0,l.kt)("p",null,"Update repository and install"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"$ sudo apt-get update\n$ sudo apt-get install elasticsearch\n$ sudo /etc/init.d/elasticsearch start\n")),(0,l.kt)("h3",{id:"os-x"},"OS X"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"$ brew install elasticsearch\n")),(0,l.kt)("h2",{id:"application-part"},"Application part"),(0,l.kt)("h3",{id:"python-and-other-requirements"},"Python and other requirements"),(0,l.kt)("p",null,"We use ",(0,l.kt)("inlineCode",{parentName:"p"},"Python 3.6")," which is the one installed by default in ",(0,l.kt)("inlineCode",{parentName:"p"},"Ubuntu 18.04"),"."),(0,l.kt)("p",null,"You can install it on OS X using the following commands. Make sure to always run\n",(0,l.kt)("inlineCode",{parentName:"p"},"python3")," instead of ",(0,l.kt)("inlineCode",{parentName:"p"},"python")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"pip3")," instead of ",(0,l.kt)("inlineCode",{parentName:"p"},"pip")," to ensure the correct\nversion of Python (your homebrew install of 3) is used."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"brew install python3\nbrew postinstall python3\n")),(0,l.kt)("h3",{id:"the-virtualenv"},"The virtualenv"),(0,l.kt)("p",null,"Place yourself in the application directory ",(0,l.kt)("inlineCode",{parentName:"p"},"app"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"cd app\n")),(0,l.kt)("p",null,"We choose to run our application in a virtual environment."),(0,l.kt)("p",null,"For this, we'll install ",(0,l.kt)("inlineCode",{parentName:"p"},"virtualenvwrapper")," and add an environment:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"pip install virtualenvwrapper\n")),(0,l.kt)("p",null,"You can open a new shell to activate the virtualenvwrapper commands, or simply\ndo:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"source $(which virtualenvwrapper.sh)\n")),(0,l.kt)("p",null,"Then create the virtual environment for ",(0,l.kt)("inlineCode",{parentName:"p"},"richie"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"mkvirtualenv richie --no-site-packages --python=python3\n")),(0,l.kt)("p",null,"The virtualenv should now be activated and you can install the Python\ndependencies for development:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"pip install -e .[dev]\n")),(0,l.kt)("p",null,'The "dev.txt" requirement file installs packages specific to a dev environment\nand should not be used in production.'),(0,l.kt)("h3",{id:"frontend-build"},"Frontend build"),(0,l.kt)("p",null,"This project is a hybrid that uses both Django generated pages and frontend JS\ncode. As such, it includes a frontend build process that comes in two parts: JS\n& CSS."),(0,l.kt)("p",null,"We need NPM to install the dependencies and run the build, which depends on a\nversion of Nodejs specified in ",(0,l.kt)("inlineCode",{parentName:"p"},".nvmrc"),". See ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/creationix/nvm"},"the\nrepo")," for instructions on how to install NVM.\nTo take advantage of ",(0,l.kt)("inlineCode",{parentName:"p"},".nvmrc"),", run this in the context of the repository:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"nvm install\nnvm use\n")),(0,l.kt)("p",null,"As a prerequisite to running the frontend build for either JS or CSS, you'll\nneed to ",(0,l.kt)("a",{parentName:"p",href:"https://yarnpkg.com/lang/en/docs/install/"},"install yarn")," and download\ndependencies ",(0,l.kt)("em",{parentName:"p"},"via"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"yarn install\n")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"JS build")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"npm run build\n")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"CSS build")),(0,l.kt)("p",null,"This will compile all our SCSS files into one bundle and put it in the static\nfolder we're serving."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"npm run sass\n")),(0,l.kt)("h3",{id:"run-server"},"Run server"),(0,l.kt)("p",null,"Make sure your database is up-to-date before running the application the first\ntime and after each modification to your models:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"python sandbox/manage.py migrate\n")),(0,l.kt)("p",null,"You can create a superuser account:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"python sandbox/manage.py createsuperuser\n")),(0,l.kt)("p",null,"Run the tests"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"python sandbox/manage.py test\n")),(0,l.kt)("p",null,"You should now be able to start Django and view the site at\n",(0,l.kt)("a",{parentName:"p",href:"http://localhost:8000"},"localhost:8000")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"python sandbox/manage.py runserver\n")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/349388c9.cd77554a.js b/assets/js/349388c9.cd77554a.js new file mode 100644 index 0000000000..93fad400b0 --- /dev/null +++ b/assets/js/349388c9.cd77554a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[86738],{43333:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"2.21.0","label":"2.21.0","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-2.21.0","isLast":false,"docsSidebars":{"docs":[{"type":"category","label":"Getting started","items":[{"type":"link","label":"Discover Richie","href":"/docs/2.21.0/discover","docId":"discover"},{"type":"link","label":"Start your own site","href":"/docs/2.21.0/cookiecutter","docId":"cookiecutter"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Recipes","items":[{"type":"link","label":"Search filters customization","href":"/docs/2.21.0/filters-customization","docId":"filters-customization"},{"type":"link","label":"Django & React","href":"/docs/2.21.0/django-react-interop","docId":"django-react-interop"},{"type":"link","label":"Building the frontend","href":"/docs/2.21.0/building-the-frontend","docId":"building-the-frontend"},{"type":"link","label":"Frontend overrides","href":"/docs/2.21.0/frontend-overrides","docId":"frontend-overrides"},{"type":"link","label":"I18n","href":"/docs/2.21.0/internationalization","docId":"internationalization"},{"type":"link","label":"LMS connection","href":"/docs/2.21.0/lms-connection","docId":"lms-connection"},{"type":"link","label":"Web Analytics","href":"/docs/2.21.0/web-analytics","docId":"web-analytics"}],"collapsed":true,"collapsible":true},{"type":"category","label":"Contributing","items":[{"type":"link","label":"Installation","href":"/docs/2.21.0/installation","docId":"installation"},{"type":"link","label":"Docker development","href":"/docs/2.21.0/docker-development","docId":"docker-development"},{"type":"link","label":"Native installation","href":"/docs/2.21.0/native-installation","docId":"native-installation"},{"type":"link","label":"Contributing guide","href":"/docs/2.21.0/contributing-guide","docId":"contributing-guide"},{"type":"link","label":"Accessibility testing","href":"/docs/2.21.0/accessibility-testing","docId":"accessibility-testing"},{"type":"link","label":"CSS Guidelines","href":"/docs/2.21.0/css-guidelines","docId":"css-guidelines"}],"collapsed":true,"collapsible":true}]},"docs":{"accessibility-testing":{"id":"accessibility-testing","title":"Automated accessibility checks","description":"Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.","sidebar":"docs"},"api/course-run-synchronization-api":{"id":"api/course-run-synchronization-api","title":"Course run synchronization API","description":"API endpoint allowing remote systems to synchronize their course runs with a Richie instance."},"building-the-frontend":{"id":"building-the-frontend","title":"Building Richie\'s frontend in your own project","description":"Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.","sidebar":"docs"},"contributing-guide":{"id":"contributing-guide","title":"Contributing guide","description":"This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.","sidebar":"docs"},"cookiecutter":{"id":"cookiecutter","title":"Start your own site","description":"We use Cookiecutter to help you","sidebar":"docs"},"css-guidelines":{"id":"css-guidelines","title":"CSS Guidelines","description":"The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.","sidebar":"docs"},"discover":{"id":"discover","title":"Discover Richie","description":"Learning Management Systems (LMS) are great tools for hosting and playing interactive online","sidebar":"docs"},"displaying-connection-status":{"id":"displaying-connection-status","title":"Displaying OpenEdX connection status in Richie","description":"This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status"},"django-react-interop":{"id":"django-react-interop","title":"Connecting React components with Django","description":"richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.","sidebar":"docs"},"docker-development":{"id":"docker-development","title":"Developing Richie with Docker","description":"Now that you have Richie up and running, you can start working with it.","sidebar":"docs"},"filters-customization":{"id":"filters-customization","title":"Customizing search filters","description":"You may want to customize the filters on the left side bar of the search page.","sidebar":"docs"},"frontend-overrides":{"id":"frontend-overrides","title":"Overriding frontend components","description":"Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.","sidebar":"docs"},"installation":{"id":"installation","title":"Installing Richie for development","description":"Richie is a container-native application but can also be installed","sidebar":"docs"},"internationalization":{"id":"internationalization","title":"Internationalization","description":"richie has built-in localization and internationalization:","sidebar":"docs"},"joanie-connection":{"id":"joanie-connection","title":"Joanie Connection","description":"Joanie delivers an API able to manage course"},"lms-backends":{"id":"lms-backends","title":"Configuring LMS Backends","description":"Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless"},"lms-connection":{"id":"lms-connection","title":"Connecting Richie with one or more LMS","description":"Connecting Richie to an LMS","sidebar":"docs"},"native-installation":{"id":"native-installation","title":"Installing Richie on your machine","description":"This document aims to list all needed steps to have a working Richie","sidebar":"docs"},"synchronizing-course-runs":{"id":"synchronizing-course-runs","title":"Synchronizing course runs between Richie and OpenEdX","description":"Richie can receive automatic course runs updates on a dedicated API endpoint."},"tls-connection":{"id":"tls-connection","title":"Connecting Richie and OpenEdX over TLS for development","description":"Purpose"},"web-analytics":{"id":"web-analytics","title":"Add web analytics to your site","description":"Richie has native support to Google Universal Analytics and Google Tag Manager Web Analytics solutions.","sidebar":"docs"}}}')}}]); \ No newline at end of file diff --git a/assets/js/3c7d7aed.9a20e8f0.js b/assets/js/3c7d7aed.9a20e8f0.js new file mode 100644 index 0000000000..7fa540baa3 --- /dev/null +++ b/assets/js/3c7d7aed.9a20e8f0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[54688],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var r=n(67294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function s(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,a=e.originalType,l=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),d=c(n),m=i,h=d["".concat(l,".").concat(m)]||d[m]||u[m]||a;return n?r.createElement(h,s(s({ref:t},p),{},{components:n})):r.createElement(h,s({ref:t},p))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=n.length,s=new Array(a);s[0]=d;var o={};for(var l in t)hasOwnProperty.call(t,l)&&(o[l]=t[l]);o.originalType=e,o.mdxType="string"==typeof e?e:i,s[1]=o;for(var c=2;c{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>m,frontMatter:()=>o,metadata:()=>c,toc:()=>u});var r=n(83117),i=n(80102),a=(n(67294),n(3905)),s=["components"],o={id:"accessibility-testing",title:"Automated accessibility checks",sidebar_label:"Accessibility testing"},l=void 0,c={unversionedId:"accessibility-testing",id:"version-2.21.1/accessibility-testing",title:"Automated accessibility checks",description:"Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.",source:"@site/versioned_docs/version-2.21.1/accessibility-testing.md",sourceDirName:".",slug:"/accessibility-testing",permalink:"/docs/accessibility-testing",draft:!1,tags:[],version:"2.21.1",lastUpdatedBy:"jbpenrath",lastUpdatedAt:1680624606,formattedLastUpdatedAt:"Apr 4, 2023",frontMatter:{id:"accessibility-testing",title:"Automated accessibility checks",sidebar_label:"Accessibility testing"},sidebar:"docs",previous:{title:"Contributing guide",permalink:"/docs/contributing-guide"},next:{title:"CSS Guidelines",permalink:"/docs/css-guidelines"}},p={},u=[{value:"Testing environment setup",id:"testing-environment-setup",level:2},{value:"Running the tests",id:"running-the-tests",level:2},{value:"Documentation reference",id:"documentation-reference",level:2}],d={toc:u};function m(e){var t=e.components,n=(0,i.Z)(e,s);return(0,a.kt)("wrapper",(0,r.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"Richie includes automated accessibility checks built through a ",(0,a.kt)("inlineCode",{parentName:"p"},"Cypress")," end-to-end testing infrastructure."),(0,a.kt)("p",null,"Automated accessibility checks can only surface around 30% of possible problems on any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency."),(0,a.kt)("p",null,"We use ",(0,a.kt)("inlineCode",{parentName:"p"},"axe")," to run these checks. You can find more about axe on the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/dequelabs/axe-core"},(0,a.kt)("inlineCode",{parentName:"a"},"axe-core")," GitHub repository"),"."),(0,a.kt)("h2",{id:"testing-environment-setup"},"Testing environment setup"),(0,a.kt)("p",null,"Both ",(0,a.kt)("inlineCode",{parentName:"p"},"Cypress")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"axe")," are used through their respective NPM packages. This means everything goes through ",(0,a.kt)("inlineCode",{parentName:"p"},"yarn")," commands. You need to have ",(0,a.kt)("inlineCode",{parentName:"p"},"node")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"yarn")," installed locally to run the tests."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"cd tests_e2e\nyarn install\n")),(0,a.kt)("p",null,"This should install everything you need."),(0,a.kt)("h2",{id:"running-the-tests"},"Running the tests"),(0,a.kt)("p",null,"There are two ways to use the ",(0,a.kt)("inlineCode",{parentName:"p"},"Cypress")," tests: through a terminal-based runner and through the ",(0,a.kt)("inlineCode",{parentName:"p"},"Cypress")," UI. Both are started through ",(0,a.kt)("inlineCode",{parentName:"p"},"yarn")," but they have different use cases."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"yarn cypress run\n")),(0,a.kt)("p",null,"You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running ",(0,a.kt)("inlineCode",{parentName:"p"},"Cypress")," in the CI."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"yarn cypress open\n")),(0,a.kt)("p",null,"This command simply opens the ",(0,a.kt)("inlineCode",{parentName:"p"},"Cypress")," UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations."),(0,a.kt)("p",null,"When there are a11y violations, an assertion fails and prints out a list in the ",(0,a.kt)("inlineCode",{parentName:"p"},"Cypress")," UI. You can then click on a violation to print more information in the browser console."),(0,a.kt)("h2",{id:"documentation-reference"},"Documentation reference"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://dequeuniversity.com/rules/axe/3.4"},"List of all possible violations covered by ",(0,a.kt)("inlineCode",{parentName:"a"},"axe"))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://docs.cypress.io"},(0,a.kt)("inlineCode",{parentName:"a"},"Cypress")," documentation")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/avanslaars/cypress-axe"},(0,a.kt)("inlineCode",{parentName:"a"},"axe")," and ",(0,a.kt)("inlineCode",{parentName:"a"},"Cypress")," integration"))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/4220d24c.e7b32db4.js b/assets/js/4220d24c.e7b32db4.js new file mode 100644 index 0000000000..cacc3b64a4 --- /dev/null +++ b/assets/js/4220d24c.e7b32db4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[4464],{3905:(e,n,t)=>{t.d(n,{Zo:()=>c,kt:()=>h});var a=t(67294);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var s=a.createContext({}),u=function(e){var n=a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},c=function(e){var n=u(e.components);return a.createElement(s.Provider,{value:n},e.children)},p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},d=a.forwardRef((function(e,n){var t=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=u(t),h=i,m=d["".concat(s,".").concat(h)]||d[h]||p[h]||r;return t?a.createElement(m,o(o({ref:n},c),{},{components:t})):a.createElement(m,o({ref:n},c))}));function h(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var r=t.length,o=new Array(r);o[0]=d;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l.mdxType="string"==typeof e?e:i,o[1]=l;for(var u=2;u{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>s,default:()=>h,frontMatter:()=>l,metadata:()=>u,toc:()=>p});var a=t(83117),i=t(80102),r=(t(67294),t(3905)),o=["components"],l={id:"lms-backends",title:"Configuring LMS Backends",sidebar_label:"LMS Backends"},s=void 0,u={unversionedId:"lms-backends",id:"version-2.21.1/lms-backends",title:"Configuring LMS Backends",description:"Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless",source:"@site/versioned_docs/version-2.21.1/lms-backends.md",sourceDirName:".",slug:"/lms-backends",permalink:"/docs/lms-backends",draft:!1,tags:[],version:"2.21.1",lastUpdatedBy:"jbpenrath",lastUpdatedAt:1680624606,formattedLastUpdatedAt:"Apr 4, 2023",frontMatter:{id:"lms-backends",title:"Configuring LMS Backends",sidebar_label:"LMS Backends"}},c={},p=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Configuring the LMS handler",id:"configuring-the-lms-handler",level:2},{value:"BASE_URL",id:"base_url",level:3},{value:"BACKEND",id:"backend",level:3},{value:"COURSE_REGEX",id:"course_regex",level:3},{value:"JS_BACKEND",id:"js_backend",level:3},{value:"JS_COURSE_REGEX",id:"js_course_regex",level:3},{value:"DEFAULT_COURSE_RUN_SYNC_MODE",id:"default_course_run_sync_mode",level:3},{value:"COURSE_RUN_SYNC_NO_UPDATE_FIELDS",id:"course_run_sync_no_update_fields",level:3},{value:"Technical support",id:"technical-support",level:2}],d={toc:p};function h(e){var n=e.components,t=(0,i.Z)(e,o);return(0,r.kt)("wrapper",(0,a.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless\nexperience between browsing the course catalog on Richie, enrolling to a course and following the\ncourse itself on the LMS."),(0,r.kt)("p",null,"It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the\ncost of writing a custom LMS handler backend."),(0,r.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,r.kt)("p",null,"This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that\nare both subdomains of the same root domain, e.g. ",(0,r.kt)("inlineCode",{parentName:"p"},"richie.example.com")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"lms.example.com"),"."),(0,r.kt)("p",null,"OpenEdX will need to generate a CORS CSRF Cookie and this cookie is flagged as secure, which\nimplies that we are not able to use it without SSL connections."),(0,r.kt)("p",null,"As a consequence, you need to configure your OpenEdX instance as follows:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python"},'FEATURES = {\n ...\n "ENABLE_CORS_HEADERS": True,\n "ENABLE_CROSS_DOMAIN_CSRF_COOKIE": True,\n}\n\nCORS_ALLOW_CREDENTIALS = True\nCORS_ALLOW_INSECURE = False\nCORS_ORIGIN_WHITELIST: ["richie.example.com"] # The domain on which Richie is hosted\n\nCROSS_DOMAIN_CSRF_COOKIE_DOMAIN = ".example.com" # The parent domain shared by Richie and OpenEdX\nCROSS_DOMAIN_CSRF_COOKIE_NAME: "edx_csrf_token"\nSESSION_COOKIE_NAME: "edx_session"\n')),(0,r.kt)("h2",{id:"configuring-the-lms-handler"},"Configuring the LMS handler"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"LMSHandler")," utility acts as a proxy that routes queries to the correct LMS backend API,\nbased on a regex match on the URL of the course. It is configured via the ",(0,r.kt)("inlineCode",{parentName:"p"},"RICHIE_LMS_BACKENDS"),"\nsetting. As an example, here is how it would be configured to connect to an Ironwood OpenEdX\ninstance hosted on ",(0,r.kt)("inlineCode",{parentName:"p"},"https://lms.example.com"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python"},'RICHIE_LMS_BACKENDS=[\n {\n "BASE_URL": "https://lms.example.com",\n # Django\n "BACKEND": "richie.apps.courses.lms.edx.EdXLMSBackend",\n "COURSE_REGEX": r"^https://lms\\.example\\.com/courses/(?P.*)/course/?$",\n # ReactJS\n "JS_BACKEND": "openedx-hawthorn",\n "JS_COURSE_REGEX": r"^https://lms\\.example\\.com/courses/(.*)/course/?$",\n # Course runs synchronization\n "COURSE_RUN_SYNC_NO_UPDATE_FIELDS": [],\n "DEFAULT_COURSE_RUN_SYNC_MODE": "sync_to_public",\n },\n]\n')),(0,r.kt)("p",null,"The following should help you understand how to configure this setting:"),(0,r.kt)("h3",{id:"base_url"},"BASE_URL"),(0,r.kt)("p",null,"The base url on which the OpenEdX instance is hosted. This is used to construct the complete url\nof the API endpoint on which the enrollment request is made by Richie's frontend application."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Type: string"),(0,r.kt)("li",{parentName:"ul"},"Required: Yes"),(0,r.kt)("li",{parentName:"ul"},"Value: for example ",(0,r.kt)("a",{parentName:"li",href:"https://lms.example.com"},"https://lms.example.com"))),(0,r.kt)("h3",{id:"backend"},"BACKEND"),(0,r.kt)("p",null,"The path to a Python class serving as LMS backend for the targeted LMS."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Type: string"),(0,r.kt)("li",{parentName:"ul"},"Required: Yes"),(0,r.kt)("li",{parentName:"ul"},"Value: Richie ships with the following Python backends (custom backends can be written to fit\nanother specific LMS):",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"richie.apps.courses.lms.edx.EdXLMSBackend"),": backend for OpenEdX"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"richie.apps.courses.lms.base.BaseLMSBackend"),": fake backend for development purposes")))),(0,r.kt)("h3",{id:"course_regex"},"COURSE_REGEX"),(0,r.kt)("p",null,"A Python regex that should match the course syllabus urls of the targeted LMS and return a\n",(0,r.kt)("inlineCode",{parentName:"p"},"course_id")," named group on the id of the course extracted from these urls."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Type: string"),(0,r.kt)("li",{parentName:"ul"},"Required: Yes"),(0,r.kt)("li",{parentName:"ul"},"Value: for example ",(0,r.kt)("inlineCode",{parentName:"li"},"^.*/courses/(?P.*)/course/?$"))),(0,r.kt)("h3",{id:"js_backend"},"JS_BACKEND"),(0,r.kt)("p",null,"The name of the ReactJS backend to use for the targeted LMS."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Type: string"),(0,r.kt)("li",{parentName:"ul"},"Required: Yes"),(0,r.kt)("li",{parentName:"ul"},"Value: Richie ships with the following Javascript backends (custom backends can be written to\nfit another specific LMS):",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"openedx-dogwood"),": backend for OpenEdX versions equal to ",(0,r.kt)("inlineCode",{parentName:"li"},"dogwood")," or ",(0,r.kt)("inlineCode",{parentName:"li"},"eucalyptus")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"openedx-hawthorn"),": backend for OpenEdX versions equal to ",(0,r.kt)("inlineCode",{parentName:"li"},"hawthorn")," or higher"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"openedx-fonzie"),": backend for OpenEdX via ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/openfun/fonzie"},"Fonzie"),"\n(extra user info and JWT tokens)"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"dummy"),": fake backend for development purposes")))),(0,r.kt)("h3",{id:"js_course_regex"},"JS_COURSE_REGEX"),(0,r.kt)("p",null,"A Javascript regex that should match the course syllabus urls of the targeted LMS and return an\nunnamed group on the id of the course extracted from these urls."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Type: string"),(0,r.kt)("li",{parentName:"ul"},"Required: Yes"),(0,r.kt)("li",{parentName:"ul"},"Value: for example ",(0,r.kt)("inlineCode",{parentName:"li"},"^.*/courses/(.*)/course/?$"))),(0,r.kt)("h3",{id:"default_course_run_sync_mode"},"DEFAULT_COURSE_RUN_SYNC_MODE"),(0,r.kt)("p",null,"When a course run is created, this setting is used to set the value of the ",(0,r.kt)("inlineCode",{parentName:"p"},"sync_mode")," field.\nThis value defines how the course runs synchronization script will impact this course run after\ncreation."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Type: enum(string)"),(0,r.kt)("li",{parentName:"ul"},"Required: No"),(0,r.kt)("li",{parentName:"ul"},"Value: possible values are ",(0,r.kt)("inlineCode",{parentName:"li"},"manual"),", ",(0,r.kt)("inlineCode",{parentName:"li"},"sync_to_draft")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"sync_to_public"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"manual"),": this course run is ignored by the course runs synchronization script"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"sync_to_draft"),": only the draft version of this course run is synchronized. A manual\npublication is necessary for the update to be visible on the public site."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"sync_to_public"),": the public version of this course run is updated by the synchronization\nscript. As a results, updates are directly visible on the public site without further\npublication by a staff user in Richie.")))),(0,r.kt)("h3",{id:"course_run_sync_no_update_fields"},"COURSE_RUN_SYNC_NO_UPDATE_FIELDS"),(0,r.kt)("p",null,"A list of fields that must only be set the first time a course run is synchronized. During this\nfirst synchronization, a new course run is created in Richie and all fields sent to the API\nendpoint via the payload are set on the object. For subsequent synchronization calls, the fields\nlisted in this setting are ignored and not synchronized. This can be used to allow modifying some\nfields manually in Richie regardless of what OpenEdX sends after an initial value is set."),(0,r.kt)("p",null,"Note that this setting is only effective for course runs with the ",(0,r.kt)("inlineCode",{parentName:"p"},"sync_mode")," field set to a\nvalue other then ",(0,r.kt)("inlineCode",{parentName:"p"},"manual"),"."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Type: enum(string)"),(0,r.kt)("li",{parentName:"ul"},"Required: No"),(0,r.kt)("li",{parentName:"ul"},"Value: for example ",'["languages"]')),(0,r.kt)("h2",{id:"technical-support"},"Technical support"),(0,r.kt)("p",null,"If you encounter an issue with this documentation or the backends included in Richie, please\n",(0,r.kt)("a",{parentName:"p",href:"https://github.com/openfun/richie/issues"},"open an issue on our repository"),"."),(0,r.kt)("p",null,"If you need a custom backend, you can ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/openfun/richie/pulls"},"submit a PR")," or\n",(0,r.kt)("a",{parentName:"p",href:"https://github.com/openfun/richie/issues"},"open an issue")," and we will consider adding it."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/4b3d2ce7.4f37e633.js b/assets/js/4b3d2ce7.4f37e633.js new file mode 100644 index 0000000000..6ad79aab04 --- /dev/null +++ b/assets/js/4b3d2ce7.4f37e633.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[34221],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>m});var o=t(67294);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,o)}return t}function a(e){for(var n=1;n=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var s=o.createContext({}),c=function(e){var n=o.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):a(a({},n),e)),t},p=function(e){var n=c(e.components);return o.createElement(s.Provider,{value:n},e.children)},u={inlineCode:"code",wrapper:function(e){var n=e.children;return o.createElement(o.Fragment,{},n)}},d=o.forwardRef((function(e,n){var t=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(t),m=i,h=d["".concat(s,".").concat(m)]||d[m]||u[m]||r;return t?o.createElement(h,a(a({ref:n},p),{},{components:t})):o.createElement(h,a({ref:n},p))}));function m(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var r=t.length,a=new Array(r);a[0]=d;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l.mdxType="string"==typeof e?e:i,a[1]=l;for(var c=2;c{t.r(n),t.d(n,{assets:()=>p,contentTitle:()=>s,default:()=>m,frontMatter:()=>l,metadata:()=>c,toc:()=>u});var o=t(83117),i=t(80102),r=(t(67294),t(3905)),a=["components"],l={id:"lms-connection",title:"Connecting Richie with one or more LMS",sidebar_label:"LMS connection"},s=void 0,c={unversionedId:"lms-connection",id:"version-2.21.1/lms-connection",title:"Connecting Richie with one or more LMS",description:"Connecting Richie to an LMS",source:"@site/versioned_docs/version-2.21.1/lms-connection.md",sourceDirName:".",slug:"/lms-connection",permalink:"/docs/lms-connection",draft:!1,tags:[],version:"2.21.1",lastUpdatedBy:"jbpenrath",lastUpdatedAt:1680624606,formattedLastUpdatedAt:"Apr 4, 2023",frontMatter:{id:"lms-connection",title:"Connecting Richie with one or more LMS",sidebar_label:"LMS connection"},sidebar:"docs",previous:{title:"I18n",permalink:"/docs/internationalization"},next:{title:"Web Analytics",permalink:"/docs/web-analytics"}},p={},u=[{value:"Connecting Richie to an LMS",id:"connecting-richie-to-an-lms",level:2},{value:"1. Displaying connection status",id:"1-displaying-connection-status",level:3},{value:"2. Seamless enrollment",id:"2-seamless-enrollment",level:3},{value:"3. Synchronizing course runs details",id:"3-synchronizing-course-runs-details",level:3},{value:"4. Joanie, the enrollment manager",id:"4-joanie-the-enrollment-manager",level:3},{value:"Development",id:"development",level:2}],d={toc:u};function m(e){var n=e.components,t=(0,i.Z)(e,a);return(0,r.kt)("wrapper",(0,o.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"connecting-richie-to-an-lms"},"Connecting Richie to an LMS"),(0,r.kt)("p",null,"Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated\nseamless experience."),(0,r.kt)("p",null,"As of today, each approach has been implemented for OpenEdX but the same could be done for\nother LMSes like Moodle, at the cost of minor adaptations."),(0,r.kt)("h3",{id:"1-displaying-connection-status"},"1. Displaying connection status"),(0,r.kt)("p",null,"OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's\nconnection status from OpenEdx and display the user's profile information directly on the Richie\nsite: username, dashboard url, etc."),(0,r.kt)("p",null,"In this approach, a user visiting your Richie site and trying to signup or login, is sent to the\nOpenEdX site for authentication and is redirected back to the Richie site upon successful login."),(0,r.kt)("p",null,"You can see this in action on ",(0,r.kt)("a",{parentName:"p",href:"https://www.fun-mooc.fr"},"https://www.fun-mooc.fr"),"."),(0,r.kt)("p",null,"We provide detailed instructions on\n",(0,r.kt)("a",{parentName:"p",href:"/docs/displaying-connection-status"},"how to configure displaying OpenEdX connection status in Richie"),"."),(0,r.kt)("h3",{id:"2-seamless-enrollment"},"2. Seamless enrollment"),(0,r.kt)("p",null,"Thanks to OpenEdX's enrollment API, it is possible to let users enroll on course runs without\nleaving Richie."),(0,r.kt)("p",null,"You can see this in action on ",(0,r.kt)("a",{parentName:"p",href:"https://www.fun-mooc.fr"},"https://www.fun-mooc.fr"),"."),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},"This feature requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that\nare both subdomains of the same root domain, e.g. ",(0,r.kt)("inlineCode",{parentName:"p"},"richie.example.com")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"lms.example.com"),".")),(0,r.kt)("p",null,"You should read our guide on ",(0,r.kt)("a",{parentName:"p",href:"lms-backends"},"how to use OpenEdX as LMS backend for Richie"),"."),(0,r.kt)("h3",{id:"3-synchronizing-course-runs-details"},"3. Synchronizing course runs details"),(0,r.kt)("p",null,"Course runs in Richie can be handled manually, filling all fields via the DjangoCMS front-end\nediting interface. But a better way to handle course runs is to synchronize them automatically\nfrom your LMS using the course run synchronization API."),(0,r.kt)("p",null,"Please refer to our guide on ",(0,r.kt)("a",{parentName:"p",href:"synchronizing-course-runs"},"how to synchronize course runs between Richie and OpenEdx")),(0,r.kt)("h3",{id:"4-joanie-the-enrollment-manager"},"4. Joanie, the enrollment manager"),(0,r.kt)("p",null,"For more advanced use cases, we have started a new project called ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/openfun/joanie"},"Joanie")," which acts as an\nenrollment manager for Richie."),(0,r.kt)("p",null,"Authentication in Joanie is done via JWT Tokens for maximum flexibility and decoupling in\nidentity management."),(0,r.kt)("p",null,"The project started early 2021, but over time, Joanie will handle:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"paid enrollments / certification"),(0,r.kt)("li",{parentName:"ul"},"micro-credentials"),(0,r.kt)("li",{parentName:"ul"},"user dashboard"),(0,r.kt)("li",{parentName:"ul"},"cohorts management (academic or B2B)"),(0,r.kt)("li",{parentName:"ul"},"multi-LMS catalogs"),(0,r.kt)("li",{parentName:"ul"},"time based enrollment")),(0,r.kt)("h2",{id:"development"},"Development"),(0,r.kt)("p",null,"For development purposes, the docker-compose project provided on\n",(0,r.kt)("a",{parentName:"p",href:"https://github.com/openfun/richie"},"Richie's code repository")," is pre-configured to connect\nwith an OpenEdx instance started with\n",(0,r.kt)("a",{parentName:"p",href:"https://github.com/openfun/openedx-docker"},"OpenEdx Docker"),", which provides a ready-to-use\ndocker-compose stack of OpenEdx in several flavors. Head over to\n",(0,r.kt)("a",{parentName:"p",href:"https://github.com/openfun/openedx-docker#readme"},"OpenEdx Docker README")," for instructions on how to bootstrap an OpenEdX instance."),(0,r.kt)("p",null,"Now, start both the OpenEdX and Richie projects separately with ",(0,r.kt)("inlineCode",{parentName:"p"},"make run"),"."),(0,r.kt)("p",null,"Richie should respond on ",(0,r.kt)("inlineCode",{parentName:"p"},"http://localhost:8070"),", OpenEdx on ",(0,r.kt)("inlineCode",{parentName:"p"},"http://localhost:8073")," and both\napps should be able to communicate with each other via the network bridge defined in\ndocker-compose."),(0,r.kt)("p",null,"If you want to activate ",(0,r.kt)("a",{parentName:"p",href:"#2-seamless-enrollment"},"seamless enrollment")," locally for development,\nyou will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our\nguide on ",(0,r.kt)("a",{parentName:"p",href:"tls-connection"},"setting-up TLS connections for Richie and OpenEdX"),"."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c866602a.8f571bb5.js b/assets/js/4ee76bca.8c6cf3ab.js similarity index 80% rename from assets/js/c866602a.8f571bb5.js rename to assets/js/4ee76bca.8c6cf3ab.js index 9c6e2f3f76..77fe82d025 100644 --- a/assets/js/c866602a.8f571bb5.js +++ b/assets/js/4ee76bca.8c6cf3ab.js @@ -1 +1 @@ -"use strict";(self.webpackChunkrichie_education_docs=self.webpackChunkrichie_education_docs||[]).push([[6688],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var a=n(67294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),c=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,s=e.parentName,p=r(e,["components","mdxType","originalType","parentName"]),u=c(n),m=i,g=u["".concat(s,".").concat(m)]||u[m]||d[m]||o;return n?a.createElement(g,l(l({ref:t},p),{},{components:n})):a.createElement(g,l({ref:t},p))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,l=new Array(o);l[0]=u;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r.mdxType="string"==typeof e?e:i,l[1]=r;for(var c=2;c{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>s,default:()=>m,frontMatter:()=>r,metadata:()=>c,toc:()=>d});var a=n(83117),i=n(80102),o=(n(67294),n(3905)),l=["components"],r={id:"web-analytics",title:"Add web analytics to your site",sidebar_label:"Web Analytics"},s=void 0,c={unversionedId:"web-analytics",id:"version-2.21.0/web-analytics",title:"Add web analytics to your site",description:"Richie has native support to Google Universal Analytics and Google Tag Manager Web Analytics solutions.",source:"@site/versioned_docs/version-2.21.0/web-analytics.md",sourceDirName:".",slug:"/web-analytics",permalink:"/docs/web-analytics",draft:!1,tags:[],version:"2.21.0",lastUpdatedBy:"jbpenrath",lastUpdatedAt:1679473023,formattedLastUpdatedAt:"Mar 22, 2023",frontMatter:{id:"web-analytics",title:"Add web analytics to your site",sidebar_label:"Web Analytics"},sidebar:"docs",previous:{title:"LMS connection",permalink:"/docs/lms-connection"},next:{title:"Installation",permalink:"/docs/installation"}},p={},d=[{value:"Google Universal Analytics",id:"google-universal-analytics",level:2},{value:"Google Tag",id:"google-tag",level:2},{value:"Google Tag Manager",id:"google-tag-manager",level:2},{value:"Multiple Web Analytics at the same time",id:"multiple-web-analytics-at-the-same-time",level:2},{value:"Location of the web analytics javascript",id:"location-of-the-web-analytics-javascript",level:2},{value:"Add a new Web Analytics solution",id:"add-a-new-web-analytics-solution",level:2}],u={toc:d};function m(e){var t=e.components,n=(0,i.Z)(e,l);return(0,o.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Richie has native support to ",(0,o.kt)("a",{parentName:"p",href:"#google-analytics"},"Google Universal Analytics")," and ",(0,o.kt)("a",{parentName:"p",href:"#google-tag-manager"},"Google Tag Manager")," Web Analytics solutions.\nThe purpose of this file is to explain how you can enable one of the supported Web Analytics providers\nand how you can extend Richie with an alternative solution."),(0,o.kt)("h2",{id:"google-universal-analytics"},"Google Universal Analytics"),(0,o.kt)("p",null,"Next, it is described how you can configure the ",(0,o.kt)("strong",{parentName:"p"},"Google Universal Analytics")," on your Richie site."),(0,o.kt)("p",null,"Add the ",(0,o.kt)("inlineCode",{parentName:"p"},"WEB_ANALYTICS")," setting, with the Google Universal Analytics configuration. From the next example replace ",(0,o.kt)("inlineCode",{parentName:"p"},"TRACKING_ID")," with your tracking id code."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-python"},"{\n 'google_universal_analytics': {\n 'tracking_id': 'TRACKING_ID',\n }\n}\n")),(0,o.kt)("p",null,"The current Google Universal Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Universal Analytics or even use them to create custom reports.\nCustom dimensions with a value as example:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Organizations codes - ",(0,o.kt)("inlineCode",{parentName:"li"},"UNIV_LISBON | UNIV_PORTO")),(0,o.kt)("li",{parentName:"ul"},"Course code - ",(0,o.kt)("inlineCode",{parentName:"li"},"COURSE_XPTO")),(0,o.kt)("li",{parentName:"ul"},"Course runs titles - ",(0,o.kt)("inlineCode",{parentName:"li"},"Summer edition | Winter edition")),(0,o.kt)("li",{parentName:"ul"},"Course runs resource links - ",(0,o.kt)("inlineCode",{parentName:"li"},"http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info")),(0,o.kt)("li",{parentName:"ul"},"Page title - ",(0,o.kt)("inlineCode",{parentName:"li"},"Introduction to Programming"))),(0,o.kt)("h2",{id:"google-tag"},"Google Tag"),(0,o.kt)("p",null,"It is possible to configure the ",(0,o.kt)("strong",{parentName:"p"},"Google Tag"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"gtag.js"),", on your Richie site."),(0,o.kt)("p",null,"Add the ",(0,o.kt)("inlineCode",{parentName:"p"},"WEB_ANALYTICS")," setting, with the Google Tag configuration like for example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-python"},"{\n 'google_tag': {\n 'tracking_id': 'TRACKING_ID',\n }\n}\n")),(0,o.kt)("p",null,"And don't forget to replace the ",(0,o.kt)("inlineCode",{parentName:"p"},"TRACKING_ID")," with your tracking id/code from Google Ads, Google Analytics, or other Google product compatible with the ",(0,o.kt)("inlineCode",{parentName:"p"},"gtag.js"),"."),(0,o.kt)("p",null,"The Google Tag is initialized with custom dimensions like the ",(0,o.kt)("a",{parentName:"p",href:"#google-analytics"},"Google Universal Analytics"),"."),(0,o.kt)("h2",{id:"google-tag-manager"},"Google Tag Manager"),(0,o.kt)("p",null,"Next, it is described how you can configure the ",(0,o.kt)("strong",{parentName:"p"},"Google Tag Manager"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"gtm.js"),", on your Richie site."),(0,o.kt)("p",null,"Add the ",(0,o.kt)("inlineCode",{parentName:"p"},"WEB_ANALYTICS")," setting, with the Google Tag Manager configuration, for example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-python"},"{\n 'google_tag_manager': {\n 'tracking_id': 'TRACKING_ID',\n }\n}\n")),(0,o.kt)("p",null,"And don't forget to replace the ",(0,o.kt)("inlineCode",{parentName:"p"},"TRACKING_ID")," with your ",(0,o.kt)("inlineCode",{parentName:"p"},"GTM")," tracking id/code."),(0,o.kt)("p",null,"The current Google Tag Manager implementation also defines a custom dimensions like the ",(0,o.kt)("a",{parentName:"p",href:"#google-analytics"},"Google Universal Analytics"),"."),(0,o.kt)("p",null,"If you want to use the Environments feature of the Google Tag Manager, you need to include the ",(0,o.kt)("inlineCode",{parentName:"p"},"environment")," key with its value on ",(0,o.kt)("inlineCode",{parentName:"p"},"google_tag_manager")," dict inside the ",(0,o.kt)("inlineCode",{parentName:"p"},"WEB_ANALYTICS")," setting. "),(0,o.kt)("p",null,(0,o.kt)("em",{parentName:"p"},"The environments feature in Google Tag Manager is ideal for organizations that want to preview their container changes in a test environment before those changes are published"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-python"},"{\n 'google_tag_manager': {\n 'tracking_id': 'TRACKING_ID',\n 'environment': '>m_auth=aaaaaaaaaaaaaaaa>m_preview=env-99>m_cookies_win=x';\n }\n}\n")),(0,o.kt)("h2",{id:"multiple-web-analytics-at-the-same-time"},"Multiple Web Analytics at the same time"),(0,o.kt)("p",null,"It is possible to configure several web analytics solutions at the same time or the same solution with different tracking identifications."),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"WEB_ANALYTICS")," setting example to have both Google Universal Analytics and Google Tag Manager:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-python"},"{\n 'google_universal_analytics': {\n 'tracking_id': 'UA-TRACKING_ID',\n },\n 'google_tag_manager': {\n 'tracking_id': 'GTM-TRACKING_ID',\n }\n}\n")),(0,o.kt)("h2",{id:"location-of-the-web-analytics-javascript"},"Location of the web analytics javascript"),(0,o.kt)("p",null,"Each web analytics js code can be put on the ",(0,o.kt)("inlineCode",{parentName:"p"},"footer")," (",(0,o.kt)("strong",{parentName:"p"},"default")," value), to put the Javascript on HTML body footer, or ",(0,o.kt)("inlineCode",{parentName:"p"},"header"),", to put the Javascript code at the end of the HTML ",(0,o.kt)("inlineCode",{parentName:"p"},"head"),"."),(0,o.kt)("p",null,"Update the ",(0,o.kt)("inlineCode",{parentName:"p"},"WEB_ANALYTICS")," setting, like:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-python"},"{\n 'google_universal_analytics': {\n 'tracking_id': 'UA-TRACKING_ID',\n 'location': 'footer,\n },\n}\n")),(0,o.kt)("h2",{id:"add-a-new-web-analytics-solution"},"Add a new Web Analytics solution"),(0,o.kt)("p",null,"In this section it's described how you can add support to a different Web Analytics solution."),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"override the ",(0,o.kt)("inlineCode",{parentName:"li"},"richie/web_analytics.html")," template"),(0,o.kt)("li",{parentName:"ul"},"define the ",(0,o.kt)("inlineCode",{parentName:"li"},"WEB_ANALYTICS")," setting with a value that represents your solution, eg. ",(0,o.kt)("inlineCode",{parentName:"li"},"my-custom-web-analytics-software")),(0,o.kt)("li",{parentName:"ul"},"define the ",(0,o.kt)("inlineCode",{parentName:"li"},"WEB_ANALYTICS")," setting with your tracking identification"),(0,o.kt)("li",{parentName:"ul"},"optionally change ",(0,o.kt)("inlineCode",{parentName:"li"},"location")," with ",(0,o.kt)("inlineCode",{parentName:"li"},"footer")," (default) or ",(0,o.kt)("inlineCode",{parentName:"li"},"head")," value")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-python"},"{\n 'my-custom-web-analytics-software': {\n 'tracking_id': 'MY_CUSTOM_TRACKING_ID',\n 'location': 'footer,\n },\n}\n")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Example of a ",(0,o.kt)("inlineCode",{parentName:"li"},"richie/web_analytics.html")," file customization that prints to the browser console log the dimension keys and values:")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"}," - - + +
-
Version: 1.12

Contributing guide

This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

We try to raise our code quality standards and expect contributors to follow the recommandations +

Version: 1.12

Contributing guide

This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

Checking your code

We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

$ make lint-back

We use strict eslint and prettier to check the validity of our frontend code:

$ make lint-front

Running tests

On the backend, we use pytest to run our test suite:

$ make test-back

On the frontend, we use karma to run our test suite:

$ make test-front

Running migrations

The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

$ make migrate

Handling new dependencies

Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

$ make bootstrap

Going further

To see all available commands, run:

$ make

We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

bin
├── exec
├── pylint
├── pytest
└── run

More details and tips & tricks can be found in our development with Docker documentation

- - + + \ No newline at end of file diff --git a/docs/1.12/css-guidelines/index.html b/docs/1.12/css-guidelines/index.html index 987de38482..71421d5f51 100644 --- a/docs/1.12/css-guidelines/index.html +++ b/docs/1.12/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
-
Version: 1.12

CSS Guidelines

The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

File structuration

Rules should be placed where their purpose is most apparent, and where they are easiest to find.

Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

Code structuration

In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

Following the BEM naming convention, we will write our classes as follows :

.block {}
.block__element {}
.block--modifier {}
  • .block represents the higher level of an abstraction or component.
  • .block__element represents a descendent of .block that helps form .block as a whole.
  • .block--modifier represents a different state or version of .block.

We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

Quick pointers

  • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
  • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
  • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
  • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
  • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

(Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

- - +
Version: 1.12

CSS Guidelines

The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

File structuration

Rules should be placed where their purpose is most apparent, and where they are easiest to find.

Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

Code structuration

In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

Following the BEM naming convention, we will write our classes as follows :

.block {}
.block__element {}
.block--modifier {}
  • .block represents the higher level of an abstraction or component.
  • .block__element represents a descendent of .block that helps form .block as a whole.
  • .block--modifier represents a different state or version of .block.

We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

Quick pointers

  • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
  • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
  • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
  • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
  • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

(Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

+ + \ No newline at end of file diff --git a/docs/1.12/discover/index.html b/docs/1.12/discover/index.html index ace2a7eae6..e880167a0f 100644 --- a/docs/1.12/discover/index.html +++ b/docs/1.12/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
-
Version: 1.12

Getting started with Richie

If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

Login/password are admin/admin. The database is regularly flushed.

Architecture

Richie is a container-native application but can also be installed +

Version: 1.12

Getting started with Richie

If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

Login/password are admin/admin. The database is regularly flushed.

Architecture

Richie is a container-native application but can also be installed on your machine.

For development, the project is defined using a docker-compose file and consists of 4 services:

  • db: the Postgresql database,
  • elasticsearch: the search engine,
  • app: the actual DjangoCMS project with all our application code,
  • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -21,7 +21,7 @@ migration-related issues.

Now that your Docker services are ready to be used, start the full CMS by running:

$ make run

Adding content

Once the CMS is up and running, you can create a superuser account:

$ make superuser

You can create a basic demo site by running:

$ make demo-site

Note that if you don't create the demo site and start from a blank CMS, you will get some errors requesting you to create some required root pages. So it is easier as a first approach to test the CMS with the demo site.

You should be able to view the site at localhost:8070

- - + + \ No newline at end of file diff --git a/docs/1.12/django-react-interop/index.html b/docs/1.12/django-react-interop/index.html index 860b0affeb..0114d0b5a2 100644 --- a/docs/1.12/django-react-interop/index.html +++ b/docs/1.12/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
-
Version: 1.12

Connecting React components with Django

richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

Convention

Therefore, we need a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

We decided to use a specific CSS class name along with its modifiers. We reserve the fun-react class and its modified children for this purpose.

Example

Here is how we would call a "FeaturedCourses" component from a template, a plugin or a snippet:

<div class="fun-react fun-react--featured-courses"></div>

When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

- - +
Version: 1.12

Connecting React components with Django

richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

Convention

Therefore, we need a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

We decided to use a specific CSS class name along with its modifiers. We reserve the fun-react class and its modified children for this purpose.

Example

Here is how we would call a "FeaturedCourses" component from a template, a plugin or a snippet:

<div class="fun-react fun-react--featured-courses"></div>

When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

+ + \ No newline at end of file diff --git a/docs/1.12/docker-development/index.html b/docs/1.12/docker-development/index.html index 99891621a8..39333e7bd1 100644 --- a/docs/1.12/docker-development/index.html +++ b/docs/1.12/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
-
Version: 1.12

Developing Richie with Docker

Now that you have Richie up and running, you can start working with it.

Settings

Settings are defined using Django +

Version: 1.12

Developing Richie with Docker

Now that you have Richie up and running, you can start working with it.

Settings

Settings are defined using Django Configurations for different environments:

  • Development: settings for development on developers' local environment,
  • Test: settings used to run our test suite,
  • ContinousIntegration: settings used on the continuous integration platform,
  • Feature: settings for deployment of each developers' feature branches,
  • Staging: settings for deployment to the staging environment,
  • PreProduction: settings for deployment to the pre-production environment,
  • Production: settings for deployment to the production environment.

The Development environment is defined as the default environment.

Front-end tools

If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

# Start the Sass watcher
$ make watch-sass

# In a new terminal or session, start the TypeScript watcher
$ make watch-ts

Container control

You can stop/start/restart a container:

$ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

or stop/start/restart all containers in one command:

$ docker-compose [stop|start|restart]

Debugging

You can easily see the latest logs for a container:

$ docker-compose logs [app|postgresql|mysql|elasticsearch]

Or follow the stream of logs:

$ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

If you need to debug a running container, you can open a Linux shell with the @@ -28,7 +28,7 @@ file

Cleanup

If you work on the Docker configuration and make repeated modifications, remember to periodically clean the unused docker images and containers by running:

$ docker image prune
$ docker container prune

Troubleshooting

ElasticSearch service is always down

If your elasticsearch container fails at booting, checkout the logs via:

$ docker-compose logs elasticsearch

You may see entries similar to:

[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

In this case, increase virtual memory as follows (UNIX systems):

$ sudo sysctl -w vm/max_map_count=262144
- - + + \ No newline at end of file diff --git a/docs/1.12/native-installation/index.html b/docs/1.12/native-installation/index.html index 164247b527..d647391aeb 100644 --- a/docs/1.12/native-installation/index.html +++ b/docs/1.12/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
-
Version: 1.12

Installing Richie on your machine

This document aims to list all needed steps to have a working Richie +

Version: 1.12

Installing Richie on your machine

This document aims to list all needed steps to have a working Richie installation on your laptop.

A better approach is to use Docker as explained in our guide for container-native instructions.

Installing a fresh server

Version

You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

npm run sass

Run server

Make sure your database is up-to-date before running the application the first time and after each modification to your models:

python sandbox/manage.py migrate

You can create a superuser account:

python sandbox/manage.py createsuperuser

Run the tests

python sandbox/manage.py test

You should now be able to start Django and view the site at localhost:8000

python sandbox/manage.py runserver
- - + + \ No newline at end of file diff --git a/docs/1.13/building-the-frontend/index.html b/docs/1.13/building-the-frontend/index.html index 4e70dcfb85..2b08e2aa15 100644 --- a/docs/1.13/building-the-frontend/index.html +++ b/docs/1.13/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
-
Version: 1.13

Building Richie's frontend in your own project

Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

Installing richie-education

If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

mkdir -p src/frontend

Then, you need to bootstrap your own frontend project in this new directory.

cd src/frontend
yarn init

With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

yarn add richie-education

In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

"dependencies": {
"richie-education": "1.12.0"
},

Building the Javascript bundle

You are now ready to run your own frontend build. We'll just be using webpack directly.

yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

Here is everything that is happening:

  • yarn webpack — run the webpack CLI;
  • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
  • --output-path ./build — make sure we get our output where we need it to be;
  • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

You can now run your build to change frontend settings or override frontend components with your own.

Building the CSS

If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

mkdir -p src/frontend/scss
touch src/frontend/scss/_mains.scss

Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

@import "richie-education/scss/main";

You are now ready to run the CSS build:

cd src/frontend
yarn build-sass

This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

- - +
Version: 1.13

Building Richie's frontend in your own project

Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

Installing richie-education

If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

mkdir -p src/frontend

Then, you need to bootstrap your own frontend project in this new directory.

cd src/frontend
yarn init

With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

yarn add richie-education

In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

"dependencies": {
"richie-education": "1.12.0"
},

Building the Javascript bundle

You are now ready to run your own frontend build. We'll just be using webpack directly.

yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

Here is everything that is happening:

  • yarn webpack — run the webpack CLI;
  • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
  • --output-path ./build — make sure we get our output where we need it to be;
  • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

You can now run your build to change frontend settings or override frontend components with your own.

Building the CSS

If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

mkdir -p src/frontend/scss
touch src/frontend/scss/_mains.scss

Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

@import "richie-education/scss/main";

You are now ready to run the CSS build:

cd src/frontend
yarn build-sass

This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

+ + \ No newline at end of file diff --git a/docs/1.13/contributing-guide/index.html b/docs/1.13/contributing-guide/index.html index 27a98e14d7..66c31e36a2 100644 --- a/docs/1.13/contributing-guide/index.html +++ b/docs/1.13/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
-
Version: 1.13

Contributing guide

This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

We try to raise our code quality standards and expect contributors to follow the recommandations +

Version: 1.13

Contributing guide

This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

Checking your code

We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

$ make lint-back

We use strict eslint and prettier to check the validity of our frontend code:

$ make lint-front

Running tests

On the backend, we use pytest to run our test suite:

$ make test-back

On the frontend, we use karma to run our test suite:

$ make test-front

Running migrations

The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

$ make migrate

Handling new dependencies

Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

$ make bootstrap

Going further

To see all available commands, run:

$ make

We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

bin
├── exec
├── pylint
├── pytest
└── run

More details and tips & tricks can be found in our development with Docker documentation

- - + + \ No newline at end of file diff --git a/docs/1.13/css-guidelines/index.html b/docs/1.13/css-guidelines/index.html index 4771e716fe..dceb64da59 100644 --- a/docs/1.13/css-guidelines/index.html +++ b/docs/1.13/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
-
Version: 1.13

CSS Guidelines

The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

File structuration

Rules should be placed where their purpose is most apparent, and where they are easiest to find.

Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

Code structuration

In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

Following the BEM naming convention, we will write our classes as follows :

.block {}
.block__element {}
.block--modifier {}
  • .block represents the higher level of an abstraction or component.
  • .block__element represents a descendent of .block that helps form .block as a whole.
  • .block--modifier represents a different state or version of .block.

We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

Quick pointers

  • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
  • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
  • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
  • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
  • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

(Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

- - +
Version: 1.13

CSS Guidelines

The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

File structuration

Rules should be placed where their purpose is most apparent, and where they are easiest to find.

Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

Code structuration

In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

Following the BEM naming convention, we will write our classes as follows :

.block {}
.block__element {}
.block--modifier {}
  • .block represents the higher level of an abstraction or component.
  • .block__element represents a descendent of .block that helps form .block as a whole.
  • .block--modifier represents a different state or version of .block.

We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

Quick pointers

  • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
  • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
  • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
  • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
  • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

(Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

+ + \ No newline at end of file diff --git a/docs/1.13/discover/index.html b/docs/1.13/discover/index.html index c3fd04b903..67031e3ebc 100644 --- a/docs/1.13/discover/index.html +++ b/docs/1.13/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
-
Version: 1.13

Getting started with Richie

If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

Login/password are admin/admin. The database is regularly flushed.

Architecture

Richie is a container-native application but can also be installed +

Version: 1.13

Getting started with Richie

If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

Login/password are admin/admin. The database is regularly flushed.

Architecture

Richie is a container-native application but can also be installed on your machine.

For development, the project is defined using a docker-compose file and consists of 4 services:

  • db: the Postgresql database,
  • elasticsearch: the search engine,
  • app: the actual DjangoCMS project with all our application code,
  • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -21,7 +21,7 @@ migration-related issues.

Now that your Docker services are ready to be used, start the full CMS by running:

$ make run

Adding content

Once the CMS is up and running, you can create a superuser account:

$ make superuser

You can create a basic demo site by running:

$ make demo-site

Note that if you don't create the demo site and start from a blank CMS, you will get some errors requesting you to create some required root pages. So it is easier as a first approach to test the CMS with the demo site.

You should be able to view the site at localhost:8070

- - + + \ No newline at end of file diff --git a/docs/1.13/django-react-interop/index.html b/docs/1.13/django-react-interop/index.html index 4572c83d3e..bd071d18c1 100644 --- a/docs/1.13/django-react-interop/index.html +++ b/docs/1.13/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
-
Version: 1.13

Connecting React components with Django

richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

Rendering components

We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

Additionally, components including internationalized data or strings need to know which locale to use. All uses of this richie-react class can be paired with a data-attribute specifying the locale. If not defined, en is used as a default.

Example

Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

<div
class="richie-react richie-react--featured-courses"
data-locale="fr-ca"
></div>

When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

Passing properties to components

Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

Example

Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

<div
class="richie-react richie-react--featured-courses"
data-locale="fr-ca"
data-props='{"categories": ["sociology", "anthropology"]}'
></div>

When the component is rendered, it will be passed a categories prop with the relevant categories.

Built-in components

Here are the React component that Richie comes with and uses out of the box.

<RootSearchSuggestField />

Renders a course search bar, like the one that appears in the default Search page.

Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

Props:

  • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
  • context [optional] — see context.

<Search />

Renders the full-page course search engine interface, including the search bar, search results, and filters pane.

NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

Props:

  • pageTitle [required] — title for the page, will be used inside the <h1> in the rendered component.
  • context [required] — see context.

<UserLogin />

Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

Props:

  • loginUrl [required] — the URL where the user is sent when they click on "Log in";
  • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
  • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

Context

All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

Here is the expected shape for this object:

{
assets: {
// SVG sprite used throughout Richie
icons: "/path/to/icons/sprite.svg"
}
}

Note that it might be expanded in further versions of Richie.

- - +
Version: 1.13

Connecting React components with Django

richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

Rendering components

We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

Additionally, components including internationalized data or strings need to know which locale to use. All uses of this richie-react class can be paired with a data-attribute specifying the locale. If not defined, en is used as a default.

Example

Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

<div
class="richie-react richie-react--featured-courses"
data-locale="fr-ca"
></div>

When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

Passing properties to components

Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

Example

Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

<div
class="richie-react richie-react--featured-courses"
data-locale="fr-ca"
data-props='{"categories": ["sociology", "anthropology"]}'
></div>

When the component is rendered, it will be passed a categories prop with the relevant categories.

Built-in components

Here are the React component that Richie comes with and uses out of the box.

<RootSearchSuggestField />

Renders a course search bar, like the one that appears in the default Search page.

Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

Props:

  • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
  • context [optional] — see context.

<Search />

Renders the full-page course search engine interface, including the search bar, search results, and filters pane.

NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

Props:

  • pageTitle [required] — title for the page, will be used inside the <h1> in the rendered component.
  • context [required] — see context.

<UserLogin />

Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

Props:

  • loginUrl [required] — the URL where the user is sent when they click on "Log in";
  • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
  • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

Context

All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

Here is the expected shape for this object:

{
assets: {
// SVG sprite used throughout Richie
icons: "/path/to/icons/sprite.svg"
}
}

Note that it might be expanded in further versions of Richie.

+ + \ No newline at end of file diff --git a/docs/1.13/docker-development/index.html b/docs/1.13/docker-development/index.html index 295ef07de2..271d901960 100644 --- a/docs/1.13/docker-development/index.html +++ b/docs/1.13/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
-
Version: 1.13

Developing Richie with Docker

Now that you have Richie up and running, you can start working with it.

Settings

Settings are defined using Django +

Version: 1.13

Developing Richie with Docker

Now that you have Richie up and running, you can start working with it.

Settings

Settings are defined using Django Configurations for different environments:

  • Development: settings for development on developers' local environment,
  • Test: settings used to run our test suite,
  • ContinousIntegration: settings used on the continuous integration platform,
  • Feature: settings for deployment of each developers' feature branches,
  • Staging: settings for deployment to the staging environment,
  • PreProduction: settings for deployment to the pre-production environment,
  • Production: settings for deployment to the production environment.

The Development environment is defined as the default environment.

Front-end tools

If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

# Start the Sass watcher
$ make watch-sass

# In a new terminal or session, start the TypeScript watcher
$ make watch-ts

Container control

You can stop/start/restart a container:

$ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

or stop/start/restart all containers in one command:

$ docker-compose [stop|start|restart]

Debugging

You can easily see the latest logs for a container:

$ docker-compose logs [app|postgresql|mysql|elasticsearch]

Or follow the stream of logs:

$ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

If you need to debug a running container, you can open a Linux shell with the @@ -28,7 +28,7 @@ file

Cleanup

If you work on the Docker configuration and make repeated modifications, remember to periodically clean the unused docker images and containers by running:

$ docker image prune
$ docker container prune

Troubleshooting

ElasticSearch service is always down

If your elasticsearch container fails at booting, checkout the logs via:

$ docker-compose logs elasticsearch

You may see entries similar to:

[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

In this case, increase virtual memory as follows (UNIX systems):

$ sudo sysctl -w vm/max_map_count=262144
- - + + \ No newline at end of file diff --git a/docs/1.13/native-installation/index.html b/docs/1.13/native-installation/index.html index d03003ebf0..61e86aaa2a 100644 --- a/docs/1.13/native-installation/index.html +++ b/docs/1.13/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
-
Version: 1.13

Installing Richie on your machine

This document aims to list all needed steps to have a working Richie +

Version: 1.13

Installing Richie on your machine

This document aims to list all needed steps to have a working Richie installation on your laptop.

A better approach is to use Docker as explained in our guide for container-native instructions.

Installing a fresh server

Version

You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

npm run sass

Run server

Make sure your database is up-to-date before running the application the first time and after each modification to your models:

python sandbox/manage.py migrate

You can create a superuser account:

python sandbox/manage.py createsuperuser

Run the tests

python sandbox/manage.py test

You should now be able to start Django and view the site at localhost:8000

python sandbox/manage.py runserver
- - + + \ No newline at end of file diff --git a/docs/1.14/building-the-frontend/index.html b/docs/1.14/building-the-frontend/index.html index 8ec4f84d06..4994cd8f58 100644 --- a/docs/1.14/building-the-frontend/index.html +++ b/docs/1.14/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
-
Version: 1.14

Building Richie's frontend in your own project

Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

Installing richie-education

If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

mkdir -p src/frontend

Then, you need to bootstrap your own frontend project in this new directory.

cd src/frontend
yarn init

With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

yarn add richie-education

In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

"dependencies": {
"richie-education": "1.12.0"
},

Building the Javascript bundle

You are now ready to run your own frontend build. We'll just be using webpack directly.

yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

Here is everything that is happening:

  • yarn webpack — run the webpack CLI;
  • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
  • --output-path ./build — make sure we get our output where we need it to be;
  • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

You can now run your build to change frontend settings or override frontend components with your own.

Building the CSS

If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

mkdir -p src/frontend/scss
touch src/frontend/scss/_mains.scss

Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

@import "richie-education/scss/main";

You are now ready to run the CSS build:

cd src/frontend
yarn build-sass

This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

- - +
Version: 1.14

Building Richie's frontend in your own project

Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

Installing richie-education

If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

mkdir -p src/frontend

Then, you need to bootstrap your own frontend project in this new directory.

cd src/frontend
yarn init

With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

yarn add richie-education

In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

"dependencies": {
"richie-education": "1.12.0"
},

Building the Javascript bundle

You are now ready to run your own frontend build. We'll just be using webpack directly.

yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

Here is everything that is happening:

  • yarn webpack — run the webpack CLI;
  • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
  • --output-path ./build — make sure we get our output where we need it to be;
  • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

You can now run your build to change frontend settings or override frontend components with your own.

Building the CSS

If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

mkdir -p src/frontend/scss
touch src/frontend/scss/_mains.scss

Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

@import "richie-education/scss/main";

You are now ready to run the CSS build:

cd src/frontend
yarn build-sass

This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

+ + \ No newline at end of file diff --git a/docs/1.14/contributing-guide/index.html b/docs/1.14/contributing-guide/index.html index fafe729797..3a37e354dc 100644 --- a/docs/1.14/contributing-guide/index.html +++ b/docs/1.14/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
-
Version: 1.14

Contributing guide

This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

We try to raise our code quality standards and expect contributors to follow the recommandations +

Version: 1.14

Contributing guide

This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

Checking your code

We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

$ make lint-back

We use strict eslint and prettier to check the validity of our frontend code:

$ make lint-front

Running tests

On the backend, we use pytest to run our test suite:

$ make test-back

On the frontend, we use karma to run our test suite:

$ make test-front

Running migrations

The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

$ make migrate

Handling new dependencies

Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

$ make bootstrap

Going further

To see all available commands, run:

$ make

We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

bin
├── exec
├── pylint
├── pytest
└── run

More details and tips & tricks can be found in our development with Docker documentation

- - + + \ No newline at end of file diff --git a/docs/1.14/css-guidelines/index.html b/docs/1.14/css-guidelines/index.html index bfcab16bf1..17a89f50ac 100644 --- a/docs/1.14/css-guidelines/index.html +++ b/docs/1.14/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
-
Version: 1.14

CSS Guidelines

The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

File structuration

Rules should be placed where their purpose is most apparent, and where they are easiest to find.

Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

Code structuration

In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

Following the BEM naming convention, we will write our classes as follows :

.block {}
.block__element {}
.block--modifier {}
  • .block represents the higher level of an abstraction or component.
  • .block__element represents a descendent of .block that helps form .block as a whole.
  • .block--modifier represents a different state or version of .block.

We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

Quick pointers

  • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
  • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
  • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
  • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
  • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

(Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

- - +
Version: 1.14

CSS Guidelines

The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

File structuration

Rules should be placed where their purpose is most apparent, and where they are easiest to find.

Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

Code structuration

In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

Following the BEM naming convention, we will write our classes as follows :

.block {}
.block__element {}
.block--modifier {}
  • .block represents the higher level of an abstraction or component.
  • .block__element represents a descendent of .block that helps form .block as a whole.
  • .block--modifier represents a different state or version of .block.

We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

Quick pointers

  • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
  • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
  • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
  • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
  • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

(Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

+ + \ No newline at end of file diff --git a/docs/1.14/discover/index.html b/docs/1.14/discover/index.html index 57ef657919..9b95ac5d1b 100644 --- a/docs/1.14/discover/index.html +++ b/docs/1.14/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
-
Version: 1.14

Getting started with Richie

If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

Login/password are admin/admin. The database is regularly flushed.

Architecture

Richie is a container-native application but can also be installed +

Version: 1.14

Getting started with Richie

If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

Login/password are admin/admin. The database is regularly flushed.

Architecture

Richie is a container-native application but can also be installed on your machine.

For development, the project is defined using a docker-compose file and consists of 4 services:

  • db: the Postgresql database,
  • elasticsearch: the search engine,
  • app: the actual DjangoCMS project with all our application code,
  • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -21,7 +21,7 @@ migration-related issues.

Now that your Docker services are ready to be used, start the full CMS by running:

$ make run

Adding content

Once the CMS is up and running, you can create a superuser account:

$ make superuser

You can create a basic demo site by running:

$ make demo-site

Note that if you don't create the demo site and start from a blank CMS, you will get some errors requesting you to create some required root pages. So it is easier as a first approach to test the CMS with the demo site.

You should be able to view the site at localhost:8070

- - + + \ No newline at end of file diff --git a/docs/1.14/django-react-interop/index.html b/docs/1.14/django-react-interop/index.html index a0f4610d45..8874edd73a 100644 --- a/docs/1.14/django-react-interop/index.html +++ b/docs/1.14/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
-
Version: 1.14

Connecting React components with Django

richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

Rendering components

We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

They use the BCP47/RFC5646 format.

<html lang="en-US">

Example

Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

<div
class="richie-react richie-react--featured-courses"
></div>

When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

Passing properties to components

Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

Example

Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

<div
class="richie-react richie-react--featured-courses"
data-props='{"categories": ["sociology", "anthropology"]}'
></div>

When the component is rendered, it will be passed a categories prop with the relevant categories.

Built-in components

Here are the React component that Richie comes with and uses out of the box.

<RootSearchSuggestField />

Renders a course search bar, like the one that appears in the default Search page.

Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

Props:

  • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
  • context [optional] — see context.

<Search />

Renders the full-page course search engine interface, including the search bar, search results, and filters pane.

NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

Props:

  • pageTitle [required] — title for the page, will be used inside the <h1> in the rendered component.
  • context [required] — see context.

<UserLogin />

Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

Props:

  • loginUrl [required] — the URL where the user is sent when they click on "Log in";
  • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
  • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

Context

All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

Here is the expected shape for this object:

{
assets: {
// SVG sprite used throughout Richie
icons: "/path/to/icons/sprite.svg"
}
}

Note that it might be expanded in further versions of Richie.

- - +
Version: 1.14

Connecting React components with Django

richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

Rendering components

We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

They use the BCP47/RFC5646 format.

<html lang="en-US">

Example

Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

<div
class="richie-react richie-react--featured-courses"
></div>

When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

Passing properties to components

Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

Example

Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

<div
class="richie-react richie-react--featured-courses"
data-props='{"categories": ["sociology", "anthropology"]}'
></div>

When the component is rendered, it will be passed a categories prop with the relevant categories.

Built-in components

Here are the React component that Richie comes with and uses out of the box.

<RootSearchSuggestField />

Renders a course search bar, like the one that appears in the default Search page.

Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

Props:

  • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
  • context [optional] — see context.

<Search />

Renders the full-page course search engine interface, including the search bar, search results, and filters pane.

NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

Props:

  • pageTitle [required] — title for the page, will be used inside the <h1> in the rendered component.
  • context [required] — see context.

<UserLogin />

Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

Props:

  • loginUrl [required] — the URL where the user is sent when they click on "Log in";
  • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
  • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

Context

All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

Here is the expected shape for this object:

{
assets: {
// SVG sprite used throughout Richie
icons: "/path/to/icons/sprite.svg"
}
}

Note that it might be expanded in further versions of Richie.

+ + \ No newline at end of file diff --git a/docs/1.14/docker-development/index.html b/docs/1.14/docker-development/index.html index 0c278383e1..7bee75cbcf 100644 --- a/docs/1.14/docker-development/index.html +++ b/docs/1.14/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
-
Version: 1.14

Developing Richie with Docker

Now that you have Richie up and running, you can start working with it.

Settings

Settings are defined using Django +

Version: 1.14

Developing Richie with Docker

Now that you have Richie up and running, you can start working with it.

Settings

Settings are defined using Django Configurations for different environments:

  • Development: settings for development on developers' local environment,
  • Test: settings used to run our test suite,
  • ContinousIntegration: settings used on the continuous integration platform,
  • Feature: settings for deployment of each developers' feature branches,
  • Staging: settings for deployment to the staging environment,
  • PreProduction: settings for deployment to the pre-production environment,
  • Production: settings for deployment to the production environment.

The Development environment is defined as the default environment.

Front-end tools

If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

# Start the Sass watcher
$ make watch-sass

# In a new terminal or session, start the TypeScript watcher
$ make watch-ts

Container control

You can stop/start/restart a container:

$ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

or stop/start/restart all containers in one command:

$ docker-compose [stop|start|restart]

Debugging

You can easily see the latest logs for a container:

$ docker-compose logs [app|postgresql|mysql|elasticsearch]

Or follow the stream of logs:

$ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

If you need to debug a running container, you can open a Linux shell with the @@ -28,7 +28,7 @@ file

Cleanup

If you work on the Docker configuration and make repeated modifications, remember to periodically clean the unused docker images and containers by running:

$ docker image prune
$ docker container prune

Troubleshooting

ElasticSearch service is always down

If your elasticsearch container fails at booting, checkout the logs via:

$ docker-compose logs elasticsearch

You may see entries similar to:

[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

In this case, increase virtual memory as follows (UNIX systems):

$ sudo sysctl -w vm/max_map_count=262144
- - + + \ No newline at end of file diff --git a/docs/1.14/native-installation/index.html b/docs/1.14/native-installation/index.html index 7d9f7fa2b1..c267418a93 100644 --- a/docs/1.14/native-installation/index.html +++ b/docs/1.14/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
-
Version: 1.14

Installing Richie on your machine

This document aims to list all needed steps to have a working Richie +

Version: 1.14

Installing Richie on your machine

This document aims to list all needed steps to have a working Richie installation on your laptop.

A better approach is to use Docker as explained in our guide for container-native instructions.

Installing a fresh server

Version

You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

npm run sass

Run server

Make sure your database is up-to-date before running the application the first time and after each modification to your models:

python sandbox/manage.py migrate

You can create a superuser account:

python sandbox/manage.py createsuperuser

Run the tests

python sandbox/manage.py test

You should now be able to start Django and view the site at localhost:8000

python sandbox/manage.py runserver
- - + + \ No newline at end of file diff --git a/docs/1.15/building-the-frontend/index.html b/docs/1.15/building-the-frontend/index.html index 65bf926908..bcdf763114 100644 --- a/docs/1.15/building-the-frontend/index.html +++ b/docs/1.15/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
-
Version: 1.15

Building Richie's frontend in your own project

Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

Installing richie-education

If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

mkdir -p src/frontend

Then, you need to bootstrap your own frontend project in this new directory.

cd src/frontend
yarn init

With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

yarn add richie-education

In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

"dependencies": {
"richie-education": "1.12.0"
},

Building the Javascript bundle

You are now ready to run your own frontend build. We'll just be using webpack directly.

yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

Here is everything that is happening:

  • yarn webpack — run the webpack CLI;
  • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
  • --output-path ./build — make sure we get our output where we need it to be;
  • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

You can now run your build to change frontend settings or override frontend components with your own.

Building the CSS

If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

mkdir -p src/frontend/scss
touch src/frontend/scss/_mains.scss

Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

@import "richie-education/scss/main";

You are now ready to run the CSS build:

cd src/frontend
yarn build-sass

This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

- - +
Version: 1.15

Building Richie's frontend in your own project

Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

Installing richie-education

If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

mkdir -p src/frontend

Then, you need to bootstrap your own frontend project in this new directory.

cd src/frontend
yarn init

With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

yarn add richie-education

In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

"dependencies": {
"richie-education": "1.12.0"
},

Building the Javascript bundle

You are now ready to run your own frontend build. We'll just be using webpack directly.

yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

Here is everything that is happening:

  • yarn webpack — run the webpack CLI;
  • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
  • --output-path ./build — make sure we get our output where we need it to be;
  • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

You can now run your build to change frontend settings or override frontend components with your own.

Building the CSS

If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

mkdir -p src/frontend/scss
touch src/frontend/scss/_mains.scss

Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

@import "richie-education/scss/main";

You are now ready to run the CSS build:

cd src/frontend
yarn build-sass

This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

+ + \ No newline at end of file diff --git a/docs/1.15/contributing-guide/index.html b/docs/1.15/contributing-guide/index.html index 0ea3230097..d82c2e93ca 100644 --- a/docs/1.15/contributing-guide/index.html +++ b/docs/1.15/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
-
Version: 1.15

Contributing guide

This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

We try to raise our code quality standards and expect contributors to follow the recommandations +

Version: 1.15

Contributing guide

This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

Checking your code

We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

$ make lint-back

We use strict eslint and prettier to check the validity of our frontend code:

$ make lint-front

Running tests

On the backend, we use pytest to run our test suite:

$ make test-back

On the frontend, we use karma to run our test suite:

$ make test-front

Running migrations

The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

$ make migrate

Handling new dependencies

Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

$ make bootstrap

Going further

To see all available commands, run:

$ make

We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

bin
├── exec
├── pylint
├── pytest
└── run

More details and tips & tricks can be found in our development with Docker documentation

- - + + \ No newline at end of file diff --git a/docs/1.15/css-guidelines/index.html b/docs/1.15/css-guidelines/index.html index 81d349c27e..beef8547a7 100644 --- a/docs/1.15/css-guidelines/index.html +++ b/docs/1.15/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
-
Version: 1.15

CSS Guidelines

The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

File structuration

Rules should be placed where their purpose is most apparent, and where they are easiest to find.

Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

Code structuration

In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

Following the BEM naming convention, we will write our classes as follows :

.block {}
.block__element {}
.block--modifier {}
  • .block represents the higher level of an abstraction or component.
  • .block__element represents a descendent of .block that helps form .block as a whole.
  • .block--modifier represents a different state or version of .block.

We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

Quick pointers

  • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
  • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
  • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
  • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
  • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

(Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

- - +
Version: 1.15

CSS Guidelines

The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

File structuration

Rules should be placed where their purpose is most apparent, and where they are easiest to find.

Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

Code structuration

In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

Following the BEM naming convention, we will write our classes as follows :

.block {}
.block__element {}
.block--modifier {}
  • .block represents the higher level of an abstraction or component.
  • .block__element represents a descendent of .block that helps form .block as a whole.
  • .block--modifier represents a different state or version of .block.

We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

Quick pointers

  • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
  • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
  • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
  • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
  • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

(Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

+ + \ No newline at end of file diff --git a/docs/1.15/discover/index.html b/docs/1.15/discover/index.html index 3d444ef007..26903015f8 100644 --- a/docs/1.15/discover/index.html +++ b/docs/1.15/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
-
Version: 1.15

Getting started with Richie

If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

Login/password are admin/admin. The database is regularly flushed.

Architecture

Richie is a container-native application but can also be installed +

Version: 1.15

Getting started with Richie

If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

Login/password are admin/admin. The database is regularly flushed.

Architecture

Richie is a container-native application but can also be installed on your machine.

For development, the project is defined using a docker-compose file and consists of 4 services:

  • db: the Postgresql database,
  • elasticsearch: the search engine,
  • app: the actual DjangoCMS project with all our application code,
  • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -21,7 +21,7 @@ migration-related issues.

Now that your Docker services are ready to be used, start the full CMS by running:

$ make run

Adding content

Once the CMS is up and running, you can create a superuser account:

$ make superuser

You can create a basic demo site by running:

$ make demo-site

Note that if you don't create the demo site and start from a blank CMS, you will get some errors requesting you to create some required root pages. So it is easier as a first approach to test the CMS with the demo site.

You should be able to view the site at localhost:8070

- - + + \ No newline at end of file diff --git a/docs/1.15/django-react-interop/index.html b/docs/1.15/django-react-interop/index.html index d7361e3dd6..8309d2da63 100644 --- a/docs/1.15/django-react-interop/index.html +++ b/docs/1.15/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
-
Version: 1.15

Connecting React components with Django

richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

Rendering components

We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

They use the BCP47/RFC5646 format.

<html lang="en-US">

Example

Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

<div
class="richie-react richie-react--featured-courses"
></div>

When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

Passing properties to components

Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

Example

Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

<div
class="richie-react richie-react--featured-courses"
data-props='{"categories": ["sociology", "anthropology"]}'
></div>

When the component is rendered, it will be passed a categories prop with the relevant categories.

Built-in components

Here are the React component that Richie comes with and uses out of the box.

<RootSearchSuggestField />

Renders a course search bar, like the one that appears in the default Search page.

Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

Props:

  • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
  • context [optional] — see context.

<Search />

Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

Props:

  • context [required] — see context.

<SearchSuggestField />

Renders the course search bar that interacts directly with <Search />.

It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

Props:

  • context [optional] — see context.

<UserLogin />

Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

Props:

  • loginUrl [required] — the URL where the user is sent when they click on "Log in";
  • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
  • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

Context

All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

Here is the expected shape for this object:

{
assets: {
// SVG sprite used throughout Richie
icons: "/path/to/icons/sprite.svg"
}
}

Note that it might be expanded in further versions of Richie.

- - +
Version: 1.15

Connecting React components with Django

richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

Rendering components

We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

They use the BCP47/RFC5646 format.

<html lang="en-US">

Example

Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

<div
class="richie-react richie-react--featured-courses"
></div>

When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

Passing properties to components

Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

Example

Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

<div
class="richie-react richie-react--featured-courses"
data-props='{"categories": ["sociology", "anthropology"]}'
></div>

When the component is rendered, it will be passed a categories prop with the relevant categories.

Built-in components

Here are the React component that Richie comes with and uses out of the box.

<RootSearchSuggestField />

Renders a course search bar, like the one that appears in the default Search page.

Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

Props:

  • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
  • context [optional] — see context.

<Search />

Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

Props:

  • context [required] — see context.

<SearchSuggestField />

Renders the course search bar that interacts directly with <Search />.

It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

Props:

  • context [optional] — see context.

<UserLogin />

Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

Props:

  • loginUrl [required] — the URL where the user is sent when they click on "Log in";
  • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
  • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

Context

All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

Here is the expected shape for this object:

{
assets: {
// SVG sprite used throughout Richie
icons: "/path/to/icons/sprite.svg"
}
}

Note that it might be expanded in further versions of Richie.

+ + \ No newline at end of file diff --git a/docs/1.15/docker-development/index.html b/docs/1.15/docker-development/index.html index 55d7e3ab47..7f05a7205f 100644 --- a/docs/1.15/docker-development/index.html +++ b/docs/1.15/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
-
Version: 1.15

Developing Richie with Docker

Now that you have Richie up and running, you can start working with it.

Settings

Settings are defined using Django +

Version: 1.15

Developing Richie with Docker

Now that you have Richie up and running, you can start working with it.

Settings

Settings are defined using Django Configurations for different environments:

  • Development: settings for development on developers' local environment,
  • Test: settings used to run our test suite,
  • ContinousIntegration: settings used on the continuous integration platform,
  • Feature: settings for deployment of each developers' feature branches,
  • Staging: settings for deployment to the staging environment,
  • PreProduction: settings for deployment to the pre-production environment,
  • Production: settings for deployment to the production environment.

The Development environment is defined as the default environment.

Front-end tools

If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

# Start the Sass watcher
$ make watch-sass

# In a new terminal or session, start the TypeScript watcher
$ make watch-ts

Container control

You can stop/start/restart a container:

$ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

or stop/start/restart all containers in one command:

$ docker-compose [stop|start|restart]

Debugging

You can easily see the latest logs for a container:

$ docker-compose logs [app|postgresql|mysql|elasticsearch]

Or follow the stream of logs:

$ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

If you need to debug a running container, you can open a Linux shell with the @@ -28,7 +28,7 @@ file

Cleanup

If you work on the Docker configuration and make repeated modifications, remember to periodically clean the unused docker images and containers by running:

$ docker image prune
$ docker container prune

Troubleshooting

ElasticSearch service is always down

If your elasticsearch container fails at booting, checkout the logs via:

$ docker-compose logs elasticsearch

You may see entries similar to:

[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

In this case, increase virtual memory as follows (UNIX systems):

$ sudo sysctl -w vm/max_map_count=262144
- - + + \ No newline at end of file diff --git a/docs/1.15/native-installation/index.html b/docs/1.15/native-installation/index.html index 175ef21177..9b1d8d3cff 100644 --- a/docs/1.15/native-installation/index.html +++ b/docs/1.15/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
-
Version: 1.15

Installing Richie on your machine

This document aims to list all needed steps to have a working Richie +

Version: 1.15

Installing Richie on your machine

This document aims to list all needed steps to have a working Richie installation on your laptop.

A better approach is to use Docker as explained in our guide for container-native instructions.

Installing a fresh server

Version

You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

npm run sass

Run server

Make sure your database is up-to-date before running the application the first time and after each modification to your models:

python sandbox/manage.py migrate

You can create a superuser account:

python sandbox/manage.py createsuperuser

Run the tests

python sandbox/manage.py test

You should now be able to start Django and view the site at localhost:8000

python sandbox/manage.py runserver
- - + + \ No newline at end of file diff --git a/docs/1.16/accessibility-testing/index.html b/docs/1.16/accessibility-testing/index.html index 73e68da385..f8db7574c6 100644 --- a/docs/1.16/accessibility-testing/index.html +++ b/docs/1.16/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
-
Version: 1.16

Automated accessibility checks

Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

Testing environment setup

Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

cd tests_e2e
yarn install

This should install everything you need.

Running the tests

There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

yarn cypress run

You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

yarn cypress open

This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

Documentation reference

- - +
Version: 1.16

Automated accessibility checks

Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

Testing environment setup

Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

cd tests_e2e
yarn install

This should install everything you need.

Running the tests

There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

yarn cypress run

You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

yarn cypress open

This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

Documentation reference

+ + \ No newline at end of file diff --git a/docs/1.16/building-the-frontend/index.html b/docs/1.16/building-the-frontend/index.html index 7219ff9e45..12ee4ce54a 100644 --- a/docs/1.16/building-the-frontend/index.html +++ b/docs/1.16/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
-
Version: 1.16

Building Richie's frontend in your own project

Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

Installing richie-education

If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

mkdir -p src/frontend

Then, you need to bootstrap your own frontend project in this new directory.

cd src/frontend
yarn init

With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

yarn add richie-education

In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

"dependencies": {
"richie-education": "1.12.0"
},

Building the Javascript bundle

You are now ready to run your own frontend build. We'll just be using webpack directly.

yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

Here is everything that is happening:

  • yarn webpack — run the webpack CLI;
  • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
  • --output-path ./build — make sure we get our output where we need it to be;
  • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

You can now run your build to change frontend settings or override frontend components with your own.

Building the CSS

If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

mkdir -p src/frontend/scss
touch src/frontend/scss/_mains.scss

Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

@import "richie-education/scss/main";

You are now ready to run the CSS build:

cd src/frontend
yarn build-sass

This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

- - +
Version: 1.16

Building Richie's frontend in your own project

Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

Installing richie-education

If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

mkdir -p src/frontend

Then, you need to bootstrap your own frontend project in this new directory.

cd src/frontend
yarn init

With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

yarn add richie-education

In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

"dependencies": {
"richie-education": "1.12.0"
},

Building the Javascript bundle

You are now ready to run your own frontend build. We'll just be using webpack directly.

yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

Here is everything that is happening:

  • yarn webpack — run the webpack CLI;
  • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
  • --output-path ./build — make sure we get our output where we need it to be;
  • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

You can now run your build to change frontend settings or override frontend components with your own.

Building the CSS

If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

mkdir -p src/frontend/scss
touch src/frontend/scss/_mains.scss

Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

@import "richie-education/scss/main";

You are now ready to run the CSS build:

cd src/frontend
yarn build-sass

This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

+ + \ No newline at end of file diff --git a/docs/1.16/contributing-guide/index.html b/docs/1.16/contributing-guide/index.html index 3b0f0b2ac0..55f4b0c378 100644 --- a/docs/1.16/contributing-guide/index.html +++ b/docs/1.16/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
-
Version: 1.16

Contributing guide

This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

We try to raise our code quality standards and expect contributors to follow the recommandations +

Version: 1.16

Contributing guide

This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

Checking your code

We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

$ make lint-back

We use strict eslint and prettier to check the validity of our frontend code:

$ make lint-front

Running tests

On the backend, we use pytest to run our test suite:

$ make test-back

On the frontend, we use karma to run our test suite:

$ make test-front

Running migrations

The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

$ make migrate

Handling new dependencies

Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

$ make bootstrap

Going further

To see all available commands, run:

$ make

We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

bin
├── exec
├── pylint
├── pytest
└── run

More details and tips & tricks can be found in our development with Docker documentation

- - + + \ No newline at end of file diff --git a/docs/1.16/css-guidelines/index.html b/docs/1.16/css-guidelines/index.html index 9ddff25a92..037cfed9ea 100644 --- a/docs/1.16/css-guidelines/index.html +++ b/docs/1.16/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
-
Version: 1.16

CSS Guidelines

The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

File structuration

Rules should be placed where their purpose is most apparent, and where they are easiest to find.

Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

Code structuration

In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

Following the BEM naming convention, we will write our classes as follows :

.block {}
.block__element {}
.block--modifier {}
  • .block represents the higher level of an abstraction or component.
  • .block__element represents a descendent of .block that helps form .block as a whole.
  • .block--modifier represents a different state or version of .block.

We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

Quick pointers

  • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
  • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
  • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
  • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
  • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

(Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

- - +
Version: 1.16

CSS Guidelines

The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

File structuration

Rules should be placed where their purpose is most apparent, and where they are easiest to find.

Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

Code structuration

In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

Following the BEM naming convention, we will write our classes as follows :

.block {}
.block__element {}
.block--modifier {}
  • .block represents the higher level of an abstraction or component.
  • .block__element represents a descendent of .block that helps form .block as a whole.
  • .block--modifier represents a different state or version of .block.

We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

Quick pointers

  • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
  • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
  • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
  • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
  • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

(Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

+ + \ No newline at end of file diff --git a/docs/1.16/discover/index.html b/docs/1.16/discover/index.html index 61191470d6..98893aa0e0 100644 --- a/docs/1.16/discover/index.html +++ b/docs/1.16/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
-
Version: 1.16

Getting started with Richie

If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

Login/password are admin/admin. The database is regularly flushed.

Architecture

Richie is a container-native application but can also be installed +

Version: 1.16

Getting started with Richie

If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

Login/password are admin/admin. The database is regularly flushed.

Architecture

Richie is a container-native application but can also be installed on your machine.

For development, the project is defined using a docker-compose file and consists of 4 services:

  • db: the Postgresql database,
  • elasticsearch: the search engine,
  • app: the actual DjangoCMS project with all our application code,
  • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -21,7 +21,7 @@ migration-related issues.

Now that your Docker services are ready to be used, start the full CMS by running:

$ make run

Adding content

Once the CMS is up and running, you can create a superuser account:

$ make superuser

You can create a basic demo site by running:

$ make demo-site

Note that if you don't create the demo site and start from a blank CMS, you will get some errors requesting you to create some required root pages. So it is easier as a first approach to test the CMS with the demo site.

You should be able to view the site at localhost:8070

- - + + \ No newline at end of file diff --git a/docs/1.16/django-react-interop/index.html b/docs/1.16/django-react-interop/index.html index 67e94f8adb..b81a5d3e5b 100644 --- a/docs/1.16/django-react-interop/index.html +++ b/docs/1.16/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
-
Version: 1.16

Connecting React components with Django

richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

Rendering components

We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

They use the BCP47/RFC5646 format.

<html lang="en-US">

Example

Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

<div
class="richie-react richie-react--featured-courses"
></div>

When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

Passing properties to components

Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

Example

Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

<div
class="richie-react richie-react--featured-courses"
data-props='{"categories": ["sociology", "anthropology"]}'
></div>

When the component is rendered, it will be passed a categories prop with the relevant categories.

Built-in components

Here are the React component that Richie comes with and uses out of the box.

<RootSearchSuggestField />

Renders a course search bar, like the one that appears in the default Search page.

Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

Props:

  • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
  • context [required] — see context.

<Search />

Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

Props:

  • context [required] — see context.

<SearchSuggestField />

Renders the course search bar that interacts directly with <Search />.

It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

Props:

  • context [required] — see context.

<UserLogin />

Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

Props:

  • loginUrl [required] — the URL where the user is sent when they click on "Log in";
  • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
  • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

Context

All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

Here is the expected shape for this object:

{
assets: {
// SVG sprite used throughout Richie
icons: "/path/to/icons/sprite.svg"
}
}

Note that it might be expanded in further versions of Richie.

- - +
Version: 1.16

Connecting React components with Django

richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

Rendering components

We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

They use the BCP47/RFC5646 format.

<html lang="en-US">

Example

Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

<div
class="richie-react richie-react--featured-courses"
></div>

When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

Passing properties to components

Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

Example

Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

<div
class="richie-react richie-react--featured-courses"
data-props='{"categories": ["sociology", "anthropology"]}'
></div>

When the component is rendered, it will be passed a categories prop with the relevant categories.

Built-in components

Here are the React component that Richie comes with and uses out of the box.

<RootSearchSuggestField />

Renders a course search bar, like the one that appears in the default Search page.

Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

Props:

  • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
  • context [required] — see context.

<Search />

Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

Props:

  • context [required] — see context.

<SearchSuggestField />

Renders the course search bar that interacts directly with <Search />.

It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

Props:

  • context [required] — see context.

<UserLogin />

Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

Props:

  • loginUrl [required] — the URL where the user is sent when they click on "Log in";
  • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
  • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

Context

All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

Here is the expected shape for this object:

{
assets: {
// SVG sprite used throughout Richie
icons: "/path/to/icons/sprite.svg"
}
}

Note that it might be expanded in further versions of Richie.

+ + \ No newline at end of file diff --git a/docs/1.16/docker-development/index.html b/docs/1.16/docker-development/index.html index d9eae27342..d19331fb40 100644 --- a/docs/1.16/docker-development/index.html +++ b/docs/1.16/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
-
Version: 1.16

Developing Richie with Docker

Now that you have Richie up and running, you can start working with it.

Settings

Settings are defined using Django +

Version: 1.16

Developing Richie with Docker

Now that you have Richie up and running, you can start working with it.

Settings

Settings are defined using Django Configurations for different environments:

  • Development: settings for development on developers' local environment,
  • Test: settings used to run our test suite,
  • ContinousIntegration: settings used on the continuous integration platform,
  • Feature: settings for deployment of each developers' feature branches,
  • Staging: settings for deployment to the staging environment,
  • PreProduction: settings for deployment to the pre-production environment,
  • Production: settings for deployment to the production environment.

The Development environment is defined as the default environment.

Front-end tools

If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

# Start the Sass watcher
$ make watch-sass

# In a new terminal or session, start the TypeScript watcher
$ make watch-ts

Container control

You can stop/start/restart a container:

$ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

or stop/start/restart all containers in one command:

$ docker-compose [stop|start|restart]

Debugging

You can easily see the latest logs for a container:

$ docker-compose logs [app|postgresql|mysql|elasticsearch]

Or follow the stream of logs:

$ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

If you need to debug a running container, you can open a Linux shell with the @@ -28,7 +28,7 @@ file

Cleanup

If you work on the Docker configuration and make repeated modifications, remember to periodically clean the unused docker images and containers by running:

$ docker image prune
$ docker container prune

Troubleshooting

ElasticSearch service is always down

If your elasticsearch container fails at booting, checkout the logs via:

$ docker-compose logs elasticsearch

You may see entries similar to:

[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

In this case, increase virtual memory as follows (UNIX systems):

$ sudo sysctl -w vm/max_map_count=262144
- - + + \ No newline at end of file diff --git a/docs/1.16/native-installation/index.html b/docs/1.16/native-installation/index.html index d61db0e412..304ec2df9f 100644 --- a/docs/1.16/native-installation/index.html +++ b/docs/1.16/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
-
Version: 1.16

Installing Richie on your machine

This document aims to list all needed steps to have a working Richie +

Version: 1.16

Installing Richie on your machine

This document aims to list all needed steps to have a working Richie installation on your laptop.

A better approach is to use Docker as explained in our guide for container-native instructions.

Installing a fresh server

Version

You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

npm run sass

Run server

Make sure your database is up-to-date before running the application the first time and after each modification to your models:

python sandbox/manage.py migrate

You can create a superuser account:

python sandbox/manage.py createsuperuser

Run the tests

python sandbox/manage.py test

You should now be able to start Django and view the site at localhost:8000

python sandbox/manage.py runserver
- - + + \ No newline at end of file diff --git a/docs/1.17/accessibility-testing/index.html b/docs/1.17/accessibility-testing/index.html index 38fde78c4c..81e9d57fe1 100644 --- a/docs/1.17/accessibility-testing/index.html +++ b/docs/1.17/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
-
Version: 1.17

Automated accessibility checks

Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

Testing environment setup

Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

cd tests_e2e
yarn install

This should install everything you need.

Running the tests

There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

yarn cypress run

You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

yarn cypress open

This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

Documentation reference

- - +
Version: 1.17

Automated accessibility checks

Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

Testing environment setup

Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

cd tests_e2e
yarn install

This should install everything you need.

Running the tests

There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

yarn cypress run

You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

yarn cypress open

This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

Documentation reference

+ + \ No newline at end of file diff --git a/docs/1.17/building-the-frontend/index.html b/docs/1.17/building-the-frontend/index.html index 4aabaeb21d..03ecd25f19 100644 --- a/docs/1.17/building-the-frontend/index.html +++ b/docs/1.17/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
-
Version: 1.17

Building Richie's frontend in your own project

Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

Installing richie-education

If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

mkdir -p src/frontend

Then, you need to bootstrap your own frontend project in this new directory.

cd src/frontend
yarn init

With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

yarn add richie-education

In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

"dependencies": {
"richie-education": "1.12.0"
},

Building the Javascript bundle

You are now ready to run your own frontend build. We'll just be using webpack directly.

yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

Here is everything that is happening:

  • yarn webpack — run the webpack CLI;
  • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
  • --output-path ./build — make sure we get our output where we need it to be;
  • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

You can now run your build to change frontend settings or override frontend components with your own.

Building the CSS

If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

mkdir -p src/frontend/scss
touch src/frontend/scss/_mains.scss

Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

@import "richie-education/scss/main";

You are now ready to run the CSS build:

cd src/frontend
yarn build-sass

This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

- - +
Version: 1.17

Building Richie's frontend in your own project

Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

Installing richie-education

If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

mkdir -p src/frontend

Then, you need to bootstrap your own frontend project in this new directory.

cd src/frontend
yarn init

With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

yarn add richie-education

In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

"dependencies": {
"richie-education": "1.12.0"
},

Building the Javascript bundle

You are now ready to run your own frontend build. We'll just be using webpack directly.

yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

Here is everything that is happening:

  • yarn webpack — run the webpack CLI;
  • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
  • --output-path ./build — make sure we get our output where we need it to be;
  • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

You can now run your build to change frontend settings or override frontend components with your own.

Building the CSS

If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

mkdir -p src/frontend/scss
touch src/frontend/scss/_mains.scss

Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

@import "richie-education/scss/main";

You are now ready to run the CSS build:

cd src/frontend
yarn build-sass

This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

+ + \ No newline at end of file diff --git a/docs/1.17/contributing-guide/index.html b/docs/1.17/contributing-guide/index.html index 9f2c3ead19..93d2326438 100644 --- a/docs/1.17/contributing-guide/index.html +++ b/docs/1.17/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
-
Version: 1.17

Contributing guide

This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

We try to raise our code quality standards and expect contributors to follow the recommandations +

Version: 1.17

Contributing guide

This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

Checking your code

We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

$ make lint-back

We use strict eslint and prettier to check the validity of our frontend code:

$ make lint-front

Running tests

On the backend, we use pytest to run our test suite:

$ make test-back

On the frontend, we use karma to run our test suite:

$ make test-front

Running migrations

The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

$ make migrate

Handling new dependencies

Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

$ make bootstrap

Going further

To see all available commands, run:

$ make

We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

bin
├── exec
├── pylint
├── pytest
└── run

More details and tips & tricks can be found in our development with Docker documentation

- - + + \ No newline at end of file diff --git a/docs/1.17/css-guidelines/index.html b/docs/1.17/css-guidelines/index.html index b4b51eaadc..eebdae65d9 100644 --- a/docs/1.17/css-guidelines/index.html +++ b/docs/1.17/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
-
Version: 1.17

CSS Guidelines

The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

File structuration

Rules should be placed where their purpose is most apparent, and where they are easiest to find.

Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

Code structuration

In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

Following the BEM naming convention, we will write our classes as follows :

.block {}
.block__element {}
.block--modifier {}
  • .block represents the higher level of an abstraction or component.
  • .block__element represents a descendent of .block that helps form .block as a whole.
  • .block--modifier represents a different state or version of .block.

We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

Quick pointers

  • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
  • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
  • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
  • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
  • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

(Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

- - +
Version: 1.17

CSS Guidelines

The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

File structuration

Rules should be placed where their purpose is most apparent, and where they are easiest to find.

Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

Code structuration

In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

Following the BEM naming convention, we will write our classes as follows :

.block {}
.block__element {}
.block--modifier {}
  • .block represents the higher level of an abstraction or component.
  • .block__element represents a descendent of .block that helps form .block as a whole.
  • .block--modifier represents a different state or version of .block.

We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

Quick pointers

  • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
  • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
  • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
  • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
  • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

(Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

+ + \ No newline at end of file diff --git a/docs/1.17/discover/index.html b/docs/1.17/discover/index.html index 3a0640acab..a39ea483b2 100644 --- a/docs/1.17/discover/index.html +++ b/docs/1.17/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
-
Version: 1.17

Getting started with Richie

If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

Login/password are admin/admin. The database is regularly flushed.

Architecture

Richie is a container-native application but can also be installed +

Version: 1.17

Getting started with Richie

If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

Login/password are admin/admin. The database is regularly flushed.

Architecture

Richie is a container-native application but can also be installed on your machine.

For development, the project is defined using a docker-compose file and consists of 4 services:

  • db: the Postgresql database,
  • elasticsearch: the search engine,
  • app: the actual DjangoCMS project with all our application code,
  • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -21,7 +21,7 @@ migration-related issues.

Now that your Docker services are ready to be used, start the full CMS by running:

$ make run

Adding content

Once the CMS is up and running, you can create a superuser account:

$ make superuser

You can create a basic demo site by running:

$ make demo-site

Note that if you don't create the demo site and start from a blank CMS, you will get some errors requesting you to create some required root pages. So it is easier as a first approach to test the CMS with the demo site.

You should be able to view the site at localhost:8070

- - + + \ No newline at end of file diff --git a/docs/1.17/django-react-interop/index.html b/docs/1.17/django-react-interop/index.html index 076f55a5d8..d141506c50 100644 --- a/docs/1.17/django-react-interop/index.html +++ b/docs/1.17/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
-
Version: 1.17

Connecting React components with Django

richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

Rendering components

We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

They use the BCP47/RFC5646 format.

<html lang="en-US">

Example

Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

<div
class="richie-react richie-react--featured-courses"
></div>

When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

Passing properties to components

Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

Example

Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

<div
class="richie-react richie-react--featured-courses"
data-props='{"categories": ["sociology", "anthropology"]}'
></div>

When the component is rendered, it will be passed a categories prop with the relevant categories.

Built-in components

Here are the React component that Richie comes with and uses out of the box.

<RootSearchSuggestField />

Renders a course search bar, like the one that appears in the default Search page.

Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

Props:

  • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
  • context [required] — see context.

<Search />

Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

Props:

  • context [required] — see context.

<SearchSuggestField />

Renders the course search bar that interacts directly with <Search />.

It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

Props:

  • context [required] — see context.

<UserLogin />

Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

Props:

  • loginUrl [required] — the URL where the user is sent when they click on "Log in";
  • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
  • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

Context

All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

Here is the expected shape for this object:

{
assets: {
// SVG sprite used throughout Richie
icons: "/path/to/icons/sprite.svg"
}
}

Note that it might be expanded in further versions of Richie.

- - +
Version: 1.17

Connecting React components with Django

richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

Rendering components

We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

They use the BCP47/RFC5646 format.

<html lang="en-US">

Example

Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

<div
class="richie-react richie-react--featured-courses"
></div>

When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

Passing properties to components

Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

Example

Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

<div
class="richie-react richie-react--featured-courses"
data-props='{"categories": ["sociology", "anthropology"]}'
></div>

When the component is rendered, it will be passed a categories prop with the relevant categories.

Built-in components

Here are the React component that Richie comes with and uses out of the box.

<RootSearchSuggestField />

Renders a course search bar, like the one that appears in the default Search page.

Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

Props:

  • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
  • context [required] — see context.

<Search />

Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

Props:

  • context [required] — see context.

<SearchSuggestField />

Renders the course search bar that interacts directly with <Search />.

It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

Props:

  • context [required] — see context.

<UserLogin />

Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

Props:

  • loginUrl [required] — the URL where the user is sent when they click on "Log in";
  • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
  • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

Context

All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

Here is the expected shape for this object:

{
assets: {
// SVG sprite used throughout Richie
icons: "/path/to/icons/sprite.svg"
}
}

Note that it might be expanded in further versions of Richie.

+ + \ No newline at end of file diff --git a/docs/1.17/docker-development/index.html b/docs/1.17/docker-development/index.html index 00138316ae..cec1b53db8 100644 --- a/docs/1.17/docker-development/index.html +++ b/docs/1.17/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
-
Version: 1.17

Developing Richie with Docker

Now that you have Richie up and running, you can start working with it.

Settings

Settings are defined using Django +

Version: 1.17

Developing Richie with Docker

Now that you have Richie up and running, you can start working with it.

Settings

Settings are defined using Django Configurations for different environments:

  • Development: settings for development on developers' local environment,
  • Test: settings used to run our test suite,
  • ContinousIntegration: settings used on the continuous integration platform,
  • Feature: settings for deployment of each developers' feature branches,
  • Staging: settings for deployment to the staging environment,
  • PreProduction: settings for deployment to the pre-production environment,
  • Production: settings for deployment to the production environment.

The Development environment is defined as the default environment.

Front-end tools

If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

# Start the Sass watcher
$ make watch-sass

# In a new terminal or session, start the TypeScript watcher
$ make watch-ts

Container control

You can stop/start/restart a container:

$ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

or stop/start/restart all containers in one command:

$ docker-compose [stop|start|restart]

Debugging

You can easily see the latest logs for a container:

$ docker-compose logs [app|postgresql|mysql|elasticsearch]

Or follow the stream of logs:

$ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

If you need to debug a running container, you can open a Linux shell with the @@ -28,7 +28,7 @@ file

Cleanup

If you work on the Docker configuration and make repeated modifications, remember to periodically clean the unused docker images and containers by running:

$ docker image prune
$ docker container prune

Troubleshooting

ElasticSearch service is always down

If your elasticsearch container fails at booting, checkout the logs via:

$ docker-compose logs elasticsearch

You may see entries similar to:

[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

In this case, increase virtual memory as follows (UNIX systems):

$ sudo sysctl -w vm/max_map_count=262144
- - + + \ No newline at end of file diff --git a/docs/1.17/native-installation/index.html b/docs/1.17/native-installation/index.html index 68e5ebb08e..38fab6bfe5 100644 --- a/docs/1.17/native-installation/index.html +++ b/docs/1.17/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
-
Version: 1.17

Installing Richie on your machine

This document aims to list all needed steps to have a working Richie +

Version: 1.17

Installing Richie on your machine

This document aims to list all needed steps to have a working Richie installation on your laptop.

A better approach is to use Docker as explained in our guide for container-native instructions.

Installing a fresh server

Version

You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

npm run sass

Run server

Make sure your database is up-to-date before running the application the first time and after each modification to your models:

python sandbox/manage.py migrate

You can create a superuser account:

python sandbox/manage.py createsuperuser

Run the tests

python sandbox/manage.py test

You should now be able to start Django and view the site at localhost:8000

python sandbox/manage.py runserver
- - + + \ No newline at end of file diff --git a/docs/2.0.0/accessibility-testing/index.html b/docs/2.0.0/accessibility-testing/index.html index 8ec22bdc1f..0050d65678 100644 --- a/docs/2.0.0/accessibility-testing/index.html +++ b/docs/2.0.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
-
Version: 2.0.0

Automated accessibility checks

Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

Testing environment setup

Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

cd tests_e2e
yarn install

This should install everything you need.

Running the tests

There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

yarn cypress run

You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

yarn cypress open

This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

Documentation reference

- - +
Version: 2.0.0

Automated accessibility checks

Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

Testing environment setup

Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

cd tests_e2e
yarn install

This should install everything you need.

Running the tests

There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

yarn cypress run

You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

yarn cypress open

This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

Documentation reference

+ + \ No newline at end of file diff --git a/docs/2.0.0/building-the-frontend/index.html b/docs/2.0.0/building-the-frontend/index.html index 470ae9b4b2..c4358f0bbe 100644 --- a/docs/2.0.0/building-the-frontend/index.html +++ b/docs/2.0.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
-
Version: 2.0.0

Building Richie's frontend in your own project

Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

Installing richie-education

If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

mkdir -p src/frontend

Then, you need to bootstrap your own frontend project in this new directory.

cd src/frontend
yarn init

With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

yarn add richie-education

In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

"dependencies": {
"richie-education": "1.12.0"
},

Building the Javascript bundle

You are now ready to run your own frontend build. We'll just be using webpack directly.

yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

Here is everything that is happening:

  • yarn webpack — run the webpack CLI;
  • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
  • --output-path ./build — make sure we get our output where we need it to be;
  • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

You can now run your build to change frontend settings or override frontend components with your own.

Building the CSS

If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

mkdir -p src/frontend/scss
touch src/frontend/scss/_mains.scss

Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

@import "richie-education/scss/main";

You are now ready to run the CSS build:

cd src/frontend
yarn build-sass

This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

- - +
Version: 2.0.0

Building Richie's frontend in your own project

Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

Installing richie-education

If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

mkdir -p src/frontend

Then, you need to bootstrap your own frontend project in this new directory.

cd src/frontend
yarn init

With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

yarn add richie-education

In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

"dependencies": {
"richie-education": "1.12.0"
},

Building the Javascript bundle

You are now ready to run your own frontend build. We'll just be using webpack directly.

yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

Here is everything that is happening:

  • yarn webpack — run the webpack CLI;
  • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
  • --output-path ./build — make sure we get our output where we need it to be;
  • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

You can now run your build to change frontend settings or override frontend components with your own.

Building the CSS

If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

mkdir -p src/frontend/scss
touch src/frontend/scss/_mains.scss

Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

@import "richie-education/scss/main";

You are now ready to run the CSS build:

cd src/frontend
yarn build-sass

This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

+ + \ No newline at end of file diff --git a/docs/2.0.0/contributing-guide/index.html b/docs/2.0.0/contributing-guide/index.html index 31d83cb6bc..1a2141b90a 100644 --- a/docs/2.0.0/contributing-guide/index.html +++ b/docs/2.0.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
-
Version: 2.0.0

Contributing guide

This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

We try to raise our code quality standards and expect contributors to follow the recommandations +

Version: 2.0.0

Contributing guide

This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

Checking your code

We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

$ make lint-back

We use strict eslint and prettier to check the validity of our frontend code:

$ make lint-front

Running tests

On the backend, we use pytest to run our test suite:

$ make test-back

On the frontend, we use karma to run our test suite:

$ make test-front

Running migrations

The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

$ make migrate

Handling new dependencies

Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

$ make bootstrap

Going further

To see all available commands, run:

$ make

We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

bin
├── exec
├── pylint
├── pytest
└── run

More details and tips & tricks can be found in our development with Docker documentation

- - + + \ No newline at end of file diff --git a/docs/2.0.0/css-guidelines/index.html b/docs/2.0.0/css-guidelines/index.html index 672574c962..da8ced3656 100644 --- a/docs/2.0.0/css-guidelines/index.html +++ b/docs/2.0.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
-
Version: 2.0.0

CSS Guidelines

The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

File structuration

Rules should be placed where their purpose is most apparent, and where they are easiest to find.

Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

Code structuration

In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

Following the BEM naming convention, we will write our classes as follows :

.block {}
.block__element {}
.block--modifier {}
  • .block represents the higher level of an abstraction or component.
  • .block__element represents a descendent of .block that helps form .block as a whole.
  • .block--modifier represents a different state or version of .block.

We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

Quick pointers

  • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
  • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
  • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
  • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
  • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

(Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

- - +
Version: 2.0.0

CSS Guidelines

The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

File structuration

Rules should be placed where their purpose is most apparent, and where they are easiest to find.

Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

Code structuration

In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

Following the BEM naming convention, we will write our classes as follows :

.block {}
.block__element {}
.block--modifier {}
  • .block represents the higher level of an abstraction or component.
  • .block__element represents a descendent of .block that helps form .block as a whole.
  • .block--modifier represents a different state or version of .block.

We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

Quick pointers

  • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
  • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
  • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
  • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
  • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

(Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

+ + \ No newline at end of file diff --git a/docs/2.0.0/discover/index.html b/docs/2.0.0/discover/index.html index e0c3f8196d..1f87c3887a 100644 --- a/docs/2.0.0/discover/index.html +++ b/docs/2.0.0/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
-
Version: 2.0.0

Getting started with Richie

If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

Login/password are admin/admin. The database is regularly flushed.

Architecture

Richie is a container-native application but can also be installed +

Version: 2.0.0

Getting started with Richie

If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

Login/password are admin/admin. The database is regularly flushed.

Architecture

Richie is a container-native application but can also be installed on your machine.

For development, the project is defined using a docker-compose file and consists of 4 services:

  • db: the Postgresql database,
  • elasticsearch: the search engine,
  • app: the actual DjangoCMS project with all our application code,
  • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -27,7 +27,7 @@ to bootstrap an instance.

Just start apps with make run.

Richie should respond on http://localhost:8070 and OpenEdx on http://localhost:8073.

Advanced - Connecting Richie to OpenEdx

If you want users to enroll on courses in OpenEdx directly from Richie via API calls, you should read the advanced guide to connect Richie to OpenEdx over TLS.

- - + + \ No newline at end of file diff --git a/docs/2.0.0/django-react-interop/index.html b/docs/2.0.0/django-react-interop/index.html index aaf1372d4e..ed13295eab 100644 --- a/docs/2.0.0/django-react-interop/index.html +++ b/docs/2.0.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
-
Version: 2.0.0

Connecting React components with Django

richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

Rendering components

We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

They use the BCP47/RFC5646 format.

<html lang="en-US">

Example

Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

<div
class="richie-react richie-react--featured-courses"
></div>

When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

Passing properties to components

Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

Example

Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

<div
class="richie-react richie-react--featured-courses"
data-props='{"categories": ["sociology", "anthropology"]}'
></div>

When the component is rendered, it will be passed a categories prop with the relevant categories.

Built-in components

Here are the React component that Richie comes with and uses out of the box.

<RootSearchSuggestField />

Renders a course search bar, like the one that appears in the default Search page.

Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

Props:

  • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
  • context [required] — see context.

<Search />

Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

Props:

  • context [required] — see context.

<SearchSuggestField />

Renders the course search bar that interacts directly with <Search />.

It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

Props:

  • context [required] — see context.

<UserLogin />

Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

Props:

  • loginUrl [required] — the URL where the user is sent when they click on "Log in";
  • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
  • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

Context

All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

Here is the expected shape for this object:

{
assets: {
// SVG sprite used throughout Richie
icons: "/path/to/icons/sprite.svg"
}
}

Note that it might be expanded in further versions of Richie.

- - +
Version: 2.0.0

Connecting React components with Django

richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

Rendering components

We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

They use the BCP47/RFC5646 format.

<html lang="en-US">

Example

Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

<div
class="richie-react richie-react--featured-courses"
></div>

When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

Passing properties to components

Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

Example

Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

<div
class="richie-react richie-react--featured-courses"
data-props='{"categories": ["sociology", "anthropology"]}'
></div>

When the component is rendered, it will be passed a categories prop with the relevant categories.

Built-in components

Here are the React component that Richie comes with and uses out of the box.

<RootSearchSuggestField />

Renders a course search bar, like the one that appears in the default Search page.

Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

Props:

  • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
  • context [required] — see context.

<Search />

Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

Props:

  • context [required] — see context.

<SearchSuggestField />

Renders the course search bar that interacts directly with <Search />.

It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

Props:

  • context [required] — see context.

<UserLogin />

Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

Props:

  • loginUrl [required] — the URL where the user is sent when they click on "Log in";
  • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
  • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

Context

All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

Here is the expected shape for this object:

{
assets: {
// SVG sprite used throughout Richie
icons: "/path/to/icons/sprite.svg"
}
}

Note that it might be expanded in further versions of Richie.

+ + \ No newline at end of file diff --git a/docs/2.0.0/docker-development/index.html b/docs/2.0.0/docker-development/index.html index a61f7aa620..52b07bad15 100644 --- a/docs/2.0.0/docker-development/index.html +++ b/docs/2.0.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
-
Version: 2.0.0

Developing Richie with Docker

Now that you have Richie up and running, you can start working with it.

Settings

Settings are defined using Django +

Version: 2.0.0

Developing Richie with Docker

Now that you have Richie up and running, you can start working with it.

Settings

Settings are defined using Django Configurations for different environments:

  • Development: settings for development on developers' local environment,
  • Test: settings used to run our test suite,
  • ContinousIntegration: settings used on the continuous integration platform,
  • Feature: settings for deployment of each developers' feature branches,
  • Staging: settings for deployment to the staging environment,
  • PreProduction: settings for deployment to the pre-production environment,
  • Production: settings for deployment to the production environment.

The Development environment is defined as the default environment.

Front-end tools

If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

# Start the Sass watcher
$ make watch-sass

# In a new terminal or session, start the TypeScript watcher
$ make watch-ts

Container control

You can stop/start/restart a container:

$ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

or stop/start/restart all containers in one command:

$ docker-compose [stop|start|restart]

Debugging

You can easily see the latest logs for a container:

$ docker-compose logs [app|postgresql|mysql|elasticsearch]

Or follow the stream of logs:

$ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

$ docker image prune
$ docker container prune

Troubleshooting

ElasticSearch service is always down

If your elasticsearch container fails at booting, checkout the logs via:

$ docker-compose logs elasticsearch

You may see entries similar to:

[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

In this case, increase virtual memory as follows (UNIX systems):

$ sudo sysctl -w vm/max_map_count=262144

This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

vm.max_map_count=262144
- - + + \ No newline at end of file diff --git a/docs/2.0.0/frontend-overrides/index.html b/docs/2.0.0/frontend-overrides/index.html index a696885ae8..e39498024f 100644 --- a/docs/2.0.0/frontend-overrides/index.html +++ b/docs/2.0.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
-
Version: 2.0.0

Overriding frontend components

Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

Defining your overrides

Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

Currently, it is only possible to override components. Richie's build is only set up to handle them.

Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

{
"overrides": {
"CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
}
}

Building a component override

As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

For example, if our component to override was the following:

export interface CourseGlimpseProps {
course: Course;
context: { someProp: string };
}

export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
// Whatever happens in this component
return <p>The glimpse</p>;
};

Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

Override translation

When you create an application based on richie, you can encounter two cases about translations:

  1. You created or overrode a react component and created new translation keys
  2. You just want to override a translation in an existing richie component

Create new translation keys

Once you created your new component with its translation keys, you have to extract them with the following command:

  formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

  node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

Override an existing translation key

As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

Richie uses one file per language. Currently 4 languages supported:

  • English: filename is en-US.json
  • French: filename is fr-FR.json
  • Canadian french: filename is fr-CA.json
  • Spanish: filename is es-ES.json

For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

{
"components.UserLogin.logIn": {
"description": "Overriden text for the login button.",
"message": "Authentication"
},
}

Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

  node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

- - +
Version: 2.0.0

Overriding frontend components

Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

Defining your overrides

Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

Currently, it is only possible to override components. Richie's build is only set up to handle them.

Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

{
"overrides": {
"CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
}
}

Building a component override

As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

For example, if our component to override was the following:

export interface CourseGlimpseProps {
course: Course;
context: { someProp: string };
}

export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
// Whatever happens in this component
return <p>The glimpse</p>;
};

Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

Override translation

When you create an application based on richie, you can encounter two cases about translations:

  1. You created or overrode a react component and created new translation keys
  2. You just want to override a translation in an existing richie component

Create new translation keys

Once you created your new component with its translation keys, you have to extract them with the following command:

  formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

  node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

Override an existing translation key

As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

Richie uses one file per language. Currently 4 languages supported:

  • English: filename is en-US.json
  • French: filename is fr-FR.json
  • Canadian french: filename is fr-CA.json
  • Spanish: filename is es-ES.json

For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

{
"components.UserLogin.logIn": {
"description": "Overriden text for the login button.",
"message": "Authentication"
},
}

Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

  node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

+ + \ No newline at end of file diff --git a/docs/2.0.0/lms-connection/index.html b/docs/2.0.0/lms-connection/index.html index 625fdd68ee..abf3d8cd38 100644 --- a/docs/2.0.0/lms-connection/index.html +++ b/docs/2.0.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with an LMS | Richie - - + +
-
Version: 2.0.0

Connecting Richie with an LMS

richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle +

Version: 2.0.0

Connecting Richie with an LMS

richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle or Canvas for a seamless experience between browsing the course catalog on richie and following the course itself on the LMS.

In order to connect richie with a LMS, there is an API bridge to synchronize course information and enrollments.

API bridge

The APIHandler utility acts as a proxy that routes queries to the correct LMS backend API, @@ -43,7 +43,7 @@ on https://richie.local.dev:8070 without browser warning about the certificate validity.

You need to follow these steps once. If you want to use SSL later, just use make run-ssl to run OpenEdx and Richie apps. Of course, you can still run apps without ssl by using make run.

- - + + \ No newline at end of file diff --git a/docs/2.0.0/native-installation/index.html b/docs/2.0.0/native-installation/index.html index 73a41d3a6a..995c063483 100644 --- a/docs/2.0.0/native-installation/index.html +++ b/docs/2.0.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
-
Version: 2.0.0

Installing Richie on your machine

This document aims to list all needed steps to have a working Richie +

Version: 2.0.0

Installing Richie on your machine

This document aims to list all needed steps to have a working Richie installation on your laptop.

A better approach is to use Docker as explained in our guide for container-native instructions.

Installing a fresh server

Version

You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

npm run sass

Run server

Make sure your database is up-to-date before running the application the first time and after each modification to your models:

python sandbox/manage.py migrate

You can create a superuser account:

python sandbox/manage.py createsuperuser

Run the tests

python sandbox/manage.py test

You should now be able to start Django and view the site at localhost:8000

python sandbox/manage.py runserver
- - + + \ No newline at end of file diff --git a/docs/2.0.1/accessibility-testing/index.html b/docs/2.0.1/accessibility-testing/index.html index e64baeb2f4..7c43719a63 100644 --- a/docs/2.0.1/accessibility-testing/index.html +++ b/docs/2.0.1/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
-
Version: 2.0.1

Automated accessibility checks

Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

Testing environment setup

Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

cd tests_e2e
yarn install

This should install everything you need.

Running the tests

There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

yarn cypress run

You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

yarn cypress open

This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

Documentation reference

- - +
Version: 2.0.1

Automated accessibility checks

Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

Testing environment setup

Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

cd tests_e2e
yarn install

This should install everything you need.

Running the tests

There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

yarn cypress run

You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

yarn cypress open

This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

Documentation reference

+ + \ No newline at end of file diff --git a/docs/2.0.1/building-the-frontend/index.html b/docs/2.0.1/building-the-frontend/index.html index 26c4486406..09ecaa384a 100644 --- a/docs/2.0.1/building-the-frontend/index.html +++ b/docs/2.0.1/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
-
Version: 2.0.1

Building Richie's frontend in your own project

Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

Installing richie-education

If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

mkdir -p src/frontend

Then, you need to bootstrap your own frontend project in this new directory.

cd src/frontend
yarn init

With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

yarn add richie-education

In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

"dependencies": {
"richie-education": "1.12.0"
},

Building the Javascript bundle

You are now ready to run your own frontend build. We'll just be using webpack directly.

yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

Here is everything that is happening:

  • yarn webpack — run the webpack CLI;
  • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
  • --output-path ./build — make sure we get our output where we need it to be;
  • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

You can now run your build to change frontend settings or override frontend components with your own.

Building the CSS

If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

mkdir -p src/frontend/scss
touch src/frontend/scss/_mains.scss

Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

@import "richie-education/scss/main";

You are now ready to run the CSS build:

cd src/frontend
yarn build-sass

This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

- - +
Version: 2.0.1

Building Richie's frontend in your own project

Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

Installing richie-education

If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

mkdir -p src/frontend

Then, you need to bootstrap your own frontend project in this new directory.

cd src/frontend
yarn init

With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

yarn add richie-education

In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

"dependencies": {
"richie-education": "1.12.0"
},

Building the Javascript bundle

You are now ready to run your own frontend build. We'll just be using webpack directly.

yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

Here is everything that is happening:

  • yarn webpack — run the webpack CLI;
  • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
  • --output-path ./build — make sure we get our output where we need it to be;
  • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

You can now run your build to change frontend settings or override frontend components with your own.

Building the CSS

If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

mkdir -p src/frontend/scss
touch src/frontend/scss/_mains.scss

Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

@import "richie-education/scss/main";

You are now ready to run the CSS build:

cd src/frontend
yarn build-sass

This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

+ + \ No newline at end of file diff --git a/docs/2.0.1/contributing-guide/index.html b/docs/2.0.1/contributing-guide/index.html index edc0587f06..80b068b96b 100644 --- a/docs/2.0.1/contributing-guide/index.html +++ b/docs/2.0.1/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
-
Version: 2.0.1

Contributing guide

This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

We try to raise our code quality standards and expect contributors to follow the recommandations +

Version: 2.0.1

Contributing guide

This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

Checking your code

We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

$ make lint-back

We use strict eslint and prettier to check the validity of our frontend code:

$ make lint-front

Running tests

On the backend, we use pytest to run our test suite:

$ make test-back

On the frontend, we use karma to run our test suite:

$ make test-front

Running migrations

The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

$ make migrate

Handling new dependencies

Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

$ make bootstrap

Going further

To see all available commands, run:

$ make

We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

bin
├── exec
├── pylint
├── pytest
└── run

More details and tips & tricks can be found in our development with Docker documentation

- - + + \ No newline at end of file diff --git a/docs/2.0.1/css-guidelines/index.html b/docs/2.0.1/css-guidelines/index.html index 11c9d9891a..6e8713cac8 100644 --- a/docs/2.0.1/css-guidelines/index.html +++ b/docs/2.0.1/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
-
Version: 2.0.1

CSS Guidelines

The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

File structuration

Rules should be placed where their purpose is most apparent, and where they are easiest to find.

Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

Code structuration

In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

Following the BEM naming convention, we will write our classes as follows :

.block {}
.block__element {}
.block--modifier {}
  • .block represents the higher level of an abstraction or component.
  • .block__element represents a descendent of .block that helps form .block as a whole.
  • .block--modifier represents a different state or version of .block.

We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

Quick pointers

  • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
  • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
  • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
  • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
  • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

(Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

- - +
Version: 2.0.1

CSS Guidelines

The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

File structuration

Rules should be placed where their purpose is most apparent, and where they are easiest to find.

Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

Code structuration

In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

Following the BEM naming convention, we will write our classes as follows :

.block {}
.block__element {}
.block--modifier {}
  • .block represents the higher level of an abstraction or component.
  • .block__element represents a descendent of .block that helps form .block as a whole.
  • .block--modifier represents a different state or version of .block.

We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

Quick pointers

  • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
  • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
  • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
  • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
  • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

(Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

+ + \ No newline at end of file diff --git a/docs/2.0.1/discover/index.html b/docs/2.0.1/discover/index.html index bf8e78b7d7..f1c87a1d9b 100644 --- a/docs/2.0.1/discover/index.html +++ b/docs/2.0.1/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
-
Version: 2.0.1

Getting started with Richie

If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

Login/password are admin/admin. The database is regularly flushed.

Architecture

Richie is a container-native application but can also be installed +

Version: 2.0.1

Getting started with Richie

If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

Login/password are admin/admin. The database is regularly flushed.

Architecture

Richie is a container-native application but can also be installed on your machine.

For development, the project is defined using a docker-compose file and consists of 4 services:

  • db: the Postgresql database,
  • elasticsearch: the search engine,
  • app: the actual DjangoCMS project with all our application code,
  • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -27,7 +27,7 @@ to bootstrap an instance.

Just start apps with make run.

Richie should respond on http://localhost:8070 and OpenEdx on http://localhost:8073.

Advanced - Connecting Richie to OpenEdx

If you want users to enroll on courses in OpenEdx directly from Richie via API calls, you should read the advanced guide to connect Richie to OpenEdx over TLS.

- - + + \ No newline at end of file diff --git a/docs/2.0.1/django-react-interop/index.html b/docs/2.0.1/django-react-interop/index.html index ac3f410629..259239d5b6 100644 --- a/docs/2.0.1/django-react-interop/index.html +++ b/docs/2.0.1/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
-
Version: 2.0.1

Connecting React components with Django

richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

Rendering components

We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

They use the BCP47/RFC5646 format.

<html lang="en-US">

Example

Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

<div
class="richie-react richie-react--featured-courses"
></div>

When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

Passing properties to components

Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

Example

Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

<div
class="richie-react richie-react--featured-courses"
data-props='{"categories": ["sociology", "anthropology"]}'
></div>

When the component is rendered, it will be passed a categories prop with the relevant categories.

Built-in components

Here are the React component that Richie comes with and uses out of the box.

<RootSearchSuggestField />

Renders a course search bar, like the one that appears in the default Search page.

Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

Props:

  • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
  • context [required] — see context.

<Search />

Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

Props:

  • context [required] — see context.

<SearchSuggestField />

Renders the course search bar that interacts directly with <Search />.

It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

Props:

  • context [required] — see context.

<UserLogin />

Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

Props:

  • loginUrl [required] — the URL where the user is sent when they click on "Log in";
  • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
  • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

Context

All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

Here is the expected shape for this object:

{
assets: {
// SVG sprite used throughout Richie
icons: "/path/to/icons/sprite.svg"
}
}

Note that it might be expanded in further versions of Richie.

- - +
Version: 2.0.1

Connecting React components with Django

richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

Rendering components

We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

They use the BCP47/RFC5646 format.

<html lang="en-US">

Example

Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

<div
class="richie-react richie-react--featured-courses"
></div>

When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

Passing properties to components

Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

Example

Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

<div
class="richie-react richie-react--featured-courses"
data-props='{"categories": ["sociology", "anthropology"]}'
></div>

When the component is rendered, it will be passed a categories prop with the relevant categories.

Built-in components

Here are the React component that Richie comes with and uses out of the box.

<RootSearchSuggestField />

Renders a course search bar, like the one that appears in the default Search page.

Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

Props:

  • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
  • context [required] — see context.

<Search />

Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

Props:

  • context [required] — see context.

<SearchSuggestField />

Renders the course search bar that interacts directly with <Search />.

It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

Props:

  • context [required] — see context.

<UserLogin />

Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

Props:

  • loginUrl [required] — the URL where the user is sent when they click on "Log in";
  • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
  • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

Context

All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

Here is the expected shape for this object:

{
assets: {
// SVG sprite used throughout Richie
icons: "/path/to/icons/sprite.svg"
}
}

Note that it might be expanded in further versions of Richie.

+ + \ No newline at end of file diff --git a/docs/2.0.1/docker-development/index.html b/docs/2.0.1/docker-development/index.html index 35a2924c8a..0af77ba82b 100644 --- a/docs/2.0.1/docker-development/index.html +++ b/docs/2.0.1/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
-
Version: 2.0.1

Developing Richie with Docker

Now that you have Richie up and running, you can start working with it.

Settings

Settings are defined using Django +

Version: 2.0.1

Developing Richie with Docker

Now that you have Richie up and running, you can start working with it.

Settings

Settings are defined using Django Configurations for different environments:

  • Development: settings for development on developers' local environment,
  • Test: settings used to run our test suite,
  • ContinousIntegration: settings used on the continuous integration platform,
  • Feature: settings for deployment of each developers' feature branches,
  • Staging: settings for deployment to the staging environment,
  • PreProduction: settings for deployment to the pre-production environment,
  • Production: settings for deployment to the production environment.

The Development environment is defined as the default environment.

Front-end tools

If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

# Start the Sass watcher
$ make watch-sass

# In a new terminal or session, start the TypeScript watcher
$ make watch-ts

Container control

You can stop/start/restart a container:

$ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

or stop/start/restart all containers in one command:

$ docker-compose [stop|start|restart]

Debugging

You can easily see the latest logs for a container:

$ docker-compose logs [app|postgresql|mysql|elasticsearch]

Or follow the stream of logs:

$ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

$ docker image prune
$ docker container prune

Troubleshooting

ElasticSearch service is always down

If your elasticsearch container fails at booting, checkout the logs via:

$ docker-compose logs elasticsearch

You may see entries similar to:

[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

In this case, increase virtual memory as follows (UNIX systems):

$ sudo sysctl -w vm/max_map_count=262144

This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

vm.max_map_count=262144
- - + + \ No newline at end of file diff --git a/docs/2.0.1/frontend-overrides/index.html b/docs/2.0.1/frontend-overrides/index.html index 6ba68ca876..af14674411 100644 --- a/docs/2.0.1/frontend-overrides/index.html +++ b/docs/2.0.1/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
-
Version: 2.0.1

Overriding frontend components

Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

Defining your overrides

Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

Currently, it is only possible to override components. Richie's build is only set up to handle them.

Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

{
"overrides": {
"CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
}
}

Building a component override

As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

For example, if our component to override was the following:

export interface CourseGlimpseProps {
course: Course;
context: { someProp: string };
}

export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
// Whatever happens in this component
return <p>The glimpse</p>;
};

Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

Override translation

When you create an application based on richie, you can encounter two cases about translations:

  1. You created or overrode a react component and created new translation keys
  2. You just want to override a translation in an existing richie component

Create new translation keys

Once you created your new component with its translation keys, you have to extract them with the following command:

  formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

  node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

Override an existing translation key

As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

Richie uses one file per language. Currently 4 languages supported:

  • English: filename is en-US.json
  • French: filename is fr-FR.json
  • Canadian french: filename is fr-CA.json
  • Spanish: filename is es-ES.json

For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

{
"components.UserLogin.logIn": {
"description": "Overriden text for the login button.",
"message": "Authentication"
},
}

Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

  node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

- - +
Version: 2.0.1

Overriding frontend components

Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

Defining your overrides

Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

Currently, it is only possible to override components. Richie's build is only set up to handle them.

Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

{
"overrides": {
"CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
}
}

Building a component override

As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

For example, if our component to override was the following:

export interface CourseGlimpseProps {
course: Course;
context: { someProp: string };
}

export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
// Whatever happens in this component
return <p>The glimpse</p>;
};

Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

Override translation

When you create an application based on richie, you can encounter two cases about translations:

  1. You created or overrode a react component and created new translation keys
  2. You just want to override a translation in an existing richie component

Create new translation keys

Once you created your new component with its translation keys, you have to extract them with the following command:

  formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

  node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

Override an existing translation key

As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

Richie uses one file per language. Currently 4 languages supported:

  • English: filename is en-US.json
  • French: filename is fr-FR.json
  • Canadian french: filename is fr-CA.json
  • Spanish: filename is es-ES.json

For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

{
"components.UserLogin.logIn": {
"description": "Overriden text for the login button.",
"message": "Authentication"
},
}

Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

  node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

+ + \ No newline at end of file diff --git a/docs/2.0.1/lms-connection/index.html b/docs/2.0.1/lms-connection/index.html index 89c4182692..2b9d259bea 100644 --- a/docs/2.0.1/lms-connection/index.html +++ b/docs/2.0.1/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with an LMS | Richie - - + +
-
Version: 2.0.1

Connecting Richie with an LMS

richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle +

Version: 2.0.1

Connecting Richie with an LMS

richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle or Canvas for a seamless experience between browsing the course catalog on richie and following the course itself on the LMS.

In order to connect richie with a LMS, there is an API bridge to synchronize course information and enrollments.

API bridge

The APIHandler utility acts as a proxy that routes queries to the correct LMS backend API, @@ -43,7 +43,7 @@ on https://richie.local.dev:8070 without browser warning about the certificate validity.

You need to follow these steps once. If you want to use SSL later, just use make run-ssl to run OpenEdx and Richie apps. Of course, you can still run apps without ssl by using make run.

- - + + \ No newline at end of file diff --git a/docs/2.0.1/native-installation/index.html b/docs/2.0.1/native-installation/index.html index 09f387e2f8..b8939169b8 100644 --- a/docs/2.0.1/native-installation/index.html +++ b/docs/2.0.1/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
-
Version: 2.0.1

Installing Richie on your machine

This document aims to list all needed steps to have a working Richie +

Version: 2.0.1

Installing Richie on your machine

This document aims to list all needed steps to have a working Richie installation on your laptop.

A better approach is to use Docker as explained in our guide for container-native instructions.

Installing a fresh server

Version

You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

npm run sass

Run server

Make sure your database is up-to-date before running the application the first time and after each modification to your models:

python sandbox/manage.py migrate

You can create a superuser account:

python sandbox/manage.py createsuperuser

Run the tests

python sandbox/manage.py test

You should now be able to start Django and view the site at localhost:8000

python sandbox/manage.py runserver
- - + + \ No newline at end of file diff --git a/docs/2.1.0/accessibility-testing/index.html b/docs/2.1.0/accessibility-testing/index.html index 63e423d8c7..ca3035c321 100644 --- a/docs/2.1.0/accessibility-testing/index.html +++ b/docs/2.1.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
-
Version: 2.1.0

Automated accessibility checks

Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

Testing environment setup

Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

cd tests_e2e
yarn install

This should install everything you need.

Running the tests

There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

yarn cypress run

You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

yarn cypress open

This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

Documentation reference

- - +
Version: 2.1.0

Automated accessibility checks

Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

Testing environment setup

Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

cd tests_e2e
yarn install

This should install everything you need.

Running the tests

There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

yarn cypress run

You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

yarn cypress open

This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

Documentation reference

+ + \ No newline at end of file diff --git a/docs/2.1.0/building-the-frontend/index.html b/docs/2.1.0/building-the-frontend/index.html index 31dd0b1356..22a1c97bc4 100644 --- a/docs/2.1.0/building-the-frontend/index.html +++ b/docs/2.1.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
-
Version: 2.1.0

Building Richie's frontend in your own project

Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

Installing richie-education

If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

mkdir -p src/frontend

Then, you need to bootstrap your own frontend project in this new directory.

cd src/frontend
yarn init

With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

yarn add richie-education

In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

"dependencies": {
"richie-education": "1.12.0"
},

Building the Javascript bundle

You are now ready to run your own frontend build. We'll just be using webpack directly.

yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

Here is everything that is happening:

  • yarn webpack — run the webpack CLI;
  • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
  • --output-path ./build — make sure we get our output where we need it to be;
  • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

You can now run your build to change frontend settings or override frontend components with your own.

Building the CSS

If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

mkdir -p src/frontend/scss
touch src/frontend/scss/_mains.scss

Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

@import "richie-education/scss/main";

You are now ready to run the CSS build:

cd src/frontend
yarn build-sass

This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

- - +
Version: 2.1.0

Building Richie's frontend in your own project

Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

Installing richie-education

If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

mkdir -p src/frontend

Then, you need to bootstrap your own frontend project in this new directory.

cd src/frontend
yarn init

With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

yarn add richie-education

In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

"dependencies": {
"richie-education": "1.12.0"
},

Building the Javascript bundle

You are now ready to run your own frontend build. We'll just be using webpack directly.

yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

Here is everything that is happening:

  • yarn webpack — run the webpack CLI;
  • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
  • --output-path ./build — make sure we get our output where we need it to be;
  • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

You can now run your build to change frontend settings or override frontend components with your own.

Building the CSS

If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

mkdir -p src/frontend/scss
touch src/frontend/scss/_mains.scss

Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

@import "richie-education/scss/main";

You are now ready to run the CSS build:

cd src/frontend
yarn build-sass

This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

+ + \ No newline at end of file diff --git a/docs/2.1.0/contributing-guide/index.html b/docs/2.1.0/contributing-guide/index.html index db0c52b54c..10ac33c052 100644 --- a/docs/2.1.0/contributing-guide/index.html +++ b/docs/2.1.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
-
Version: 2.1.0

Contributing guide

This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

We try to raise our code quality standards and expect contributors to follow the recommandations +

Version: 2.1.0

Contributing guide

This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

Checking your code

We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

$ make lint-back

We use strict eslint and prettier to check the validity of our frontend code:

$ make lint-front

Running tests

On the backend, we use pytest to run our test suite:

$ make test-back

On the frontend, we use karma to run our test suite:

$ make test-front

Running migrations

The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

$ make migrate

Handling new dependencies

Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

$ make bootstrap

Going further

To see all available commands, run:

$ make

We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

bin
├── exec
├── pylint
├── pytest
└── run

More details and tips & tricks can be found in our development with Docker documentation

- - + + \ No newline at end of file diff --git a/docs/2.1.0/css-guidelines/index.html b/docs/2.1.0/css-guidelines/index.html index 0364ddfa02..f8a8a34730 100644 --- a/docs/2.1.0/css-guidelines/index.html +++ b/docs/2.1.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
-
Version: 2.1.0

CSS Guidelines

The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

File structuration

Rules should be placed where their purpose is most apparent, and where they are easiest to find.

Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

Code structuration

In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

Following the BEM naming convention, we will write our classes as follows :

.block {}
.block__element {}
.block--modifier {}
  • .block represents the higher level of an abstraction or component.
  • .block__element represents a descendent of .block that helps form .block as a whole.
  • .block--modifier represents a different state or version of .block.

We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

Quick pointers

  • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
  • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
  • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
  • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
  • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

(Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

- - +
Version: 2.1.0

CSS Guidelines

The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

File structuration

Rules should be placed where their purpose is most apparent, and where they are easiest to find.

Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

Code structuration

In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

Following the BEM naming convention, we will write our classes as follows :

.block {}
.block__element {}
.block--modifier {}
  • .block represents the higher level of an abstraction or component.
  • .block__element represents a descendent of .block that helps form .block as a whole.
  • .block--modifier represents a different state or version of .block.

We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

Quick pointers

  • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
  • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
  • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
  • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
  • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

(Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

+ + \ No newline at end of file diff --git a/docs/2.1.0/discover/index.html b/docs/2.1.0/discover/index.html index 03c749a688..ed02bed626 100644 --- a/docs/2.1.0/discover/index.html +++ b/docs/2.1.0/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
-
Version: 2.1.0

Getting started with Richie

If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

Login/password are admin/admin. The database is regularly flushed.

Architecture

Richie is a container-native application but can also be installed +

Version: 2.1.0

Getting started with Richie

If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

Login/password are admin/admin. The database is regularly flushed.

Architecture

Richie is a container-native application but can also be installed on your machine.

For development, the project is defined using a docker-compose file and consists of 4 services:

  • db: the Postgresql database,
  • elasticsearch: the search engine,
  • app: the actual DjangoCMS project with all our application code,
  • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -27,7 +27,7 @@ to bootstrap an instance.

Just start apps with make run.

Richie should respond on http://localhost:8070 and OpenEdx on http://localhost:8073.

Advanced - Connecting Richie to OpenEdx

If you want users to enroll on courses in OpenEdx directly from Richie via API calls, you should read the advanced guide to connect Richie to OpenEdx over TLS.

- - + + \ No newline at end of file diff --git a/docs/2.1.0/django-react-interop/index.html b/docs/2.1.0/django-react-interop/index.html index 3b845a2762..69027145cb 100644 --- a/docs/2.1.0/django-react-interop/index.html +++ b/docs/2.1.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
-
Version: 2.1.0

Connecting React components with Django

richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

Rendering components

We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

They use the BCP47/RFC5646 format.

<html lang="en-US">

Example

Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

<div
class="richie-react richie-react--featured-courses"
></div>

When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

Passing properties to components

Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

Example

Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

<div
class="richie-react richie-react--featured-courses"
data-props='{"categories": ["sociology", "anthropology"]}'
></div>

When the component is rendered, it will be passed a categories prop with the relevant categories.

Built-in components

Here are the React component that Richie comes with and uses out of the box.

<RootSearchSuggestField />

Renders a course search bar, like the one that appears in the default Search page.

Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

Props:

  • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
  • context [required] — see context.

<Search />

Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

Props:

  • context [required] — see context.

<SearchSuggestField />

Renders the course search bar that interacts directly with <Search />.

It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

Props:

  • context [required] — see context.

<UserLogin />

Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

Props:

  • loginUrl [required] — the URL where the user is sent when they click on "Log in";
  • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
  • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

Context

All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

Here is the expected shape for this object:

{
assets: {
// SVG sprite used throughout Richie
icons: "/path/to/icons/sprite.svg"
}
}

Note that it might be expanded in further versions of Richie.

- - +
Version: 2.1.0

Connecting React components with Django

richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

Rendering components

We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

They use the BCP47/RFC5646 format.

<html lang="en-US">

Example

Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

<div
class="richie-react richie-react--featured-courses"
></div>

When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

Passing properties to components

Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

Example

Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

<div
class="richie-react richie-react--featured-courses"
data-props='{"categories": ["sociology", "anthropology"]}'
></div>

When the component is rendered, it will be passed a categories prop with the relevant categories.

Built-in components

Here are the React component that Richie comes with and uses out of the box.

<RootSearchSuggestField />

Renders a course search bar, like the one that appears in the default Search page.

Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

Props:

  • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
  • context [required] — see context.

<Search />

Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

Props:

  • context [required] — see context.

<SearchSuggestField />

Renders the course search bar that interacts directly with <Search />.

It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

Props:

  • context [required] — see context.

<UserLogin />

Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

Props:

  • loginUrl [required] — the URL where the user is sent when they click on "Log in";
  • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
  • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

Context

All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

Here is the expected shape for this object:

{
assets: {
// SVG sprite used throughout Richie
icons: "/path/to/icons/sprite.svg"
}
}

Note that it might be expanded in further versions of Richie.

+ + \ No newline at end of file diff --git a/docs/2.1.0/docker-development/index.html b/docs/2.1.0/docker-development/index.html index d52af974be..f99aec5d72 100644 --- a/docs/2.1.0/docker-development/index.html +++ b/docs/2.1.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
-
Version: 2.1.0

Developing Richie with Docker

Now that you have Richie up and running, you can start working with it.

Settings

Settings are defined using Django +

Version: 2.1.0

Developing Richie with Docker

Now that you have Richie up and running, you can start working with it.

Settings

Settings are defined using Django Configurations for different environments:

  • Development: settings for development on developers' local environment,
  • Test: settings used to run our test suite,
  • ContinousIntegration: settings used on the continuous integration platform,
  • Feature: settings for deployment of each developers' feature branches,
  • Staging: settings for deployment to the staging environment,
  • PreProduction: settings for deployment to the pre-production environment,
  • Production: settings for deployment to the production environment.

The Development environment is defined as the default environment.

Front-end tools

If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

# Start the Sass watcher
$ make watch-sass

# In a new terminal or session, start the TypeScript watcher
$ make watch-ts

Container control

You can stop/start/restart a container:

$ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

or stop/start/restart all containers in one command:

$ docker-compose [stop|start|restart]

Debugging

You can easily see the latest logs for a container:

$ docker-compose logs [app|postgresql|mysql|elasticsearch]

Or follow the stream of logs:

$ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

$ docker image prune
$ docker container prune

Troubleshooting

ElasticSearch service is always down

If your elasticsearch container fails at booting, checkout the logs via:

$ docker-compose logs elasticsearch

You may see entries similar to:

[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

In this case, increase virtual memory as follows (UNIX systems):

$ sudo sysctl -w vm/max_map_count=262144

This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

vm.max_map_count=262144
- - + + \ No newline at end of file diff --git a/docs/2.1.0/frontend-overrides/index.html b/docs/2.1.0/frontend-overrides/index.html index 5e1d219384..4f359cd030 100644 --- a/docs/2.1.0/frontend-overrides/index.html +++ b/docs/2.1.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
-
Version: 2.1.0

Overriding frontend components

Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

Defining your overrides

Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

Currently, it is only possible to override components. Richie's build is only set up to handle them.

Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

{
"overrides": {
"CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
}
}

Building a component override

As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

For example, if our component to override was the following:

export interface CourseGlimpseProps {
course: Course;
context: { someProp: string };
}

export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
// Whatever happens in this component
return <p>The glimpse</p>;
};

Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

Override translation

When you create an application based on richie, you can encounter two cases about translations:

  1. You created or overrode a react component and created new translation keys
  2. You just want to override a translation in an existing richie component

Create new translation keys

Once you created your new component with its translation keys, you have to extract them with the following command:

  formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

  node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

Override an existing translation key

As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

Richie uses one file per language. Currently 4 languages supported:

  • English: filename is en-US.json
  • French: filename is fr-FR.json
  • Canadian french: filename is fr-CA.json
  • Spanish: filename is es-ES.json

For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

{
"components.UserLogin.logIn": {
"description": "Overriden text for the login button.",
"message": "Authentication"
},
}

Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

  node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

- - +
Version: 2.1.0

Overriding frontend components

Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

Defining your overrides

Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

Currently, it is only possible to override components. Richie's build is only set up to handle them.

Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

{
"overrides": {
"CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
}
}

Building a component override

As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

For example, if our component to override was the following:

export interface CourseGlimpseProps {
course: Course;
context: { someProp: string };
}

export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
// Whatever happens in this component
return <p>The glimpse</p>;
};

Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

Override translation

When you create an application based on richie, you can encounter two cases about translations:

  1. You created or overrode a react component and created new translation keys
  2. You just want to override a translation in an existing richie component

Create new translation keys

Once you created your new component with its translation keys, you have to extract them with the following command:

  formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

  node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

Override an existing translation key

As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

Richie uses one file per language. Currently 4 languages supported:

  • English: filename is en-US.json
  • French: filename is fr-FR.json
  • Canadian french: filename is fr-CA.json
  • Spanish: filename is es-ES.json

For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

{
"components.UserLogin.logIn": {
"description": "Overriden text for the login button.",
"message": "Authentication"
},
}

Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

  node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

+ + \ No newline at end of file diff --git a/docs/2.1.0/lms-connection/index.html b/docs/2.1.0/lms-connection/index.html index 135d8c4dca..b901bc2cda 100644 --- a/docs/2.1.0/lms-connection/index.html +++ b/docs/2.1.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with an LMS | Richie - - + +
-
Version: 2.1.0

Connecting Richie with an LMS

richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle +

Version: 2.1.0

Connecting Richie with an LMS

richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle or Canvas for a seamless experience between browsing the course catalog on richie and following the course itself on the LMS.

In order to connect richie with a LMS, there is an API bridge to synchronize course information and enrollments.

API bridge

The APIHandler utility acts as a proxy that routes queries to the correct LMS backend API, @@ -43,7 +43,7 @@ on https://richie.local.dev:8070 without browser warning about the certificate validity.

You need to follow these steps once. If you want to use SSL later, just use make run-ssl to run OpenEdx and Richie apps. Of course, you can still run apps without ssl by using make run.

- - + + \ No newline at end of file diff --git a/docs/2.1.0/native-installation/index.html b/docs/2.1.0/native-installation/index.html index bf1498783e..883f20a8e0 100644 --- a/docs/2.1.0/native-installation/index.html +++ b/docs/2.1.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
-
Version: 2.1.0

Installing Richie on your machine

This document aims to list all needed steps to have a working Richie +

Version: 2.1.0

Installing Richie on your machine

This document aims to list all needed steps to have a working Richie installation on your laptop.

A better approach is to use Docker as explained in our guide for container-native instructions.

Installing a fresh server

Version

You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

npm run sass

Run server

Make sure your database is up-to-date before running the application the first time and after each modification to your models:

python sandbox/manage.py migrate

You can create a superuser account:

python sandbox/manage.py createsuperuser

Run the tests

python sandbox/manage.py test

You should now be able to start Django and view the site at localhost:8000

python sandbox/manage.py runserver
- - + + \ No newline at end of file diff --git a/docs/2.10.0/accessibility-testing/index.html b/docs/2.10.0/accessibility-testing/index.html index 43e7088add..3bf712af1d 100644 --- a/docs/2.10.0/accessibility-testing/index.html +++ b/docs/2.10.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
-
Version: 2.10.0

Automated accessibility checks

Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

Testing environment setup

Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

cd tests_e2e
yarn install

This should install everything you need.

Running the tests

There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

yarn cypress run

You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

yarn cypress open

This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

Documentation reference

- - +
Version: 2.10.0

Automated accessibility checks

Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

Testing environment setup

Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

cd tests_e2e
yarn install

This should install everything you need.

Running the tests

There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

yarn cypress run

You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

yarn cypress open

This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

Documentation reference

+ + \ No newline at end of file diff --git a/docs/2.10.0/api/course-run-synchronization-api/index.html b/docs/2.10.0/api/course-run-synchronization-api/index.html index 6b52135be6..ba128823b5 100644 --- a/docs/2.10.0/api/course-run-synchronization-api/index.html +++ b/docs/2.10.0/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
-
Version: 2.10.0

Course run synchronization API

API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

Synchronization endpoint [/api/1.0/course-runs-sync]

This documentation describes version "1.0" of this API endpoint.

Synchronize a course run [POST]

It takes a JSON object containing the course run details:

  • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
    Version: 2.10.0

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
    • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
    • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
    • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
  • Body

      {
    "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
    "start": "2021-02-01T00:00:00Z",
    "end": "2021-02-31T23:59:59Z",
    "enrollment_start": "2021-01-01T00:00:00Z",
    "enrollment_end": "2021-01-31T23:59:59Z",
    "languages": ["en", "fr"]
    }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/2.10.0/building-the-frontend/index.html b/docs/2.10.0/building-the-frontend/index.html index f747806027..203df34351 100644 --- a/docs/2.10.0/building-the-frontend/index.html +++ b/docs/2.10.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.10.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.10.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.10.0/contributing-guide/index.html b/docs/2.10.0/contributing-guide/index.html index 34ac74c416..c385f883ae 100644 --- a/docs/2.10.0/contributing-guide/index.html +++ b/docs/2.10.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.10.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.10.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.10.0/css-guidelines/index.html b/docs/2.10.0/css-guidelines/index.html index c334c7de57..8583435d82 100644 --- a/docs/2.10.0/css-guidelines/index.html +++ b/docs/2.10.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.10.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.10.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.10.0/discover/index.html b/docs/2.10.0/discover/index.html index 69ae7e9947..6b77748497 100644 --- a/docs/2.10.0/discover/index.html +++ b/docs/2.10.0/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.10.0

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.10.0

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -24,7 +24,7 @@ a course on the LMS, and the LMS points back to the catalogue to browse courses.

    This approach is used for example on https://www.fun-campus.fr or https://catalogue.edulib.org.

    For a seamless user experience, it is possible to connect a Richie instance to an OpenEdX instance (or some other LMS like Moodle at the cost of minor adaptations), in several ways that we explain in the LMS connection guide.

    - - + + \ No newline at end of file diff --git a/docs/2.10.0/displaying-connection-status/index.html b/docs/2.10.0/displaying-connection-status/index.html index b5ed690cbc..95d5d810cf 100644 --- a/docs/2.10.0/displaying-connection-status/index.html +++ b/docs/2.10.0/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: 2.10.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.10.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/2.10.0/django-react-interop/index.html b/docs/2.10.0/django-react-interop/index.html index b5f60b6aa8..ee2d129746 100644 --- a/docs/2.10.0/django-react-interop/index.html +++ b/docs/2.10.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.10.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.10.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.10.0/docker-development/index.html b/docs/2.10.0/docker-development/index.html index 825917ca17..c6616e7a41 100644 --- a/docs/2.10.0/docker-development/index.html +++ b/docs/2.10.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.10.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.10.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.10.0/frontend-overrides/index.html b/docs/2.10.0/frontend-overrides/index.html index 7d699e0292..20568602cb 100644 --- a/docs/2.10.0/frontend-overrides/index.html +++ b/docs/2.10.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.10.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.10.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.10.0/internationalization/index.html b/docs/2.10.0/internationalization/index.html index 69f879c636..e467e0bdf4 100644 --- a/docs/2.10.0/internationalization/index.html +++ b/docs/2.10.0/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.10.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.10.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.10.0/lms-backends/index.html b/docs/2.10.0/lms-backends/index.html index 70b59fed82..f0f2ddc60f 100644 --- a/docs/2.10.0/lms-backends/index.html +++ b/docs/2.10.0/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: 2.10.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.10.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/2.10.0/lms-connection/index.html b/docs/2.10.0/lms-connection/index.html index 292447f182..7fe015bf97 100644 --- a/docs/2.10.0/lms-connection/index.html +++ b/docs/2.10.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: 2.10.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.10.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/2.10.0/native-installation/index.html b/docs/2.10.0/native-installation/index.html index 2c28af0a55..0d126e2bcd 100644 --- a/docs/2.10.0/native-installation/index.html +++ b/docs/2.10.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.10.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.10.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.10.0/synchronizing-course-runs/index.html b/docs/2.10.0/synchronizing-course-runs/index.html index 1e0cf445f6..a613ba18e3 100644 --- a/docs/2.10.0/synchronizing-course-runs/index.html +++ b/docs/2.10.0/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: 2.10.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.10.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -29,7 +29,7 @@ course run is modified and published.

    Or you can use the Richie Open edX Synchronization which is based on the following code sample and also includes the enrollment count.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/2.10.0/tls-connection/index.html b/docs/2.10.0/tls-connection/index.html index 9dc9bd0092..288acd4f66 100644 --- a/docs/2.10.0/tls-connection/index.html +++ b/docs/2.10.0/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: 2.10.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.10.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/2.10.0/web-analytics/index.html b/docs/2.10.0/web-analytics/index.html index 9ea74ed98d..a370f146b2 100644 --- a/docs/2.10.0/web-analytics/index.html +++ b/docs/2.10.0/web-analytics/index.html @@ -4,16 +4,16 @@ Add web analytics to your site | Richie - - + +
    -
    Version: 2.10.0

    Add web analytics to your site

    The purpose of this file is to document how you can enable a Web Analytics solution. +

    Version: 2.10.0

    Add web analytics to your site

    The purpose of this file is to document how you can enable a Web Analytics solution. Currently Richie only supports by default the Google Analytics using the Google Tag Manager Javascript. But it is possible with little cost to add support for other web analytics solutions.

    Google Analytics

    Next, it is decribed how you can configure the Google Analytics on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Analytics tracking id code.

    The current Google Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Location of the web analytics javascript

    Use the WEB_ANALYTICS_LOCATION settings to decide where do you want to put the Javascript code. Use head (default value), to put the Javascript on HTML header, or footer, to put the Javascript code to the bottom of the body.

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS_ID setting with your tracking identification
    • define the WEB_ANALYTICS_PROVIDER setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • optionally change WEB_ANALYTICS_LOCATION setting with head (default) or footer value
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% block web_analytics %}
    {% if WEB_ANALYTICS_ID %}
    {% if WEB_ANALYTICS_PROVIDER == "my_custom_web_analytics_software" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endif %}
    {% endblock web_analytics %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>
    - - + + \ No newline at end of file diff --git a/docs/2.11.0/accessibility-testing/index.html b/docs/2.11.0/accessibility-testing/index.html index dd07b88473..c3ccb1d387 100644 --- a/docs/2.11.0/accessibility-testing/index.html +++ b/docs/2.11.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.11.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.11.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.11.0/api/course-run-synchronization-api/index.html b/docs/2.11.0/api/course-run-synchronization-api/index.html index a425ba364e..47af6e8c75 100644 --- a/docs/2.11.0/api/course-run-synchronization-api/index.html +++ b/docs/2.11.0/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
    -
    Version: 2.11.0

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: 2.11.0

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
    • Body

        {
      "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
      "start": "2021-02-01T00:00:00Z",
      "end": "2021-02-31T23:59:59Z",
      "enrollment_start": "2021-01-01T00:00:00Z",
      "enrollment_end": "2021-01-31T23:59:59Z",
      "languages": ["en", "fr"]
      }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/2.11.0/building-the-frontend/index.html b/docs/2.11.0/building-the-frontend/index.html index 835e6383f5..a3a07e23b3 100644 --- a/docs/2.11.0/building-the-frontend/index.html +++ b/docs/2.11.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.11.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.11.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.11.0/contributing-guide/index.html b/docs/2.11.0/contributing-guide/index.html index e1a34e13c4..c9cbff60b2 100644 --- a/docs/2.11.0/contributing-guide/index.html +++ b/docs/2.11.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.11.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.11.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.11.0/css-guidelines/index.html b/docs/2.11.0/css-guidelines/index.html index 97b2b801d4..d6cb916741 100644 --- a/docs/2.11.0/css-guidelines/index.html +++ b/docs/2.11.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.11.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.11.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.11.0/discover/index.html b/docs/2.11.0/discover/index.html index 57fa343b09..7608fdee53 100644 --- a/docs/2.11.0/discover/index.html +++ b/docs/2.11.0/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.11.0

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.11.0

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -24,7 +24,7 @@ a course on the LMS, and the LMS points back to the catalogue to browse courses.

    This approach is used for example on https://www.fun-campus.fr or https://catalogue.edulib.org.

    For a seamless user experience, it is possible to connect a Richie instance to an OpenEdX instance (or some other LMS like Moodle at the cost of minor adaptations), in several ways that we explain in the LMS connection guide.

    - - + + \ No newline at end of file diff --git a/docs/2.11.0/displaying-connection-status/index.html b/docs/2.11.0/displaying-connection-status/index.html index bcfd20fabc..853ad36118 100644 --- a/docs/2.11.0/displaying-connection-status/index.html +++ b/docs/2.11.0/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: 2.11.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.11.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/2.11.0/django-react-interop/index.html b/docs/2.11.0/django-react-interop/index.html index 80f8cb9e6b..a8f15c7982 100644 --- a/docs/2.11.0/django-react-interop/index.html +++ b/docs/2.11.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.11.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.11.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.11.0/docker-development/index.html b/docs/2.11.0/docker-development/index.html index 7ce65ee3bf..1bffa5e3b0 100644 --- a/docs/2.11.0/docker-development/index.html +++ b/docs/2.11.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.11.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.11.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.11.0/frontend-overrides/index.html b/docs/2.11.0/frontend-overrides/index.html index 575d6634ad..64b1245eda 100644 --- a/docs/2.11.0/frontend-overrides/index.html +++ b/docs/2.11.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.11.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.11.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.11.0/internationalization/index.html b/docs/2.11.0/internationalization/index.html index f38a43a411..bab5ed327f 100644 --- a/docs/2.11.0/internationalization/index.html +++ b/docs/2.11.0/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.11.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.11.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.11.0/lms-backends/index.html b/docs/2.11.0/lms-backends/index.html index 719e23390d..db4e88eda1 100644 --- a/docs/2.11.0/lms-backends/index.html +++ b/docs/2.11.0/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: 2.11.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.11.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/2.11.0/lms-connection/index.html b/docs/2.11.0/lms-connection/index.html index b3119d3986..79704c6880 100644 --- a/docs/2.11.0/lms-connection/index.html +++ b/docs/2.11.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: 2.11.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.11.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/2.11.0/native-installation/index.html b/docs/2.11.0/native-installation/index.html index 25f27ad335..338a84a12a 100644 --- a/docs/2.11.0/native-installation/index.html +++ b/docs/2.11.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.11.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.11.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.11.0/synchronizing-course-runs/index.html b/docs/2.11.0/synchronizing-course-runs/index.html index ece53c1f53..1c46024a4a 100644 --- a/docs/2.11.0/synchronizing-course-runs/index.html +++ b/docs/2.11.0/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: 2.11.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.11.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -29,7 +29,7 @@ course run is modified and published.

    Or you can use the Richie Open edX Synchronization which is based on the following code sample and also includes the enrollment count.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/2.11.0/tls-connection/index.html b/docs/2.11.0/tls-connection/index.html index 725827da46..b540af0580 100644 --- a/docs/2.11.0/tls-connection/index.html +++ b/docs/2.11.0/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: 2.11.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.11.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/2.11.0/web-analytics/index.html b/docs/2.11.0/web-analytics/index.html index c82cc0e189..cf0f025882 100644 --- a/docs/2.11.0/web-analytics/index.html +++ b/docs/2.11.0/web-analytics/index.html @@ -4,16 +4,16 @@ Add web analytics to your site | Richie - - + +
    -
    Version: 2.11.0

    Add web analytics to your site

    The purpose of this file is to document how you can enable a Web Analytics solution. +

    Version: 2.11.0

    Add web analytics to your site

    The purpose of this file is to document how you can enable a Web Analytics solution. Currently Richie only supports by default the Google Analytics using the Google Tag Manager Javascript. But it is possible with little cost to add support for other web analytics solutions.

    Google Analytics

    Next, it is decribed how you can configure the Google Analytics on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Analytics tracking id code.

    The current Google Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Location of the web analytics javascript

    Use the WEB_ANALYTICS_LOCATION settings to decide where do you want to put the Javascript code. Use head (default value), to put the Javascript on HTML header, or footer, to put the Javascript code to the bottom of the body.

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS_ID setting with your tracking identification
    • define the WEB_ANALYTICS_PROVIDER setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • optionally change WEB_ANALYTICS_LOCATION setting with head (default) or footer value
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% block web_analytics %}
    {% if WEB_ANALYTICS_ID %}
    {% if WEB_ANALYTICS_PROVIDER == "my_custom_web_analytics_software" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endif %}
    {% endblock web_analytics %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>
    - - + + \ No newline at end of file diff --git a/docs/2.12.0/accessibility-testing/index.html b/docs/2.12.0/accessibility-testing/index.html index 0f4302aa5d..d2571f1aa9 100644 --- a/docs/2.12.0/accessibility-testing/index.html +++ b/docs/2.12.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.12.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.12.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.12.0/api/course-run-synchronization-api/index.html b/docs/2.12.0/api/course-run-synchronization-api/index.html index ed2130e92c..cb30ff1ad4 100644 --- a/docs/2.12.0/api/course-run-synchronization-api/index.html +++ b/docs/2.12.0/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
    -
    Version: 2.12.0

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: 2.12.0

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
    • Body

        {
      "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
      "start": "2021-02-01T00:00:00Z",
      "end": "2021-02-31T23:59:59Z",
      "enrollment_start": "2021-01-01T00:00:00Z",
      "enrollment_end": "2021-01-31T23:59:59Z",
      "languages": ["en", "fr"]
      }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/2.12.0/building-the-frontend/index.html b/docs/2.12.0/building-the-frontend/index.html index fef4d90879..9a13ee1855 100644 --- a/docs/2.12.0/building-the-frontend/index.html +++ b/docs/2.12.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.12.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.12.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.12.0/contributing-guide/index.html b/docs/2.12.0/contributing-guide/index.html index a648208bf0..079d4de297 100644 --- a/docs/2.12.0/contributing-guide/index.html +++ b/docs/2.12.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.12.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.12.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.12.0/css-guidelines/index.html b/docs/2.12.0/css-guidelines/index.html index 509cb6231d..fc317ef96d 100644 --- a/docs/2.12.0/css-guidelines/index.html +++ b/docs/2.12.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.12.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.12.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.12.0/discover/index.html b/docs/2.12.0/discover/index.html index 05ffa6eca2..ef5591b5e6 100644 --- a/docs/2.12.0/discover/index.html +++ b/docs/2.12.0/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.12.0

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.12.0

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -24,7 +24,7 @@ a course on the LMS, and the LMS points back to the catalogue to browse courses.

    This approach is used for example on https://www.fun-campus.fr or https://catalogue.edulib.org.

    For a seamless user experience, it is possible to connect a Richie instance to an OpenEdX instance (or some other LMS like Moodle at the cost of minor adaptations), in several ways that we explain in the LMS connection guide.

    - - + + \ No newline at end of file diff --git a/docs/2.12.0/displaying-connection-status/index.html b/docs/2.12.0/displaying-connection-status/index.html index bb82902ff7..132175bb12 100644 --- a/docs/2.12.0/displaying-connection-status/index.html +++ b/docs/2.12.0/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: 2.12.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.12.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/2.12.0/django-react-interop/index.html b/docs/2.12.0/django-react-interop/index.html index 31fc8b76d4..fec6b62480 100644 --- a/docs/2.12.0/django-react-interop/index.html +++ b/docs/2.12.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.12.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.12.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.12.0/docker-development/index.html b/docs/2.12.0/docker-development/index.html index 6936474f16..7995e39f3c 100644 --- a/docs/2.12.0/docker-development/index.html +++ b/docs/2.12.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.12.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.12.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.12.0/frontend-overrides/index.html b/docs/2.12.0/frontend-overrides/index.html index 98f5d021c0..0ae2a8e1a3 100644 --- a/docs/2.12.0/frontend-overrides/index.html +++ b/docs/2.12.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.12.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.12.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.12.0/internationalization/index.html b/docs/2.12.0/internationalization/index.html index 8109feaaa8..0de05cd679 100644 --- a/docs/2.12.0/internationalization/index.html +++ b/docs/2.12.0/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.12.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.12.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.12.0/lms-backends/index.html b/docs/2.12.0/lms-backends/index.html index f56f1cac76..48b43b68e1 100644 --- a/docs/2.12.0/lms-backends/index.html +++ b/docs/2.12.0/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: 2.12.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.12.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/2.12.0/lms-connection/index.html b/docs/2.12.0/lms-connection/index.html index c5a8332dcb..45bf8bb687 100644 --- a/docs/2.12.0/lms-connection/index.html +++ b/docs/2.12.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: 2.12.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.12.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/2.12.0/native-installation/index.html b/docs/2.12.0/native-installation/index.html index faccca045c..6405538e17 100644 --- a/docs/2.12.0/native-installation/index.html +++ b/docs/2.12.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.12.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.12.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.12.0/synchronizing-course-runs/index.html b/docs/2.12.0/synchronizing-course-runs/index.html index 1e6f198cbb..77c75f935f 100644 --- a/docs/2.12.0/synchronizing-course-runs/index.html +++ b/docs/2.12.0/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: 2.12.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.12.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -29,7 +29,7 @@ course run is modified and published.

    Or you can use the Richie Open edX Synchronization which is based on the following code sample and also includes the enrollment count.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/2.12.0/tls-connection/index.html b/docs/2.12.0/tls-connection/index.html index 4b86c39c85..eb8250ec07 100644 --- a/docs/2.12.0/tls-connection/index.html +++ b/docs/2.12.0/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: 2.12.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.12.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/2.12.0/web-analytics/index.html b/docs/2.12.0/web-analytics/index.html index 8cee6a6e7c..72a058dcb6 100644 --- a/docs/2.12.0/web-analytics/index.html +++ b/docs/2.12.0/web-analytics/index.html @@ -4,16 +4,16 @@ Add web analytics to your site | Richie - - + +
    -
    Version: 2.12.0

    Add web analytics to your site

    The purpose of this file is to document how you can enable a Web Analytics solution. +

    Version: 2.12.0

    Add web analytics to your site

    The purpose of this file is to document how you can enable a Web Analytics solution. Currently Richie only supports by default the Google Analytics using the Google Tag Manager Javascript. But it is possible with little cost to add support for other web analytics solutions.

    Google Analytics

    Next, it is decribed how you can configure the Google Analytics on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Analytics tracking id code.

    The current Google Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Location of the web analytics javascript

    Use the WEB_ANALYTICS_LOCATION settings to decide where do you want to put the Javascript code. Use head (default value), to put the Javascript on HTML header, or footer, to put the Javascript code to the bottom of the body.

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS_ID setting with your tracking identification
    • define the WEB_ANALYTICS_PROVIDER setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • optionally change WEB_ANALYTICS_LOCATION setting with head (default) or footer value
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% block web_analytics %}
    {% if WEB_ANALYTICS_ID %}
    {% if WEB_ANALYTICS_PROVIDER == "my_custom_web_analytics_software" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endif %}
    {% endblock web_analytics %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>
    - - + + \ No newline at end of file diff --git a/docs/2.13.0/accessibility-testing/index.html b/docs/2.13.0/accessibility-testing/index.html index 372f411c96..db1ebde9b7 100644 --- a/docs/2.13.0/accessibility-testing/index.html +++ b/docs/2.13.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.13.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.13.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.13.0/api/course-run-synchronization-api/index.html b/docs/2.13.0/api/course-run-synchronization-api/index.html index c1278db8ae..36b76a5706 100644 --- a/docs/2.13.0/api/course-run-synchronization-api/index.html +++ b/docs/2.13.0/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
    -
    Version: 2.13.0

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: 2.13.0

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
    • Body

        {
      "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
      "start": "2021-02-01T00:00:00Z",
      "end": "2021-02-31T23:59:59Z",
      "enrollment_start": "2021-01-01T00:00:00Z",
      "enrollment_end": "2021-01-31T23:59:59Z",
      "languages": ["en", "fr"]
      }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/2.13.0/building-the-frontend/index.html b/docs/2.13.0/building-the-frontend/index.html index 2d11217bb0..55226f5973 100644 --- a/docs/2.13.0/building-the-frontend/index.html +++ b/docs/2.13.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.13.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.13.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.13.0/contributing-guide/index.html b/docs/2.13.0/contributing-guide/index.html index a8f33254cc..84ff45fd1f 100644 --- a/docs/2.13.0/contributing-guide/index.html +++ b/docs/2.13.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.13.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.13.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.13.0/css-guidelines/index.html b/docs/2.13.0/css-guidelines/index.html index f03c026628..2ea44dc62c 100644 --- a/docs/2.13.0/css-guidelines/index.html +++ b/docs/2.13.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.13.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.13.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.13.0/discover/index.html b/docs/2.13.0/discover/index.html index 7937b0f49f..44d92098de 100644 --- a/docs/2.13.0/discover/index.html +++ b/docs/2.13.0/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.13.0

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.13.0

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -24,7 +24,7 @@ a course on the LMS, and the LMS points back to the catalogue to browse courses.

    This approach is used for example on https://www.fun-campus.fr or https://catalogue.edulib.org.

    For a seamless user experience, it is possible to connect a Richie instance to an OpenEdX instance (or some other LMS like Moodle at the cost of minor adaptations), in several ways that we explain in the LMS connection guide.

    - - + + \ No newline at end of file diff --git a/docs/2.13.0/displaying-connection-status/index.html b/docs/2.13.0/displaying-connection-status/index.html index d5872021c6..daaab58c85 100644 --- a/docs/2.13.0/displaying-connection-status/index.html +++ b/docs/2.13.0/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: 2.13.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.13.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/2.13.0/django-react-interop/index.html b/docs/2.13.0/django-react-interop/index.html index 656a76999c..f3325dee1b 100644 --- a/docs/2.13.0/django-react-interop/index.html +++ b/docs/2.13.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.13.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.13.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.13.0/docker-development/index.html b/docs/2.13.0/docker-development/index.html index e9ab9857f3..19060f93a0 100644 --- a/docs/2.13.0/docker-development/index.html +++ b/docs/2.13.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.13.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.13.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.13.0/frontend-overrides/index.html b/docs/2.13.0/frontend-overrides/index.html index d6b2d14b9f..dcb1eb0fd4 100644 --- a/docs/2.13.0/frontend-overrides/index.html +++ b/docs/2.13.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.13.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.13.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.13.0/internationalization/index.html b/docs/2.13.0/internationalization/index.html index 07ad528c39..1926140a2e 100644 --- a/docs/2.13.0/internationalization/index.html +++ b/docs/2.13.0/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.13.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.13.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.13.0/lms-backends/index.html b/docs/2.13.0/lms-backends/index.html index 137b8bc0a9..289b783adc 100644 --- a/docs/2.13.0/lms-backends/index.html +++ b/docs/2.13.0/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: 2.13.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.13.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/2.13.0/lms-connection/index.html b/docs/2.13.0/lms-connection/index.html index 6c0a781171..1969994e03 100644 --- a/docs/2.13.0/lms-connection/index.html +++ b/docs/2.13.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: 2.13.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.13.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/2.13.0/native-installation/index.html b/docs/2.13.0/native-installation/index.html index 2aaa14190b..5c06c50b8a 100644 --- a/docs/2.13.0/native-installation/index.html +++ b/docs/2.13.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.13.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.13.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.13.0/synchronizing-course-runs/index.html b/docs/2.13.0/synchronizing-course-runs/index.html index ff4652edd6..cdac904f9b 100644 --- a/docs/2.13.0/synchronizing-course-runs/index.html +++ b/docs/2.13.0/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: 2.13.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.13.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -29,7 +29,7 @@ course run is modified and published.

    Or you can use the Richie Open edX Synchronization which is based on the following code sample and also includes the enrollment count.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/2.13.0/tls-connection/index.html b/docs/2.13.0/tls-connection/index.html index b030fc2bb7..179b0877e6 100644 --- a/docs/2.13.0/tls-connection/index.html +++ b/docs/2.13.0/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: 2.13.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.13.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/2.13.0/web-analytics/index.html b/docs/2.13.0/web-analytics/index.html index d858bf94be..0e040e379c 100644 --- a/docs/2.13.0/web-analytics/index.html +++ b/docs/2.13.0/web-analytics/index.html @@ -4,16 +4,16 @@ Add web analytics to your site | Richie - - + +
    -
    Version: 2.13.0

    Add web analytics to your site

    The purpose of this file is to document how you can enable a Web Analytics solution. +

    Version: 2.13.0

    Add web analytics to your site

    The purpose of this file is to document how you can enable a Web Analytics solution. Currently Richie only supports by default the Google Analytics using the Google Tag Manager Javascript. But it is possible with little cost to add support for other web analytics solutions.

    Google Analytics

    Next, it is decribed how you can configure the Google Analytics on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Analytics tracking id code.

    The current Google Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Location of the web analytics javascript

    Use the WEB_ANALYTICS_LOCATION settings to decide where do you want to put the Javascript code. Use head (default value), to put the Javascript on HTML header, or footer, to put the Javascript code to the bottom of the body.

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS_ID setting with your tracking identification
    • define the WEB_ANALYTICS_PROVIDER setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • optionally change WEB_ANALYTICS_LOCATION setting with head (default) or footer value
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% block web_analytics %}
    {% if WEB_ANALYTICS_ID %}
    {% if WEB_ANALYTICS_PROVIDER == "my_custom_web_analytics_software" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endif %}
    {% endblock web_analytics %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>
    - - + + \ No newline at end of file diff --git a/docs/2.14.0/accessibility-testing/index.html b/docs/2.14.0/accessibility-testing/index.html index 7d8ee4713c..b17ed15cd9 100644 --- a/docs/2.14.0/accessibility-testing/index.html +++ b/docs/2.14.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.14.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.14.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.14.0/api/course-run-synchronization-api/index.html b/docs/2.14.0/api/course-run-synchronization-api/index.html index 221f870fd5..0d169eb604 100644 --- a/docs/2.14.0/api/course-run-synchronization-api/index.html +++ b/docs/2.14.0/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
    -
    Version: 2.14.0

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: 2.14.0

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
    • Body

        {
      "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
      "start": "2021-02-01T00:00:00Z",
      "end": "2021-02-31T23:59:59Z",
      "enrollment_start": "2021-01-01T00:00:00Z",
      "enrollment_end": "2021-01-31T23:59:59Z",
      "languages": ["en", "fr"]
      }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/2.14.0/building-the-frontend/index.html b/docs/2.14.0/building-the-frontend/index.html index f37dda707f..f3c729e45e 100644 --- a/docs/2.14.0/building-the-frontend/index.html +++ b/docs/2.14.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.14.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.14.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.14.0/contributing-guide/index.html b/docs/2.14.0/contributing-guide/index.html index 32e0f64fce..c132797471 100644 --- a/docs/2.14.0/contributing-guide/index.html +++ b/docs/2.14.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.14.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.14.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.14.0/css-guidelines/index.html b/docs/2.14.0/css-guidelines/index.html index 666ca26331..580d715755 100644 --- a/docs/2.14.0/css-guidelines/index.html +++ b/docs/2.14.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.14.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.14.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.14.0/discover/index.html b/docs/2.14.0/discover/index.html index a6e20d690c..d93f5cfd29 100644 --- a/docs/2.14.0/discover/index.html +++ b/docs/2.14.0/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.14.0

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.14.0

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -24,7 +24,7 @@ a course on the LMS, and the LMS points back to the catalogue to browse courses.

    This approach is used for example on https://www.fun-campus.fr or https://catalogue.edulib.org.

    For a seamless user experience, it is possible to connect a Richie instance to an OpenEdX instance (or some other LMS like Moodle at the cost of minor adaptations), in several ways that we explain in the LMS connection guide.

    - - + + \ No newline at end of file diff --git a/docs/2.14.0/displaying-connection-status/index.html b/docs/2.14.0/displaying-connection-status/index.html index be93eafe95..54de82650b 100644 --- a/docs/2.14.0/displaying-connection-status/index.html +++ b/docs/2.14.0/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: 2.14.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.14.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/2.14.0/django-react-interop/index.html b/docs/2.14.0/django-react-interop/index.html index f9398e968c..c0fc23ba33 100644 --- a/docs/2.14.0/django-react-interop/index.html +++ b/docs/2.14.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.14.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.14.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.14.0/docker-development/index.html b/docs/2.14.0/docker-development/index.html index d2ddd57da9..7c1a9cbc5c 100644 --- a/docs/2.14.0/docker-development/index.html +++ b/docs/2.14.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.14.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.14.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.14.0/frontend-overrides/index.html b/docs/2.14.0/frontend-overrides/index.html index f11ab5dd99..01699badfd 100644 --- a/docs/2.14.0/frontend-overrides/index.html +++ b/docs/2.14.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.14.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.14.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.14.0/internationalization/index.html b/docs/2.14.0/internationalization/index.html index 9328307eca..d6809c86f9 100644 --- a/docs/2.14.0/internationalization/index.html +++ b/docs/2.14.0/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.14.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.14.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.14.0/lms-backends/index.html b/docs/2.14.0/lms-backends/index.html index 3f0554d311..14a9c67b90 100644 --- a/docs/2.14.0/lms-backends/index.html +++ b/docs/2.14.0/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: 2.14.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.14.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/2.14.0/lms-connection/index.html b/docs/2.14.0/lms-connection/index.html index 093f1886b1..d30c8979ef 100644 --- a/docs/2.14.0/lms-connection/index.html +++ b/docs/2.14.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: 2.14.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.14.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/2.14.0/native-installation/index.html b/docs/2.14.0/native-installation/index.html index c1d876591c..c71ed3a23b 100644 --- a/docs/2.14.0/native-installation/index.html +++ b/docs/2.14.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.14.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.14.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.14.0/synchronizing-course-runs/index.html b/docs/2.14.0/synchronizing-course-runs/index.html index c0190324d1..0ecd4603ab 100644 --- a/docs/2.14.0/synchronizing-course-runs/index.html +++ b/docs/2.14.0/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: 2.14.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.14.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -29,7 +29,7 @@ course run is modified and published.

    Or you can use the Richie Open edX Synchronization which is based on the following code sample and also includes the enrollment count.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/2.14.0/tls-connection/index.html b/docs/2.14.0/tls-connection/index.html index 4ecf94b91f..5ef8c7181c 100644 --- a/docs/2.14.0/tls-connection/index.html +++ b/docs/2.14.0/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: 2.14.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.14.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/2.14.0/web-analytics/index.html b/docs/2.14.0/web-analytics/index.html index 7d08b39343..56445c6613 100644 --- a/docs/2.14.0/web-analytics/index.html +++ b/docs/2.14.0/web-analytics/index.html @@ -4,19 +4,19 @@ Add web analytics to your site | Richie - - + +
    -
    Version: 2.14.0

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. +

    Version: 2.14.0

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. The purpose of this file is to explain how you can enable one of the supported Web Analytics providers and how you can extend Richie with an alternative solution.

    Google Analytics

    Next, it is described how you can configure the Google Analytics on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Analytics tracking id code.

    The current Google Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Google Tag Manager

    Next, it is described how you can configure the Google Tag Manager on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Tag Manager tracking id code.
    • Add the WEB_ANALYTICS_PROVIDER setting with the google_tag_manager value.

    The current Google Tag Manager implementation also defines a custom dimensions like the Google Analytics.

    Location of the web analytics javascript

    Use the WEB_ANALYTICS_LOCATION settings to decide where do you want to put the Javascript code. Use head (default value), to put the Javascript on HTML header, or footer, to put the Javascript code to the bottom of the body.

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS_ID setting with your tracking identification
    • define the WEB_ANALYTICS_PROVIDER setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • optionally change WEB_ANALYTICS_LOCATION setting with head (default) or footer value
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% block web_analytics %}
    {% if WEB_ANALYTICS_ID %}
    {% if WEB_ANALYTICS_PROVIDER == "my_custom_web_analytics_software" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endif %}
    {% endblock web_analytics %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>

    The frontend code also sends events to the web analytics provider. Richie sends events when the user is enrolled on a course run. To support different providers, you need to create a similar file of src/frontend/js/utils/api/web-analytics/google_analytics.ts and change the src/frontend/js/utils/api/web-analytics/index.ts file to include that newer provider.

    - - + + \ No newline at end of file diff --git a/docs/2.14.1/accessibility-testing/index.html b/docs/2.14.1/accessibility-testing/index.html index 3bc0dbb612..92f70326c7 100644 --- a/docs/2.14.1/accessibility-testing/index.html +++ b/docs/2.14.1/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.14.1

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.14.1

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.14.1/api/course-run-synchronization-api/index.html b/docs/2.14.1/api/course-run-synchronization-api/index.html index 1bbbb6b473..6f34e3b7fa 100644 --- a/docs/2.14.1/api/course-run-synchronization-api/index.html +++ b/docs/2.14.1/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
    -
    Version: 2.14.1

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: 2.14.1

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
    • Body

        {
      "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
      "start": "2021-02-01T00:00:00Z",
      "end": "2021-02-31T23:59:59Z",
      "enrollment_start": "2021-01-01T00:00:00Z",
      "enrollment_end": "2021-01-31T23:59:59Z",
      "languages": ["en", "fr"]
      }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/2.14.1/building-the-frontend/index.html b/docs/2.14.1/building-the-frontend/index.html index b9f7b97d75..ad449bf361 100644 --- a/docs/2.14.1/building-the-frontend/index.html +++ b/docs/2.14.1/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.14.1

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.14.1

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.14.1/contributing-guide/index.html b/docs/2.14.1/contributing-guide/index.html index d24828812c..432e338889 100644 --- a/docs/2.14.1/contributing-guide/index.html +++ b/docs/2.14.1/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.14.1

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.14.1

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.14.1/cookiecutter/index.html b/docs/2.14.1/cookiecutter/index.html index 9191703e80..bac85f035b 100644 --- a/docs/2.14.1/cookiecutter/index.html +++ b/docs/2.14.1/cookiecutter/index.html @@ -4,12 +4,12 @@ Start your own site | Richie - - + +
    -
    Version: 2.14.1

    Start your own site

    We use Cookiecutter to help you +

    Version: 2.14.1

    Start your own site

    We use Cookiecutter to help you set up a production-ready learning portal website based on Richie in seconds.

    Run Cookiecutter

    There are 2 options to run Cookiecutter:

    While you think of it, navigate to the directory in which you want to create your site factory:

    cd /path/to/your/code/directory

    If you chose to install Cookiecutter, you can now run it against our @@ -30,7 +30,7 @@ project's scaffolding but, don't worry, it will respect all the sites you will have created in the sites directory:

    cookiecutter --overwrite-if-exists gh:openfun/richie --directory=cookiecutter

    Help us improve this project

    After starting your project, please submit an issue let us know how it went and what other features we should add to make it better.

    - - + + \ No newline at end of file diff --git a/docs/2.14.1/css-guidelines/index.html b/docs/2.14.1/css-guidelines/index.html index 47d191b3fb..3c91e273c9 100644 --- a/docs/2.14.1/css-guidelines/index.html +++ b/docs/2.14.1/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.14.1

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.14.1

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.14.1/discover/index.html b/docs/2.14.1/discover/index.html index 99f7c2bc63..b713a93a68 100644 --- a/docs/2.14.1/discover/index.html +++ b/docs/2.14.1/discover/index.html @@ -4,12 +4,12 @@ Discover Richie | Richie - - + +
    -
    Version: 2.14.1

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online +

    Version: 2.14.1

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online courses and MOOCs.

    However, if you need to build a complete website with flexible content to aggregate your courses, in several languages and from different sources, you will soon need a CMS.

    At "France Université Numérique", we wanted to build an OpenSource portal with Python and Django. That's why we built Richie on top of DjangoCMS, one of @@ -21,7 +21,7 @@ OpenEdX Docker.

    Two users are available for testing:

    • admin: admin@example.com/admin
    • student: edx@example.com/edx

    The database is regularly flushed.

    Start your own site

    The next step after discovering Richie on the demo is to start your own project. We provide a production-ready template based on Cookiecutter that allows you to generate your project in seconds.

    Follow the guide on starting your own Richie site with Cookiecutter.

    Once you created a new site, you will be able to fully customize it:

    - - + + \ No newline at end of file diff --git a/docs/2.14.1/displaying-connection-status/index.html b/docs/2.14.1/displaying-connection-status/index.html index 571535f144..74c00f357b 100644 --- a/docs/2.14.1/displaying-connection-status/index.html +++ b/docs/2.14.1/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: 2.14.1

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.14.1

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/2.14.1/django-react-interop/index.html b/docs/2.14.1/django-react-interop/index.html index 160ec83faa..6acc28ec46 100644 --- a/docs/2.14.1/django-react-interop/index.html +++ b/docs/2.14.1/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.14.1

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.14.1

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.14.1/docker-development/index.html b/docs/2.14.1/docker-development/index.html index dd6a7ebaed..cd4f134d60 100644 --- a/docs/2.14.1/docker-development/index.html +++ b/docs/2.14.1/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.14.1

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.14.1

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.14.1/frontend-overrides/index.html b/docs/2.14.1/frontend-overrides/index.html index 0daddbef64..9634b7ea2a 100644 --- a/docs/2.14.1/frontend-overrides/index.html +++ b/docs/2.14.1/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.14.1

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.14.1

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.14.1/installation/index.html b/docs/2.14.1/installation/index.html index aea33c69c0..76e4382d95 100644 --- a/docs/2.14.1/installation/index.html +++ b/docs/2.14.1/installation/index.html @@ -4,12 +4,12 @@ Installing Richie for development | Richie - - + +
    -
    Version: 2.14.1

    Installing Richie for development

    Richie is a container-native application but can also be installed +

    Version: 2.14.1

    Installing Richie for development

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of:

    • 3 running services:

      • database: postgresql or mysql at your preference,
      • elasticsearch: the search engine,
      • app: the actual DjangoCMS project with all our application code.
    • 2 containers for building purposes:

    - - + + \ No newline at end of file diff --git a/docs/2.14.1/internationalization/index.html b/docs/2.14.1/internationalization/index.html index 93042ffa13..a2385d885a 100644 --- a/docs/2.14.1/internationalization/index.html +++ b/docs/2.14.1/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.14.1

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.14.1

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.14.1/joanie-connection/index.html b/docs/2.14.1/joanie-connection/index.html index f6a2f36fba..b18a930dd4 100644 --- a/docs/2.14.1/joanie-connection/index.html +++ b/docs/2.14.1/joanie-connection/index.html @@ -4,12 +4,12 @@ Joanie Connection | Richie - - + +
    -
    Version: 2.14.1

    Joanie Connection

    Settings

    All settings related to Joanie have to be declared in the JOANIE dictionary +

    Version: 2.14.1

    Joanie Connection

    Settings

    All settings related to Joanie have to be declared in the JOANIE dictionary within settings.py. To enable Joanie, the minimal configuration requires one property:

    • BASE_URL : the endpoint at which Joanie is accessible

    Add to your settings.py:

    ...
    JOANIE = {
    "BASE_URL": values.Value(environ_name="JOANIE_BASE_URL", environ_prefix=None)
    }
    ...

    Access Token

    Lifetime configuration

    Access Token is stored within the SessionStorage through react-query client persistor. @@ -19,7 +19,7 @@ lifetime of the access token defined by your authentication server. For example, if your authentication server is using djangorestframework-simplejwt to generate the access token, its lifetime is 5 minutes by default.

    - - + + \ No newline at end of file diff --git a/docs/2.14.1/lms-backends/index.html b/docs/2.14.1/lms-backends/index.html index bf128788d4..0b527ed630 100644 --- a/docs/2.14.1/lms-backends/index.html +++ b/docs/2.14.1/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: 2.14.1

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.14.1

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/2.14.1/lms-connection/index.html b/docs/2.14.1/lms-connection/index.html index 2a860dce37..4185775555 100644 --- a/docs/2.14.1/lms-connection/index.html +++ b/docs/2.14.1/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: 2.14.1

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.14.1

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/2.14.1/native-installation/index.html b/docs/2.14.1/native-installation/index.html index 0e11ac3d79..22d1d6513b 100644 --- a/docs/2.14.1/native-installation/index.html +++ b/docs/2.14.1/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.14.1

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.14.1

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native installation instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.14.1/synchronizing-course-runs/index.html b/docs/2.14.1/synchronizing-course-runs/index.html index 68058ae178..8ae8b5ec31 100644 --- a/docs/2.14.1/synchronizing-course-runs/index.html +++ b/docs/2.14.1/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: 2.14.1

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.14.1

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -29,7 +29,7 @@ course run is modified and published.

    Or you can use the Richie Open edX Synchronization which is based on the following code sample and also includes the enrollment count.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/2.14.1/tls-connection/index.html b/docs/2.14.1/tls-connection/index.html index 47328bab9a..774bd5d9e6 100644 --- a/docs/2.14.1/tls-connection/index.html +++ b/docs/2.14.1/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: 2.14.1

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.14.1

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/2.14.1/web-analytics/index.html b/docs/2.14.1/web-analytics/index.html index bd15c89f92..5b64a75e83 100644 --- a/docs/2.14.1/web-analytics/index.html +++ b/docs/2.14.1/web-analytics/index.html @@ -4,19 +4,19 @@ Add web analytics to your site | Richie - - + +
    -
    Version: 2.14.1

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. +

    Version: 2.14.1

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. The purpose of this file is to explain how you can enable one of the supported Web Analytics providers and how you can extend Richie with an alternative solution.

    Google Analytics

    Next, it is described how you can configure the Google Analytics on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Analytics tracking id code.

    The current Google Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Google Tag Manager

    Next, it is described how you can configure the Google Tag Manager on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Tag Manager tracking id code.
    • Add the WEB_ANALYTICS_PROVIDER setting with the google_tag_manager value.

    The current Google Tag Manager implementation also defines a custom dimensions like the Google Analytics.

    Location of the web analytics javascript

    Use the WEB_ANALYTICS_LOCATION settings to decide where do you want to put the Javascript code. Use head (default value), to put the Javascript on HTML header, or footer, to put the Javascript code to the bottom of the body.

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS_ID setting with your tracking identification
    • define the WEB_ANALYTICS_PROVIDER setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • optionally change WEB_ANALYTICS_LOCATION setting with head (default) or footer value
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% block web_analytics %}
    {% if WEB_ANALYTICS_ID %}
    {% if WEB_ANALYTICS_PROVIDER == "my_custom_web_analytics_software" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endif %}
    {% endblock web_analytics %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>

    The frontend code also sends events to the web analytics provider. Richie sends events when the user is enrolled on a course run. To support different providers, you need to create a similar file of src/frontend/js/utils/api/web-analytics/google_analytics.ts and change the src/frontend/js/utils/api/web-analytics/index.ts file to include that newer provider.

    - - + + \ No newline at end of file diff --git a/docs/2.15.0/accessibility-testing/index.html b/docs/2.15.0/accessibility-testing/index.html index f605c79a60..8a10ddee84 100644 --- a/docs/2.15.0/accessibility-testing/index.html +++ b/docs/2.15.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.15.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.15.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.15.0/api/course-run-synchronization-api/index.html b/docs/2.15.0/api/course-run-synchronization-api/index.html index f6bc08f8b3..d19b812e27 100644 --- a/docs/2.15.0/api/course-run-synchronization-api/index.html +++ b/docs/2.15.0/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
    -
    Version: 2.15.0

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: 2.15.0

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
    • Body

        {
      "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
      "start": "2021-02-01T00:00:00Z",
      "end": "2021-02-31T23:59:59Z",
      "enrollment_start": "2021-01-01T00:00:00Z",
      "enrollment_end": "2021-01-31T23:59:59Z",
      "languages": ["en", "fr"]
      }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/2.15.0/building-the-frontend/index.html b/docs/2.15.0/building-the-frontend/index.html index ae84af3ea5..c16110b188 100644 --- a/docs/2.15.0/building-the-frontend/index.html +++ b/docs/2.15.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.15.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.15.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.15.0/contributing-guide/index.html b/docs/2.15.0/contributing-guide/index.html index 0ce38a1b88..e280bd58c7 100644 --- a/docs/2.15.0/contributing-guide/index.html +++ b/docs/2.15.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.15.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.15.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.15.0/cookiecutter/index.html b/docs/2.15.0/cookiecutter/index.html index edff1f6f1d..ad361a66ae 100644 --- a/docs/2.15.0/cookiecutter/index.html +++ b/docs/2.15.0/cookiecutter/index.html @@ -4,12 +4,12 @@ Start your own site | Richie - - + +
    -
    Version: 2.15.0

    Start your own site

    We use Cookiecutter to help you +

    Version: 2.15.0

    Start your own site

    We use Cookiecutter to help you set up a production-ready learning portal website based on Richie in seconds.

    Run Cookiecutter

    There are 2 options to run Cookiecutter:

    While you think of it, navigate to the directory in which you want to create your site factory:

    cd /path/to/your/code/directory

    If you chose to install Cookiecutter, you can now run it against our @@ -30,7 +30,7 @@ project's scaffolding but, don't worry, it will respect all the sites you will have created in the sites directory:

    cookiecutter --overwrite-if-exists gh:openfun/richie --directory=cookiecutter

    Help us improve this project

    After starting your project, please submit an issue let us know how it went and what other features we should add to make it better.

    - - + + \ No newline at end of file diff --git a/docs/2.15.0/css-guidelines/index.html b/docs/2.15.0/css-guidelines/index.html index 295a914f2d..6174eb0eb5 100644 --- a/docs/2.15.0/css-guidelines/index.html +++ b/docs/2.15.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.15.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.15.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.15.0/discover/index.html b/docs/2.15.0/discover/index.html index d5378ba1ad..1f7465cc97 100644 --- a/docs/2.15.0/discover/index.html +++ b/docs/2.15.0/discover/index.html @@ -4,12 +4,12 @@ Discover Richie | Richie - - + +
    -
    Version: 2.15.0

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online +

    Version: 2.15.0

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online courses and MOOCs.

    However, if you need to build a complete website with flexible content to aggregate your courses, in several languages and from different sources, you will soon need a CMS.

    At "France Université Numérique", we wanted to build an OpenSource portal with Python and Django. That's why we built Richie on top of DjangoCMS, one of @@ -21,7 +21,7 @@ OpenEdX Docker.

    Two users are available for testing:

    • admin: admin@example.com/admin
    • student: edx@example.com/edx

    The database is regularly flushed.

    Start your own site

    The next step after discovering Richie on the demo is to start your own project. We provide a production-ready template based on Cookiecutter that allows you to generate your project in seconds.

    Follow the guide on starting your own Richie site with Cookiecutter.

    Once you created a new site, you will be able to fully customize it:

    - - + + \ No newline at end of file diff --git a/docs/2.15.0/displaying-connection-status/index.html b/docs/2.15.0/displaying-connection-status/index.html index 3804d5eec6..57ab7e439a 100644 --- a/docs/2.15.0/displaying-connection-status/index.html +++ b/docs/2.15.0/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: 2.15.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.15.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/2.15.0/django-react-interop/index.html b/docs/2.15.0/django-react-interop/index.html index 684a5a9acd..e846033d55 100644 --- a/docs/2.15.0/django-react-interop/index.html +++ b/docs/2.15.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.15.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.15.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.15.0/docker-development/index.html b/docs/2.15.0/docker-development/index.html index 9420211549..ee1c252e34 100644 --- a/docs/2.15.0/docker-development/index.html +++ b/docs/2.15.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.15.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.15.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.15.0/frontend-overrides/index.html b/docs/2.15.0/frontend-overrides/index.html index 7d9f023c72..0abeaa4349 100644 --- a/docs/2.15.0/frontend-overrides/index.html +++ b/docs/2.15.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.15.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.15.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.15.0/installation/index.html b/docs/2.15.0/installation/index.html index cdc52c403a..e5126b7dee 100644 --- a/docs/2.15.0/installation/index.html +++ b/docs/2.15.0/installation/index.html @@ -4,12 +4,12 @@ Installing Richie for development | Richie - - + +
    -
    Version: 2.15.0

    Installing Richie for development

    Richie is a container-native application but can also be installed +

    Version: 2.15.0

    Installing Richie for development

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of:

    • 3 running services:

      • database: postgresql or mysql at your preference,
      • elasticsearch: the search engine,
      • app: the actual DjangoCMS project with all our application code.
    • 2 containers for building purposes:

    - - + + \ No newline at end of file diff --git a/docs/2.15.0/internationalization/index.html b/docs/2.15.0/internationalization/index.html index 141b5e812b..04ac2e5bc7 100644 --- a/docs/2.15.0/internationalization/index.html +++ b/docs/2.15.0/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.15.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.15.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.15.0/joanie-connection/index.html b/docs/2.15.0/joanie-connection/index.html index c45703f059..1247f0fb0d 100644 --- a/docs/2.15.0/joanie-connection/index.html +++ b/docs/2.15.0/joanie-connection/index.html @@ -4,12 +4,12 @@ Joanie Connection | Richie - - + +
    -
    Version: 2.15.0

    Joanie Connection

    Settings

    All settings related to Joanie have to be declared in the JOANIE dictionary +

    Version: 2.15.0

    Joanie Connection

    Settings

    All settings related to Joanie have to be declared in the JOANIE dictionary within settings.py. To enable Joanie, the minimal configuration requires one property:

    • BASE_URL : the endpoint at which Joanie is accessible

    Add to your settings.py:

    ...
    JOANIE = {
    "BASE_URL": values.Value(environ_name="JOANIE_BASE_URL", environ_prefix=None)
    }
    ...

    Access Token

    Lifetime configuration

    Access Token is stored within the SessionStorage through react-query client persistor. @@ -19,7 +19,7 @@ lifetime of the access token defined by your authentication server. For example, if your authentication server is using djangorestframework-simplejwt to generate the access token, its lifetime is 5 minutes by default.

    - - + + \ No newline at end of file diff --git a/docs/2.15.0/lms-backends/index.html b/docs/2.15.0/lms-backends/index.html index 18bf5ae178..ae726c4dcb 100644 --- a/docs/2.15.0/lms-backends/index.html +++ b/docs/2.15.0/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: 2.15.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.15.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/2.15.0/lms-connection/index.html b/docs/2.15.0/lms-connection/index.html index 89d1080424..8709202caa 100644 --- a/docs/2.15.0/lms-connection/index.html +++ b/docs/2.15.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: 2.15.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.15.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/2.15.0/native-installation/index.html b/docs/2.15.0/native-installation/index.html index d6cb99e373..8363195143 100644 --- a/docs/2.15.0/native-installation/index.html +++ b/docs/2.15.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.15.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.15.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native installation instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.15.0/synchronizing-course-runs/index.html b/docs/2.15.0/synchronizing-course-runs/index.html index f8e8da000e..4aa163fae6 100644 --- a/docs/2.15.0/synchronizing-course-runs/index.html +++ b/docs/2.15.0/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: 2.15.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.15.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -29,7 +29,7 @@ course run is modified and published.

    Or you can use the Richie Open edX Synchronization which is based on the following code sample and also includes the enrollment count.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/2.15.0/tls-connection/index.html b/docs/2.15.0/tls-connection/index.html index e87cc33532..47d441d073 100644 --- a/docs/2.15.0/tls-connection/index.html +++ b/docs/2.15.0/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: 2.15.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.15.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/2.15.0/web-analytics/index.html b/docs/2.15.0/web-analytics/index.html index 553377ffc0..d29483c224 100644 --- a/docs/2.15.0/web-analytics/index.html +++ b/docs/2.15.0/web-analytics/index.html @@ -4,19 +4,19 @@ Add web analytics to your site | Richie - - + +
    -
    Version: 2.15.0

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. +

    Version: 2.15.0

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. The purpose of this file is to explain how you can enable one of the supported Web Analytics providers and how you can extend Richie with an alternative solution.

    Google Analytics

    Next, it is described how you can configure the Google Analytics on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Analytics tracking id code.

    The current Google Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Google Tag Manager

    Next, it is described how you can configure the Google Tag Manager on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Tag Manager tracking id code.
    • Add the WEB_ANALYTICS_PROVIDER setting with the google_tag_manager value.

    The current Google Tag Manager implementation also defines a custom dimensions like the Google Analytics.

    Location of the web analytics javascript

    Use the WEB_ANALYTICS_LOCATION settings to decide where do you want to put the Javascript code. Use head (default value), to put the Javascript on HTML header, or footer, to put the Javascript code to the bottom of the body.

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS_ID setting with your tracking identification
    • define the WEB_ANALYTICS_PROVIDER setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • optionally change WEB_ANALYTICS_LOCATION setting with head (default) or footer value
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% block web_analytics %}
    {% if WEB_ANALYTICS_ID %}
    {% if WEB_ANALYTICS_PROVIDER == "my_custom_web_analytics_software" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endif %}
    {% endblock web_analytics %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>

    The frontend code also sends events to the web analytics provider. Richie sends events when the user is enrolled on a course run. To support different providers, you need to create a similar file of src/frontend/js/utils/api/web-analytics/google_analytics.ts and change the src/frontend/js/utils/api/web-analytics/index.ts file to include that newer provider.

    - - + + \ No newline at end of file diff --git a/docs/2.15.1/accessibility-testing/index.html b/docs/2.15.1/accessibility-testing/index.html index 7554d3927a..410f0741d8 100644 --- a/docs/2.15.1/accessibility-testing/index.html +++ b/docs/2.15.1/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.15.1

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.15.1

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.15.1/api/course-run-synchronization-api/index.html b/docs/2.15.1/api/course-run-synchronization-api/index.html index e4138e7223..cda2e2ec36 100644 --- a/docs/2.15.1/api/course-run-synchronization-api/index.html +++ b/docs/2.15.1/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
    -
    Version: 2.15.1

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: 2.15.1

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
    • Body

        {
      "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
      "start": "2021-02-01T00:00:00Z",
      "end": "2021-02-31T23:59:59Z",
      "enrollment_start": "2021-01-01T00:00:00Z",
      "enrollment_end": "2021-01-31T23:59:59Z",
      "languages": ["en", "fr"]
      }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/2.15.1/building-the-frontend/index.html b/docs/2.15.1/building-the-frontend/index.html index 9cc4441ca3..40091c0eed 100644 --- a/docs/2.15.1/building-the-frontend/index.html +++ b/docs/2.15.1/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.15.1

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.15.1

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.15.1/contributing-guide/index.html b/docs/2.15.1/contributing-guide/index.html index 965443b139..0ca08b748d 100644 --- a/docs/2.15.1/contributing-guide/index.html +++ b/docs/2.15.1/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.15.1

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.15.1

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.15.1/cookiecutter/index.html b/docs/2.15.1/cookiecutter/index.html index 28448a04b1..2b4ebaa041 100644 --- a/docs/2.15.1/cookiecutter/index.html +++ b/docs/2.15.1/cookiecutter/index.html @@ -4,12 +4,12 @@ Start your own site | Richie - - + +
    -
    Version: 2.15.1

    Start your own site

    We use Cookiecutter to help you +

    Version: 2.15.1

    Start your own site

    We use Cookiecutter to help you set up a production-ready learning portal website based on Richie in seconds.

    Run Cookiecutter

    There are 2 options to run Cookiecutter:

    While you think of it, navigate to the directory in which you want to create your site factory:

    cd /path/to/your/code/directory

    If you chose to install Cookiecutter, you can now run it against our @@ -30,7 +30,7 @@ project's scaffolding but, don't worry, it will respect all the sites you will have created in the sites directory:

    cookiecutter --overwrite-if-exists gh:openfun/richie --directory=cookiecutter

    Help us improve this project

    After starting your project, please submit an issue let us know how it went and what other features we should add to make it better.

    - - + + \ No newline at end of file diff --git a/docs/2.15.1/css-guidelines/index.html b/docs/2.15.1/css-guidelines/index.html index 129621fbd0..5cc227d002 100644 --- a/docs/2.15.1/css-guidelines/index.html +++ b/docs/2.15.1/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.15.1

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.15.1

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.15.1/discover/index.html b/docs/2.15.1/discover/index.html index b0f189a19d..e0fd3d1830 100644 --- a/docs/2.15.1/discover/index.html +++ b/docs/2.15.1/discover/index.html @@ -4,12 +4,12 @@ Discover Richie | Richie - - + +
    -
    Version: 2.15.1

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online +

    Version: 2.15.1

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online courses and MOOCs.

    However, if you need to build a complete website with flexible content to aggregate your courses, in several languages and from different sources, you will soon need a CMS.

    At "France Université Numérique", we wanted to build an OpenSource portal with Python and Django. That's why we built Richie on top of DjangoCMS, one of @@ -21,7 +21,7 @@ OpenEdX Docker.

    Two users are available for testing:

    • admin: admin@example.com/admin
    • student: edx@example.com/edx

    The database is regularly flushed.

    Start your own site

    The next step after discovering Richie on the demo is to start your own project. We provide a production-ready template based on Cookiecutter that allows you to generate your project in seconds.

    Follow the guide on starting your own Richie site with Cookiecutter.

    Once you created a new site, you will be able to fully customize it:

    - - + + \ No newline at end of file diff --git a/docs/2.15.1/displaying-connection-status/index.html b/docs/2.15.1/displaying-connection-status/index.html index 06c871fcd3..d5fdeb9382 100644 --- a/docs/2.15.1/displaying-connection-status/index.html +++ b/docs/2.15.1/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: 2.15.1

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.15.1

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/2.15.1/django-react-interop/index.html b/docs/2.15.1/django-react-interop/index.html index b85e7cd205..f57b0823ea 100644 --- a/docs/2.15.1/django-react-interop/index.html +++ b/docs/2.15.1/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.15.1

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.15.1

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.15.1/docker-development/index.html b/docs/2.15.1/docker-development/index.html index ef554ac207..66bcb1f695 100644 --- a/docs/2.15.1/docker-development/index.html +++ b/docs/2.15.1/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.15.1

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.15.1

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.15.1/frontend-overrides/index.html b/docs/2.15.1/frontend-overrides/index.html index 8bab552a0e..5d23f1c6ae 100644 --- a/docs/2.15.1/frontend-overrides/index.html +++ b/docs/2.15.1/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.15.1

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.15.1

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.15.1/installation/index.html b/docs/2.15.1/installation/index.html index fc4110587c..aa1aff241f 100644 --- a/docs/2.15.1/installation/index.html +++ b/docs/2.15.1/installation/index.html @@ -4,12 +4,12 @@ Installing Richie for development | Richie - - + +
    -
    Version: 2.15.1

    Installing Richie for development

    Richie is a container-native application but can also be installed +

    Version: 2.15.1

    Installing Richie for development

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of:

    • 3 running services:

      • database: postgresql or mysql at your preference,
      • elasticsearch: the search engine,
      • app: the actual DjangoCMS project with all our application code.
    • 2 containers for building purposes:

    - - + + \ No newline at end of file diff --git a/docs/2.15.1/internationalization/index.html b/docs/2.15.1/internationalization/index.html index a96ec12acd..73ea0009ce 100644 --- a/docs/2.15.1/internationalization/index.html +++ b/docs/2.15.1/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.15.1

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.15.1

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.15.1/joanie-connection/index.html b/docs/2.15.1/joanie-connection/index.html index 6e6d790a83..bd6eaffac9 100644 --- a/docs/2.15.1/joanie-connection/index.html +++ b/docs/2.15.1/joanie-connection/index.html @@ -4,12 +4,12 @@ Joanie Connection | Richie - - + +
    -
    Version: 2.15.1

    Joanie Connection

    Settings

    All settings related to Joanie have to be declared in the JOANIE dictionary +

    Version: 2.15.1

    Joanie Connection

    Settings

    All settings related to Joanie have to be declared in the JOANIE dictionary within settings.py. To enable Joanie, the minimal configuration requires one property:

    • BASE_URL : the endpoint at which Joanie is accessible

    Add to your settings.py:

    ...
    JOANIE = {
    "BASE_URL": values.Value(environ_name="JOANIE_BASE_URL", environ_prefix=None)
    }
    ...

    Access Token

    Lifetime configuration

    Access Token is stored within the SessionStorage through react-query client persistor. @@ -19,7 +19,7 @@ lifetime of the access token defined by your authentication server. For example, if your authentication server is using djangorestframework-simplejwt to generate the access token, its lifetime is 5 minutes by default.

    - - + + \ No newline at end of file diff --git a/docs/2.15.1/lms-backends/index.html b/docs/2.15.1/lms-backends/index.html index 67f6636fcb..159af7cb69 100644 --- a/docs/2.15.1/lms-backends/index.html +++ b/docs/2.15.1/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: 2.15.1

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.15.1

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/2.15.1/lms-connection/index.html b/docs/2.15.1/lms-connection/index.html index bf4046f279..a3856d214d 100644 --- a/docs/2.15.1/lms-connection/index.html +++ b/docs/2.15.1/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: 2.15.1

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.15.1

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/2.15.1/native-installation/index.html b/docs/2.15.1/native-installation/index.html index 54705b517a..73e9b7b9a1 100644 --- a/docs/2.15.1/native-installation/index.html +++ b/docs/2.15.1/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.15.1

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.15.1

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native installation instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.15.1/synchronizing-course-runs/index.html b/docs/2.15.1/synchronizing-course-runs/index.html index 5dde2c9cf0..30eb8d761a 100644 --- a/docs/2.15.1/synchronizing-course-runs/index.html +++ b/docs/2.15.1/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: 2.15.1

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.15.1

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -29,7 +29,7 @@ course run is modified and published.

    Or you can use the Richie Open edX Synchronization which is based on the following code sample and also includes the enrollment count.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/2.15.1/tls-connection/index.html b/docs/2.15.1/tls-connection/index.html index 21b630168c..99d0113be5 100644 --- a/docs/2.15.1/tls-connection/index.html +++ b/docs/2.15.1/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: 2.15.1

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.15.1

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/2.15.1/web-analytics/index.html b/docs/2.15.1/web-analytics/index.html index 8830b5fc50..c1ab1688fa 100644 --- a/docs/2.15.1/web-analytics/index.html +++ b/docs/2.15.1/web-analytics/index.html @@ -4,19 +4,19 @@ Add web analytics to your site | Richie - - + +
    -
    Version: 2.15.1

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. +

    Version: 2.15.1

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. The purpose of this file is to explain how you can enable one of the supported Web Analytics providers and how you can extend Richie with an alternative solution.

    Google Analytics

    Next, it is described how you can configure the Google Analytics on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Analytics tracking id code.

    The current Google Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Google Tag Manager

    Next, it is described how you can configure the Google Tag Manager on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Tag Manager tracking id code.
    • Add the WEB_ANALYTICS_PROVIDER setting with the google_tag_manager value.

    The current Google Tag Manager implementation also defines a custom dimensions like the Google Analytics.

    Location of the web analytics javascript

    Use the WEB_ANALYTICS_LOCATION settings to decide where do you want to put the Javascript code. Use head (default value), to put the Javascript on HTML header, or footer, to put the Javascript code to the bottom of the body.

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS_ID setting with your tracking identification
    • define the WEB_ANALYTICS_PROVIDER setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • optionally change WEB_ANALYTICS_LOCATION setting with head (default) or footer value
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% block web_analytics %}
    {% if WEB_ANALYTICS_ID %}
    {% if WEB_ANALYTICS_PROVIDER == "my_custom_web_analytics_software" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endif %}
    {% endblock web_analytics %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>

    The frontend code also sends events to the web analytics provider. Richie sends events when the user is enrolled on a course run. To support different providers, you need to create a similar file of src/frontend/js/utils/api/web-analytics/google_analytics.ts and change the src/frontend/js/utils/api/web-analytics/index.ts file to include that newer provider.

    - - + + \ No newline at end of file diff --git a/docs/2.16.0/accessibility-testing/index.html b/docs/2.16.0/accessibility-testing/index.html index c375551025..a11a4482c9 100644 --- a/docs/2.16.0/accessibility-testing/index.html +++ b/docs/2.16.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.16.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.16.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.16.0/api/course-run-synchronization-api/index.html b/docs/2.16.0/api/course-run-synchronization-api/index.html index 79c9e58aa1..c10f788cfb 100644 --- a/docs/2.16.0/api/course-run-synchronization-api/index.html +++ b/docs/2.16.0/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
    -
    Version: 2.16.0

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: 2.16.0

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
    • Body

        {
      "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
      "start": "2021-02-01T00:00:00Z",
      "end": "2021-02-31T23:59:59Z",
      "enrollment_start": "2021-01-01T00:00:00Z",
      "enrollment_end": "2021-01-31T23:59:59Z",
      "languages": ["en", "fr"]
      }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/2.16.0/building-the-frontend/index.html b/docs/2.16.0/building-the-frontend/index.html index 37e5776e28..11eec4f8ea 100644 --- a/docs/2.16.0/building-the-frontend/index.html +++ b/docs/2.16.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.16.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.16.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.16.0/contributing-guide/index.html b/docs/2.16.0/contributing-guide/index.html index 9cb9fb9f2b..529d22df6d 100644 --- a/docs/2.16.0/contributing-guide/index.html +++ b/docs/2.16.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.16.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.16.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.16.0/cookiecutter/index.html b/docs/2.16.0/cookiecutter/index.html index c07a8f320b..24e9eee0ca 100644 --- a/docs/2.16.0/cookiecutter/index.html +++ b/docs/2.16.0/cookiecutter/index.html @@ -4,12 +4,12 @@ Start your own site | Richie - - + +
    -
    Version: 2.16.0

    Start your own site

    We use Cookiecutter to help you +

    Version: 2.16.0

    Start your own site

    We use Cookiecutter to help you set up a production-ready learning portal website based on Richie in seconds.

    Run Cookiecutter

    There are 2 options to run Cookiecutter:

    While you think of it, navigate to the directory in which you want to create your site factory:

    cd /path/to/your/code/directory

    If you chose to install Cookiecutter, you can now run it against our @@ -30,7 +30,7 @@ project's scaffolding but, don't worry, it will respect all the sites you will have created in the sites directory:

    cookiecutter --overwrite-if-exists gh:openfun/richie --directory=cookiecutter

    Help us improve this project

    After starting your project, please submit an issue let us know how it went and what other features we should add to make it better.

    - - + + \ No newline at end of file diff --git a/docs/2.16.0/css-guidelines/index.html b/docs/2.16.0/css-guidelines/index.html index f16d742a92..6d1f382ecd 100644 --- a/docs/2.16.0/css-guidelines/index.html +++ b/docs/2.16.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.16.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.16.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.16.0/discover/index.html b/docs/2.16.0/discover/index.html index 2538ba61cd..ea65b283de 100644 --- a/docs/2.16.0/discover/index.html +++ b/docs/2.16.0/discover/index.html @@ -4,12 +4,12 @@ Discover Richie | Richie - - + +
    -
    Version: 2.16.0

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online +

    Version: 2.16.0

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online courses and MOOCs.

    However, if you need to build a complete website with flexible content to aggregate your courses, in several languages and from different sources, you will soon need a CMS.

    At "France Université Numérique", we wanted to build an OpenSource portal with Python and Django. That's why we built Richie on top of DjangoCMS, one of @@ -21,7 +21,7 @@ OpenEdX Docker.

    Two users are available for testing:

    • admin: admin@example.com/admin
    • student: edx@example.com/edx

    The database is regularly flushed.

    Start your own site

    The next step after discovering Richie on the demo is to start your own project. We provide a production-ready template based on Cookiecutter that allows you to generate your project in seconds.

    Follow the guide on starting your own Richie site with Cookiecutter.

    Once you created a new site, you will be able to fully customize it:

    - - + + \ No newline at end of file diff --git a/docs/2.16.0/displaying-connection-status/index.html b/docs/2.16.0/displaying-connection-status/index.html index 8d4d3be176..902c869945 100644 --- a/docs/2.16.0/displaying-connection-status/index.html +++ b/docs/2.16.0/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: 2.16.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.16.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/2.16.0/django-react-interop/index.html b/docs/2.16.0/django-react-interop/index.html index 26dd1ebaa9..9bddc2ef7d 100644 --- a/docs/2.16.0/django-react-interop/index.html +++ b/docs/2.16.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.16.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.16.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.16.0/docker-development/index.html b/docs/2.16.0/docker-development/index.html index bce9f6d9f7..91508b9390 100644 --- a/docs/2.16.0/docker-development/index.html +++ b/docs/2.16.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.16.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.16.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.16.0/frontend-overrides/index.html b/docs/2.16.0/frontend-overrides/index.html index 6192c475b4..2cf6c96112 100644 --- a/docs/2.16.0/frontend-overrides/index.html +++ b/docs/2.16.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.16.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.16.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.16.0/installation/index.html b/docs/2.16.0/installation/index.html index 0268772023..3e85e2d256 100644 --- a/docs/2.16.0/installation/index.html +++ b/docs/2.16.0/installation/index.html @@ -4,12 +4,12 @@ Installing Richie for development | Richie - - + +
    -
    Version: 2.16.0

    Installing Richie for development

    Richie is a container-native application but can also be installed +

    Version: 2.16.0

    Installing Richie for development

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of:

    • 3 running services:

      • database: postgresql or mysql at your preference,
      • elasticsearch: the search engine,
      • app: the actual DjangoCMS project with all our application code.
    • 2 containers for building purposes:

    - - + + \ No newline at end of file diff --git a/docs/2.16.0/internationalization/index.html b/docs/2.16.0/internationalization/index.html index d547f8cfd6..5d836316f6 100644 --- a/docs/2.16.0/internationalization/index.html +++ b/docs/2.16.0/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.16.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.16.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.16.0/joanie-connection/index.html b/docs/2.16.0/joanie-connection/index.html index 63d409cde9..a8601c1308 100644 --- a/docs/2.16.0/joanie-connection/index.html +++ b/docs/2.16.0/joanie-connection/index.html @@ -4,12 +4,12 @@ Joanie Connection | Richie - - + +
    -
    Version: 2.16.0

    Joanie Connection

    Settings

    All settings related to Joanie have to be declared in the JOANIE dictionary +

    Version: 2.16.0

    Joanie Connection

    Settings

    All settings related to Joanie have to be declared in the JOANIE dictionary within settings.py. To enable Joanie, the minimal configuration requires one property:

    • BASE_URL : the endpoint at which Joanie is accessible

    Add to your settings.py:

    ...
    JOANIE = {
    "BASE_URL": values.Value(environ_name="JOANIE_BASE_URL", environ_prefix=None)
    }
    ...

    Access Token

    Lifetime configuration

    Access Token is stored within the SessionStorage through react-query client persistor. @@ -19,7 +19,7 @@ lifetime of the access token defined by your authentication server. For example, if your authentication server is using djangorestframework-simplejwt to generate the access token, its lifetime is 5 minutes by default.

    - - + + \ No newline at end of file diff --git a/docs/2.16.0/lms-backends/index.html b/docs/2.16.0/lms-backends/index.html index f7133bc0f2..081e1120b6 100644 --- a/docs/2.16.0/lms-backends/index.html +++ b/docs/2.16.0/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: 2.16.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.16.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/2.16.0/lms-connection/index.html b/docs/2.16.0/lms-connection/index.html index 6b2c4f8d5d..8c79cc4b16 100644 --- a/docs/2.16.0/lms-connection/index.html +++ b/docs/2.16.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: 2.16.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.16.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/2.16.0/native-installation/index.html b/docs/2.16.0/native-installation/index.html index 8494f6ee78..3f25b0a834 100644 --- a/docs/2.16.0/native-installation/index.html +++ b/docs/2.16.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.16.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.16.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native installation instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.16.0/synchronizing-course-runs/index.html b/docs/2.16.0/synchronizing-course-runs/index.html index 7aa2227f95..7054df70cc 100644 --- a/docs/2.16.0/synchronizing-course-runs/index.html +++ b/docs/2.16.0/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: 2.16.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.16.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -29,7 +29,7 @@ course run is modified and published.

    Or you can use the Richie Open edX Synchronization which is based on the following code sample and also includes the enrollment count.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/2.16.0/tls-connection/index.html b/docs/2.16.0/tls-connection/index.html index 9109e6a3a8..d868240dd6 100644 --- a/docs/2.16.0/tls-connection/index.html +++ b/docs/2.16.0/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: 2.16.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.16.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/2.16.0/web-analytics/index.html b/docs/2.16.0/web-analytics/index.html index e1bf9493b5..f462cced38 100644 --- a/docs/2.16.0/web-analytics/index.html +++ b/docs/2.16.0/web-analytics/index.html @@ -4,19 +4,19 @@ Add web analytics to your site | Richie - - + +
    -
    Version: 2.16.0

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. +

    Version: 2.16.0

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. The purpose of this file is to explain how you can enable one of the supported Web Analytics providers and how you can extend Richie with an alternative solution.

    Google Analytics

    Next, it is described how you can configure the Google Analytics on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Analytics tracking id code.

    The current Google Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Google Tag Manager

    Next, it is described how you can configure the Google Tag Manager on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Tag Manager tracking id code.
    • Add the WEB_ANALYTICS_PROVIDER setting with the google_tag_manager value.

    The current Google Tag Manager implementation also defines a custom dimensions like the Google Analytics.

    Location of the web analytics javascript

    Use the WEB_ANALYTICS_LOCATION settings to decide where do you want to put the Javascript code. Use head (default value), to put the Javascript on HTML header, or footer, to put the Javascript code to the bottom of the body.

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS_ID setting with your tracking identification
    • define the WEB_ANALYTICS_PROVIDER setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • optionally change WEB_ANALYTICS_LOCATION setting with head (default) or footer value
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% block web_analytics %}
    {% if WEB_ANALYTICS_ID %}
    {% if WEB_ANALYTICS_PROVIDER == "my_custom_web_analytics_software" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endif %}
    {% endblock web_analytics %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>

    The frontend code also sends events to the web analytics provider. Richie sends events when the user is enrolled on a course run. To support different providers, you need to create a similar file of src/frontend/js/utils/api/web-analytics/google_analytics.ts and change the src/frontend/js/utils/api/web-analytics/index.ts file to include that newer provider.

    - - + + \ No newline at end of file diff --git a/docs/2.17.0/accessibility-testing/index.html b/docs/2.17.0/accessibility-testing/index.html index 33e990d067..e1c09ae444 100644 --- a/docs/2.17.0/accessibility-testing/index.html +++ b/docs/2.17.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.17.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.17.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.17.0/api/course-run-synchronization-api/index.html b/docs/2.17.0/api/course-run-synchronization-api/index.html index e530dcf549..2d008ac200 100644 --- a/docs/2.17.0/api/course-run-synchronization-api/index.html +++ b/docs/2.17.0/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
    -
    Version: 2.17.0

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: 2.17.0

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
    • Body

        {
      "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
      "start": "2021-02-01T00:00:00Z",
      "end": "2021-02-31T23:59:59Z",
      "enrollment_start": "2021-01-01T00:00:00Z",
      "enrollment_end": "2021-01-31T23:59:59Z",
      "languages": ["en", "fr"]
      }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/2.17.0/building-the-frontend/index.html b/docs/2.17.0/building-the-frontend/index.html index 0b64b7067e..ce268b9416 100644 --- a/docs/2.17.0/building-the-frontend/index.html +++ b/docs/2.17.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.17.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.17.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.17.0/contributing-guide/index.html b/docs/2.17.0/contributing-guide/index.html index 7cdf123cf4..106a6d6de7 100644 --- a/docs/2.17.0/contributing-guide/index.html +++ b/docs/2.17.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.17.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.17.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.17.0/cookiecutter/index.html b/docs/2.17.0/cookiecutter/index.html index 064fd124fb..3bea584c1b 100644 --- a/docs/2.17.0/cookiecutter/index.html +++ b/docs/2.17.0/cookiecutter/index.html @@ -4,12 +4,12 @@ Start your own site | Richie - - + +
    -
    Version: 2.17.0

    Start your own site

    We use Cookiecutter to help you +

    Version: 2.17.0

    Start your own site

    We use Cookiecutter to help you set up a production-ready learning portal website based on Richie in seconds.

    Run Cookiecutter

    There are 2 options to run Cookiecutter:

    While you think of it, navigate to the directory in which you want to create your site factory:

    cd /path/to/your/code/directory

    If you chose to install Cookiecutter, you can now run it against our @@ -30,7 +30,7 @@ project's scaffolding but, don't worry, it will respect all the sites you will have created in the sites directory:

    cookiecutter --overwrite-if-exists gh:openfun/richie --directory=cookiecutter

    Help us improve this project

    After starting your project, please submit an issue let us know how it went and what other features we should add to make it better.

    - - + + \ No newline at end of file diff --git a/docs/2.17.0/css-guidelines/index.html b/docs/2.17.0/css-guidelines/index.html index edfe2b0840..3cfb9e72a4 100644 --- a/docs/2.17.0/css-guidelines/index.html +++ b/docs/2.17.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.17.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.17.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.17.0/discover/index.html b/docs/2.17.0/discover/index.html index 5f528ae8e3..80ac71d284 100644 --- a/docs/2.17.0/discover/index.html +++ b/docs/2.17.0/discover/index.html @@ -4,12 +4,12 @@ Discover Richie | Richie - - + +
    -
    Version: 2.17.0

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online +

    Version: 2.17.0

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online courses and MOOCs.

    However, if you need to build a complete website with flexible content to aggregate your courses, in several languages and from different sources, you will soon need a CMS.

    At "France Université Numérique", we wanted to build an OpenSource portal with Python and Django. That's why we built Richie on top of DjangoCMS, one of @@ -21,7 +21,7 @@ OpenEdX Docker.

    Two users are available for testing:

    • admin: admin@example.com/admin
    • student: edx@example.com/edx

    The database is regularly flushed.

    Start your own site

    The next step after discovering Richie on the demo is to start your own project. We provide a production-ready template based on Cookiecutter that allows you to generate your project in seconds.

    Follow the guide on starting your own Richie site with Cookiecutter.

    Once you created a new site, you will be able to fully customize it:

    - - + + \ No newline at end of file diff --git a/docs/2.17.0/displaying-connection-status/index.html b/docs/2.17.0/displaying-connection-status/index.html index 378ab07b1b..2df985d0f6 100644 --- a/docs/2.17.0/displaying-connection-status/index.html +++ b/docs/2.17.0/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: 2.17.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.17.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/2.17.0/django-react-interop/index.html b/docs/2.17.0/django-react-interop/index.html index bbb149d363..a56322317f 100644 --- a/docs/2.17.0/django-react-interop/index.html +++ b/docs/2.17.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.17.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.17.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.17.0/docker-development/index.html b/docs/2.17.0/docker-development/index.html index 818308a0b8..bdfeb78247 100644 --- a/docs/2.17.0/docker-development/index.html +++ b/docs/2.17.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.17.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.17.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.17.0/filters-customization/index.html b/docs/2.17.0/filters-customization/index.html index aa322b3555..24392f862f 100644 --- a/docs/2.17.0/filters-customization/index.html +++ b/docs/2.17.0/filters-customization/index.html @@ -4,12 +4,12 @@ Customizing search filters | Richie - - + +
    -
    Version: 2.17.0

    Customizing search filters

    You may want to customize the filters on the left side bar of the search page.

    Richie makes it easy to choose which filters you want to display among the existing filters +

    Version: 2.17.0

    Customizing search filters

    You may want to customize the filters on the left side bar of the search page.

    Richie makes it easy to choose which filters you want to display among the existing filters and in which order. You can also configure the existing filters to change their title or the way they behave. Lastly, you can completely override a filter or create your own custom filter from scratch.

    Filters configuration

    Filters must first be defined in the FILTERS_CONFIGURATION setting. It is a dictionary defining @@ -48,7 +48,7 @@ trivial, was given much care and includes many comments in an attempt to help writing new custom filters. Of course, don't hesitate to ask for help by opening an issue!

    - - + + \ No newline at end of file diff --git a/docs/2.17.0/frontend-overrides/index.html b/docs/2.17.0/frontend-overrides/index.html index 57b296bd5c..173c80906f 100644 --- a/docs/2.17.0/frontend-overrides/index.html +++ b/docs/2.17.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.17.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.17.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.17.0/installation/index.html b/docs/2.17.0/installation/index.html index 6eebfe12bf..b7be1d5563 100644 --- a/docs/2.17.0/installation/index.html +++ b/docs/2.17.0/installation/index.html @@ -4,12 +4,12 @@ Installing Richie for development | Richie - - + +
    -
    Version: 2.17.0

    Installing Richie for development

    Richie is a container-native application but can also be installed +

    Version: 2.17.0

    Installing Richie for development

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of:

    • 3 running services:

      • database: postgresql or mysql at your preference,
      • elasticsearch: the search engine,
      • app: the actual DjangoCMS project with all our application code.
    • 2 containers for building purposes:

    - - + + \ No newline at end of file diff --git a/docs/2.17.0/internationalization/index.html b/docs/2.17.0/internationalization/index.html index efbaa4cde0..e5dff2a8ee 100644 --- a/docs/2.17.0/internationalization/index.html +++ b/docs/2.17.0/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.17.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.17.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.17.0/joanie-connection/index.html b/docs/2.17.0/joanie-connection/index.html index e5e7b14181..2bfdfce104 100644 --- a/docs/2.17.0/joanie-connection/index.html +++ b/docs/2.17.0/joanie-connection/index.html @@ -4,12 +4,12 @@ Joanie Connection | Richie - - + +
    -
    Version: 2.17.0

    Joanie Connection

    Settings

    All settings related to Joanie have to be declared in the JOANIE dictionary +

    Version: 2.17.0

    Joanie Connection

    Settings

    All settings related to Joanie have to be declared in the JOANIE dictionary within settings.py. To enable Joanie, the minimal configuration requires one property:

    • BASE_URL : the endpoint at which Joanie is accessible

    Add to your settings.py:

    ...
    JOANIE = {
    "BASE_URL": values.Value(environ_name="JOANIE_BASE_URL", environ_prefix=None)
    }
    ...

    Access Token

    Lifetime configuration

    Access Token is stored within the SessionStorage through react-query client persistor. @@ -19,7 +19,7 @@ lifetime of the access token defined by your authentication server. For example, if your authentication server is using djangorestframework-simplejwt to generate the access token, its lifetime is 5 minutes by default.

    - - + + \ No newline at end of file diff --git a/docs/2.17.0/lms-backends/index.html b/docs/2.17.0/lms-backends/index.html index 28f17d256b..c4c85a5848 100644 --- a/docs/2.17.0/lms-backends/index.html +++ b/docs/2.17.0/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: 2.17.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.17.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/2.17.0/lms-connection/index.html b/docs/2.17.0/lms-connection/index.html index 382a91c4e3..dc51a9f38c 100644 --- a/docs/2.17.0/lms-connection/index.html +++ b/docs/2.17.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: 2.17.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.17.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/2.17.0/native-installation/index.html b/docs/2.17.0/native-installation/index.html index 8efdfbf68f..cd66fb5667 100644 --- a/docs/2.17.0/native-installation/index.html +++ b/docs/2.17.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.17.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.17.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native installation instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.17.0/synchronizing-course-runs/index.html b/docs/2.17.0/synchronizing-course-runs/index.html index 2871c5ae77..58888f860f 100644 --- a/docs/2.17.0/synchronizing-course-runs/index.html +++ b/docs/2.17.0/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: 2.17.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.17.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -29,7 +29,7 @@ course run is modified and published.

    Or you can use the Richie Open edX Synchronization which is based on the following code sample and also includes the enrollment count.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/2.17.0/tls-connection/index.html b/docs/2.17.0/tls-connection/index.html index f39b88db9d..1322fc0061 100644 --- a/docs/2.17.0/tls-connection/index.html +++ b/docs/2.17.0/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: 2.17.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.17.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/2.17.0/web-analytics/index.html b/docs/2.17.0/web-analytics/index.html index 7b11c4d0f7..9bf195adda 100644 --- a/docs/2.17.0/web-analytics/index.html +++ b/docs/2.17.0/web-analytics/index.html @@ -4,19 +4,19 @@ Add web analytics to your site | Richie - - + +
    -
    Version: 2.17.0

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. +

    Version: 2.17.0

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. The purpose of this file is to explain how you can enable one of the supported Web Analytics providers and how you can extend Richie with an alternative solution.

    Google Analytics

    Next, it is described how you can configure the Google Analytics on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Analytics tracking id code.

    The current Google Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Google Tag Manager

    Next, it is described how you can configure the Google Tag Manager on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Tag Manager tracking id code.
    • Add the WEB_ANALYTICS_PROVIDER setting with the google_tag_manager value.

    The current Google Tag Manager implementation also defines a custom dimensions like the Google Analytics.

    Location of the web analytics javascript

    Use the WEB_ANALYTICS_LOCATION settings to decide where do you want to put the Javascript code. Use head (default value), to put the Javascript on HTML header, or footer, to put the Javascript code to the bottom of the body.

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS_ID setting with your tracking identification
    • define the WEB_ANALYTICS_PROVIDER setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • optionally change WEB_ANALYTICS_LOCATION setting with head (default) or footer value
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% block web_analytics %}
    {% if WEB_ANALYTICS_ID %}
    {% if WEB_ANALYTICS_PROVIDER == "my_custom_web_analytics_software" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endif %}
    {% endblock web_analytics %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>

    The frontend code also sends events to the web analytics provider. Richie sends events when the user is enrolled on a course run. To support different providers, you need to create a similar file of src/frontend/js/utils/api/web-analytics/google_analytics.ts and change the src/frontend/js/utils/api/web-analytics/index.ts file to include that newer provider.

    - - + + \ No newline at end of file diff --git a/docs/2.18.0/accessibility-testing/index.html b/docs/2.18.0/accessibility-testing/index.html index c282001346..0fb11dfbd1 100644 --- a/docs/2.18.0/accessibility-testing/index.html +++ b/docs/2.18.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.18.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.18.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.18.0/api/course-run-synchronization-api/index.html b/docs/2.18.0/api/course-run-synchronization-api/index.html index 51e8680e03..d7feb24f35 100644 --- a/docs/2.18.0/api/course-run-synchronization-api/index.html +++ b/docs/2.18.0/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
    -
    Version: 2.18.0

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: 2.18.0

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
    • Body

        {
      "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
      "start": "2021-02-01T00:00:00Z",
      "end": "2021-02-31T23:59:59Z",
      "enrollment_start": "2021-01-01T00:00:00Z",
      "enrollment_end": "2021-01-31T23:59:59Z",
      "languages": ["en", "fr"]
      }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/2.18.0/building-the-frontend/index.html b/docs/2.18.0/building-the-frontend/index.html index f7701d578a..13d221fe23 100644 --- a/docs/2.18.0/building-the-frontend/index.html +++ b/docs/2.18.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.18.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.18.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.18.0/contributing-guide/index.html b/docs/2.18.0/contributing-guide/index.html index cd58b191fc..627441c796 100644 --- a/docs/2.18.0/contributing-guide/index.html +++ b/docs/2.18.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.18.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.18.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.18.0/cookiecutter/index.html b/docs/2.18.0/cookiecutter/index.html index 5b7c4ce742..b941c46599 100644 --- a/docs/2.18.0/cookiecutter/index.html +++ b/docs/2.18.0/cookiecutter/index.html @@ -4,12 +4,12 @@ Start your own site | Richie - - + +
    -
    Version: 2.18.0

    Start your own site

    We use Cookiecutter to help you +

    Version: 2.18.0

    Start your own site

    We use Cookiecutter to help you set up a production-ready learning portal website based on Richie in seconds.

    Run Cookiecutter

    There are 2 options to run Cookiecutter:

    While you think of it, navigate to the directory in which you want to create your site factory:

    cd /path/to/your/code/directory

    If you chose to install Cookiecutter, you can now run it against our @@ -30,7 +30,7 @@ project's scaffolding but, don't worry, it will respect all the sites you will have created in the sites directory:

    cookiecutter --overwrite-if-exists gh:openfun/richie --directory=cookiecutter

    Help us improve this project

    After starting your project, please submit an issue let us know how it went and what other features we should add to make it better.

    - - + + \ No newline at end of file diff --git a/docs/2.18.0/css-guidelines/index.html b/docs/2.18.0/css-guidelines/index.html index 50d9fe721b..995de3b4a2 100644 --- a/docs/2.18.0/css-guidelines/index.html +++ b/docs/2.18.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.18.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.18.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.18.0/discover/index.html b/docs/2.18.0/discover/index.html index 86589fd163..7411121da8 100644 --- a/docs/2.18.0/discover/index.html +++ b/docs/2.18.0/discover/index.html @@ -4,12 +4,12 @@ Discover Richie | Richie - - + +
    -
    Version: 2.18.0

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online +

    Version: 2.18.0

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online courses and MOOCs.

    However, if you need to build a complete website with flexible content to aggregate your courses, in several languages and from different sources, you will soon need a CMS.

    At "France Université Numérique", we wanted to build an OpenSource portal with Python and Django. That's why we built Richie on top of DjangoCMS, one of @@ -21,7 +21,7 @@ OpenEdX Docker.

    Two users are available for testing:

    • admin: admin@example.com/admin
    • student: edx@example.com/edx

    The database is regularly flushed.

    Start your own site

    The next step after discovering Richie on the demo is to start your own project. We provide a production-ready template based on Cookiecutter that allows you to generate your project in seconds.

    Follow the guide on starting your own Richie site with Cookiecutter.

    Once you created a new site, you will be able to fully customize it:

    - - + + \ No newline at end of file diff --git a/docs/2.18.0/displaying-connection-status/index.html b/docs/2.18.0/displaying-connection-status/index.html index 53ea49e67f..f5ebef476c 100644 --- a/docs/2.18.0/displaying-connection-status/index.html +++ b/docs/2.18.0/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: 2.18.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.18.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/2.18.0/django-react-interop/index.html b/docs/2.18.0/django-react-interop/index.html index 2c188d5cb7..01fef43a55 100644 --- a/docs/2.18.0/django-react-interop/index.html +++ b/docs/2.18.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.18.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.18.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.18.0/docker-development/index.html b/docs/2.18.0/docker-development/index.html index 80fd3c3bba..c9d0036cfd 100644 --- a/docs/2.18.0/docker-development/index.html +++ b/docs/2.18.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.18.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.18.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.18.0/filters-customization/index.html b/docs/2.18.0/filters-customization/index.html index 9771edb988..729fb25974 100644 --- a/docs/2.18.0/filters-customization/index.html +++ b/docs/2.18.0/filters-customization/index.html @@ -4,12 +4,12 @@ Customizing search filters | Richie - - + +
    -
    Version: 2.18.0

    Customizing search filters

    You may want to customize the filters on the left side bar of the search page.

    Richie makes it easy to choose which filters you want to display among the existing filters +

    Version: 2.18.0

    Customizing search filters

    You may want to customize the filters on the left side bar of the search page.

    Richie makes it easy to choose which filters you want to display among the existing filters and in which order. You can also configure the existing filters to change their title or the way they behave. Lastly, you can completely override a filter or create your own custom filter from scratch.

    Filters configuration

    Filters must first be defined in the FILTERS_CONFIGURATION setting. It is a dictionary defining @@ -48,7 +48,7 @@ trivial, was given much care and includes many comments in an attempt to help writing new custom filters. Of course, don't hesitate to ask for help by opening an issue!

    - - + + \ No newline at end of file diff --git a/docs/2.18.0/frontend-overrides/index.html b/docs/2.18.0/frontend-overrides/index.html index b85a2165f7..acf485ff19 100644 --- a/docs/2.18.0/frontend-overrides/index.html +++ b/docs/2.18.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.18.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.18.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.18.0/installation/index.html b/docs/2.18.0/installation/index.html index cf0ecfd4fe..6ce24bfec9 100644 --- a/docs/2.18.0/installation/index.html +++ b/docs/2.18.0/installation/index.html @@ -4,12 +4,12 @@ Installing Richie for development | Richie - - + +
    -
    Version: 2.18.0

    Installing Richie for development

    Richie is a container-native application but can also be installed +

    Version: 2.18.0

    Installing Richie for development

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of:

    • 3 running services:

      • database: postgresql or mysql at your preference,
      • elasticsearch: the search engine,
      • app: the actual DjangoCMS project with all our application code.
    • 2 containers for building purposes:

    - - + + \ No newline at end of file diff --git a/docs/2.18.0/internationalization/index.html b/docs/2.18.0/internationalization/index.html index 27d5f4173f..702a5a4808 100644 --- a/docs/2.18.0/internationalization/index.html +++ b/docs/2.18.0/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.18.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.18.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.18.0/joanie-connection/index.html b/docs/2.18.0/joanie-connection/index.html index 2a955df45f..89980cfef4 100644 --- a/docs/2.18.0/joanie-connection/index.html +++ b/docs/2.18.0/joanie-connection/index.html @@ -4,12 +4,12 @@ Joanie Connection | Richie - - + +
    -
    Version: 2.18.0

    Joanie Connection

    Settings

    All settings related to Joanie have to be declared in the JOANIE_BACKEND dictionary +

    Version: 2.18.0

    Joanie Connection

    Settings

    All settings related to Joanie have to be declared in the JOANIE_BACKEND dictionary within settings.py. To enable Joanie, the minimal configuration requires following properties:

    • BASE_URL
    • BACKEND
    • COURSE_REGEX
    • JS_COURSE_REGEX

    Take a look to LMS Backend documentation to get details about those properties.

    Add to your settings.py:

    ...
    JOANIE_BACKEND = {
    "BASE_URL": values.Value(environ_name="JOANIE_BASE_URL", environ_prefix=None),
    "BACKEND": values.Value("richie.apps.courses.lms.joanie.JoanieBackend", environ_name="JOANIE_BACKEND", environ_prefix=None),
    "JS_BACKEND": values.Value("joanie", environ_name="JOANIE_JS_BACKEND", environ_prefix=None),
    "COURSE_REGEX": values.Value(
    r"^.*/api/(?P<resource_type>(course-runs|products))/(?P<resource_id>.*)/?$",
    environ_name="JOANIE_COURSE_REGEX",
    environ_prefix=None,
    ),
    "JS_COURSE_REGEX": values.Value(
    r"^.*/api/(course-runs|products)/(.*)/?$",
    environ_name="JOANIE_JS_COURSE_REGEX",
    environ_prefix=None,
    ),
    }
    ...

    Access Token

    Lifetime configuration

    Access Token is stored within the SessionStorage through react-query client persister. By default, richie frontend considered access token as stale after 5 minutes. You can change this @@ -18,7 +18,7 @@ lifetime of the access token defined by your authentication server. For example, if your authentication server is using djangorestframework-simplejwt to generate the access token, its lifetime is 5 minutes by default.

    - - + + \ No newline at end of file diff --git a/docs/2.18.0/lms-backends/index.html b/docs/2.18.0/lms-backends/index.html index 56c5cb1337..9bdf9a1c2e 100644 --- a/docs/2.18.0/lms-backends/index.html +++ b/docs/2.18.0/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: 2.18.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.18.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/2.18.0/lms-connection/index.html b/docs/2.18.0/lms-connection/index.html index 2745c0d94a..64613e443b 100644 --- a/docs/2.18.0/lms-connection/index.html +++ b/docs/2.18.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: 2.18.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.18.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/2.18.0/native-installation/index.html b/docs/2.18.0/native-installation/index.html index 80f1dba678..5480485cb7 100644 --- a/docs/2.18.0/native-installation/index.html +++ b/docs/2.18.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.18.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.18.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native installation instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.18.0/synchronizing-course-runs/index.html b/docs/2.18.0/synchronizing-course-runs/index.html index d0a91e2640..92214d3118 100644 --- a/docs/2.18.0/synchronizing-course-runs/index.html +++ b/docs/2.18.0/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: 2.18.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.18.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -29,7 +29,7 @@ course run is modified and published.

    Or you can use the Richie Open edX Synchronization which is based on the following code sample and also includes the enrollment count.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/2.18.0/tls-connection/index.html b/docs/2.18.0/tls-connection/index.html index 4e7ae06d7b..1f3153975d 100644 --- a/docs/2.18.0/tls-connection/index.html +++ b/docs/2.18.0/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: 2.18.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.18.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/2.18.0/web-analytics/index.html b/docs/2.18.0/web-analytics/index.html index d434565ac9..0623e7e87d 100644 --- a/docs/2.18.0/web-analytics/index.html +++ b/docs/2.18.0/web-analytics/index.html @@ -4,19 +4,19 @@ Add web analytics to your site | Richie - - + +
    -
    Version: 2.18.0

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. +

    Version: 2.18.0

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. The purpose of this file is to explain how you can enable one of the supported Web Analytics providers and how you can extend Richie with an alternative solution.

    Google Analytics

    Next, it is described how you can configure the Google Analytics on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Analytics tracking id code.

    The current Google Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Google Tag Manager

    Next, it is described how you can configure the Google Tag Manager on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Tag Manager tracking id code.
    • Add the WEB_ANALYTICS_PROVIDER setting with the google_tag_manager value.

    The current Google Tag Manager implementation also defines a custom dimensions like the Google Analytics.

    Location of the web analytics javascript

    Use the WEB_ANALYTICS_LOCATION settings to decide where do you want to put the Javascript code. Use head (default value), to put the Javascript on HTML header, or footer, to put the Javascript code to the bottom of the body.

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS_ID setting with your tracking identification
    • define the WEB_ANALYTICS_PROVIDER setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • optionally change WEB_ANALYTICS_LOCATION setting with head (default) or footer value
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% block web_analytics %}
    {% if WEB_ANALYTICS_ID %}
    {% if WEB_ANALYTICS_PROVIDER == "my_custom_web_analytics_software" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endif %}
    {% endblock web_analytics %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>

    The frontend code also sends events to the web analytics provider. Richie sends events when the user is enrolled on a course run. To support different providers, you need to create a similar file of src/frontend/js/utils/api/web-analytics/google_analytics.ts and change the src/frontend/js/utils/api/web-analytics/index.ts file to include that newer provider.

    - - + + \ No newline at end of file diff --git a/docs/2.19.0/accessibility-testing/index.html b/docs/2.19.0/accessibility-testing/index.html index 17a9ef7092..9faa48eb16 100644 --- a/docs/2.19.0/accessibility-testing/index.html +++ b/docs/2.19.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.19.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.19.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.19.0/api/course-run-synchronization-api/index.html b/docs/2.19.0/api/course-run-synchronization-api/index.html index f2ea09200a..7836041d3f 100644 --- a/docs/2.19.0/api/course-run-synchronization-api/index.html +++ b/docs/2.19.0/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
    -
    Version: 2.19.0

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: 2.19.0

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
    • Body

        {
      "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
      "start": "2021-02-01T00:00:00Z",
      "end": "2021-02-31T23:59:59Z",
      "enrollment_start": "2021-01-01T00:00:00Z",
      "enrollment_end": "2021-01-31T23:59:59Z",
      "languages": ["en", "fr"]
      }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/2.19.0/building-the-frontend/index.html b/docs/2.19.0/building-the-frontend/index.html index d06411f84a..6b0cca344f 100644 --- a/docs/2.19.0/building-the-frontend/index.html +++ b/docs/2.19.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.19.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.19.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.19.0/contributing-guide/index.html b/docs/2.19.0/contributing-guide/index.html index 13f48f5558..1d57801af0 100644 --- a/docs/2.19.0/contributing-guide/index.html +++ b/docs/2.19.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.19.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.19.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.19.0/cookiecutter/index.html b/docs/2.19.0/cookiecutter/index.html index d0d8b81557..ea05009788 100644 --- a/docs/2.19.0/cookiecutter/index.html +++ b/docs/2.19.0/cookiecutter/index.html @@ -4,12 +4,12 @@ Start your own site | Richie - - + +
    -
    Version: 2.19.0

    Start your own site

    We use Cookiecutter to help you +

    Version: 2.19.0

    Start your own site

    We use Cookiecutter to help you set up a production-ready learning portal website based on Richie in seconds.

    Run Cookiecutter

    There are 2 options to run Cookiecutter:

    While you think of it, navigate to the directory in which you want to create your site factory:

    cd /path/to/your/code/directory

    If you chose to install Cookiecutter, you can now run it against our @@ -30,7 +30,7 @@ project's scaffolding but, don't worry, it will respect all the sites you will have created in the sites directory:

    cookiecutter --overwrite-if-exists gh:openfun/richie --directory=cookiecutter

    Help us improve this project

    After starting your project, please submit an issue let us know how it went and what other features we should add to make it better.

    - - + + \ No newline at end of file diff --git a/docs/2.19.0/css-guidelines/index.html b/docs/2.19.0/css-guidelines/index.html index e4dda022e5..2815b7ad9b 100644 --- a/docs/2.19.0/css-guidelines/index.html +++ b/docs/2.19.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.19.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.19.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.19.0/discover/index.html b/docs/2.19.0/discover/index.html index ceac4d7634..544d9672ce 100644 --- a/docs/2.19.0/discover/index.html +++ b/docs/2.19.0/discover/index.html @@ -4,12 +4,12 @@ Discover Richie | Richie - - + +
    -
    Version: 2.19.0

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online +

    Version: 2.19.0

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online courses and MOOCs.

    However, if you need to build a complete website with flexible content to aggregate your courses, in several languages and from different sources, you will soon need a CMS.

    At "France Université Numérique", we wanted to build an OpenSource portal with Python and Django. That's why we built Richie on top of DjangoCMS, one of @@ -21,7 +21,7 @@ OpenEdX Docker.

    Two users are available for testing:

    • admin: admin@example.com/admin
    • student: edx@example.com/edx

    The database is regularly flushed.

    Start your own site

    The next step after discovering Richie on the demo is to start your own project. We provide a production-ready template based on Cookiecutter that allows you to generate your project in seconds.

    Follow the guide on starting your own Richie site with Cookiecutter.

    Once you created a new site, you will be able to fully customize it:

    - - + + \ No newline at end of file diff --git a/docs/2.19.0/displaying-connection-status/index.html b/docs/2.19.0/displaying-connection-status/index.html index 29472d3688..030d4ed0d6 100644 --- a/docs/2.19.0/displaying-connection-status/index.html +++ b/docs/2.19.0/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: 2.19.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.19.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/2.19.0/django-react-interop/index.html b/docs/2.19.0/django-react-interop/index.html index b815bdb116..6fbaf76623 100644 --- a/docs/2.19.0/django-react-interop/index.html +++ b/docs/2.19.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.19.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.19.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.19.0/docker-development/index.html b/docs/2.19.0/docker-development/index.html index f8327e6b49..c420d6b730 100644 --- a/docs/2.19.0/docker-development/index.html +++ b/docs/2.19.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.19.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.19.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.19.0/filters-customization/index.html b/docs/2.19.0/filters-customization/index.html index 4f57bc5157..e08caddfd0 100644 --- a/docs/2.19.0/filters-customization/index.html +++ b/docs/2.19.0/filters-customization/index.html @@ -4,12 +4,12 @@ Customizing search filters | Richie - - + +
    -
    Version: 2.19.0

    Customizing search filters

    You may want to customize the filters on the left side bar of the search page.

    Richie makes it easy to choose which filters you want to display among the existing filters +

    Version: 2.19.0

    Customizing search filters

    You may want to customize the filters on the left side bar of the search page.

    Richie makes it easy to choose which filters you want to display among the existing filters and in which order. You can also configure the existing filters to change their title or the way they behave. Lastly, you can completely override a filter or create your own custom filter from scratch.

    Filters configuration

    Filters must first be defined in the FILTERS_CONFIGURATION setting. It is a dictionary defining @@ -48,7 +48,7 @@ trivial, was given much care and includes many comments in an attempt to help writing new custom filters. Of course, don't hesitate to ask for help by opening an issue!

    - - + + \ No newline at end of file diff --git a/docs/2.19.0/frontend-overrides/index.html b/docs/2.19.0/frontend-overrides/index.html index 502756ce6a..17a7c823ab 100644 --- a/docs/2.19.0/frontend-overrides/index.html +++ b/docs/2.19.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.19.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.19.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.19.0/installation/index.html b/docs/2.19.0/installation/index.html index d886165c39..2c51e3ba75 100644 --- a/docs/2.19.0/installation/index.html +++ b/docs/2.19.0/installation/index.html @@ -4,12 +4,12 @@ Installing Richie for development | Richie - - + +
    -
    Version: 2.19.0

    Installing Richie for development

    Richie is a container-native application but can also be installed +

    Version: 2.19.0

    Installing Richie for development

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of:

    • 3 running services:

      • database: postgresql or mysql at your preference,
      • elasticsearch: the search engine,
      • app: the actual DjangoCMS project with all our application code.
    • 2 containers for building purposes:

    - - + + \ No newline at end of file diff --git a/docs/2.19.0/internationalization/index.html b/docs/2.19.0/internationalization/index.html index 7b1b5745a6..cc2b350f5e 100644 --- a/docs/2.19.0/internationalization/index.html +++ b/docs/2.19.0/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.19.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.19.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.19.0/joanie-connection/index.html b/docs/2.19.0/joanie-connection/index.html index 268b84b982..6671c2f670 100644 --- a/docs/2.19.0/joanie-connection/index.html +++ b/docs/2.19.0/joanie-connection/index.html @@ -4,12 +4,12 @@ Joanie Connection | Richie - - + +
    -
    Version: 2.19.0

    Joanie Connection

    Joanie delivers an API able to manage course +

    Version: 2.19.0

    Joanie Connection

    Joanie delivers an API able to manage course enrollment/subscription, payment and certificates delivery. Richie can be configured to display course runs and micro-credentials managed through Joanie.

    In fact, Richie treats Joanie almost like a LMS backend that's why settings are similars.

    Configuring Joanie

    All settings related to Joanie have to be declared in the JOANIE_BACKEND dictionnary @@ -40,7 +40,7 @@ authentication server is using djangorestframework-simplejwt to generate the access token, its lifetime is 5 minutes by default.

    Technical support

    If you encounter an issue with this documentation, please open an issue on our repository.

    - - + + \ No newline at end of file diff --git a/docs/2.19.0/lms-backends/index.html b/docs/2.19.0/lms-backends/index.html index 86dd536649..86b63aa818 100644 --- a/docs/2.19.0/lms-backends/index.html +++ b/docs/2.19.0/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: 2.19.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.19.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/2.19.0/lms-connection/index.html b/docs/2.19.0/lms-connection/index.html index 6fa8d7e2bc..e48b4b98ba 100644 --- a/docs/2.19.0/lms-connection/index.html +++ b/docs/2.19.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: 2.19.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.19.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/2.19.0/native-installation/index.html b/docs/2.19.0/native-installation/index.html index 6ff2d67570..c17ed15bc0 100644 --- a/docs/2.19.0/native-installation/index.html +++ b/docs/2.19.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.19.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.19.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native installation instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.19.0/synchronizing-course-runs/index.html b/docs/2.19.0/synchronizing-course-runs/index.html index bfe784849c..4c250648a4 100644 --- a/docs/2.19.0/synchronizing-course-runs/index.html +++ b/docs/2.19.0/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: 2.19.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.19.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -29,7 +29,7 @@ course run is modified and published.

    Or you can use the Richie Open edX Synchronization which is based on the following code sample and also includes the enrollment count.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/2.19.0/tls-connection/index.html b/docs/2.19.0/tls-connection/index.html index e4a62e2ba5..db478762cc 100644 --- a/docs/2.19.0/tls-connection/index.html +++ b/docs/2.19.0/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: 2.19.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.19.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/2.19.0/web-analytics/index.html b/docs/2.19.0/web-analytics/index.html index 92a6efe276..98d98e8045 100644 --- a/docs/2.19.0/web-analytics/index.html +++ b/docs/2.19.0/web-analytics/index.html @@ -4,19 +4,19 @@ Add web analytics to your site | Richie - - + +
    -
    Version: 2.19.0

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. +

    Version: 2.19.0

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. The purpose of this file is to explain how you can enable one of the supported Web Analytics providers and how you can extend Richie with an alternative solution.

    Google Analytics

    Next, it is described how you can configure the Google Analytics on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Analytics tracking id code.

    The current Google Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Google Tag Manager

    Next, it is described how you can configure the Google Tag Manager on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Tag Manager tracking id code.
    • Add the WEB_ANALYTICS_PROVIDER setting with the google_tag_manager value.

    The current Google Tag Manager implementation also defines a custom dimensions like the Google Analytics.

    Location of the web analytics javascript

    Use the WEB_ANALYTICS_LOCATION settings to decide where do you want to put the Javascript code. Use head (default value), to put the Javascript on HTML header, or footer, to put the Javascript code to the bottom of the body.

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS_ID setting with your tracking identification
    • define the WEB_ANALYTICS_PROVIDER setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • optionally change WEB_ANALYTICS_LOCATION setting with head (default) or footer value
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% block web_analytics %}
    {% if WEB_ANALYTICS_ID %}
    {% if WEB_ANALYTICS_PROVIDER == "my_custom_web_analytics_software" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endif %}
    {% endblock web_analytics %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>

    The frontend code also sends events to the web analytics provider. Richie sends events when the user is enrolled on a course run. To support different providers, you need to create a similar file of src/frontend/js/utils/api/web-analytics/google_analytics.ts and change the src/frontend/js/utils/api/web-analytics/index.ts file to include that newer provider.

    - - + + \ No newline at end of file diff --git a/docs/2.2.0/accessibility-testing/index.html b/docs/2.2.0/accessibility-testing/index.html index d0cbd6c6dc..4c176f5b92 100644 --- a/docs/2.2.0/accessibility-testing/index.html +++ b/docs/2.2.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.2.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.2.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.2.0/building-the-frontend/index.html b/docs/2.2.0/building-the-frontend/index.html index 429aa03182..54ab5f86d4 100644 --- a/docs/2.2.0/building-the-frontend/index.html +++ b/docs/2.2.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.2.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.2.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.2.0/contributing-guide/index.html b/docs/2.2.0/contributing-guide/index.html index 17d091d6b5..9c0f68ec09 100644 --- a/docs/2.2.0/contributing-guide/index.html +++ b/docs/2.2.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.2.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.2.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.2.0/css-guidelines/index.html b/docs/2.2.0/css-guidelines/index.html index 6db0561c2c..71735d9d7a 100644 --- a/docs/2.2.0/css-guidelines/index.html +++ b/docs/2.2.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.2.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.2.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.2.0/discover/index.html b/docs/2.2.0/discover/index.html index ae31a36ac7..d32dc1b042 100644 --- a/docs/2.2.0/discover/index.html +++ b/docs/2.2.0/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.2.0

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.2.0

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -27,7 +27,7 @@ to bootstrap an instance.

    Just start apps with make run.

    Richie should respond on http://localhost:8070 and OpenEdx on http://localhost:8073.

    Advanced - Connecting Richie to OpenEdx

    If you want users to enroll on courses in OpenEdx directly from Richie via API calls, you should read the advanced guide to connect Richie to OpenEdx over TLS.

    - - + + \ No newline at end of file diff --git a/docs/2.2.0/django-react-interop/index.html b/docs/2.2.0/django-react-interop/index.html index e8926589dd..2df33011bc 100644 --- a/docs/2.2.0/django-react-interop/index.html +++ b/docs/2.2.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.2.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.2.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.2.0/docker-development/index.html b/docs/2.2.0/docker-development/index.html index 99235898dd..19d10d602c 100644 --- a/docs/2.2.0/docker-development/index.html +++ b/docs/2.2.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.2.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.2.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.2.0/frontend-overrides/index.html b/docs/2.2.0/frontend-overrides/index.html index a970f44c2b..f57b7ef844 100644 --- a/docs/2.2.0/frontend-overrides/index.html +++ b/docs/2.2.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.2.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.2.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.2.0/internationalization/index.html b/docs/2.2.0/internationalization/index.html index b01c982f09..18907ab9b6 100644 --- a/docs/2.2.0/internationalization/index.html +++ b/docs/2.2.0/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.2.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.2.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.2.0/lms-connection/index.html b/docs/2.2.0/lms-connection/index.html index 189abc65f1..61f6d4ebd8 100644 --- a/docs/2.2.0/lms-connection/index.html +++ b/docs/2.2.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with an LMS | Richie - - + +
    -
    Version: 2.2.0

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle +

    Version: 2.2.0

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle or Canvas for a seamless experience between browsing the course catalog on richie and following the course itself on the LMS.

    In order to connect richie with a LMS, there is an API bridge to synchronize course information and enrollments.

    API bridge

    The APIHandler utility acts as a proxy that routes queries to the correct LMS backend API, @@ -43,7 +43,7 @@ on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. If you want to use SSL later, just use make run-ssl to run OpenEdx and Richie apps. Of course, you can still run apps without ssl by using make run.

    - - + + \ No newline at end of file diff --git a/docs/2.2.0/native-installation/index.html b/docs/2.2.0/native-installation/index.html index e9c0ca7428..5185a45f6d 100644 --- a/docs/2.2.0/native-installation/index.html +++ b/docs/2.2.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.2.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.2.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.20.0/accessibility-testing/index.html b/docs/2.20.0/accessibility-testing/index.html index 9da068ec54..84a8d09a8e 100644 --- a/docs/2.20.0/accessibility-testing/index.html +++ b/docs/2.20.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.20.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems on any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two ways to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.20.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems on any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two ways to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.20.0/api/course-run-synchronization-api/index.html b/docs/2.20.0/api/course-run-synchronization-api/index.html index 244ea45aa9..d18b291d6b 100644 --- a/docs/2.20.0/api/course-run-synchronization-api/index.html +++ b/docs/2.20.0/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
    -
    Version: 2.20.0

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: 2.20.0

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
    • Body

        {
      "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
      "start": "2021-02-01T00:00:00Z",
      "end": "2021-02-31T23:59:59Z",
      "enrollment_start": "2021-01-01T00:00:00Z",
      "enrollment_end": "2021-01-31T23:59:59Z",
      "languages": ["en", "fr"]
      }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/2.20.0/building-the-frontend/index.html b/docs/2.20.0/building-the-frontend/index.html index 62c21e11d2..e81705f89c 100644 --- a/docs/2.20.0/building-the-frontend/index.html +++ b/docs/2.20.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.20.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.20.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.20.0/contributing-guide/index.html b/docs/2.20.0/contributing-guide/index.html index 2d8d94ce15..5ac26ee9ad 100644 --- a/docs/2.20.0/contributing-guide/index.html +++ b/docs/2.20.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.20.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.20.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.20.0/cookiecutter/index.html b/docs/2.20.0/cookiecutter/index.html index b0a5be6fec..7d60ddfd2f 100644 --- a/docs/2.20.0/cookiecutter/index.html +++ b/docs/2.20.0/cookiecutter/index.html @@ -4,12 +4,12 @@ Start your own site | Richie - - + +
    -
    Version: 2.20.0

    Start your own site

    We use Cookiecutter to help you +

    Version: 2.20.0

    Start your own site

    We use Cookiecutter to help you set up a production-ready learning portal website based on Richie in seconds.

    Run Cookiecutter

    There are 2 options to run Cookiecutter:

    While you think of it, navigate to the directory in which you want to create your site factory:

    cd /path/to/your/code/directory

    If you chose to install Cookiecutter, you can now run it against our @@ -30,7 +30,7 @@ project's scaffolding but, don't worry, it will respect all the sites you will have created in the sites directory:

    cookiecutter --overwrite-if-exists gh:openfun/richie --directory=cookiecutter

    Help us improve this project

    After starting your project, please submit an issue let us know how it went and what other features we should add to make it better.

    - - + + \ No newline at end of file diff --git a/docs/2.20.0/css-guidelines/index.html b/docs/2.20.0/css-guidelines/index.html index 00f9638e8f..0721b59706 100644 --- a/docs/2.20.0/css-guidelines/index.html +++ b/docs/2.20.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.20.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.20.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.20.0/discover/index.html b/docs/2.20.0/discover/index.html index 5090ee0633..f3f00f8604 100644 --- a/docs/2.20.0/discover/index.html +++ b/docs/2.20.0/discover/index.html @@ -4,12 +4,12 @@ Discover Richie | Richie - - + +
    -
    Version: 2.20.0

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online +

    Version: 2.20.0

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online courses and MOOCs.

    However, if you need to build a complete website with flexible content to aggregate your courses, in several languages and from different sources, you will soon need a CMS.

    At "France Université Numérique", we wanted to build an OpenSource portal with Python and Django. That's why we built Richie on top of DjangoCMS, one of @@ -21,7 +21,7 @@ OpenEdX Docker.

    Two users are available for testing:

    • admin: admin@example.com/admin
    • student: edx@example.com/edx

    The database is regularly flushed.

    Start your own site

    The next step after discovering Richie on the demo is to start your own project. We provide a production-ready template based on Cookiecutter that allows you to generate your project in seconds.

    Follow the guide on starting your own Richie site with Cookiecutter.

    Once you created a new site, you will be able to fully customize it:

    - - + + \ No newline at end of file diff --git a/docs/2.20.0/displaying-connection-status/index.html b/docs/2.20.0/displaying-connection-status/index.html index a5131cc946..0a66caa38f 100644 --- a/docs/2.20.0/displaying-connection-status/index.html +++ b/docs/2.20.0/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: 2.20.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.20.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/2.20.0/django-react-interop/index.html b/docs/2.20.0/django-react-interop/index.html index fb7d443800..9a7f3f0579 100644 --- a/docs/2.20.0/django-react-interop/index.html +++ b/docs/2.20.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.20.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.20.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.20.0/docker-development/index.html b/docs/2.20.0/docker-development/index.html index f7969b60c3..b4e6602449 100644 --- a/docs/2.20.0/docker-development/index.html +++ b/docs/2.20.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.20.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.20.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.20.0/filters-customization/index.html b/docs/2.20.0/filters-customization/index.html index 46f21a5579..80bc029bff 100644 --- a/docs/2.20.0/filters-customization/index.html +++ b/docs/2.20.0/filters-customization/index.html @@ -4,12 +4,12 @@ Customizing search filters | Richie - - + +
    -
    Version: 2.20.0

    Customizing search filters

    You may want to customize the filters on the left side bar of the search page.

    Richie makes it easy to choose which filters you want to display among the existing filters +

    Version: 2.20.0

    Customizing search filters

    You may want to customize the filters on the left side bar of the search page.

    Richie makes it easy to choose which filters you want to display among the existing filters and in which order. You can also configure the existing filters to change their title or the way they behave. Lastly, you can completely override a filter or create your own custom filter from scratch.

    Filters configuration

    Filters must first be defined in the FILTERS_CONFIGURATION setting. It is a dictionary defining @@ -48,7 +48,7 @@ trivial, was given much care and includes many comments in an attempt to help writing new custom filters. Of course, don't hesitate to ask for help by opening an issue!

    - - + + \ No newline at end of file diff --git a/docs/2.20.0/frontend-overrides/index.html b/docs/2.20.0/frontend-overrides/index.html index b3195b73a6..2435aa5fea 100644 --- a/docs/2.20.0/frontend-overrides/index.html +++ b/docs/2.20.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.20.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.20.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.20.0/installation/index.html b/docs/2.20.0/installation/index.html index 22569e76a1..cd45b035d0 100644 --- a/docs/2.20.0/installation/index.html +++ b/docs/2.20.0/installation/index.html @@ -4,12 +4,12 @@ Installing Richie for development | Richie - - + +
    -
    Version: 2.20.0

    Installing Richie for development

    Richie is a container-native application but can also be installed +

    Version: 2.20.0

    Installing Richie for development

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of:

    • 3 running services:

      • database: postgresql or mysql at your preference,
      • elasticsearch: the search engine,
      • app: the actual DjangoCMS project with all our application code.
    • 2 containers for building purposes:

    - - + + \ No newline at end of file diff --git a/docs/2.20.0/internationalization/index.html b/docs/2.20.0/internationalization/index.html index 6b035389a8..8b3c09729e 100644 --- a/docs/2.20.0/internationalization/index.html +++ b/docs/2.20.0/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.20.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.20.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.20.0/joanie-connection/index.html b/docs/2.20.0/joanie-connection/index.html index d662b655c3..929666c80d 100644 --- a/docs/2.20.0/joanie-connection/index.html +++ b/docs/2.20.0/joanie-connection/index.html @@ -4,12 +4,12 @@ Joanie Connection | Richie - - + +
    -
    Version: 2.20.0

    Joanie Connection

    Joanie delivers an API able to manage course +

    Version: 2.20.0

    Joanie Connection

    Joanie delivers an API able to manage course enrollment/subscription, payment and certificates delivery. Richie can be configured to display course runs and micro-credentials managed through Joanie.

    In fact, Richie treats Joanie almost like a LMS backend that's why settings are similars.

    Configuring Joanie

    All settings related to Joanie have to be declared in the JOANIE_BACKEND dictionnary @@ -40,7 +40,7 @@ authentication server is using djangorestframework-simplejwt to generate the access token, its lifetime is 5 minutes by default.

    Technical support

    If you encounter an issue with this documentation, please open an issue on our repository.

    - - + + \ No newline at end of file diff --git a/docs/2.20.0/lms-backends/index.html b/docs/2.20.0/lms-backends/index.html index 5ad4ffae84..96e444549f 100644 --- a/docs/2.20.0/lms-backends/index.html +++ b/docs/2.20.0/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: 2.20.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.20.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/2.20.0/lms-connection/index.html b/docs/2.20.0/lms-connection/index.html index cf4a3d7dca..50ed606a2e 100644 --- a/docs/2.20.0/lms-connection/index.html +++ b/docs/2.20.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: 2.20.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.20.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/2.20.0/native-installation/index.html b/docs/2.20.0/native-installation/index.html index ce91cc5a17..fd0e3cd9fb 100644 --- a/docs/2.20.0/native-installation/index.html +++ b/docs/2.20.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.20.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.20.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native installation instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.20.0/synchronizing-course-runs/index.html b/docs/2.20.0/synchronizing-course-runs/index.html index 523c365e30..3a5f72010c 100644 --- a/docs/2.20.0/synchronizing-course-runs/index.html +++ b/docs/2.20.0/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: 2.20.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.20.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -29,7 +29,7 @@ course run is modified and published.

    Or you can use the Richie Open edX Synchronization which is based on the following code sample and also includes the enrollment count.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/2.20.0/tls-connection/index.html b/docs/2.20.0/tls-connection/index.html index 89ad771b22..ebd929da99 100644 --- a/docs/2.20.0/tls-connection/index.html +++ b/docs/2.20.0/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: 2.20.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.20.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/2.20.0/web-analytics/index.html b/docs/2.20.0/web-analytics/index.html index 6c62856b4c..28615aa729 100644 --- a/docs/2.20.0/web-analytics/index.html +++ b/docs/2.20.0/web-analytics/index.html @@ -4,19 +4,19 @@ Add web analytics to your site | Richie - - + +
    -
    Version: 2.20.0

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. +

    Version: 2.20.0

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. The purpose of this file is to explain how you can enable one of the supported Web Analytics providers and how you can extend Richie with an alternative solution.

    Google Analytics

    Next, it is described how you can configure the Google Analytics on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Analytics tracking id code.

    The current Google Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Google Tag Manager

    Next, it is described how you can configure the Google Tag Manager on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Tag Manager tracking id code.
    • Add the WEB_ANALYTICS_PROVIDER setting with the google_tag_manager value.

    The current Google Tag Manager implementation also defines a custom dimensions like the Google Analytics.

    Location of the web analytics javascript

    Use the WEB_ANALYTICS_LOCATION settings to decide where do you want to put the Javascript code. Use head (default value), to put the Javascript on HTML header, or footer, to put the Javascript code to the bottom of the body.

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS_ID setting with your tracking identification
    • define the WEB_ANALYTICS_PROVIDER setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • optionally change WEB_ANALYTICS_LOCATION setting with head (default) or footer value
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% block web_analytics %}
    {% if WEB_ANALYTICS_ID %}
    {% if WEB_ANALYTICS_PROVIDER == "my_custom_web_analytics_software" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endif %}
    {% endblock web_analytics %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>

    The frontend code also sends events to the web analytics provider. Richie sends events when the user is enrolled on a course run. To support different providers, you need to create a similar file of src/frontend/js/utils/api/web-analytics/google_analytics.ts and change the src/frontend/js/utils/api/web-analytics/index.ts file to include that newer provider.

    - - + + \ No newline at end of file diff --git a/docs/2.20.1/accessibility-testing/index.html b/docs/2.20.1/accessibility-testing/index.html index dac4dc378d..ad9ca3baa3 100644 --- a/docs/2.20.1/accessibility-testing/index.html +++ b/docs/2.20.1/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.20.1

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems on any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two ways to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.20.1

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems on any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two ways to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.20.1/api/course-run-synchronization-api/index.html b/docs/2.20.1/api/course-run-synchronization-api/index.html index 85f41dfafa..be0ae49d8c 100644 --- a/docs/2.20.1/api/course-run-synchronization-api/index.html +++ b/docs/2.20.1/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
    -
    Version: 2.20.1

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: 2.20.1

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
    • Body

        {
      "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
      "start": "2021-02-01T00:00:00Z",
      "end": "2021-02-31T23:59:59Z",
      "enrollment_start": "2021-01-01T00:00:00Z",
      "enrollment_end": "2021-01-31T23:59:59Z",
      "languages": ["en", "fr"]
      }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/2.20.1/building-the-frontend/index.html b/docs/2.20.1/building-the-frontend/index.html index 4aba185521..a12edd96b0 100644 --- a/docs/2.20.1/building-the-frontend/index.html +++ b/docs/2.20.1/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.20.1

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.20.1

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.20.1/contributing-guide/index.html b/docs/2.20.1/contributing-guide/index.html index 80419565ce..ef5d41a89f 100644 --- a/docs/2.20.1/contributing-guide/index.html +++ b/docs/2.20.1/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.20.1

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.20.1

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.20.1/cookiecutter/index.html b/docs/2.20.1/cookiecutter/index.html index 1b0a930b71..7cfdbc1cae 100644 --- a/docs/2.20.1/cookiecutter/index.html +++ b/docs/2.20.1/cookiecutter/index.html @@ -4,12 +4,12 @@ Start your own site | Richie - - + +
    -
    Version: 2.20.1

    Start your own site

    We use Cookiecutter to help you +

    Version: 2.20.1

    Start your own site

    We use Cookiecutter to help you set up a production-ready learning portal website based on Richie in seconds.

    Run Cookiecutter

    There are 2 options to run Cookiecutter:

    While you think of it, navigate to the directory in which you want to create your site factory:

    cd /path/to/your/code/directory

    If you chose to install Cookiecutter, you can now run it against our @@ -30,7 +30,7 @@ project's scaffolding but, don't worry, it will respect all the sites you will have created in the sites directory:

    cookiecutter --overwrite-if-exists gh:openfun/richie --directory=cookiecutter

    Help us improve this project

    After starting your project, please submit an issue let us know how it went and what other features we should add to make it better.

    - - + + \ No newline at end of file diff --git a/docs/2.20.1/css-guidelines/index.html b/docs/2.20.1/css-guidelines/index.html index 0f99419c98..ad87041b87 100644 --- a/docs/2.20.1/css-guidelines/index.html +++ b/docs/2.20.1/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.20.1

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.20.1

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.20.1/discover/index.html b/docs/2.20.1/discover/index.html index ce8dca23e4..1c613c5d8e 100644 --- a/docs/2.20.1/discover/index.html +++ b/docs/2.20.1/discover/index.html @@ -4,12 +4,12 @@ Discover Richie | Richie - - + +
    -
    Version: 2.20.1

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online +

    Version: 2.20.1

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online courses and MOOCs.

    However, if you need to build a complete website with flexible content to aggregate your courses, in several languages and from different sources, you will soon need a CMS.

    At "France Université Numérique", we wanted to build an OpenSource portal with Python and Django. That's why we built Richie on top of DjangoCMS, one of @@ -21,7 +21,7 @@ OpenEdX Docker.

    Two users are available for testing:

    • admin: admin@example.com/admin
    • student: edx@example.com/edx

    The database is regularly flushed.

    Start your own site

    The next step after discovering Richie on the demo is to start your own project. We provide a production-ready template based on Cookiecutter that allows you to generate your project in seconds.

    Follow the guide on starting your own Richie site with Cookiecutter.

    Once you created a new site, you will be able to fully customize it:

    - - + + \ No newline at end of file diff --git a/docs/2.20.1/displaying-connection-status/index.html b/docs/2.20.1/displaying-connection-status/index.html index a4e9a04b09..49f2b4994f 100644 --- a/docs/2.20.1/displaying-connection-status/index.html +++ b/docs/2.20.1/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: 2.20.1

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.20.1

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/2.20.1/django-react-interop/index.html b/docs/2.20.1/django-react-interop/index.html index 126664ba7c..8c1e7930e5 100644 --- a/docs/2.20.1/django-react-interop/index.html +++ b/docs/2.20.1/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.20.1

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.20.1

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.20.1/docker-development/index.html b/docs/2.20.1/docker-development/index.html index 42e4a9e540..470c4e3ed5 100644 --- a/docs/2.20.1/docker-development/index.html +++ b/docs/2.20.1/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.20.1

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.20.1

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.20.1/filters-customization/index.html b/docs/2.20.1/filters-customization/index.html index 142017df34..c0e026e6bc 100644 --- a/docs/2.20.1/filters-customization/index.html +++ b/docs/2.20.1/filters-customization/index.html @@ -4,12 +4,12 @@ Customizing search filters | Richie - - + +
    -
    Version: 2.20.1

    Customizing search filters

    You may want to customize the filters on the left side bar of the search page.

    Richie makes it easy to choose which filters you want to display among the existing filters +

    Version: 2.20.1

    Customizing search filters

    You may want to customize the filters on the left side bar of the search page.

    Richie makes it easy to choose which filters you want to display among the existing filters and in which order. You can also configure the existing filters to change their title or the way they behave. Lastly, you can completely override a filter or create your own custom filter from scratch.

    Filters configuration

    Filters must first be defined in the FILTERS_CONFIGURATION setting. It is a dictionary defining @@ -48,7 +48,7 @@ trivial, was given much care and includes many comments in an attempt to help writing new custom filters. Of course, don't hesitate to ask for help by opening an issue!

    - - + + \ No newline at end of file diff --git a/docs/2.20.1/frontend-overrides/index.html b/docs/2.20.1/frontend-overrides/index.html index 19e69de055..30d10c3016 100644 --- a/docs/2.20.1/frontend-overrides/index.html +++ b/docs/2.20.1/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.20.1

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.20.1

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.20.1/installation/index.html b/docs/2.20.1/installation/index.html index ec0d485e69..9fa1e40ade 100644 --- a/docs/2.20.1/installation/index.html +++ b/docs/2.20.1/installation/index.html @@ -4,12 +4,12 @@ Installing Richie for development | Richie - - + +
    -
    Version: 2.20.1

    Installing Richie for development

    Richie is a container-native application but can also be installed +

    Version: 2.20.1

    Installing Richie for development

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of:

    • 3 running services:

      • database: postgresql or mysql at your preference,
      • elasticsearch: the search engine,
      • app: the actual DjangoCMS project with all our application code.
    • 2 containers for building purposes:

    - - + + \ No newline at end of file diff --git a/docs/2.20.1/internationalization/index.html b/docs/2.20.1/internationalization/index.html index 47bc379384..67c5c35c6b 100644 --- a/docs/2.20.1/internationalization/index.html +++ b/docs/2.20.1/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.20.1

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.20.1

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.20.1/joanie-connection/index.html b/docs/2.20.1/joanie-connection/index.html index fa155847b5..aef6075ee8 100644 --- a/docs/2.20.1/joanie-connection/index.html +++ b/docs/2.20.1/joanie-connection/index.html @@ -4,12 +4,12 @@ Joanie Connection | Richie - - + +
    -
    Version: 2.20.1

    Joanie Connection

    Joanie delivers an API able to manage course +

    Version: 2.20.1

    Joanie Connection

    Joanie delivers an API able to manage course enrollment/subscription, payment and certificates delivery. Richie can be configured to display course runs and micro-credentials managed through Joanie.

    In fact, Richie treats Joanie almost like a LMS backend that's why settings are similars.

    Configuring Joanie

    All settings related to Joanie have to be declared in the JOANIE_BACKEND dictionnary @@ -40,7 +40,7 @@ authentication server is using djangorestframework-simplejwt to generate the access token, its lifetime is 5 minutes by default.

    Technical support

    If you encounter an issue with this documentation, please open an issue on our repository.

    - - + + \ No newline at end of file diff --git a/docs/2.20.1/lms-backends/index.html b/docs/2.20.1/lms-backends/index.html index 399a440cdf..1ec8eb4cdc 100644 --- a/docs/2.20.1/lms-backends/index.html +++ b/docs/2.20.1/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: 2.20.1

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.20.1

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/2.20.1/lms-connection/index.html b/docs/2.20.1/lms-connection/index.html index b2b8ef45f1..b7d1345485 100644 --- a/docs/2.20.1/lms-connection/index.html +++ b/docs/2.20.1/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: 2.20.1

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.20.1

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/2.20.1/native-installation/index.html b/docs/2.20.1/native-installation/index.html index 0dbada8fda..2a03106ce7 100644 --- a/docs/2.20.1/native-installation/index.html +++ b/docs/2.20.1/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.20.1

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.20.1

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native installation instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.20.1/synchronizing-course-runs/index.html b/docs/2.20.1/synchronizing-course-runs/index.html index afa0831d40..48b8e99c6c 100644 --- a/docs/2.20.1/synchronizing-course-runs/index.html +++ b/docs/2.20.1/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: 2.20.1

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.20.1

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -29,7 +29,7 @@ course run is modified and published.

    Or you can use the Richie Open edX Synchronization which is based on the following code sample and also includes the enrollment count.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/2.20.1/tls-connection/index.html b/docs/2.20.1/tls-connection/index.html index e72b3cd60b..2bc055463c 100644 --- a/docs/2.20.1/tls-connection/index.html +++ b/docs/2.20.1/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: 2.20.1

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.20.1

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/2.20.1/web-analytics/index.html b/docs/2.20.1/web-analytics/index.html index 3f5901c02d..d34ce87392 100644 --- a/docs/2.20.1/web-analytics/index.html +++ b/docs/2.20.1/web-analytics/index.html @@ -4,19 +4,19 @@ Add web analytics to your site | Richie - - + +
    -
    Version: 2.20.1

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. +

    Version: 2.20.1

    Add web analytics to your site

    Richie has native support to Google Analytics and Google Tag Manager Web Analytics solutions. The purpose of this file is to explain how you can enable one of the supported Web Analytics providers and how you can extend Richie with an alternative solution.

    Google Analytics

    Next, it is described how you can configure the Google Analytics on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Analytics tracking id code.

    The current Google Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Google Tag Manager

    Next, it is described how you can configure the Google Tag Manager on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Tag Manager tracking id code.
    • Add the WEB_ANALYTICS_PROVIDER setting with the google_tag_manager value.

    The current Google Tag Manager implementation also defines a custom dimensions like the Google Analytics.

    Location of the web analytics javascript

    Use the WEB_ANALYTICS_LOCATION settings to decide where do you want to put the Javascript code. Use head (default value), to put the Javascript on HTML header, or footer, to put the Javascript code to the bottom of the body.

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS_ID setting with your tracking identification
    • define the WEB_ANALYTICS_PROVIDER setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • optionally change WEB_ANALYTICS_LOCATION setting with head (default) or footer value
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% block web_analytics %}
    {% if WEB_ANALYTICS_ID %}
    {% if WEB_ANALYTICS_PROVIDER == "my_custom_web_analytics_software" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endif %}
    {% endblock web_analytics %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>

    The frontend code also sends events to the web analytics provider. Richie sends events when the user is enrolled on a course run. To support different providers, you need to create a similar file of src/frontend/js/utils/api/web-analytics/google_analytics.ts and change the src/frontend/js/utils/api/web-analytics/index.ts file to include that newer provider.

    - - + + \ No newline at end of file diff --git a/docs/2.21.0/accessibility-testing/index.html b/docs/2.21.0/accessibility-testing/index.html new file mode 100644 index 0000000000..762e767d81 --- /dev/null +++ b/docs/2.21.0/accessibility-testing/index.html @@ -0,0 +1,16 @@ + + + + + +Automated accessibility checks | Richie + + + + +
    +
    Version: 2.21.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems on any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two ways to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + + + \ No newline at end of file diff --git a/docs/2.21.0/api/course-run-synchronization-api/index.html b/docs/2.21.0/api/course-run-synchronization-api/index.html new file mode 100644 index 0000000000..fa49a3460f --- /dev/null +++ b/docs/2.21.0/api/course-run-synchronization-api/index.html @@ -0,0 +1,25 @@ + + + + + +Course run synchronization API | Richie + + + + +
    +
    Version: 2.21.0

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +url of the course syllabus on the LMS from which a unique course identifier can be extracted
    • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the +course starts
    • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course +ends
    • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment +for this session of the course starts
    • enrollment_end: 2018-01-31T06:00:00Z (string, optional) - ISO 8601 date, when enrollment for +this session of the course ends
    • languages: ['fr', 'en'] (array[string], required) - ISO 639-1 code (2 letters) for the course's +languages
    • Request (application/json)

      • Headers

        • Authorization: SIG-HMAC-SHA256 xxxxxxx (string, required) - Authorization header +containing the digest of the utf-8 encoded json representation of the submitted data +for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] +for an example).
      • Body

          {
        "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
        "start": "2021-02-01T00:00:00Z",
        "end": "2021-02-31T23:59:59Z",
        "enrollment_start": "2021-01-01T00:00:00Z",
        "enrollment_end": "2021-01-31T23:59:59Z",
        "languages": ["en", "fr"]
        }
    • Response 200 (application/json)

      • Body

          {
        "success": True
        }
    + + + + \ No newline at end of file diff --git a/docs/2.21.0/building-the-frontend/index.html b/docs/2.21.0/building-the-frontend/index.html new file mode 100644 index 0000000000..543dffc1df --- /dev/null +++ b/docs/2.21.0/building-the-frontend/index.html @@ -0,0 +1,16 @@ + + + + + +Building Richie's frontend in your own project | Richie + + + + +
    +
    Version: 2.21.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + + + \ No newline at end of file diff --git a/docs/2.21.0/contributing-guide/index.html b/docs/2.21.0/contributing-guide/index.html new file mode 100644 index 0000000000..942effa233 --- /dev/null +++ b/docs/2.21.0/contributing-guide/index.html @@ -0,0 +1,22 @@ + + + + + +Contributing guide | Richie + + + + +
    +
    Version: 2.21.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically +creates a fresh database named richie and performs database migrations. Each time a new +database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the +application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the +bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker +documentation

    + + + + \ No newline at end of file diff --git a/docs/2.21.0/cookiecutter/index.html b/docs/2.21.0/cookiecutter/index.html new file mode 100644 index 0000000000..898c94a652 --- /dev/null +++ b/docs/2.21.0/cookiecutter/index.html @@ -0,0 +1,36 @@ + + + + + +Start your own site | Richie + + + + +
    +
    Version: 2.21.0

    Start your own site

    We use Cookiecutter to help you +set up a production-ready learning portal website based on +Richie in seconds.

    Run Cookiecutter

    There are 2 options to run Cookiecutter:

    While you think of it, navigate to the directory in which you want to create +your site factory:

    cd /path/to/your/code/directory

    If you chose to install Cookiecutter, you can now run it against our +template as follows:

    cookiecutter gh:openfun/richie --directory cookiecutter  --checkout v2.21.0

    If you didn't want to install it on your machine, we provide a Docker image +built with our own repository that you can use as follows:

    docker run --rm -it -u $(id -u):$(id -g) -v $PWD:/app \
    fundocker/cookiecutter gh:openfun/richie --directory cookiecutter --checkout v2.21.0

    The --directory option is to indicate that our Cookiecutter template is in +a cookiecutter directory inside our git repository and not at the root.

    You will be prompted to enter an organization name, which will determine the +name of your repository. For example, if you choose "foo" as organization +name, your repository will be named foo-richie-site-factory. It's +nice if you keep it that way so all richie site factories follow this +convention.

    When you confirm the organization name, Cookiecutter will generate your +project from the Cookiecutter template and place it at the level where you +currently are.

    Bootstrap your project

    Enter the newly created project and add a new site to your site factory:

    cd foo-richie-site-factory
    make add-site

    This script also uses Cookiecutter against our site template.

    Once your new site is created, activate it:

    bin/activate

    Now bootstrap the site to build its docker image, create its media folder, +database, etc.:

    make bootstrap

    Once the bootstrap phase is finished, you should be able to view the site at +localhost:8070.

    You can create a full fledge demo to test your site by running:

    make demo-site

    Note that the README of your newly created site factory contains detailed +information about how to configure and run a site.

    Once you're happy with your site, don't forget to backup your work e.g. by +committing it and pushing it to a new git repository.

    Theming

    You probably want to change the default theme. The cookiecutter adds an extra scss frontend folder with a couple of templates that you can use to change the default styling of the site.

    • sites/<site>/src/frontend/scss/extras/colors/_palette.scss
    • sites/<site>/src/frontend/scss/extras/colors/_theme.scss

    To change the default logo of the site, you need to create the folder sites/<site>/src/backend/base/static/richie/images and then override the new logo.png picture.

    For more advanced customization, refer to our recipes:

    Update your Richie site factory

    If we later improve our scripts, you will be able to update your own site +factory by replaying Cookiecutter. This will override your files in the +project's scaffolding but, don't worry, it will respect all the sites you +will have created in the sites directory:

    cookiecutter --overwrite-if-exists gh:openfun/richie --directory=cookiecutter

    Help us improve this project

    After starting your project, please submit an issue let us know how it went and +what other features we should add to make it better.

    + + + + \ No newline at end of file diff --git a/docs/2.21.0/css-guidelines/index.html b/docs/2.21.0/css-guidelines/index.html new file mode 100644 index 0000000000..1070cfac6e --- /dev/null +++ b/docs/2.21.0/css-guidelines/index.html @@ -0,0 +1,16 @@ + + + + + +CSS Guidelines | Richie + + + + +
    +
    Version: 2.21.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + + + \ No newline at end of file diff --git a/docs/2.21.0/discover/index.html b/docs/2.21.0/discover/index.html new file mode 100644 index 0000000000..50a730ed50 --- /dev/null +++ b/docs/2.21.0/discover/index.html @@ -0,0 +1,27 @@ + + + + + +Discover Richie | Richie + + + + +
    +
    Version: 2.21.0

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online +courses and MOOCs.

    However, if you need to build a complete website with flexible content to aggregate your courses, +in several languages and from different sources, you will soon need a CMS.

    At "France Université Numérique", we wanted to build an OpenSource portal with Python and +Django. That's why we built Richie on top of DjangoCMS, one of +the best CMS on the market, as a toolbox to easily create full fledged websites with a catalog of +online courses.

    screenshot of richie demo site

    Among the features that Richie offers out of the box:

    • multi-lingual by default,
    • advanced access rights and moderation,
    • catalog of courses synchronized with one or more LMS instances,
    • search engine based on Elasticsearch and pre-configured to offer full-text queries, +multi-facetting, auto-complete,...
    • flexible custom pages for courses, organizations, categories, teachers, blog posts, +programs (and their inter-relations),
    • Extensible with any third-party DjangoCMS plugin or any third-party Django application.

    Quick preview

    If you're looking for a quick preview of Richie, you can take a look and have a tour of +Richie on our dedicated demo site.

    It is connected back-to-back with a demo of OpenEdX running on +OpenEdX Docker.

    Two users are available for testing:

    • admin: admin@example.com/admin
    • student: edx@example.com/edx

    The database is regularly flushed.

    Start your own site

    The next step after discovering Richie on the demo is to start your own project. We provide a +production-ready template based on Cookiecutter that +allows you to generate your project in seconds.

    Follow the guide on starting your own Richie site with Cookiecutter.

    Once you created a new site, you will be able to fully customize it:

    + + + + \ No newline at end of file diff --git a/docs/2.21.0/displaying-connection-status/index.html b/docs/2.21.0/displaying-connection-status/index.html new file mode 100644 index 0000000000..c842f0491c --- /dev/null +++ b/docs/2.21.0/displaying-connection-status/index.html @@ -0,0 +1,32 @@ + + + + + +Displaying OpenEdX connection status in Richie | Richie + + + + +
    +
    Version: 2.21.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the +site, are editors and staff users. Your instructors and learners will not have user accounts on +Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or +your own centralized identity management service.

    In the following, we will explain how to use OpenEdX as your authentication delegation service.

    Prerequisites

    Richie will need to make CORS requests to the OpenEdX instance. As a consequence, you need to +activate CORS requests on your OpenEdX instance:

    FEATURES = {
    ...
    "ENABLE_CORS_HEADERS": True,
    }

    Then, make sure the following settings are set as follows on your OpenEdX instance:

    CORS_ALLOW_CREDENTIALS = True
    CORS_ALLOW_INSECURE = False
    CORS_ORIGIN_ALLOW_ALL = False
    CORS_ORIGIN_WHITELIST: ["richie.example.com"] # The domain on which Richie is hosted

    Allow redirects

    When Richie sends the user to the OpenEdX instance for authentication, and wants OpenEdX to +redirect the user back to Richie after a successful login or signup, it prefixes the path with +/richie. Adding the following rule to your Nginx server (or equivalent) and replacing the +richie host by yours will allow this redirect to follow through to your Richie instance:

    rewrite ^/richie/(.*)$ https://richie.example.com/$1 permanent;

    Configure authentication delegation

    Now, on your Richie instance, you need to configure the service to which Richie will delegate +authentication using the RICHIE_AUTHENTICATION_DELEGATION setting:

    RICHIE_AUTHENTICATION_DELEGATION = {
    "BASE_URL": "https://lms.example.com",
    "BACKEND": "openedx-hawthorn",
    "PROFILE_URLS": {
    "dashboard": {
    "label": _("Dashboard"),
    "href": "{base_url:s}/dashboard",
    },
    },
    }

    The following should help you understand how to configure this setting:

    BASE_URL

    The base url on which the OpenEdX instance is hosted. This is used to construct the complete url +of the login/signup pages to which the frontend application will send the user for authentication.

    BACKEND

    The name of the ReactJS backend to use for the targeted LMS.

    • Type: string
    • Required: Yes
    • Value: Richie ships with the following Javascript backends:
      • openedx-dogwood: backend for OpenEdX versions equal to dogwood or eucalyptus
      • openedx-hawthorn: backend for OpenEdX versions equal to hawthorn or higher
      • openedx-fonzie: backend for OpenEdX via Fonzie +(extra user info and JWT tokens)
      • base: fake backend for development purposes

    PROFILE_URLS

    Mapping definition of custom links presented to the logged-in user as a dropdown menu when he/she +clicks on his/her username in Richie's page header.

    Links order will be respected to build the dropdown menu.

    • Type: dictionary

    • Required: No

    • Value: For example, to emulate the links proposed in OpenEdX, you can configure this setting +as follows:

          {
      "dashboard": {
      "label": _("Dashboard"),
      "href": "{base_url:s}/dashboard",
      },
      "profile": {
      "label": _("Profile"),
      "href": "{base_url:s}/u/(username)",
      },
      "account": {
      "label": _("Account"),
      "href": "{base_url:s}/account/settings",
      }
      }

      The base_url variable is used as a Python format parameter and will be replaced by the value +set for the above authentication delegation BASE_URL setting.

      If you need to bind user data into a url, wrap the property between brackets. For example, the +link configured above for the profile page {base_url:s}/u/(username) would point to +https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    + + + + \ No newline at end of file diff --git a/docs/2.21.0/django-react-interop/index.html b/docs/2.21.0/django-react-interop/index.html new file mode 100644 index 0000000000..a4c39dcfaf --- /dev/null +++ b/docs/2.21.0/django-react-interop/index.html @@ -0,0 +1,16 @@ + + + + + +Connecting React components with Django | Richie + + + + +
    +
    Version: 2.21.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + + + \ No newline at end of file diff --git a/docs/2.21.0/docker-development/index.html b/docs/2.21.0/docker-development/index.html new file mode 100644 index 0000000000..fc20bdb7c5 --- /dev/null +++ b/docs/2.21.0/docker-development/index.html @@ -0,0 +1,35 @@ + + + + + +Developing Richie with Docker | Richie + + + + +
    +
    Version: 2.21.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +Configurations for +different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have +sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the +docker-compose exec command (we use a sugar script here, see next section):

    $ bin/exec [app|postgresql|mysql|elasticsearch] bash

    While developing on Richie, you will also need to run a Django shell and it +has to be done in the app container (we use a sugar script here, see next +section):

    $ bin/run app python sandbox/manage.py shell

    Using sugar scripts

    While developing using Docker, you will fall into permission issues if you mount +the code directory as a volume in the container. Indeed, the Docker engine will, +by default, run the containers using the root user. Any file created or +updated by the app container on your host, as a result of the volume mounts, +will be owned by the local root user. One way to solve this is to use the +--user="$(id -u)" flag when calling the docker-compose run or +docker-compose exec commands. By using the user flag trick, the running +container user ID will match your local user ID. But, as it's repetitive and +error-prone, we provide shortcuts that we call our "sugar scripts":

    • bin/run: is a shortcut for docker-compose run --rm --user="$(id -u)"
    • bin/exec: is a shortcut for docker-compose exec --user="$(id -u)"
    • bin/pylint: runs pylint in the app service using the test docker-compose +file
    • bin/pytest: runs pytest in the app service using the test docker-compose +file

    Cleanup

    If you work on the Docker configuration and make repeated modifications, +remember to periodically clean the unused docker images and containers by +running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the +/etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    + + + + \ No newline at end of file diff --git a/docs/2.21.0/filters-customization/index.html b/docs/2.21.0/filters-customization/index.html new file mode 100644 index 0000000000..250d828a48 --- /dev/null +++ b/docs/2.21.0/filters-customization/index.html @@ -0,0 +1,54 @@ + + + + + +Customizing search filters | Richie + + + + +
    +
    Version: 2.21.0

    Customizing search filters

    You may want to customize the filters on the left side bar of the search page.

    Richie makes it easy to choose which filters you want to display among the existing filters +and in which order. You can also configure the existing filters to change their title or the +way they behave. Lastly, you can completely override a filter or create your own custom filter +from scratch.

    Filters configuration

    Filters must first be defined in the FILTERS_CONFIGURATION setting. It is a dictionary defining +for each filter, a predefined class in the code where the filter is implemented and the +parameters to apply to this class when instantiating it.

    Let's study a few examples of filters in the default configuration:

    FILTERS_CONFIGURATION = {
    ...
    "pace": {
    "class": "richie.apps.search.filter_definitions.StaticChoicesFilterDefinition",
    "params": {
    "fragment_map": {
    "self-paced": [{"bool": {"must_not": {"exists": {"field": "pace"}}}}],
    "lt-1h": [{"range": {"pace": {"lt": 60}}}],
    "1h-2h": [{"range": {"pace": {"gte": 60, "lte": 120}}}],
    "gt-2h": [{"range": {"pace": {"gt": 120}}}],
    },
    "human_name": _("Weekly pace"),
    "min_doc_count": 0,
    "sorting": "conf",
    "values": {
    "self-paced": _("Self-paced"),
    "lt-1h": _("Less than one hour"),
    "1h-2h": _("One to two hours"),
    "gt-2h": _("More than two hours"),
    },
    },
    },
    ...
    }

    This filter uses the StaticChoicesFilterDefinition filter definition class and allows filtering +on the pace field present in the Elasticsearch index. The values parameter defines 4 ranges +and their human readable format that will appear as 4 filtering options to the user.

    The fragment_map parameter defines a fragment of the Elasticsearch query to apply on the pace +field when one of these options is selected.

    The human_nameparameter defines how the filter is entitled. It is defined as a lazy i18n string +so that it can be translated.

    The sorting parameter determines how the facets are sorted in the left side panel of the filter:

    • conf: facets are sorted as defined in the values configuration parameter
    • count: facets are sorted according to the number of course results associated with each facet
    • name: facets are sorted by their name in alphabetical order

    The min_doc_count parameter defines how many associated results a facet must have at the minimum +before it is displayed as an option for the filter.

    Let's study another interesting example:

    FILTERS_CONFIGURATION = {
    ...
    "organizations": {
    "class": "richie.apps.search.filter_definitions.IndexableHierarchicalFilterDefinition",
    "params": {
    "human_name": _("Organizations"),
    "is_autocompletable": True,
    "is_drilldown": False,
    "is_searchable": True,
    "min_doc_count": 0,
    "reverse_id": "organizations",
    },
    },
    ...
    }

    This filter uses the IndexableHierarchicalFilterDefinition filter definition class and allows +filtering on the link between course pages and other pages identified by their IDs like for +example here Organization pages.

    In the example above, when an option is selected, results will only include the courses for which +the organizations field in the index is including the ID of the selected organization page.

    The reverse_id parameter should point to a page's reverse ID (see DjangoCMS documentation) in +the CMS. The filter will propose a filtering option for each children organization under this +page.

    The is_autocompletable field determines whether organizations should be searched and suggested +by the autocomplete feature (organizations must have an associated index and API endpoint for +autocompletion carrying the same name).

    The is_drilldown parameter determines whether the filter is limited to one active value at a +time or allows multi-facetting.

    The is_searchable field determines whether organizations filters should present a "more options" +button in case there are more facet options in results than can be displayed (organizations must +have an associated API endpoint for full-text search, carrying the same name).

    Lastly, let's look at nested filters which, as their name indicates, allow filtering on nested +fields.

    For example, in the course index, one of the fields is named course_runs and contains a list of +objects in the following format:

    "course_runs": [
    {
    "start": "2022-09-09T09:00:00.000000",
    "end": "2021-10-30T00:00:00.000000Z",
    "enrollment_start": "2022-08-01T09:00:00.000000Z",
    "enrollment_end": "2022-09-08T00:00:00.000000Z",
    "languages": ["en", "fr"],
    },
    {
    "start": "2023-03-01T09:00:00.000000",
    "end": "2023-06-03T00:00:00.000000Z",
    "enrollment_start": "2023-01-01T09:00:00.000000Z",
    "enrollment_end": "2023-03-01T00:00:00.000000Z",
    "languages": ["fr"],
    },
    ]

    If we want to filter courses that are available in the english language, we can thus configure the +following filter:

    FILTERS_CONFIGURATION = {
    ...
    "course_runs": {
    "class": "richie.apps.search.filter_definitions.NestingWrapper",
    "params": {
    "filters": {
    "languages": {
    "class": "richie.apps.search.filter_definitions.LanguagesFilterDefinition",
    "params": {
    "human_name": _("Languages"),
    # There are too many available languages to show them all, all the time.
    # Eg. 200 languages, 190+ of which will have 0 matching courses.
    "min_doc_count": 1,
    },
    },
    }
    },
    },
    ...
    }

    Filters presentation

    Which filters are displayed in the left side bar of the search page and in which order is defined +by the RICHIE_FILTERS_PRESENTATION setting.

    This setting is expecting a list of strings, which are the names of the filters as defined +in the FILTERS_CONFIGURATION setting decribed in the previous section. If it, for example, +contains the 3 filters presented in the previous section, we could define the following +presentation:

    RICHIE_FILTERS_PRESENTATION = ["organizations", "languages", "pace"]

    Writing your own custom filters

    You can write your own filters from scratch although we must warn you that it is not trivial +because it requires a good knowledge of Elasticsearch and studying the mapping defined in the +courses indexer.

    A filter is a class deriving from BaseFilterDefinition and defining methods to return the +information to display the filter and query fragments for elasticsearch:

    • get_form_fields: returns the form field instance that will be used to parse and validate this +filter's values from the querystring
    • get_query_fragment: returns the query fragment to use as filter in ElasticSearch
    • get_aggs_fragment: returns the query fragment to use to extract facets from +ElasticSearch aggregations
    • get_facet_info: returns the dynamic facet information from a filter's Elasticsearch facet +results. Together with the facet's static information, it will be used to display the filter +in its current status in the left side panel of the search page.

    We will not go into more details here about how filter definition classes work, but you can refer +to the code of the existing filters as good examples of what is possible. The code, although not +trivial, was given much care and includes many comments in an attempt to help writing new custom +filters. Of course, don't hesitate to ask for help by +opening an issue!

    + + + + \ No newline at end of file diff --git a/docs/2.21.0/frontend-overrides/index.html b/docs/2.21.0/frontend-overrides/index.html new file mode 100644 index 0000000000..0e8b7ee07b --- /dev/null +++ b/docs/2.21.0/frontend-overrides/index.html @@ -0,0 +1,16 @@ + + + + + +Overriding frontend components | Richie + + + + +
    +
    Version: 2.21.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + + + \ No newline at end of file diff --git a/docs/2.21.0/installation/index.html b/docs/2.21.0/installation/index.html new file mode 100644 index 0000000000..20cbcb4cae --- /dev/null +++ b/docs/2.21.0/installation/index.html @@ -0,0 +1,41 @@ + + + + + +Installing Richie for development | Richie + + + + +
    +
    Version: 2.21.0

    Installing Richie for development

    Richie is a container-native application but can also be installed +on your machine.

    For development, the project is defined using a +docker-compose file and consists of:

    • 3 running services:

      • database: postgresql or mysql at your preference,
      • elasticsearch: the search engine,
      • app: the actual DjangoCMS project with all our application code.
    • 2 containers for building purposes:

      • node: used for front-end related tasks, i.e. transpiling +TypeScript sources, bundling them into a JS package, and building the +CSS files from Sass sources,
      • crowdin: used to upload and retrieve i18n files to and from the +Crowding service that we use to crowd source +translations,

    At "France Université Numérique", we deploy our applications on Kubernetes +using Arnold.

    Docker

    First, make sure you have a recent version of Docker and +Docker Compose installed on your +laptop:

    $ docker -v
    Docker version 20.10.12, build e91ed57

    $ docker-compose --version
    docker-compose version 1.29.2, build 5becea4c

    ⚠️ You may need to run the following commands with sudo but this can be +avoided by assigning your user to the docker group.

    Project bootstrap

    The easiest way to start working on the project is to use our Makefile:

    $ make bootstrap

    This command builds the app container, installs front-end and back-end +dependencies, builds the front-end application and styles, and performs +database migrations. It's a good idea to use this command each time you are +pulling code from the project repository to avoid dependency-related or +migration-related issues.

    Now that your Docker services are ready to be used, start the full CMS by +running:

    $ make run

    Adding content

    Once the CMS is up and running, you can create a superuser account:

    $ make superuser

    You can create a basic demo site by running:

    $ make demo-site

    Note that if you don't create the demo site and start from a blank CMS, you +will get some errors requesting you to create some required root pages. So it +is easier as a first approach to test the CMS with the demo site.

    You should be able to view the site at localhost:8070

    Connecting Richie to an LMS

    It is possible to use Richie as a catalogue aggregating courses from one or +more LMS without any specific connection. In this case, each course run in +the catalogue points to a course on the LMS, and the LMS points back to the +catalogue to browse courses.

    This approach is used for example on https://www.fun-campus.fr or +https://catalogue.edulib.org.

    For a seamless user experience, it is possible to connect a Richie instance +to an OpenEdX instance (or some other LMS like Moodle at the cost of minor +adaptations), in several ways that we explain in the +LMS connection guide.

    This approach is used for example on https://www.fun-mooc.fr or +https://www.nau.edu.pt.

    + + + + \ No newline at end of file diff --git a/docs/2.21.0/internationalization/index.html b/docs/2.21.0/internationalization/index.html new file mode 100644 index 0000000000..3fb2934fcc --- /dev/null +++ b/docs/2.21.0/internationalization/index.html @@ -0,0 +1,28 @@ + + + + + +Internationalization | Richie + + + + +
    +
    Version: 2.21.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +All translations are hosted at https://i18n.richie.education, which allows translators and +proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and +fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, +look for the project called "Richie", select the language +on which you wish to contribute and click the "Join" button as demonstrated below:

    How to join Richie on Crowdin

    We will then review you application and you should soon start translating strings!

    For more information on how Crowdin works, you can refer to +their documentation.

    Add a new language

    If Richie is not yet translated in the language you want, let us know by clicking the "contact" +link on Richie's Crowdin profile page and we will consider adding +it.

    If you request a new language, the Richie community will expect you to keep this language +up-to-date each time strings are modified or new strings are added, and this before each +release.

    Before asking for a new language, make sure it does not already exist. If your language already +exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider +contributing on the existing language if your resources to contribute are limited.

    + + + + \ No newline at end of file diff --git a/docs/2.21.0/joanie-connection/index.html b/docs/2.21.0/joanie-connection/index.html new file mode 100644 index 0000000000..56c3c4b15f --- /dev/null +++ b/docs/2.21.0/joanie-connection/index.html @@ -0,0 +1,46 @@ + + + + + +Joanie Connection | Richie + + + + +
    +
    Version: 2.21.0

    Joanie Connection

    Joanie delivers an API able to manage course +enrollment/subscription, payment and certificates delivery. Richie can be configured to display +course runs and micro-credentials managed through Joanie.

    In fact, Richie treats Joanie almost like a LMS backend that's why settings +are similars.

    Configuring Joanie

    All settings related to Joanie have to be declared in the JOANIE_BACKEND dictionnary +within settings.py.

    JOANIE_BACKEND = {
    "BASE_URL": values.Value(environ_name="JOANIE_BASE_URL", environ_prefix=None),
    "BACKEND": values.Value("richie.apps.courses.lms.joanie.JoanieBackend", environ_name="JOANIE_BACKEND", environ_prefix=None),
    "JS_BACKEND": values.Value("joanie", environ_name="JOANIE_JS_BACKEND", environ_prefix=None),
    "COURSE_REGEX": values.Value(
    r"^.*/api/v1.0/(?P<resource_type>(course-runs|products))/(?P<resource_id>[^/]*)/?$",
    environ_name="JOANIE_COURSE_REGEX",
    environ_prefix=None,
    ),
    "JS_COURSE_REGEX": values.Value(
    r"^.*/api/v1.0/(course-runs|products)/([^/]*)/?$",
    environ_name="JOANIE_JS_COURSE_REGEX",
    environ_prefix=None,
    ),
    # Course runs synchronization
    "COURSE_RUN_SYNC_NO_UPDATE_FIELDS": [],
    "DEFAULT_COURSE_RUN_SYNC_MODE": "sync_to_public",
    }
    ...

    As mentioned earlier, Joanie is treated as a LMS by Richie, so we have to bind Joanie settings with +LMS backends settings. We achieve this by dynamically appending the JOANIE_BACKEND setting value +into the RICHIE_LMS_BACKENDS list, if Joanie is enabled. To understand this point, you can take a +look at the post_setup method of the Base class configuration into settings.py.

    Here they are all settings available into JOANIE_BACKEND:

    BASE_URL

    The base url on which the Joanie instance is hosted. This is used to construct the complete url of +the API endpoint on which requests are made by Richie's frontend application. Richie checks if this +settings is set to know if Joanie should be enabled or not.

    BACKEND

    The path to a Python class serving as Joanie backend. You should not need to change this setting +until you want to customize the behavior of the python Joanie backend.

    • Type: string
    • Required: No
    • Value: By default it is richie.apps.courses.lms.joanie.JoanieBackend

    JS_BACKEND

    The name of the ReactJS backend to use Joanie. You should not need to change this setting +until you want to customize the behavior of the js Joanie backend.

    • Type: string
    • Required: No
    • Value: By default it is joanie.

    COURSE_REGEX

    A python regex that should match the ressource api urls of Joanie and return a +resource_type named group ("course_runs" or "products") and also a resource_id +named group corresponding to the resource uuid.

    • Type: string
    • Required: No
    • Value: for example r"^.*/api/v1.0/(?P<resource_type>(course-runs|products))/(?P<resource_id>[^/]*)/?$"

    JS_COURSE_REGEX

    A Javascript regex that should match the ressource api urls of Joanie and return two +unnamed groups. The first one corresponds to the resource type ("course_runs" or "products") and +the second one corresponds to the resource uuid.

    • Type: string
    • Required: No
    • Value: for example r"^.*/api/v1.0/(course-runs|products)/([^/]*)/?$"

    COURSE_RUN_SYNC_NO_UPDATE_FIELDS

    A list of fields that must only be set the first time a course run is synchronized. During this +first synchronization, a new course run is created in Richie and all fields sent to the API +endpoint via the payload are set on the object. For subsequent synchronization calls, the fields +listed in this setting are ignored and not synchronized. This can be used to allow modifying some +fields manually in Richie regardless of what OpenEdX sends after an initial value is set.

    Read documentation of the eponym LMS_BACKENDS settings, +to discover how it can be configured.

    DEFAULT_COURSE_RUN_SYNC_MODE

    Joanie resources (course runs and products) are all synchronized with Richie as a CourseRun. This +setting is used to set the value of the sync_mode field when a course run is created on Richie. +Read documentation of the eponym LMS_BACKENDS settings, +to discover how it can be configured.

    Access Token

    Lifetime configuration

    Access Token is stored within the SessionStorage through react-query client persister. +By default, richie frontend considered access token as stale after 5 minutes. You can change this +value into settings.ts +by editing REACT_QUERY_SETTINGS.staleTimes.session.

    To always have a valid access token, you have to configure properly its stale time according to the +lifetime of the access token defined by your authentication server. For example, if your +authentication server is using djangorestframework-simplejwt to generate the access token, +its lifetime is 5 minutes by default.

    Technical support

    If you encounter an issue with this documentation, please +open an issue on our repository.

    + + + + \ No newline at end of file diff --git a/docs/2.21.0/lms-backends/index.html b/docs/2.21.0/lms-backends/index.html new file mode 100644 index 0000000000..cd72484524 --- /dev/null +++ b/docs/2.21.0/lms-backends/index.html @@ -0,0 +1,42 @@ + + + + + +Configuring LMS Backends | Richie + + + + +
    +
    Version: 2.21.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +experience between browsing the course catalog on Richie, enrolling to a course and following the +course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the +cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that +are both subdomains of the same root domain, e.g. richie.example.com and lms.example.com.

    OpenEdX will need to generate a CORS CSRF Cookie and this cookie is flagged as secure, which +implies that we are not able to use it without SSL connections.

    As a consequence, you need to configure your OpenEdX instance as follows:

    FEATURES = {
    ...
    "ENABLE_CORS_HEADERS": True,
    "ENABLE_CROSS_DOMAIN_CSRF_COOKIE": True,
    }

    CORS_ALLOW_CREDENTIALS = True
    CORS_ALLOW_INSECURE = False
    CORS_ORIGIN_WHITELIST: ["richie.example.com"] # The domain on which Richie is hosted

    CROSS_DOMAIN_CSRF_COOKIE_DOMAIN = ".example.com" # The parent domain shared by Richie and OpenEdX
    CROSS_DOMAIN_CSRF_COOKIE_NAME: "edx_csrf_token"
    SESSION_COOKIE_NAME: "edx_session"

    Configuring the LMS handler

    The LMSHandler utility acts as a proxy that routes queries to the correct LMS backend API, +based on a regex match on the URL of the course. It is configured via the RICHIE_LMS_BACKENDS +setting. As an example, here is how it would be configured to connect to an Ironwood OpenEdX +instance hosted on https://lms.example.com:

    RICHIE_LMS_BACKENDS=[
    {
    "BASE_URL": "https://lms.example.com",
    # Django
    "BACKEND": "richie.apps.courses.lms.edx.EdXLMSBackend",
    "COURSE_REGEX": r"^https://lms\.example\.com/courses/(?P<course_id>.*)/course/?$",
    # ReactJS
    "JS_BACKEND": "openedx-hawthorn",
    "JS_COURSE_REGEX": r"^https://lms\.example\.com/courses/(.*)/course/?$",
    # Course runs synchronization
    "COURSE_RUN_SYNC_NO_UPDATE_FIELDS": [],
    "DEFAULT_COURSE_RUN_SYNC_MODE": "sync_to_public",
    },
    ]

    The following should help you understand how to configure this setting:

    BASE_URL

    The base url on which the OpenEdX instance is hosted. This is used to construct the complete url +of the API endpoint on which the enrollment request is made by Richie's frontend application.

    BACKEND

    The path to a Python class serving as LMS backend for the targeted LMS.

    • Type: string
    • Required: Yes
    • Value: Richie ships with the following Python backends (custom backends can be written to fit +another specific LMS):
      • richie.apps.courses.lms.edx.EdXLMSBackend: backend for OpenEdX
      • richie.apps.courses.lms.base.BaseLMSBackend: fake backend for development purposes

    COURSE_REGEX

    A Python regex that should match the course syllabus urls of the targeted LMS and return a +course_id named group on the id of the course extracted from these urls.

    • Type: string
    • Required: Yes
    • Value: for example ^.*/courses/(?P<course_id>.*)/course/?$

    JS_BACKEND

    The name of the ReactJS backend to use for the targeted LMS.

    • Type: string
    • Required: Yes
    • Value: Richie ships with the following Javascript backends (custom backends can be written to +fit another specific LMS):
      • openedx-dogwood: backend for OpenEdX versions equal to dogwood or eucalyptus
      • openedx-hawthorn: backend for OpenEdX versions equal to hawthorn or higher
      • openedx-fonzie: backend for OpenEdX via Fonzie +(extra user info and JWT tokens)
      • dummy: fake backend for development purposes

    JS_COURSE_REGEX

    A Javascript regex that should match the course syllabus urls of the targeted LMS and return an +unnamed group on the id of the course extracted from these urls.

    • Type: string
    • Required: Yes
    • Value: for example ^.*/courses/(.*)/course/?$

    DEFAULT_COURSE_RUN_SYNC_MODE

    When a course run is created, this setting is used to set the value of the sync_mode field. +This value defines how the course runs synchronization script will impact this course run after +creation.

    • Type: enum(string)
    • Required: No
    • Value: possible values are manual, sync_to_draft and sync_to_public
      • manual: this course run is ignored by the course runs synchronization script
      • sync_to_draft: only the draft version of this course run is synchronized. A manual +publication is necessary for the update to be visible on the public site.
      • sync_to_public: the public version of this course run is updated by the synchronization +script. As a results, updates are directly visible on the public site without further +publication by a staff user in Richie.

    COURSE_RUN_SYNC_NO_UPDATE_FIELDS

    A list of fields that must only be set the first time a course run is synchronized. During this +first synchronization, a new course run is created in Richie and all fields sent to the API +endpoint via the payload are set on the object. For subsequent synchronization calls, the fields +listed in this setting are ignored and not synchronized. This can be used to allow modifying some +fields manually in Richie regardless of what OpenEdX sends after an initial value is set.

    Note that this setting is only effective for course runs with the sync_mode field set to a +value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please +open an issue on our repository.

    If you need a custom backend, you can submit a PR or +open an issue and we will consider adding it.

    + + + + \ No newline at end of file diff --git a/docs/2.21.0/lms-connection/index.html b/docs/2.21.0/lms-connection/index.html new file mode 100644 index 0000000000..241efb47be --- /dev/null +++ b/docs/2.21.0/lms-connection/index.html @@ -0,0 +1,37 @@ + + + + + +Connecting Richie with one or more LMS | Richie + + + + +
    +
    Version: 2.21.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for +other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's +connection status from OpenEdx and display the user's profile information directly on the Richie +site: username, dashboard url, etc.

    In this approach, a user visiting your Richie site and trying to signup or login, is sent to the +OpenEdX site for authentication and is redirected back to the Richie site upon successful login.

    You can see this in action on https://www.fun-mooc.fr.

    We provide detailed instructions on +how to configure displaying OpenEdX connection status in Richie.

    2. Seamless enrollment

    Thanks to OpenEdX's enrollment API, it is possible to let users enroll on course runs without +leaving Richie.

    You can see this in action on https://www.fun-mooc.fr.

    This feature requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that +are both subdomains of the same root domain, e.g. richie.example.com and lms.example.com.

    You should read our guide on how to use OpenEdX as LMS backend for Richie.

    3. Synchronizing course runs details

    Course runs in Richie can be handled manually, filling all fields via the DjangoCMS front-end +editing interface. But a better way to handle course runs is to synchronize them automatically +from your LMS using the course run synchronization API.

    Please refer to our guide on how to synchronize course runs between Richie and OpenEdx

    4. Joanie, the enrollment manager

    For more advanced use cases, we have started a new project called Joanie which acts as an +enrollment manager for Richie.

    Authentication in Joanie is done via JWT Tokens for maximum flexibility and decoupling in +identity management.

    The project started early 2021, but over time, Joanie will handle:

    • paid enrollments / certification
    • micro-credentials
    • user dashboard
    • cohorts management (academic or B2B)
    • multi-LMS catalogs
    • time based enrollment

    Development

    For development purposes, the docker-compose project provided on +Richie's code repository is pre-configured to connect +with an OpenEdx instance started with +OpenEdx Docker, which provides a ready-to-use +docker-compose stack of OpenEdx in several flavors. Head over to +OpenEdx Docker README for instructions on how to bootstrap an OpenEdX instance.

    Now, start both the OpenEdX and Richie projects separately with make run.

    Richie should respond on http://localhost:8070, OpenEdx on http://localhost:8073 and both +apps should be able to communicate with each other via the network bridge defined in +docker-compose.

    If you want to activate seamless enrollment locally for development, +you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our +guide on setting-up TLS connections for Richie and OpenEdX.

    + + + + \ No newline at end of file diff --git a/docs/2.21.0/native-installation/index.html b/docs/2.21.0/native-installation/index.html new file mode 100644 index 0000000000..151442ee98 --- /dev/null +++ b/docs/2.21.0/native-installation/index.html @@ -0,0 +1,40 @@ + + + + + +Installing Richie on your machine | Richie + + + + +
    +
    Version: 2.21.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +installation on your laptop.

    A better approach is to use Docker as explained in +our guide for container-native installation instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh +installation.

    If you are using another operating system or distribution, you can use +Vagrant to get a +running Ubuntu 18.04 server in seconds.

    System update

    Be sure to have fresh packages on the server (kernel, libc, ssl patches...): +post

    sudo apt-get -y update
    sudo apt-get -y dist-upgrade

    Database part

    You must first install postgresql.

    // On Linux
    sudo apt-get -y install postgresql

    // On OS X
    brew install postgresql@10
    brew services start postgresql@10
    // don't forget to add your new postgres install to the $PATH

    Postgresql is now running.

    Then you can create the database owner and the database itself, using the +postgres user:

    sudo -u postgres -i // skip this on OS X as the default install will use your local user
    createuser fun -sP

    Note: we created the user as a superuser. This should only be done in dev/test +environments.

    Now, create the database with this user:

    createdb richie -O fun -W
    exit

    Elasticsearch

    Ubuntu

    Download and install the Public Signing Key

    $ wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -

    You may need to install the apt-transport-https package on Debian before +proceeding:

    $ sudo apt-get install apt-transport-https

    Save the repository definition to /etc/apt/sources.list.d/elastic-6.3.1.list:

    $ echo "deb https://artifacts.elastic.co/packages/6.3.1/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-6.3.1.list

    Update repository and install

    $ sudo apt-get update
    $ sudo apt-get install elasticsearch
    $ sudo /etc/init.d/elasticsearch start

    OS X

    $ brew install elasticsearch

    Application part

    Python and other requirements

    We use Python 3.6 which is the one installed by default in Ubuntu 18.04.

    You can install it on OS X using the following commands. Make sure to always run +python3 instead of python and pip3 instead of pip to ensure the correct +version of Python (your homebrew install of 3) is used.

    brew install python3
    brew postinstall python3

    The virtualenv

    Place yourself in the application directory app:

    cd app

    We choose to run our application in a virtual environment.

    For this, we'll install virtualenvwrapper and add an environment:

    pip install virtualenvwrapper

    You can open a new shell to activate the virtualenvwrapper commands, or simply +do:

    source $(which virtualenvwrapper.sh)

    Then create the virtual environment for richie:

    mkvirtualenv richie --no-site-packages --python=python3

    The virtualenv should now be activated and you can install the Python +dependencies for development:

    pip install -e .[dev]

    The "dev.txt" requirement file installs packages specific to a dev environment +and should not be used in production.

    Frontend build

    This project is a hybrid that uses both Django generated pages and frontend JS +code. As such, it includes a frontend build process that comes in two parts: JS +& CSS.

    We need NPM to install the dependencies and run the build, which depends on a +version of Nodejs specified in .nvmrc. See the +repo for instructions on how to install NVM. +To take advantage of .nvmrc, run this in the context of the repository:

    nvm install
    nvm use

    As a prerequisite to running the frontend build for either JS or CSS, you'll +need to install yarn and download +dependencies via:

    yarn install
    • JS build
    npm run build
    • CSS build

    This will compile all our SCSS files into one bundle and put it in the static +folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first +time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at +localhost:8000

    python sandbox/manage.py runserver
    + + + + \ No newline at end of file diff --git a/docs/2.21.0/synchronizing-course-runs/index.html b/docs/2.21.0/synchronizing-course-runs/index.html new file mode 100644 index 0000000000..1a6bde849b --- /dev/null +++ b/docs/2.21.0/synchronizing-course-runs/index.html @@ -0,0 +1,35 @@ + + + + + +Synchronizing course runs between Richie and OpenEdX | Richie + + + + +
    +
    Version: 2.21.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any +of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course +runs with the Richie instance. Richie will try the declared secrets one by one until it finds +one that matches the signature sent by the remote system.

    Configure LMS backends

    You then need to configure the LMS handler via the RICHIE_LMS_BACKENDS setting as explained +in our guide on configuring LMS backends. This is +required if you want Richie to create a new course run automatically and associate it with the +right course when the resource link submitted to the course run synchronization API endpoint is +unknown to Richie.

    Each course run can be set to react differently to a synchronization request, thanks to the +sync_mode field. This field can be set to one of the following values:

    • manual: this course run is ignored by the course runs synchronization script. In this case, +the course run can only be edited manually using the DjangoCMS frontend editing.
    • sync_to_draft: only the draft version of this course run is synchronized. A manual +publication is necessary for the update to be visible on the public site.
    • sync_to_public: the public version of this course run is updated by the synchronization +script. As a results, updates are directly visible on the public site without further +publication by a staff user in Richie.

    A DEFAULT_COURSE_RUN_SYNC_MODE parameter in the +RICHIE_LMS_BACKENDS setting, defines what default value is used for new course runs.

    Make a synchronization query

    You can refer to the documentation of the course run synchronization API for details +on the query expected by this endpoint.

    We also share here our sample code to call this synchronization endpoint from OpenEdX. This code +should run on the post_publish signal emitted by the OpenEdX cms application each time a +course run is modified and published.

    Or you can use the Richie Open edX Synchronization +which is based on the following code sample and also includes the enrollment count.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course +is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    + + + + \ No newline at end of file diff --git a/docs/2.21.0/tls-connection/index.html b/docs/2.21.0/tls-connection/index.html new file mode 100644 index 0000000000..a78c6ced5d --- /dev/null +++ b/docs/2.21.0/tls-connection/index.html @@ -0,0 +1,38 @@ + + + + + +Connecting Richie and OpenEdX over TLS for development | Richie + + + + +
    +
    Version: 2.21.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the +RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX +will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that +we are not able to use it without SSL connections.

    So if you need to use the OpenEdx API to Create, Update or Delete data from Richie, you have to +enable SSL on Richie and OpenEdx on your development environment, which requires a little bit more +configuration. Below, we explain how to serve OpenEdx and Richie over SSL.

    Run OpenEdx and Richie on sibling domains

    Richie and OpenEdx must be on sibling domains ie domains that both are subdomains of the same +parent domain, because sharing secure Cookies on localhost or unrelated domains is blocked. +To do that, you have to edit your hosts file (.e.g /etc/hosts on a *NIX system) to alias a +domain local.dev with two subdomains richie and edx pointing to localhost:

    # /etc/hosts
    127.0.0.1 richie.local.dev
    127.0.0.1 edx.local.dev

    Once this has been done, the OpenEdx app should respond on http://edx.local.dev:8073 +and Richie should respond on http://richie.local.dev:8070. The Richie application should now be +able to make CORS XHR requests to the OpenEdX application.

    Enable TLS

    If you want to develop with OpenEdx as LMS backend of the Richie application (see the +RICHIE_LMS_BACKENDS setting), you need to enable TLS for your development servers. +Both Richie and OpenEdx use Nginx as reverse proxy which eases the SSL setup.

    1. Install mkcert and its Certificate Authority

    First you will need to install mkcert and its Certificate Authority. +mkcert is a little util to ease local certificate generation.

    a. Install mkcert on your local machine

    b. Install Mkcert Certificate Authority

    mkcert -install

    If you do not want to use mkcert, you can generate CA and certificate with openssl. +You will have to put your certificate and its key in the docker/files/etc/nginx/ssl directory +and respectively name them richie.local.dev.pem and richie.local.dev.key.

    2. On Richie

    Then, to setup the SSL configuration with mkcert, run our helper script:

    $ bin/setup-ssl

    If you do not want to use mkcert, read the instructions above to generate a Richie certificate, +and run the helper script with the --no-cert option:

    bin/setup-ssl --no-cert

    3. On OpenEdx

    In the same way, you also have to enable SSL in OpenEdx, by updating the Nginx configuration. +Read how to enable SSL on OpenEdx.

    Once this has been done, the OpenEdx app should respond on https://edx.local.dev:8073 +and Richie should respond on https://richie.local.dev:8070. The richie application should be able +to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie +on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following +command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    + + + + \ No newline at end of file diff --git a/docs/2.21.0/web-analytics/index.html b/docs/2.21.0/web-analytics/index.html new file mode 100644 index 0000000000..eb95bc83dd --- /dev/null +++ b/docs/2.21.0/web-analytics/index.html @@ -0,0 +1,22 @@ + + + + + +Add web analytics to your site | Richie + + + + +
    +
    Version: 2.21.0

    Add web analytics to your site

    Richie has native support to Google Universal Analytics and Google Tag Manager Web Analytics solutions. +The purpose of this file is to explain how you can enable one of the supported Web Analytics providers +and how you can extend Richie with an alternative solution.

    Google Universal Analytics

    Next, it is described how you can configure the Google Universal Analytics on your Richie site.

    Add the WEB_ANALYTICS setting, with the Google Universal Analytics configuration. From the next example replace TRACKING_ID with your tracking id code.

    {
    'google_universal_analytics': {
    'tracking_id': 'TRACKING_ID',
    }
    }

    The current Google Universal Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Universal Analytics or even use them to create custom reports. +Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Google Tag

    It is possible to configure the Google Tag, gtag.js, on your Richie site.

    Add the WEB_ANALYTICS setting, with the Google Tag configuration like for example:

    {
    'google_tag': {
    'tracking_id': 'TRACKING_ID',
    }
    }

    And don't forget to replace the TRACKING_ID with your tracking id/code from Google Ads, Google Analytics, or other Google product compatible with the gtag.js.

    The Google Tag is initialized with custom dimensions like the Google Universal Analytics.

    Google Tag Manager

    Next, it is described how you can configure the Google Tag Manager, gtm.js, on your Richie site.

    Add the WEB_ANALYTICS setting, with the Google Tag Manager configuration, for example:

    {
    'google_tag_manager': {
    'tracking_id': 'TRACKING_ID',
    }
    }

    And don't forget to replace the TRACKING_ID with your GTM tracking id/code.

    The current Google Tag Manager implementation also defines a custom dimensions like the Google Universal Analytics.

    If you want to use the Environments feature of the Google Tag Manager, you need to include the environment key with its value on google_tag_manager dict inside the WEB_ANALYTICS setting.

    The environments feature in Google Tag Manager is ideal for organizations that want to preview their container changes in a test environment before those changes are published.

    {
    'google_tag_manager': {
    'tracking_id': 'TRACKING_ID',
    'environment': '&gtm_auth=aaaaaaaaaaaaaaaa&gtm_preview=env-99&gtm_cookies_win=x';
    }
    }

    Multiple Web Analytics at the same time

    It is possible to configure several web analytics solutions at the same time or the same solution with different tracking identifications.

    WEB_ANALYTICS setting example to have both Google Universal Analytics and Google Tag Manager:

    {
    'google_universal_analytics': {
    'tracking_id': 'UA-TRACKING_ID',
    },
    'google_tag_manager': {
    'tracking_id': 'GTM-TRACKING_ID',
    }
    }

    Location of the web analytics javascript

    Each web analytics js code can be put on the footer (default value), to put the Javascript on HTML body footer, or header, to put the Javascript code at the end of the HTML head.

    Update the WEB_ANALYTICS setting, like:

    {
    'google_universal_analytics': {
    'tracking_id': 'UA-TRACKING_ID',
    'location': 'footer,
    },
    }

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • define the WEB_ANALYTICS setting with your tracking identification
    • optionally change location with footer (default) or head value
    {
    'my-custom-web-analytics-software': {
    'tracking_id': 'MY_CUSTOM_TRACKING_ID',
    'location': 'footer,
    },
    }
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% extends "richie/web_analytics.html" %}
    {% block web_analytics_additional_providers %}
    {% if provider == "my_custom_web_analytics_software_provider" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endblock web_analytics_additional_providers %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>

    The frontend code also sends events to the web analytics provider. +Richie sends events when the user is enrolled on a course run. +To support different providers, you need to create a similar file +of src/frontend/js/utils/api/web-analytics/google_universal_analytics.ts and change the src/frontend/js/utils/api/web-analytics/index.ts file to include that newer provider.

    + + + + \ No newline at end of file diff --git a/docs/2.3.0/accessibility-testing/index.html b/docs/2.3.0/accessibility-testing/index.html index 13a7b289f0..561522ae1a 100644 --- a/docs/2.3.0/accessibility-testing/index.html +++ b/docs/2.3.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.3.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.3.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.3.0/building-the-frontend/index.html b/docs/2.3.0/building-the-frontend/index.html index c484951700..d3570493b1 100644 --- a/docs/2.3.0/building-the-frontend/index.html +++ b/docs/2.3.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.3.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.3.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.3.0/contributing-guide/index.html b/docs/2.3.0/contributing-guide/index.html index afbfc07283..06a786143e 100644 --- a/docs/2.3.0/contributing-guide/index.html +++ b/docs/2.3.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.3.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.3.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.3.0/css-guidelines/index.html b/docs/2.3.0/css-guidelines/index.html index b3bd03d0e2..dca7c439fa 100644 --- a/docs/2.3.0/css-guidelines/index.html +++ b/docs/2.3.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.3.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.3.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.3.0/discover/index.html b/docs/2.3.0/discover/index.html index 9ceee782db..f3a820d36f 100644 --- a/docs/2.3.0/discover/index.html +++ b/docs/2.3.0/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.3.0

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.3.0

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -27,7 +27,7 @@ to bootstrap an instance.

    Just start apps with make run.

    Richie should respond on http://localhost:8070 and OpenEdx on http://localhost:8073.

    Advanced - Connecting Richie to OpenEdx

    If you want users to enroll on courses in OpenEdx directly from Richie via API calls, you should read the advanced guide to connect Richie to OpenEdx over TLS.

    - - + + \ No newline at end of file diff --git a/docs/2.3.0/django-react-interop/index.html b/docs/2.3.0/django-react-interop/index.html index 961aa14136..5f53d2498a 100644 --- a/docs/2.3.0/django-react-interop/index.html +++ b/docs/2.3.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.3.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.3.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.3.0/docker-development/index.html b/docs/2.3.0/docker-development/index.html index 908a612c95..251ecf9ed3 100644 --- a/docs/2.3.0/docker-development/index.html +++ b/docs/2.3.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.3.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.3.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.3.0/frontend-overrides/index.html b/docs/2.3.0/frontend-overrides/index.html index 8fbd94e0e4..156b156f97 100644 --- a/docs/2.3.0/frontend-overrides/index.html +++ b/docs/2.3.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.3.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.3.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.3.0/internationalization/index.html b/docs/2.3.0/internationalization/index.html index a2c1f70287..b0866c09ef 100644 --- a/docs/2.3.0/internationalization/index.html +++ b/docs/2.3.0/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.3.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.3.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.3.0/lms-connection/index.html b/docs/2.3.0/lms-connection/index.html index 04aac7666e..e0171d1119 100644 --- a/docs/2.3.0/lms-connection/index.html +++ b/docs/2.3.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with an LMS | Richie - - + +
    -
    Version: 2.3.0

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle +

    Version: 2.3.0

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle or Canvas for a seamless experience between browsing the course catalog on richie and following the course itself on the LMS.

    In order to connect richie with a LMS, there is an API bridge to synchronize course information and enrollments.

    API bridge

    The APIHandler utility acts as a proxy that routes queries to the correct LMS backend API, @@ -43,7 +43,7 @@ on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. If you want to use SSL later, just use make run-ssl to run OpenEdx and Richie apps. Of course, you can still run apps without ssl by using make run.

    - - + + \ No newline at end of file diff --git a/docs/2.3.0/native-installation/index.html b/docs/2.3.0/native-installation/index.html index b9af9237ec..8a7695279a 100644 --- a/docs/2.3.0/native-installation/index.html +++ b/docs/2.3.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.3.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.3.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.3.1/accessibility-testing/index.html b/docs/2.3.1/accessibility-testing/index.html index 302213ac19..d1d6935c7b 100644 --- a/docs/2.3.1/accessibility-testing/index.html +++ b/docs/2.3.1/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.3.1

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.3.1

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.3.1/building-the-frontend/index.html b/docs/2.3.1/building-the-frontend/index.html index 9c9a76493d..f5667d6f03 100644 --- a/docs/2.3.1/building-the-frontend/index.html +++ b/docs/2.3.1/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.3.1

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.3.1

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.3.1/contributing-guide/index.html b/docs/2.3.1/contributing-guide/index.html index 72b7b6c83b..206ce5791d 100644 --- a/docs/2.3.1/contributing-guide/index.html +++ b/docs/2.3.1/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.3.1

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.3.1

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.3.1/css-guidelines/index.html b/docs/2.3.1/css-guidelines/index.html index 0c2404dbb6..077dfeb73c 100644 --- a/docs/2.3.1/css-guidelines/index.html +++ b/docs/2.3.1/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.3.1

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.3.1

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.3.1/discover/index.html b/docs/2.3.1/discover/index.html index d8cff3b429..2c9b2b6950 100644 --- a/docs/2.3.1/discover/index.html +++ b/docs/2.3.1/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.3.1

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.3.1

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -27,7 +27,7 @@ to bootstrap an instance.

    Just start apps with make run.

    Richie should respond on http://localhost:8070 and OpenEdx on http://localhost:8073.

    Advanced - Connecting Richie to OpenEdx

    If you want users to enroll on courses in OpenEdx directly from Richie via API calls, you should read the advanced guide to connect Richie to OpenEdx over TLS.

    - - + + \ No newline at end of file diff --git a/docs/2.3.1/django-react-interop/index.html b/docs/2.3.1/django-react-interop/index.html index 8100ce3782..cf74fa8fe8 100644 --- a/docs/2.3.1/django-react-interop/index.html +++ b/docs/2.3.1/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.3.1

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.3.1

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.3.1/docker-development/index.html b/docs/2.3.1/docker-development/index.html index 0b8ce46b5d..7998a6f4bb 100644 --- a/docs/2.3.1/docker-development/index.html +++ b/docs/2.3.1/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.3.1

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.3.1

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.3.1/frontend-overrides/index.html b/docs/2.3.1/frontend-overrides/index.html index 82fcb0f75c..957ee930e0 100644 --- a/docs/2.3.1/frontend-overrides/index.html +++ b/docs/2.3.1/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.3.1

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.3.1

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.3.1/internationalization/index.html b/docs/2.3.1/internationalization/index.html index 1c740bf469..8c55e41af0 100644 --- a/docs/2.3.1/internationalization/index.html +++ b/docs/2.3.1/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.3.1

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.3.1

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.3.1/lms-connection/index.html b/docs/2.3.1/lms-connection/index.html index 7d759686cf..e7a00b0726 100644 --- a/docs/2.3.1/lms-connection/index.html +++ b/docs/2.3.1/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with an LMS | Richie - - + +
    -
    Version: 2.3.1

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle +

    Version: 2.3.1

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle or Canvas for a seamless experience between browsing the course catalog on richie and following the course itself on the LMS.

    In order to connect richie with a LMS, there is an API bridge to synchronize course information and enrollments.

    API bridge

    The APIHandler utility acts as a proxy that routes queries to the correct LMS backend API, @@ -43,7 +43,7 @@ on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. If you want to use SSL later, just use make run-ssl to run OpenEdx and Richie apps. Of course, you can still run apps without ssl by using make run.

    - - + + \ No newline at end of file diff --git a/docs/2.3.1/native-installation/index.html b/docs/2.3.1/native-installation/index.html index 1f3bf65734..b77600fd93 100644 --- a/docs/2.3.1/native-installation/index.html +++ b/docs/2.3.1/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.3.1

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.3.1

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.3.2/accessibility-testing/index.html b/docs/2.3.2/accessibility-testing/index.html index 8831adeb06..fd047e9692 100644 --- a/docs/2.3.2/accessibility-testing/index.html +++ b/docs/2.3.2/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.3.2

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.3.2

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.3.2/building-the-frontend/index.html b/docs/2.3.2/building-the-frontend/index.html index 76a402d4c3..3da2178979 100644 --- a/docs/2.3.2/building-the-frontend/index.html +++ b/docs/2.3.2/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.3.2

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.3.2

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.3.2/contributing-guide/index.html b/docs/2.3.2/contributing-guide/index.html index 4c90a909a1..d7bc9336d7 100644 --- a/docs/2.3.2/contributing-guide/index.html +++ b/docs/2.3.2/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.3.2

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.3.2

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.3.2/css-guidelines/index.html b/docs/2.3.2/css-guidelines/index.html index 2b313a4c2f..cacd357128 100644 --- a/docs/2.3.2/css-guidelines/index.html +++ b/docs/2.3.2/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.3.2

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.3.2

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.3.2/discover/index.html b/docs/2.3.2/discover/index.html index 67784d9470..c638c26668 100644 --- a/docs/2.3.2/discover/index.html +++ b/docs/2.3.2/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.3.2

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.3.2

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -27,7 +27,7 @@ to bootstrap an instance.

    Just start apps with make run.

    Richie should respond on http://localhost:8070 and OpenEdx on http://localhost:8073.

    Advanced - Connecting Richie to OpenEdx

    If you want users to enroll on courses in OpenEdx directly from Richie via API calls, you should read the advanced guide to connect Richie to OpenEdx over TLS.

    - - + + \ No newline at end of file diff --git a/docs/2.3.2/django-react-interop/index.html b/docs/2.3.2/django-react-interop/index.html index a9ce226a83..d162c16ff4 100644 --- a/docs/2.3.2/django-react-interop/index.html +++ b/docs/2.3.2/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.3.2

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.3.2

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.3.2/docker-development/index.html b/docs/2.3.2/docker-development/index.html index ca126738cc..2ef6290c6c 100644 --- a/docs/2.3.2/docker-development/index.html +++ b/docs/2.3.2/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.3.2

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.3.2

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.3.2/frontend-overrides/index.html b/docs/2.3.2/frontend-overrides/index.html index 8974d4010a..ec020a4134 100644 --- a/docs/2.3.2/frontend-overrides/index.html +++ b/docs/2.3.2/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.3.2

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.3.2

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.3.2/internationalization/index.html b/docs/2.3.2/internationalization/index.html index 31a734380c..1a21975428 100644 --- a/docs/2.3.2/internationalization/index.html +++ b/docs/2.3.2/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.3.2

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.3.2

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.3.2/lms-connection/index.html b/docs/2.3.2/lms-connection/index.html index 02c368f062..4fd6ad24c0 100644 --- a/docs/2.3.2/lms-connection/index.html +++ b/docs/2.3.2/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with an LMS | Richie - - + +
    -
    Version: 2.3.2

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle +

    Version: 2.3.2

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle or Canvas for a seamless experience between browsing the course catalog on richie and following the course itself on the LMS.

    In order to connect richie with a LMS, there is an API bridge to synchronize course information and enrollments.

    API bridge

    The APIHandler utility acts as a proxy that routes queries to the correct LMS backend API, @@ -43,7 +43,7 @@ on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. If you want to use SSL later, just use make run-ssl to run OpenEdx and Richie apps. Of course, you can still run apps without ssl by using make run.

    - - + + \ No newline at end of file diff --git a/docs/2.3.2/native-installation/index.html b/docs/2.3.2/native-installation/index.html index dba387f2f3..d43e87d9b4 100644 --- a/docs/2.3.2/native-installation/index.html +++ b/docs/2.3.2/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.3.2

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.3.2

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.3.3/accessibility-testing/index.html b/docs/2.3.3/accessibility-testing/index.html index 07e40cc316..d0119b4690 100644 --- a/docs/2.3.3/accessibility-testing/index.html +++ b/docs/2.3.3/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.3.3

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.3.3

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.3.3/building-the-frontend/index.html b/docs/2.3.3/building-the-frontend/index.html index 5877ef2ee6..b3f3d4329e 100644 --- a/docs/2.3.3/building-the-frontend/index.html +++ b/docs/2.3.3/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.3.3

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.3.3

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.3.3/contributing-guide/index.html b/docs/2.3.3/contributing-guide/index.html index 3a3e2056a0..2150f7a37e 100644 --- a/docs/2.3.3/contributing-guide/index.html +++ b/docs/2.3.3/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.3.3

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.3.3

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.3.3/css-guidelines/index.html b/docs/2.3.3/css-guidelines/index.html index b8d91dc45c..96cf5c1411 100644 --- a/docs/2.3.3/css-guidelines/index.html +++ b/docs/2.3.3/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.3.3

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.3.3

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.3.3/discover/index.html b/docs/2.3.3/discover/index.html index 4bc6fb97b1..206744d59a 100644 --- a/docs/2.3.3/discover/index.html +++ b/docs/2.3.3/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.3.3

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.3.3

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -27,7 +27,7 @@ to bootstrap an instance.

    Just start apps with make run.

    Richie should respond on http://localhost:8070 and OpenEdx on http://localhost:8073.

    Advanced - Connecting Richie to OpenEdx

    If you want users to enroll on courses in OpenEdx directly from Richie via API calls, you should read the advanced guide to connect Richie to OpenEdx over TLS.

    - - + + \ No newline at end of file diff --git a/docs/2.3.3/django-react-interop/index.html b/docs/2.3.3/django-react-interop/index.html index 44060b0e71..774d55368c 100644 --- a/docs/2.3.3/django-react-interop/index.html +++ b/docs/2.3.3/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.3.3

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.3.3

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.3.3/docker-development/index.html b/docs/2.3.3/docker-development/index.html index 7134fccf6c..4f6a7f9a9f 100644 --- a/docs/2.3.3/docker-development/index.html +++ b/docs/2.3.3/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.3.3

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.3.3

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.3.3/frontend-overrides/index.html b/docs/2.3.3/frontend-overrides/index.html index 229ba954db..f9a84b1214 100644 --- a/docs/2.3.3/frontend-overrides/index.html +++ b/docs/2.3.3/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.3.3

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.3.3

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.3.3/internationalization/index.html b/docs/2.3.3/internationalization/index.html index 035b73fb28..5729d2c0a7 100644 --- a/docs/2.3.3/internationalization/index.html +++ b/docs/2.3.3/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.3.3

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.3.3

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.3.3/lms-connection/index.html b/docs/2.3.3/lms-connection/index.html index b3728576ba..edd5f37b07 100644 --- a/docs/2.3.3/lms-connection/index.html +++ b/docs/2.3.3/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with an LMS | Richie - - + +
    -
    Version: 2.3.3

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle +

    Version: 2.3.3

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle or Canvas for a seamless experience between browsing the course catalog on richie and following the course itself on the LMS.

    In order to connect richie with a LMS, there is an API bridge to synchronize course information and enrollments.

    API bridge

    The APIHandler utility acts as a proxy that routes queries to the correct LMS backend API, @@ -43,7 +43,7 @@ on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. If you want to use SSL later, just use make run-ssl to run OpenEdx and Richie apps. Of course, you can still run apps without ssl by using make run.

    - - + + \ No newline at end of file diff --git a/docs/2.3.3/native-installation/index.html b/docs/2.3.3/native-installation/index.html index 60be47fc2f..40aae8838c 100644 --- a/docs/2.3.3/native-installation/index.html +++ b/docs/2.3.3/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.3.3

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.3.3

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.4.0/accessibility-testing/index.html b/docs/2.4.0/accessibility-testing/index.html index a246f6376a..472580979e 100644 --- a/docs/2.4.0/accessibility-testing/index.html +++ b/docs/2.4.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.4.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.4.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.4.0/building-the-frontend/index.html b/docs/2.4.0/building-the-frontend/index.html index 7df4f480ad..fdad51de55 100644 --- a/docs/2.4.0/building-the-frontend/index.html +++ b/docs/2.4.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.4.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.4.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.4.0/contributing-guide/index.html b/docs/2.4.0/contributing-guide/index.html index 8e1f407e25..9c0056e580 100644 --- a/docs/2.4.0/contributing-guide/index.html +++ b/docs/2.4.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.4.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.4.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.4.0/css-guidelines/index.html b/docs/2.4.0/css-guidelines/index.html index 8ecf636709..501a569e9d 100644 --- a/docs/2.4.0/css-guidelines/index.html +++ b/docs/2.4.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.4.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.4.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.4.0/discover/index.html b/docs/2.4.0/discover/index.html index 1d902d3749..55df164d9d 100644 --- a/docs/2.4.0/discover/index.html +++ b/docs/2.4.0/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.4.0

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.4.0

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -27,7 +27,7 @@ to bootstrap an instance.

    Just start apps with make run.

    Richie should respond on http://localhost:8070 and OpenEdx on http://localhost:8073.

    Advanced - Connecting Richie to OpenEdx

    If you want users to enroll on courses in OpenEdx directly from Richie via API calls, you should read the advanced guide to connect Richie to OpenEdx over TLS.

    - - + + \ No newline at end of file diff --git a/docs/2.4.0/django-react-interop/index.html b/docs/2.4.0/django-react-interop/index.html index d22d3dff77..6847e49d27 100644 --- a/docs/2.4.0/django-react-interop/index.html +++ b/docs/2.4.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.4.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.4.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.4.0/docker-development/index.html b/docs/2.4.0/docker-development/index.html index 4519a2dcfb..789c6add06 100644 --- a/docs/2.4.0/docker-development/index.html +++ b/docs/2.4.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.4.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.4.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.4.0/frontend-overrides/index.html b/docs/2.4.0/frontend-overrides/index.html index 9276ac6df6..6d8dddbcda 100644 --- a/docs/2.4.0/frontend-overrides/index.html +++ b/docs/2.4.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.4.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.4.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.4.0/internationalization/index.html b/docs/2.4.0/internationalization/index.html index d031ace2f0..3acd438015 100644 --- a/docs/2.4.0/internationalization/index.html +++ b/docs/2.4.0/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.4.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.4.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.4.0/lms-connection/index.html b/docs/2.4.0/lms-connection/index.html index 85dea775a3..5f1c864d2c 100644 --- a/docs/2.4.0/lms-connection/index.html +++ b/docs/2.4.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with an LMS | Richie - - + +
    -
    Version: 2.4.0

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle +

    Version: 2.4.0

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle or Canvas for a seamless experience between browsing the course catalog on richie and following the course itself on the LMS.

    In order to connect richie with a LMS, there is an API bridge to synchronize course information and enrollments.

    API bridge

    The APIHandler utility acts as a proxy that routes queries to the correct LMS backend API, @@ -43,7 +43,7 @@ on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. If you want to use SSL later, just use make run-ssl to run OpenEdx and Richie apps. Of course, you can still run apps without ssl by using make run.

    - - + + \ No newline at end of file diff --git a/docs/2.4.0/native-installation/index.html b/docs/2.4.0/native-installation/index.html index 541ebf7580..849919c612 100644 --- a/docs/2.4.0/native-installation/index.html +++ b/docs/2.4.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.4.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.4.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.5.0/accessibility-testing/index.html b/docs/2.5.0/accessibility-testing/index.html index 181a7cc92a..3ab9ddbdbe 100644 --- a/docs/2.5.0/accessibility-testing/index.html +++ b/docs/2.5.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.5.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.5.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.5.0/building-the-frontend/index.html b/docs/2.5.0/building-the-frontend/index.html index ad1f412bbc..0c01e71672 100644 --- a/docs/2.5.0/building-the-frontend/index.html +++ b/docs/2.5.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.5.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.5.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.5.0/contributing-guide/index.html b/docs/2.5.0/contributing-guide/index.html index b8e313947f..33ffd494ec 100644 --- a/docs/2.5.0/contributing-guide/index.html +++ b/docs/2.5.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.5.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.5.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.5.0/css-guidelines/index.html b/docs/2.5.0/css-guidelines/index.html index ff1903d41b..0511466719 100644 --- a/docs/2.5.0/css-guidelines/index.html +++ b/docs/2.5.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.5.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.5.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.5.0/discover/index.html b/docs/2.5.0/discover/index.html index 1d3b56af5d..8b0542adfb 100644 --- a/docs/2.5.0/discover/index.html +++ b/docs/2.5.0/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.5.0

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.5.0

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -27,7 +27,7 @@ to bootstrap an instance.

    Just start apps with make run.

    Richie should respond on http://localhost:8070 and OpenEdx on http://localhost:8073.

    Advanced - Connecting Richie to OpenEdx

    If you want users to enroll on courses in OpenEdx directly from Richie via API calls, you should read the advanced guide to connect Richie to OpenEdx over TLS.

    - - + + \ No newline at end of file diff --git a/docs/2.5.0/django-react-interop/index.html b/docs/2.5.0/django-react-interop/index.html index d1f8568d35..b0209be63c 100644 --- a/docs/2.5.0/django-react-interop/index.html +++ b/docs/2.5.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.5.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.5.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.5.0/docker-development/index.html b/docs/2.5.0/docker-development/index.html index 9ea5f26218..e98142bf6e 100644 --- a/docs/2.5.0/docker-development/index.html +++ b/docs/2.5.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.5.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.5.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.5.0/frontend-overrides/index.html b/docs/2.5.0/frontend-overrides/index.html index ec611a1be1..0b7cb0f10c 100644 --- a/docs/2.5.0/frontend-overrides/index.html +++ b/docs/2.5.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.5.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.5.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.5.0/internationalization/index.html b/docs/2.5.0/internationalization/index.html index 1691ee6c7b..bca0be67ca 100644 --- a/docs/2.5.0/internationalization/index.html +++ b/docs/2.5.0/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.5.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.5.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.5.0/lms-connection/index.html b/docs/2.5.0/lms-connection/index.html index a09aabba49..4cae47e20d 100644 --- a/docs/2.5.0/lms-connection/index.html +++ b/docs/2.5.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with an LMS | Richie - - + +
    -
    Version: 2.5.0

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle +

    Version: 2.5.0

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle or Canvas for a seamless experience between browsing the course catalog on richie and following the course itself on the LMS.

    In order to connect richie with a LMS, there is an API bridge to synchronize course information and enrollments.

    API bridge

    The APIHandler utility acts as a proxy that routes queries to the correct LMS backend API, @@ -43,7 +43,7 @@ on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. If you want to use SSL later, just use make run-ssl to run OpenEdx and Richie apps. Of course, you can still run apps without ssl by using make run.

    - - + + \ No newline at end of file diff --git a/docs/2.5.0/native-installation/index.html b/docs/2.5.0/native-installation/index.html index 7788239b28..9e49412150 100644 --- a/docs/2.5.0/native-installation/index.html +++ b/docs/2.5.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.5.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.5.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.6.0/accessibility-testing/index.html b/docs/2.6.0/accessibility-testing/index.html index a0c365c988..0caa94dbbd 100644 --- a/docs/2.6.0/accessibility-testing/index.html +++ b/docs/2.6.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.6.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.6.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.6.0/building-the-frontend/index.html b/docs/2.6.0/building-the-frontend/index.html index c30b16568e..a6098819fb 100644 --- a/docs/2.6.0/building-the-frontend/index.html +++ b/docs/2.6.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.6.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.6.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.6.0/contributing-guide/index.html b/docs/2.6.0/contributing-guide/index.html index 94ed215e36..a7029f2aa9 100644 --- a/docs/2.6.0/contributing-guide/index.html +++ b/docs/2.6.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.6.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.6.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.6.0/css-guidelines/index.html b/docs/2.6.0/css-guidelines/index.html index b493af9535..02fba798c6 100644 --- a/docs/2.6.0/css-guidelines/index.html +++ b/docs/2.6.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.6.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.6.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.6.0/discover/index.html b/docs/2.6.0/discover/index.html index 8c548fb511..c94fcca195 100644 --- a/docs/2.6.0/discover/index.html +++ b/docs/2.6.0/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.6.0

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.6.0

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -27,7 +27,7 @@ to bootstrap an instance.

    Just start apps with make run.

    Richie should respond on http://localhost:8070 and OpenEdx on http://localhost:8073.

    Advanced - Connecting Richie to OpenEdx

    If you want users to enroll on courses in OpenEdx directly from Richie via API calls, you should read the advanced guide to connect Richie to OpenEdx over TLS.

    - - + + \ No newline at end of file diff --git a/docs/2.6.0/django-react-interop/index.html b/docs/2.6.0/django-react-interop/index.html index 821545ad44..1c2086f8f8 100644 --- a/docs/2.6.0/django-react-interop/index.html +++ b/docs/2.6.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.6.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.6.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.6.0/docker-development/index.html b/docs/2.6.0/docker-development/index.html index 84dc5b4c90..ae1371b411 100644 --- a/docs/2.6.0/docker-development/index.html +++ b/docs/2.6.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.6.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.6.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.6.0/frontend-overrides/index.html b/docs/2.6.0/frontend-overrides/index.html index 8c8e3c920a..e2c7dc3ce9 100644 --- a/docs/2.6.0/frontend-overrides/index.html +++ b/docs/2.6.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.6.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.6.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.6.0/internationalization/index.html b/docs/2.6.0/internationalization/index.html index a93fa8c3dd..1c7a5ef7fa 100644 --- a/docs/2.6.0/internationalization/index.html +++ b/docs/2.6.0/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.6.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.6.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.6.0/lms-connection/index.html b/docs/2.6.0/lms-connection/index.html index f266669a83..b6caedf719 100644 --- a/docs/2.6.0/lms-connection/index.html +++ b/docs/2.6.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with an LMS | Richie - - + +
    -
    Version: 2.6.0

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle +

    Version: 2.6.0

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle or Canvas for a seamless experience between browsing the course catalog on richie and following the course itself on the LMS.

    In order to connect richie with a LMS, there is an API bridge to synchronize course information and enrollments.

    API bridge

    The APIHandler utility acts as a proxy that routes queries to the correct LMS backend API, @@ -43,7 +43,7 @@ on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. If you want to use SSL later, just use make run-ssl to run OpenEdx and Richie apps. Of course, you can still run apps without ssl by using make run.

    - - + + \ No newline at end of file diff --git a/docs/2.6.0/native-installation/index.html b/docs/2.6.0/native-installation/index.html index 133ab4415b..4d348324ab 100644 --- a/docs/2.6.0/native-installation/index.html +++ b/docs/2.6.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.6.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.6.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.7.0/accessibility-testing/index.html b/docs/2.7.0/accessibility-testing/index.html index 161b99eca1..46aaa7bb38 100644 --- a/docs/2.7.0/accessibility-testing/index.html +++ b/docs/2.7.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.7.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.7.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.7.0/building-the-frontend/index.html b/docs/2.7.0/building-the-frontend/index.html index 47b351d647..5aae5ff7af 100644 --- a/docs/2.7.0/building-the-frontend/index.html +++ b/docs/2.7.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.7.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.7.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.7.0/contributing-guide/index.html b/docs/2.7.0/contributing-guide/index.html index ebf9bee819..bb385ac0a0 100644 --- a/docs/2.7.0/contributing-guide/index.html +++ b/docs/2.7.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.7.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.7.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.7.0/css-guidelines/index.html b/docs/2.7.0/css-guidelines/index.html index 5c63357817..f0601f57bf 100644 --- a/docs/2.7.0/css-guidelines/index.html +++ b/docs/2.7.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.7.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.7.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.7.0/discover/index.html b/docs/2.7.0/discover/index.html index 340ace79c8..91aff505ea 100644 --- a/docs/2.7.0/discover/index.html +++ b/docs/2.7.0/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.7.0

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.7.0

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -27,7 +27,7 @@ to bootstrap an instance.

    Just start apps with make run.

    Richie should respond on http://localhost:8070 and OpenEdx on http://localhost:8073.

    Advanced - Connecting Richie to OpenEdx

    If you want users to enroll on courses in OpenEdx directly from Richie via API calls, you should read the advanced guide to connect Richie to OpenEdx over TLS.

    - - + + \ No newline at end of file diff --git a/docs/2.7.0/django-react-interop/index.html b/docs/2.7.0/django-react-interop/index.html index f1e258d6db..63f8d55f46 100644 --- a/docs/2.7.0/django-react-interop/index.html +++ b/docs/2.7.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.7.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.7.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.7.0/docker-development/index.html b/docs/2.7.0/docker-development/index.html index ae256b519e..e7ef2d2007 100644 --- a/docs/2.7.0/docker-development/index.html +++ b/docs/2.7.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.7.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.7.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.7.0/frontend-overrides/index.html b/docs/2.7.0/frontend-overrides/index.html index 4ccf5ec699..4e5871fb94 100644 --- a/docs/2.7.0/frontend-overrides/index.html +++ b/docs/2.7.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.7.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.7.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.7.0/internationalization/index.html b/docs/2.7.0/internationalization/index.html index 705afc99b3..b97238e5b5 100644 --- a/docs/2.7.0/internationalization/index.html +++ b/docs/2.7.0/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.7.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.7.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.7.0/lms-connection/index.html b/docs/2.7.0/lms-connection/index.html index 842fd0215c..cad1f864d7 100644 --- a/docs/2.7.0/lms-connection/index.html +++ b/docs/2.7.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with an LMS | Richie - - + +
    -
    Version: 2.7.0

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle +

    Version: 2.7.0

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle or Canvas for a seamless experience between browsing the course catalog on richie and following the course itself on the LMS.

    In order to connect richie with a LMS, there is an API bridge to synchronize course information and enrollments.

    API bridge

    The APIHandler utility acts as a proxy that routes queries to the correct LMS backend API, @@ -43,7 +43,7 @@ on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. If you want to use SSL later, just use make run-ssl to run OpenEdx and Richie apps. Of course, you can still run apps without ssl by using make run.

    - - + + \ No newline at end of file diff --git a/docs/2.7.0/native-installation/index.html b/docs/2.7.0/native-installation/index.html index 5ecfe03c16..07d86678d2 100644 --- a/docs/2.7.0/native-installation/index.html +++ b/docs/2.7.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.7.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.7.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.7.1/accessibility-testing/index.html b/docs/2.7.1/accessibility-testing/index.html index 7359f9f915..97e65936fe 100644 --- a/docs/2.7.1/accessibility-testing/index.html +++ b/docs/2.7.1/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.7.1

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.7.1

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.7.1/building-the-frontend/index.html b/docs/2.7.1/building-the-frontend/index.html index dd3d5213f4..8fda489c29 100644 --- a/docs/2.7.1/building-the-frontend/index.html +++ b/docs/2.7.1/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.7.1

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.7.1

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.7.1/contributing-guide/index.html b/docs/2.7.1/contributing-guide/index.html index 177576f321..f4d6328f5f 100644 --- a/docs/2.7.1/contributing-guide/index.html +++ b/docs/2.7.1/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.7.1

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.7.1

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.7.1/css-guidelines/index.html b/docs/2.7.1/css-guidelines/index.html index 606b74d4d7..1d21afcbdd 100644 --- a/docs/2.7.1/css-guidelines/index.html +++ b/docs/2.7.1/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.7.1

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.7.1

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.7.1/discover/index.html b/docs/2.7.1/discover/index.html index 2fde23729a..a49184094a 100644 --- a/docs/2.7.1/discover/index.html +++ b/docs/2.7.1/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.7.1

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.7.1

    Getting started with Richie

    If you're just looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -27,7 +27,7 @@ to bootstrap an instance.

    Just start apps with make run.

    Richie should respond on http://localhost:8070 and OpenEdx on http://localhost:8073.

    Advanced - Connecting Richie to OpenEdx

    If you want users to enroll on courses in OpenEdx directly from Richie via API calls, you should read the advanced guide to connect Richie to OpenEdx over TLS.

    - - + + \ No newline at end of file diff --git a/docs/2.7.1/django-react-interop/index.html b/docs/2.7.1/django-react-interop/index.html index 6827adb912..ffea36cf61 100644 --- a/docs/2.7.1/django-react-interop/index.html +++ b/docs/2.7.1/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.7.1

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.7.1

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.7.1/docker-development/index.html b/docs/2.7.1/docker-development/index.html index e0718222c4..b64f75702b 100644 --- a/docs/2.7.1/docker-development/index.html +++ b/docs/2.7.1/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.7.1

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.7.1

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.7.1/frontend-overrides/index.html b/docs/2.7.1/frontend-overrides/index.html index ac70d74165..363881d7d4 100644 --- a/docs/2.7.1/frontend-overrides/index.html +++ b/docs/2.7.1/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.7.1

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.7.1

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.7.1/internationalization/index.html b/docs/2.7.1/internationalization/index.html index d67703f6e1..528cbf13fa 100644 --- a/docs/2.7.1/internationalization/index.html +++ b/docs/2.7.1/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.7.1

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.7.1

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.7.1/lms-connection/index.html b/docs/2.7.1/lms-connection/index.html index c88f520a01..8b2385cc8e 100644 --- a/docs/2.7.1/lms-connection/index.html +++ b/docs/2.7.1/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with an LMS | Richie - - + +
    -
    Version: 2.7.1

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle +

    Version: 2.7.1

    Connecting Richie with an LMS

    richie can be connected to one or more Learning Management Systems (LMS) like OpenEdx, Moodle or Canvas for a seamless experience between browsing the course catalog on richie and following the course itself on the LMS.

    In order to connect richie with a LMS, there is an API bridge to synchronize course information and enrollments.

    API bridge

    The APIHandler utility acts as a proxy that routes queries to the correct LMS backend API, @@ -43,7 +43,7 @@ on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. If you want to use SSL later, just use make run-ssl to run OpenEdx and Richie apps. Of course, you can still run apps without ssl by using make run.

    - - + + \ No newline at end of file diff --git a/docs/2.7.1/native-installation/index.html b/docs/2.7.1/native-installation/index.html index 1a5788503d..637511d4ec 100644 --- a/docs/2.7.1/native-installation/index.html +++ b/docs/2.7.1/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.7.1

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.7.1

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.8.0/accessibility-testing/index.html b/docs/2.8.0/accessibility-testing/index.html index 351b5fc095..9bfc42e777 100644 --- a/docs/2.8.0/accessibility-testing/index.html +++ b/docs/2.8.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.8.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.8.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.8.0/api/course-run-synchronization-api/index.html b/docs/2.8.0/api/course-run-synchronization-api/index.html index 0419309cba..6a018b0e2b 100644 --- a/docs/2.8.0/api/course-run-synchronization-api/index.html +++ b/docs/2.8.0/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
    -
    Version: 2.8.0

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: 2.8.0

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
    • Body

        {
      "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
      "start": "2021-02-01T00:00:00Z",
      "end": "2021-02-31T23:59:59Z",
      "enrollment_start": "2021-01-01T00:00:00Z",
      "enrollment_end": "2021-01-31T23:59:59Z",
      "languages": ["en", "fr"]
      }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/2.8.0/building-the-frontend/index.html b/docs/2.8.0/building-the-frontend/index.html index 63cec69008..b24e797ac0 100644 --- a/docs/2.8.0/building-the-frontend/index.html +++ b/docs/2.8.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.8.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.8.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.8.0/contributing-guide/index.html b/docs/2.8.0/contributing-guide/index.html index 14c50c22d5..7dbfbd89ec 100644 --- a/docs/2.8.0/contributing-guide/index.html +++ b/docs/2.8.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.8.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.8.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.8.0/css-guidelines/index.html b/docs/2.8.0/css-guidelines/index.html index 99c6eb1395..c403f782b3 100644 --- a/docs/2.8.0/css-guidelines/index.html +++ b/docs/2.8.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.8.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.8.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.8.0/discover/index.html b/docs/2.8.0/discover/index.html index 53d719a53e..f9c369ec5a 100644 --- a/docs/2.8.0/discover/index.html +++ b/docs/2.8.0/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.8.0

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.8.0

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -24,7 +24,7 @@ a course on the LMS, and the LMS points back to the catalogue to browse courses.

    This approach is used for example on https://www.fun-campus.fr or https://catalogue.edulib.org.

    For a seamless user experience, it is possible to connect a Richie instance to an OpenEdX instance (or some other LMS like Moodle at the cost of minor adaptations), in several ways that we explain in the LMS connection guide.

    - - + + \ No newline at end of file diff --git a/docs/2.8.0/displaying-connection-status/index.html b/docs/2.8.0/displaying-connection-status/index.html index 8980f16554..80a9b7d692 100644 --- a/docs/2.8.0/displaying-connection-status/index.html +++ b/docs/2.8.0/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: 2.8.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.8.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/2.8.0/django-react-interop/index.html b/docs/2.8.0/django-react-interop/index.html index 6cc3d207a4..bf4ba0e069 100644 --- a/docs/2.8.0/django-react-interop/index.html +++ b/docs/2.8.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.8.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.8.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.8.0/docker-development/index.html b/docs/2.8.0/docker-development/index.html index 3bdb0ff8ae..d52ab327f8 100644 --- a/docs/2.8.0/docker-development/index.html +++ b/docs/2.8.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.8.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.8.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.8.0/frontend-overrides/index.html b/docs/2.8.0/frontend-overrides/index.html index 593fbc019a..5de8ca8368 100644 --- a/docs/2.8.0/frontend-overrides/index.html +++ b/docs/2.8.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.8.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.8.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.8.0/internationalization/index.html b/docs/2.8.0/internationalization/index.html index a62cd57434..94d5831985 100644 --- a/docs/2.8.0/internationalization/index.html +++ b/docs/2.8.0/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.8.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.8.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.8.0/lms-backends/index.html b/docs/2.8.0/lms-backends/index.html index b9cf000013..d448894fa9 100644 --- a/docs/2.8.0/lms-backends/index.html +++ b/docs/2.8.0/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: 2.8.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.8.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/2.8.0/lms-connection/index.html b/docs/2.8.0/lms-connection/index.html index 1ebfd1ccbf..c9730803f5 100644 --- a/docs/2.8.0/lms-connection/index.html +++ b/docs/2.8.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: 2.8.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.8.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/2.8.0/native-installation/index.html b/docs/2.8.0/native-installation/index.html index c4e24c3c75..8f188ebd49 100644 --- a/docs/2.8.0/native-installation/index.html +++ b/docs/2.8.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.8.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.8.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.8.0/synchronizing-course-runs/index.html b/docs/2.8.0/synchronizing-course-runs/index.html index b7efe2fd55..fd27f21ed8 100644 --- a/docs/2.8.0/synchronizing-course-runs/index.html +++ b/docs/2.8.0/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: 2.8.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.8.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -28,7 +28,7 @@ should run on the post_publish signal emitted by the OpenEdX cms application each time a course run is modified and published.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/2.8.0/tls-connection/index.html b/docs/2.8.0/tls-connection/index.html index 4f0053bbc9..be63965a8f 100644 --- a/docs/2.8.0/tls-connection/index.html +++ b/docs/2.8.0/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: 2.8.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.8.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/2.8.0/web-analytics/index.html b/docs/2.8.0/web-analytics/index.html index 92cbe30024..bf29e22987 100644 --- a/docs/2.8.0/web-analytics/index.html +++ b/docs/2.8.0/web-analytics/index.html @@ -4,16 +4,16 @@ Add web analytics to your site | Richie - - + +
    -
    Version: 2.8.0

    Add web analytics to your site

    The purpose of this file is to document how you can enable a Web Analytics solution. +

    Version: 2.8.0

    Add web analytics to your site

    The purpose of this file is to document how you can enable a Web Analytics solution. Currently Richie only supports by default the Google Analytics using the Google Tag Manager Javascript. But it is possible with little cost to add support for other web analytics solutions.

    Google Analytics

    Next, it is decribed how you can configure the Google Analytics on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Analytics tracking id code.

    The current Google Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Location of the web analytics javascript

    Use the WEB_ANALYTICS_LOCATION settings to decide where do you want to put the Javascript code. Use head (default value), to put the Javascript on HTML header, or footer, to put the Javascript code to the bottom of the body.

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS_ID setting with your tracking identification
    • define the WEB_ANALYTICS_PROVIDER setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • optionally change WEB_ANALYTICS_LOCATION setting with head (default) or footer value
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% block web_analytics %}
    {% if WEB_ANALYTICS_ID %}
    {% if WEB_ANALYTICS_PROVIDER == "my_custom_web_analytics_software" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endif %}
    {% endblock web_analytics %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>
    - - + + \ No newline at end of file diff --git a/docs/2.8.1/accessibility-testing/index.html b/docs/2.8.1/accessibility-testing/index.html index c456cc88c9..d6680e4ccf 100644 --- a/docs/2.8.1/accessibility-testing/index.html +++ b/docs/2.8.1/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.8.1

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.8.1

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.8.1/api/course-run-synchronization-api/index.html b/docs/2.8.1/api/course-run-synchronization-api/index.html index 1c0e3a76e6..35dfc95be5 100644 --- a/docs/2.8.1/api/course-run-synchronization-api/index.html +++ b/docs/2.8.1/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
    -
    Version: 2.8.1

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: 2.8.1

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
    • Body

        {
      "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
      "start": "2021-02-01T00:00:00Z",
      "end": "2021-02-31T23:59:59Z",
      "enrollment_start": "2021-01-01T00:00:00Z",
      "enrollment_end": "2021-01-31T23:59:59Z",
      "languages": ["en", "fr"]
      }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/2.8.1/building-the-frontend/index.html b/docs/2.8.1/building-the-frontend/index.html index 38ebeefc0a..06e6cd6d78 100644 --- a/docs/2.8.1/building-the-frontend/index.html +++ b/docs/2.8.1/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.8.1

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.8.1

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.8.1/contributing-guide/index.html b/docs/2.8.1/contributing-guide/index.html index d977a6ccf8..02caffd072 100644 --- a/docs/2.8.1/contributing-guide/index.html +++ b/docs/2.8.1/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.8.1

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.8.1

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.8.1/css-guidelines/index.html b/docs/2.8.1/css-guidelines/index.html index 6677e4ad9c..c5ccc76387 100644 --- a/docs/2.8.1/css-guidelines/index.html +++ b/docs/2.8.1/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.8.1

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.8.1

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.8.1/discover/index.html b/docs/2.8.1/discover/index.html index e1295cf3f4..561150d680 100644 --- a/docs/2.8.1/discover/index.html +++ b/docs/2.8.1/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.8.1

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.8.1

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -24,7 +24,7 @@ a course on the LMS, and the LMS points back to the catalogue to browse courses.

    This approach is used for example on https://www.fun-campus.fr or https://catalogue.edulib.org.

    For a seamless user experience, it is possible to connect a Richie instance to an OpenEdX instance (or some other LMS like Moodle at the cost of minor adaptations), in several ways that we explain in the LMS connection guide.

    - - + + \ No newline at end of file diff --git a/docs/2.8.1/displaying-connection-status/index.html b/docs/2.8.1/displaying-connection-status/index.html index b2bd96bb8d..bb653bcfd2 100644 --- a/docs/2.8.1/displaying-connection-status/index.html +++ b/docs/2.8.1/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: 2.8.1

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.8.1

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/2.8.1/django-react-interop/index.html b/docs/2.8.1/django-react-interop/index.html index 320aa149be..dd8fbff623 100644 --- a/docs/2.8.1/django-react-interop/index.html +++ b/docs/2.8.1/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.8.1

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.8.1

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.8.1/docker-development/index.html b/docs/2.8.1/docker-development/index.html index 0863afe42f..be7f24f08e 100644 --- a/docs/2.8.1/docker-development/index.html +++ b/docs/2.8.1/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.8.1

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.8.1

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.8.1/frontend-overrides/index.html b/docs/2.8.1/frontend-overrides/index.html index 3982d6fb18..5f5028b805 100644 --- a/docs/2.8.1/frontend-overrides/index.html +++ b/docs/2.8.1/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.8.1

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.8.1

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.8.1/internationalization/index.html b/docs/2.8.1/internationalization/index.html index 94f4d6f117..4526872509 100644 --- a/docs/2.8.1/internationalization/index.html +++ b/docs/2.8.1/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.8.1

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.8.1

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.8.1/lms-backends/index.html b/docs/2.8.1/lms-backends/index.html index 5c013007b2..f5999d35a6 100644 --- a/docs/2.8.1/lms-backends/index.html +++ b/docs/2.8.1/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: 2.8.1

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.8.1

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/2.8.1/lms-connection/index.html b/docs/2.8.1/lms-connection/index.html index 0207b487da..c43a44777c 100644 --- a/docs/2.8.1/lms-connection/index.html +++ b/docs/2.8.1/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: 2.8.1

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.8.1

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/2.8.1/native-installation/index.html b/docs/2.8.1/native-installation/index.html index 28c0b6d3f7..351e7985ab 100644 --- a/docs/2.8.1/native-installation/index.html +++ b/docs/2.8.1/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.8.1

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.8.1

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.8.1/synchronizing-course-runs/index.html b/docs/2.8.1/synchronizing-course-runs/index.html index 12dadee069..aa19bac5f6 100644 --- a/docs/2.8.1/synchronizing-course-runs/index.html +++ b/docs/2.8.1/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: 2.8.1

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.8.1

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -28,7 +28,7 @@ should run on the post_publish signal emitted by the OpenEdX cms application each time a course run is modified and published.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/2.8.1/tls-connection/index.html b/docs/2.8.1/tls-connection/index.html index 0e3087f6d5..7626d54519 100644 --- a/docs/2.8.1/tls-connection/index.html +++ b/docs/2.8.1/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: 2.8.1

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.8.1

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/2.8.1/web-analytics/index.html b/docs/2.8.1/web-analytics/index.html index c3d8c885f1..4758ffbebd 100644 --- a/docs/2.8.1/web-analytics/index.html +++ b/docs/2.8.1/web-analytics/index.html @@ -4,16 +4,16 @@ Add web analytics to your site | Richie - - + +
    -
    Version: 2.8.1

    Add web analytics to your site

    The purpose of this file is to document how you can enable a Web Analytics solution. +

    Version: 2.8.1

    Add web analytics to your site

    The purpose of this file is to document how you can enable a Web Analytics solution. Currently Richie only supports by default the Google Analytics using the Google Tag Manager Javascript. But it is possible with little cost to add support for other web analytics solutions.

    Google Analytics

    Next, it is decribed how you can configure the Google Analytics on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Analytics tracking id code.

    The current Google Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Location of the web analytics javascript

    Use the WEB_ANALYTICS_LOCATION settings to decide where do you want to put the Javascript code. Use head (default value), to put the Javascript on HTML header, or footer, to put the Javascript code to the bottom of the body.

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS_ID setting with your tracking identification
    • define the WEB_ANALYTICS_PROVIDER setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • optionally change WEB_ANALYTICS_LOCATION setting with head (default) or footer value
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% block web_analytics %}
    {% if WEB_ANALYTICS_ID %}
    {% if WEB_ANALYTICS_PROVIDER == "my_custom_web_analytics_software" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endif %}
    {% endblock web_analytics %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>
    - - + + \ No newline at end of file diff --git a/docs/2.8.2/accessibility-testing/index.html b/docs/2.8.2/accessibility-testing/index.html index b5b6c23d58..b9ab80d8af 100644 --- a/docs/2.8.2/accessibility-testing/index.html +++ b/docs/2.8.2/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.8.2

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.8.2

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.8.2/api/course-run-synchronization-api/index.html b/docs/2.8.2/api/course-run-synchronization-api/index.html index eba5b9bd9b..05f5e7b595 100644 --- a/docs/2.8.2/api/course-run-synchronization-api/index.html +++ b/docs/2.8.2/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
    -
    Version: 2.8.2

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: 2.8.2

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
    • Body

        {
      "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
      "start": "2021-02-01T00:00:00Z",
      "end": "2021-02-31T23:59:59Z",
      "enrollment_start": "2021-01-01T00:00:00Z",
      "enrollment_end": "2021-01-31T23:59:59Z",
      "languages": ["en", "fr"]
      }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/2.8.2/building-the-frontend/index.html b/docs/2.8.2/building-the-frontend/index.html index 26c9d7605b..8f44441fb2 100644 --- a/docs/2.8.2/building-the-frontend/index.html +++ b/docs/2.8.2/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.8.2

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.8.2

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.8.2/contributing-guide/index.html b/docs/2.8.2/contributing-guide/index.html index 7394ea0513..e6ad9e27c5 100644 --- a/docs/2.8.2/contributing-guide/index.html +++ b/docs/2.8.2/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.8.2

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.8.2

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.8.2/css-guidelines/index.html b/docs/2.8.2/css-guidelines/index.html index 42d7a1c702..7e23a2fb0a 100644 --- a/docs/2.8.2/css-guidelines/index.html +++ b/docs/2.8.2/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.8.2

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.8.2

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.8.2/discover/index.html b/docs/2.8.2/discover/index.html index 4fe306f714..abde686101 100644 --- a/docs/2.8.2/discover/index.html +++ b/docs/2.8.2/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.8.2

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.8.2

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -24,7 +24,7 @@ a course on the LMS, and the LMS points back to the catalogue to browse courses.

    This approach is used for example on https://www.fun-campus.fr or https://catalogue.edulib.org.

    For a seamless user experience, it is possible to connect a Richie instance to an OpenEdX instance (or some other LMS like Moodle at the cost of minor adaptations), in several ways that we explain in the LMS connection guide.

    - - + + \ No newline at end of file diff --git a/docs/2.8.2/displaying-connection-status/index.html b/docs/2.8.2/displaying-connection-status/index.html index 33cd9bf1c1..44c6a07035 100644 --- a/docs/2.8.2/displaying-connection-status/index.html +++ b/docs/2.8.2/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: 2.8.2

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.8.2

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/2.8.2/django-react-interop/index.html b/docs/2.8.2/django-react-interop/index.html index bb7496ba69..3dd0fc197f 100644 --- a/docs/2.8.2/django-react-interop/index.html +++ b/docs/2.8.2/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.8.2

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.8.2

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.8.2/docker-development/index.html b/docs/2.8.2/docker-development/index.html index 0460ee9942..2789dc5a38 100644 --- a/docs/2.8.2/docker-development/index.html +++ b/docs/2.8.2/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.8.2

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.8.2

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.8.2/frontend-overrides/index.html b/docs/2.8.2/frontend-overrides/index.html index c6c59060bc..386b957fe1 100644 --- a/docs/2.8.2/frontend-overrides/index.html +++ b/docs/2.8.2/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.8.2

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.8.2

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.8.2/internationalization/index.html b/docs/2.8.2/internationalization/index.html index bc51d19d0e..aa3c3d12b1 100644 --- a/docs/2.8.2/internationalization/index.html +++ b/docs/2.8.2/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.8.2

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.8.2

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.8.2/lms-backends/index.html b/docs/2.8.2/lms-backends/index.html index f19e287e1c..a643e7bef5 100644 --- a/docs/2.8.2/lms-backends/index.html +++ b/docs/2.8.2/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: 2.8.2

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.8.2

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/2.8.2/lms-connection/index.html b/docs/2.8.2/lms-connection/index.html index e09a53c505..46e58ed2b2 100644 --- a/docs/2.8.2/lms-connection/index.html +++ b/docs/2.8.2/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: 2.8.2

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.8.2

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/2.8.2/native-installation/index.html b/docs/2.8.2/native-installation/index.html index b683ed17d3..4ef2de8d04 100644 --- a/docs/2.8.2/native-installation/index.html +++ b/docs/2.8.2/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.8.2

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.8.2

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.8.2/synchronizing-course-runs/index.html b/docs/2.8.2/synchronizing-course-runs/index.html index ad122c0230..14e8c4a3ef 100644 --- a/docs/2.8.2/synchronizing-course-runs/index.html +++ b/docs/2.8.2/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: 2.8.2

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.8.2

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -28,7 +28,7 @@ should run on the post_publish signal emitted by the OpenEdX cms application each time a course run is modified and published.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/2.8.2/tls-connection/index.html b/docs/2.8.2/tls-connection/index.html index 3ac09b5a3a..aff7ebc921 100644 --- a/docs/2.8.2/tls-connection/index.html +++ b/docs/2.8.2/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: 2.8.2

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.8.2

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/2.8.2/web-analytics/index.html b/docs/2.8.2/web-analytics/index.html index 888508fb05..e990c936e6 100644 --- a/docs/2.8.2/web-analytics/index.html +++ b/docs/2.8.2/web-analytics/index.html @@ -4,16 +4,16 @@ Add web analytics to your site | Richie - - + +
    -
    Version: 2.8.2

    Add web analytics to your site

    The purpose of this file is to document how you can enable a Web Analytics solution. +

    Version: 2.8.2

    Add web analytics to your site

    The purpose of this file is to document how you can enable a Web Analytics solution. Currently Richie only supports by default the Google Analytics using the Google Tag Manager Javascript. But it is possible with little cost to add support for other web analytics solutions.

    Google Analytics

    Next, it is decribed how you can configure the Google Analytics on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Analytics tracking id code.

    The current Google Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Location of the web analytics javascript

    Use the WEB_ANALYTICS_LOCATION settings to decide where do you want to put the Javascript code. Use head (default value), to put the Javascript on HTML header, or footer, to put the Javascript code to the bottom of the body.

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS_ID setting with your tracking identification
    • define the WEB_ANALYTICS_PROVIDER setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • optionally change WEB_ANALYTICS_LOCATION setting with head (default) or footer value
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% block web_analytics %}
    {% if WEB_ANALYTICS_ID %}
    {% if WEB_ANALYTICS_PROVIDER == "my_custom_web_analytics_software" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endif %}
    {% endblock web_analytics %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>
    - - + + \ No newline at end of file diff --git a/docs/2.9.0/accessibility-testing/index.html b/docs/2.9.0/accessibility-testing/index.html index 31fcc4edfb..831149d81c 100644 --- a/docs/2.9.0/accessibility-testing/index.html +++ b/docs/2.9.0/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.9.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.9.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.9.0/api/course-run-synchronization-api/index.html b/docs/2.9.0/api/course-run-synchronization-api/index.html index a839818ee3..beb9da9aed 100644 --- a/docs/2.9.0/api/course-run-synchronization-api/index.html +++ b/docs/2.9.0/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
    -
    Version: 2.9.0

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: 2.9.0

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
    • Body

        {
      "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
      "start": "2021-02-01T00:00:00Z",
      "end": "2021-02-31T23:59:59Z",
      "enrollment_start": "2021-01-01T00:00:00Z",
      "enrollment_end": "2021-01-31T23:59:59Z",
      "languages": ["en", "fr"]
      }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/2.9.0/building-the-frontend/index.html b/docs/2.9.0/building-the-frontend/index.html index 9a2b70d56e..d4e9198f98 100644 --- a/docs/2.9.0/building-the-frontend/index.html +++ b/docs/2.9.0/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.9.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.9.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.9.0/contributing-guide/index.html b/docs/2.9.0/contributing-guide/index.html index 34141cdf22..42929b9b65 100644 --- a/docs/2.9.0/contributing-guide/index.html +++ b/docs/2.9.0/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.9.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.9.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.9.0/css-guidelines/index.html b/docs/2.9.0/css-guidelines/index.html index 71f31572c6..3c1289f9d4 100644 --- a/docs/2.9.0/css-guidelines/index.html +++ b/docs/2.9.0/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.9.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.9.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.9.0/discover/index.html b/docs/2.9.0/discover/index.html index 060f051ef1..ba5610fe5d 100644 --- a/docs/2.9.0/discover/index.html +++ b/docs/2.9.0/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.9.0

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.9.0

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -24,7 +24,7 @@ a course on the LMS, and the LMS points back to the catalogue to browse courses.

    This approach is used for example on https://www.fun-campus.fr or https://catalogue.edulib.org.

    For a seamless user experience, it is possible to connect a Richie instance to an OpenEdX instance (or some other LMS like Moodle at the cost of minor adaptations), in several ways that we explain in the LMS connection guide.

    - - + + \ No newline at end of file diff --git a/docs/2.9.0/displaying-connection-status/index.html b/docs/2.9.0/displaying-connection-status/index.html index 59090b8b71..8d5cf358c3 100644 --- a/docs/2.9.0/displaying-connection-status/index.html +++ b/docs/2.9.0/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: 2.9.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.9.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/2.9.0/django-react-interop/index.html b/docs/2.9.0/django-react-interop/index.html index 1bd59bc507..8fa3315ce5 100644 --- a/docs/2.9.0/django-react-interop/index.html +++ b/docs/2.9.0/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.9.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.9.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.9.0/docker-development/index.html b/docs/2.9.0/docker-development/index.html index fd97d78dd8..fad80f38e1 100644 --- a/docs/2.9.0/docker-development/index.html +++ b/docs/2.9.0/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.9.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.9.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.9.0/frontend-overrides/index.html b/docs/2.9.0/frontend-overrides/index.html index 3e5b459346..165e18ad29 100644 --- a/docs/2.9.0/frontend-overrides/index.html +++ b/docs/2.9.0/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.9.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.9.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.9.0/internationalization/index.html b/docs/2.9.0/internationalization/index.html index f3fb03a969..f389b508f6 100644 --- a/docs/2.9.0/internationalization/index.html +++ b/docs/2.9.0/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.9.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.9.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.9.0/lms-backends/index.html b/docs/2.9.0/lms-backends/index.html index 4810273d9a..8317bbbf5b 100644 --- a/docs/2.9.0/lms-backends/index.html +++ b/docs/2.9.0/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: 2.9.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.9.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/2.9.0/lms-connection/index.html b/docs/2.9.0/lms-connection/index.html index 5c1d553ca9..c28a8e19bb 100644 --- a/docs/2.9.0/lms-connection/index.html +++ b/docs/2.9.0/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: 2.9.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.9.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/2.9.0/native-installation/index.html b/docs/2.9.0/native-installation/index.html index cb8282c756..adc7624c8a 100644 --- a/docs/2.9.0/native-installation/index.html +++ b/docs/2.9.0/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.9.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.9.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.9.0/synchronizing-course-runs/index.html b/docs/2.9.0/synchronizing-course-runs/index.html index d6bb8e2c64..db0b618327 100644 --- a/docs/2.9.0/synchronizing-course-runs/index.html +++ b/docs/2.9.0/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: 2.9.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.9.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -29,7 +29,7 @@ course run is modified and published.

    Or you can use the Richie Open edX Synchronization which is based on the following code sample and also includes the enrollment count.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/2.9.0/tls-connection/index.html b/docs/2.9.0/tls-connection/index.html index 819a7adbcf..68413628e0 100644 --- a/docs/2.9.0/tls-connection/index.html +++ b/docs/2.9.0/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: 2.9.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.9.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/2.9.0/web-analytics/index.html b/docs/2.9.0/web-analytics/index.html index a4d1e73ff4..9be106cb06 100644 --- a/docs/2.9.0/web-analytics/index.html +++ b/docs/2.9.0/web-analytics/index.html @@ -4,16 +4,16 @@ Add web analytics to your site | Richie - - + +
    -
    Version: 2.9.0

    Add web analytics to your site

    The purpose of this file is to document how you can enable a Web Analytics solution. +

    Version: 2.9.0

    Add web analytics to your site

    The purpose of this file is to document how you can enable a Web Analytics solution. Currently Richie only supports by default the Google Analytics using the Google Tag Manager Javascript. But it is possible with little cost to add support for other web analytics solutions.

    Google Analytics

    Next, it is decribed how you can configure the Google Analytics on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Analytics tracking id code.

    The current Google Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Location of the web analytics javascript

    Use the WEB_ANALYTICS_LOCATION settings to decide where do you want to put the Javascript code. Use head (default value), to put the Javascript on HTML header, or footer, to put the Javascript code to the bottom of the body.

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS_ID setting with your tracking identification
    • define the WEB_ANALYTICS_PROVIDER setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • optionally change WEB_ANALYTICS_LOCATION setting with head (default) or footer value
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% block web_analytics %}
    {% if WEB_ANALYTICS_ID %}
    {% if WEB_ANALYTICS_PROVIDER == "my_custom_web_analytics_software" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endif %}
    {% endblock web_analytics %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>
    - - + + \ No newline at end of file diff --git a/docs/2.9.1/accessibility-testing/index.html b/docs/2.9.1/accessibility-testing/index.html index 311ab5126d..8a0f9e8f3b 100644 --- a/docs/2.9.1/accessibility-testing/index.html +++ b/docs/2.9.1/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: 2.9.1

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.9.1

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems in any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two way to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/2.9.1/api/course-run-synchronization-api/index.html b/docs/2.9.1/api/course-run-synchronization-api/index.html index d5128c3edf..0653556a4e 100644 --- a/docs/2.9.1/api/course-run-synchronization-api/index.html +++ b/docs/2.9.1/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
    -
    Version: 2.9.1

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: 2.9.1

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
    • Body

        {
      "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
      "start": "2021-02-01T00:00:00Z",
      "end": "2021-02-31T23:59:59Z",
      "enrollment_start": "2021-01-01T00:00:00Z",
      "enrollment_end": "2021-01-31T23:59:59Z",
      "languages": ["en", "fr"]
      }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/2.9.1/building-the-frontend/index.html b/docs/2.9.1/building-the-frontend/index.html index abe2016605..988094723e 100644 --- a/docs/2.9.1/building-the-frontend/index.html +++ b/docs/2.9.1/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: 2.9.1

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.9.1

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/2.9.1/contributing-guide/index.html b/docs/2.9.1/contributing-guide/index.html index 48eb29fd30..8fa0e6cd27 100644 --- a/docs/2.9.1/contributing-guide/index.html +++ b/docs/2.9.1/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: 2.9.1

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.9.1

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/2.9.1/css-guidelines/index.html b/docs/2.9.1/css-guidelines/index.html index ac85b57c74..7ff316bfec 100644 --- a/docs/2.9.1/css-guidelines/index.html +++ b/docs/2.9.1/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: 2.9.1

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.9.1

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/2.9.1/discover/index.html b/docs/2.9.1/discover/index.html index 9b8b818c3e..e6929e9238 100644 --- a/docs/2.9.1/discover/index.html +++ b/docs/2.9.1/discover/index.html @@ -4,12 +4,12 @@ Getting started with Richie | Richie - - + +
    -
    Version: 2.9.1

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed +

    Version: 2.9.1

    Getting started with Richie

    If you're looking for a quick preview of Richie, you can take a look and have a tour of Richie on our dedicated demo site.

    Login/password are admin/admin. The database is regularly flushed.

    Architecture

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of 4 services:

    • db: the Postgresql database,
    • elasticsearch: the search engine,
    • app: the actual DjangoCMS project with all our application code,
    • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the CSS files from Sass sources.

    At "France Université Numérique", we deploy our applications on OpenShift/Kubernetes using @@ -24,7 +24,7 @@ a course on the LMS, and the LMS points back to the catalogue to browse courses.

    This approach is used for example on https://www.fun-campus.fr or https://catalogue.edulib.org.

    For a seamless user experience, it is possible to connect a Richie instance to an OpenEdX instance (or some other LMS like Moodle at the cost of minor adaptations), in several ways that we explain in the LMS connection guide.

    - - + + \ No newline at end of file diff --git a/docs/2.9.1/displaying-connection-status/index.html b/docs/2.9.1/displaying-connection-status/index.html index c6fac57c26..c0bbb67f44 100644 --- a/docs/2.9.1/displaying-connection-status/index.html +++ b/docs/2.9.1/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: 2.9.1

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.9.1

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/2.9.1/django-react-interop/index.html b/docs/2.9.1/django-react-interop/index.html index 192382b115..fbe48b0772 100644 --- a/docs/2.9.1/django-react-interop/index.html +++ b/docs/2.9.1/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: 2.9.1

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.9.1

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/2.9.1/docker-development/index.html b/docs/2.9.1/docker-development/index.html index 60bc345702..d6098eb790 100644 --- a/docs/2.9.1/docker-development/index.html +++ b/docs/2.9.1/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: 2.9.1

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.9.1

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/2.9.1/frontend-overrides/index.html b/docs/2.9.1/frontend-overrides/index.html index 4b9d9edb96..1a93af24f0 100644 --- a/docs/2.9.1/frontend-overrides/index.html +++ b/docs/2.9.1/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: 2.9.1

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.9.1

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/2.9.1/internationalization/index.html b/docs/2.9.1/internationalization/index.html index 85b72db4b6..9740ee5987 100644 --- a/docs/2.9.1/internationalization/index.html +++ b/docs/2.9.1/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: 2.9.1

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.9.1

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/2.9.1/lms-backends/index.html b/docs/2.9.1/lms-backends/index.html index 968a9bc6a2..9c3816c583 100644 --- a/docs/2.9.1/lms-backends/index.html +++ b/docs/2.9.1/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: 2.9.1

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.9.1

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/2.9.1/lms-connection/index.html b/docs/2.9.1/lms-connection/index.html index d77ba523e9..7952765e75 100644 --- a/docs/2.9.1/lms-connection/index.html +++ b/docs/2.9.1/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: 2.9.1

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.9.1

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/2.9.1/native-installation/index.html b/docs/2.9.1/native-installation/index.html index fe04757c5a..98546382cb 100644 --- a/docs/2.9.1/native-installation/index.html +++ b/docs/2.9.1/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: 2.9.1

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.9.1

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/2.9.1/synchronizing-course-runs/index.html b/docs/2.9.1/synchronizing-course-runs/index.html index 3cdba41551..28be56b787 100644 --- a/docs/2.9.1/synchronizing-course-runs/index.html +++ b/docs/2.9.1/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: 2.9.1

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.9.1

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -29,7 +29,7 @@ course run is modified and published.

    Or you can use the Richie Open edX Synchronization which is based on the following code sample and also includes the enrollment count.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/2.9.1/tls-connection/index.html b/docs/2.9.1/tls-connection/index.html index dea08edd32..fc92d09600 100644 --- a/docs/2.9.1/tls-connection/index.html +++ b/docs/2.9.1/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: 2.9.1

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.9.1

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/2.9.1/web-analytics/index.html b/docs/2.9.1/web-analytics/index.html index 25b6a66ea5..c2597e36d4 100644 --- a/docs/2.9.1/web-analytics/index.html +++ b/docs/2.9.1/web-analytics/index.html @@ -4,16 +4,16 @@ Add web analytics to your site | Richie - - + +
    -
    Version: 2.9.1

    Add web analytics to your site

    The purpose of this file is to document how you can enable a Web Analytics solution. +

    Version: 2.9.1

    Add web analytics to your site

    The purpose of this file is to document how you can enable a Web Analytics solution. Currently Richie only supports by default the Google Analytics using the Google Tag Manager Javascript. But it is possible with little cost to add support for other web analytics solutions.

    Google Analytics

    Next, it is decribed how you can configure the Google Analytics on your Richie site.

    • Add the WEB_ANALYTICS_ID setting, with your Google Analytics tracking id code.

    The current Google Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Location of the web analytics javascript

    Use the WEB_ANALYTICS_LOCATION settings to decide where do you want to put the Javascript code. Use head (default value), to put the Javascript on HTML header, or footer, to put the Javascript code to the bottom of the body.

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS_ID setting with your tracking identification
    • define the WEB_ANALYTICS_PROVIDER setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • optionally change WEB_ANALYTICS_LOCATION setting with head (default) or footer value
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% block web_analytics %}
    {% if WEB_ANALYTICS_ID %}
    {% if WEB_ANALYTICS_PROVIDER == "my_custom_web_analytics_software" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endif %}
    {% endblock web_analytics %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>
    - - + + \ No newline at end of file diff --git a/docs/accessibility-testing/index.html b/docs/accessibility-testing/index.html index 13fb0caeae..3f2073ff7c 100644 --- a/docs/accessibility-testing/index.html +++ b/docs/accessibility-testing/index.html @@ -1,16 +1,16 @@ - + -Automated accessibility checks | Richie - - +Automated accessibility checks | Richie + +
    -
    Version: 2.21.0

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems on any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two ways to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: 2.21.1

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems on any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two ways to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/api/course-run-synchronization-api/index.html b/docs/api/course-run-synchronization-api/index.html index 2e713ea8e4..8f873b8d55 100644 --- a/docs/api/course-run-synchronization-api/index.html +++ b/docs/api/course-run-synchronization-api/index.html @@ -1,15 +1,15 @@ - + -Course run synchronization API | Richie - - +Course run synchronization API | Richie + +
    -
    Version: 2.21.0

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: 2.21.1

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -18,8 +18,8 @@ languages
      • Request (application/json)

        • Headers

          • Authorization: SIG-HMAC-SHA256 xxxxxxx (string, required) - Authorization header containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] -for an example).
        • Body

            {
          "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
          "start": "2021-02-01T00:00:00Z",
          "end": "2021-02-31T23:59:59Z",
          "enrollment_start": "2021-01-01T00:00:00Z",
          "enrollment_end": "2021-01-31T23:59:59Z",
          "languages": ["en", "fr"]
          }
      • Response 200 (application/json)

        • Body

            {
          "success": True
          }
    - - +for an example).
  • Body

      {
    "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
    "start": "2021-02-01T00:00:00Z",
    "end": "2021-02-31T23:59:59Z",
    "enrollment_start": "2021-01-01T00:00:00Z",
    "enrollment_end": "2021-01-31T23:59:59Z",
    "languages": ["en", "fr"]
    }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • + + \ No newline at end of file diff --git a/docs/building-the-frontend/index.html b/docs/building-the-frontend/index.html index 6bf5ea9c56..368f0c0ddb 100644 --- a/docs/building-the-frontend/index.html +++ b/docs/building-the-frontend/index.html @@ -1,16 +1,16 @@ - + -Building Richie's frontend in your own project | Richie - - +Building Richie's frontend in your own project | Richie + +
    -
    Version: 2.21.0

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: 2.21.1

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/contributing-guide/index.html b/docs/contributing-guide/index.html index 60724b6312..bafdac5fb4 100644 --- a/docs/contributing-guide/index.html +++ b/docs/contributing-guide/index.html @@ -1,22 +1,22 @@ - + -Contributing guide | Richie - - +Contributing guide | Richie + +
    -
    Version: 2.21.0

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: 2.21.1

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker -documentation

    - - +documentation

    + + \ No newline at end of file diff --git a/docs/cookiecutter/index.html b/docs/cookiecutter/index.html index a1098c57ee..1250052ca6 100644 --- a/docs/cookiecutter/index.html +++ b/docs/cookiecutter/index.html @@ -1,20 +1,20 @@ - + -Start your own site | Richie - - +Start your own site | Richie + +
    -
    Version: 2.21.0

    Start your own site

    We use Cookiecutter to help you +

    Version: 2.21.1

    Start your own site

    We use Cookiecutter to help you set up a production-ready learning portal website based on Richie in seconds.

    Run Cookiecutter

    There are 2 options to run Cookiecutter:

    While you think of it, navigate to the directory in which you want to create your site factory:

    cd /path/to/your/code/directory

    If you chose to install Cookiecutter, you can now run it against our -template as follows:

    cookiecutter gh:openfun/richie --directory cookiecutter  --checkout v2.21.0

    If you didn't want to install it on your machine, we provide a Docker image -built with our own repository that you can use as follows:

    docker run --rm -it -u $(id -u):$(id -g) -v $PWD:/app \
    fundocker/cookiecutter gh:openfun/richie --directory cookiecutter --checkout v2.21.0

    The --directory option is to indicate that our Cookiecutter template is in +template as follows:

    cookiecutter gh:openfun/richie --directory cookiecutter  --checkout v2.21.1

    If you didn't want to install it on your machine, we provide a Docker image +built with our own repository that you can use as follows:

    docker run --rm -it -u $(id -u):$(id -g) -v $PWD:/app \
    fundocker/cookiecutter gh:openfun/richie --directory cookiecutter --checkout v2.21.1

    The --directory option is to indicate that our Cookiecutter template is in a cookiecutter directory inside our git repository and not at the root.

    You will be prompted to enter an organization name, which will determine the name of your repository. For example, if you choose "foo" as organization name, your repository will be named foo-richie-site-factory. It's @@ -29,8 +29,8 @@ factory by replaying Cookiecutter. This will override your files in the project's scaffolding but, don't worry, it will respect all the sites you will have created in the sites directory:

    cookiecutter --overwrite-if-exists gh:openfun/richie --directory=cookiecutter

    Help us improve this project

    After starting your project, please submit an issue let us know how it went and -what other features we should add to make it better.

    - - +what other features we should add to make it better.

    + + \ No newline at end of file diff --git a/docs/css-guidelines/index.html b/docs/css-guidelines/index.html index 9ac36c066d..816b9b66fd 100644 --- a/docs/css-guidelines/index.html +++ b/docs/css-guidelines/index.html @@ -1,16 +1,16 @@ - + -CSS Guidelines | Richie - - +CSS Guidelines | Richie + +
    -
    Version: 2.21.0

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: 2.21.1

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/discover/index.html b/docs/discover/index.html index e129b514f5..507c58f1e1 100644 --- a/docs/discover/index.html +++ b/docs/discover/index.html @@ -1,15 +1,15 @@ - + -Discover Richie | Richie - - +Discover Richie | Richie + +
    -
    Version: 2.21.0

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online +

    Version: 2.21.1

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online courses and MOOCs.

    However, if you need to build a complete website with flexible content to aggregate your courses, in several languages and from different sources, you will soon need a CMS.

    At "France Université Numérique", we wanted to build an OpenSource portal with Python and Django. That's why we built Richie on top of DjangoCMS, one of @@ -20,8 +20,8 @@ Richie on our dedicated demo site.

    It is connected back-to-back with a demo of OpenEdX running on OpenEdX Docker.

    Two users are available for testing:

    • admin: admin@example.com/admin
    • student: edx@example.com/edx

    The database is regularly flushed.

    Start your own site

    The next step after discovering Richie on the demo is to start your own project. We provide a production-ready template based on Cookiecutter that -allows you to generate your project in seconds.

    Follow the guide on starting your own Richie site with Cookiecutter.

    Once you created a new site, you will be able to fully customize it:

    - - +allows you to generate your project in seconds.

    Follow the guide on starting your own Richie site with Cookiecutter.

    Once you created a new site, you will be able to fully customize it:

    + + \ No newline at end of file diff --git a/docs/displaying-connection-status/index.html b/docs/displaying-connection-status/index.html index c2448e43ba..89452277f9 100644 --- a/docs/displaying-connection-status/index.html +++ b/docs/displaying-connection-status/index.html @@ -1,15 +1,15 @@ - + -Displaying OpenEdX connection status in Richie | Richie - - +Displaying OpenEdX connection status in Richie | Richie + +
    -
    Version: 2.21.0

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: 2.21.1

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -25,8 +25,8 @@ as follows:

        {
    "dashboard": {
    "label": _("Dashboard"),
    "href": "{base_url:s}/dashboard",
    },
    "profile": {
    "label": _("Profile"),
    "href": "{base_url:s}/u/(username)",
    },
    "account": {
    "label": _("Account"),
    "href": "{base_url:s}/account/settings",
    }
    }

    The base_url variable is used as a Python format parameter and will be replaced by the value set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to -https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - +https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    + + \ No newline at end of file diff --git a/docs/django-react-interop/index.html b/docs/django-react-interop/index.html index 789730e4c5..54a323a3d1 100644 --- a/docs/django-react-interop/index.html +++ b/docs/django-react-interop/index.html @@ -1,16 +1,16 @@ - + -Connecting React components with Django | Richie - - +Connecting React components with Django | Richie + +
    -
    Version: 2.21.0

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: 2.21.1

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/docker-development/index.html b/docs/docker-development/index.html index 7955578521..07c4a4ec09 100644 --- a/docs/docker-development/index.html +++ b/docs/docker-development/index.html @@ -1,15 +1,15 @@ - + -Developing Richie with Docker | Richie - - +Developing Richie with Docker | Richie + +
    -
    Version: 2.21.0

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: 2.21.1

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -28,8 +28,8 @@ file

    Cleanup

    If you work on the Docker configuration and make repeated modifications, remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the -/etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - +/etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    + + \ No newline at end of file diff --git a/docs/filters-customization/index.html b/docs/filters-customization/index.html index 65d8b11621..08dda5307f 100644 --- a/docs/filters-customization/index.html +++ b/docs/filters-customization/index.html @@ -1,15 +1,15 @@ - + -Customizing search filters | Richie - - +Customizing search filters | Richie + +
    -
    Version: 2.21.0

    Customizing search filters

    You may want to customize the filters on the left side bar of the search page.

    Richie makes it easy to choose which filters you want to display among the existing filters +

    Version: 2.21.1

    Customizing search filters

    You may want to customize the filters on the left side bar of the search page.

    Richie makes it easy to choose which filters you want to display among the existing filters and in which order. You can also configure the existing filters to change their title or the way they behave. Lastly, you can completely override a filter or create your own custom filter from scratch.

    Filters configuration

    Filters must first be defined in the FILTERS_CONFIGURATION setting. It is a dictionary defining @@ -47,8 +47,8 @@ to the code of the existing filters as good examples of what is possible. The code, although not trivial, was given much care and includes many comments in an attempt to help writing new custom filters. Of course, don't hesitate to ask for help by -opening an issue!

    - - +opening an issue!

    + + \ No newline at end of file diff --git a/docs/frontend-overrides/index.html b/docs/frontend-overrides/index.html index 5ffeb1c06d..bf297faa28 100644 --- a/docs/frontend-overrides/index.html +++ b/docs/frontend-overrides/index.html @@ -1,16 +1,16 @@ - + -Overriding frontend components | Richie - - +Overriding frontend components | Richie + +
    -
    Version: 2.21.0

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: 2.21.1

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/installation/index.html b/docs/installation/index.html index 9728466cd2..127acf25ba 100644 --- a/docs/installation/index.html +++ b/docs/installation/index.html @@ -1,15 +1,15 @@ - + -Installing Richie for development | Richie - - +Installing Richie for development | Richie + +
    -
    Version: 2.21.0

    Installing Richie for development

    Richie is a container-native application but can also be installed +

    Version: 2.21.1

    Installing Richie for development

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of:

    • 3 running services:

      • database: postgresql or mysql at your preference,
      • elasticsearch: the search engine,
      • app: the actual DjangoCMS project with all our application code.
    • 2 containers for building purposes:

      • node: used for front-end related tasks, i.e. transpiling TypeScript sources, bundling them into a JS package, and building the @@ -34,8 +34,8 @@ to an OpenEdX instance (or some other LMS like Moodle at the cost of minor adaptations), in several ways that we explain in the LMS connection guide.

        This approach is used for example on https://www.fun-mooc.fr or -https://www.nau.edu.pt.

    - - +https://www.nau.edu.pt.

    + + \ No newline at end of file diff --git a/docs/internationalization/index.html b/docs/internationalization/index.html index 4d9ba2cde4..b65b18c811 100644 --- a/docs/internationalization/index.html +++ b/docs/internationalization/index.html @@ -1,15 +1,15 @@ - + -Internationalization | Richie - - +Internationalization | Richie + +
    -
    Version: 2.21.0

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: 2.21.1

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -21,8 +21,8 @@ up-to-date each time strings are modified or new strings are added, and this before each release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider -contributing on the existing language if your resources to contribute are limited.

    - - +contributing on the existing language if your resources to contribute are limited.

    + + \ No newline at end of file diff --git a/docs/joanie-connection/index.html b/docs/joanie-connection/index.html index 23a4eb689f..0b79db0b01 100644 --- a/docs/joanie-connection/index.html +++ b/docs/joanie-connection/index.html @@ -1,15 +1,15 @@ - + -Joanie Connection | Richie - - +Joanie Connection | Richie + +
    -
    Version: 2.21.0

    Joanie Connection

    Joanie delivers an API able to manage course +

    Version: 2.21.1

    Joanie Connection

    Joanie delivers an API able to manage course enrollment/subscription, payment and certificates delivery. Richie can be configured to display course runs and micro-credentials managed through Joanie.

    In fact, Richie treats Joanie almost like a LMS backend that's why settings are similars.

    Configuring Joanie

    All settings related to Joanie have to be declared in the JOANIE_BACKEND dictionnary @@ -39,8 +39,8 @@ lifetime of the access token defined by your authentication server. For example, if your authentication server is using djangorestframework-simplejwt to generate the access token, its lifetime is 5 minutes by default.

    Technical support

    If you encounter an issue with this documentation, please -open an issue on our repository.

    - - +open an issue on our repository.

    + + \ No newline at end of file diff --git a/docs/lms-backends/index.html b/docs/lms-backends/index.html index 1ee37a0f72..8c94040b59 100644 --- a/docs/lms-backends/index.html +++ b/docs/lms-backends/index.html @@ -1,15 +1,15 @@ - + -Configuring LMS Backends | Richie - - +Configuring LMS Backends | Richie + +
    -
    Version: 2.21.0

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: 2.21.1

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -35,8 +35,8 @@ fields manually in Richie regardless of what OpenEdX sends after an initial value is set.

    Note that this setting is only effective for course runs with the sync_mode field set to a value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or -open an issue and we will consider adding it.

    - - +open an issue and we will consider adding it.

    + + \ No newline at end of file diff --git a/docs/lms-connection/index.html b/docs/lms-connection/index.html index bbdc835821..24378476f6 100644 --- a/docs/lms-connection/index.html +++ b/docs/lms-connection/index.html @@ -1,15 +1,15 @@ - + -Connecting Richie with one or more LMS | Richie - - +Connecting Richie with one or more LMS | Richie + +
    -
    Version: 2.21.0

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: 2.21.1

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -30,8 +30,8 @@ apps should be able to communicate with each other via the network bridge defined in docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our -guide on setting-up TLS connections for Richie and OpenEdX.

    - - +guide on setting-up TLS connections for Richie and OpenEdX.

    + + \ No newline at end of file diff --git a/docs/native-installation/index.html b/docs/native-installation/index.html index 5ab6785c44..c7816942fe 100644 --- a/docs/native-installation/index.html +++ b/docs/native-installation/index.html @@ -1,15 +1,15 @@ - + -Installing Richie on your machine | Richie - - +Installing Richie on your machine | Richie + +
    -
    Version: 2.21.0

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: 2.21.1

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native installation instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -33,8 +33,8 @@ dependencies via:

    yarn install
    • JS build
    npm run build
    • CSS build

    This will compile all our SCSS files into one bundle and put it in the static folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at -localhost:8000

    python sandbox/manage.py runserver
    - - +localhost:8000

    python sandbox/manage.py runserver
    + + \ No newline at end of file diff --git a/docs/next/accessibility-testing/index.html b/docs/next/accessibility-testing/index.html index 8123e0b674..f5617c4b00 100644 --- a/docs/next/accessibility-testing/index.html +++ b/docs/next/accessibility-testing/index.html @@ -4,13 +4,13 @@ Automated accessibility checks | Richie - - + +
    -
    Version: Next

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems on any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two ways to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    - - +
    Version: Next

    Automated accessibility checks

    Richie includes automated accessibility checks built through a Cypress end-to-end testing infrastructure.

    Automated accessibility checks can only surface around 30% of possible problems on any given page. This does not mean they are not useful, but they cannot replace human audits and developer proficiency.

    We use axe to run these checks. You can find more about axe on the axe-core GitHub repository.

    Testing environment setup

    Both Cypress and axe are used through their respective NPM packages. This means everything goes through yarn commands. You need to have node and yarn installed locally to run the tests.

    cd tests_e2e
    yarn install

    This should install everything you need.

    Running the tests

    There are two ways to use the Cypress tests: through a terminal-based runner and through the Cypress UI. Both are started through yarn but they have different use cases.

    yarn cypress run

    You can start by running the tests directly from the terminal. This is the quickest way to make sure all views pass checks (or find out which ones do not). This is also the starting point for work on running Cypress in the CI.

    yarn cypress open

    This command simply opens the Cypress UI. From there, you can run all or some of the test suites with live reloading. This is a great way to understand why some tests are failing, especially when it comes to a11y violations.

    When there are a11y violations, an assertion fails and prints out a list in the Cypress UI. You can then click on a violation to print more information in the browser console.

    Documentation reference

    + + \ No newline at end of file diff --git a/docs/next/api/course-run-synchronization-api/index.html b/docs/next/api/course-run-synchronization-api/index.html index 1e8512aded..71c9ac5247 100644 --- a/docs/next/api/course-run-synchronization-api/index.html +++ b/docs/next/api/course-run-synchronization-api/index.html @@ -4,12 +4,12 @@ Course run synchronization API | Richie - - + +
    -
    Version: Next

    Course run synchronization API

    API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

    Synchronization endpoint [/api/1.0/course-runs-sync]

    This documentation describes version "1.0" of this API endpoint.

    Synchronize a course run [POST]

    It takes a JSON object containing the course run details:

    • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - +
      Version: Next

      Course run synchronization API

      API endpoint allowing remote systems to synchronize their course runs with a Richie instance.

      Synchronization endpoint [/api/1.0/course-runs-sync]

      This documentation describes version "1.0" of this API endpoint.

      Synchronize a course run [POST]

      It takes a JSON object containing the course run details:

      • resource_link: https://lms.example.com/courses/course-v1:001+001+001/info (string, required) - url of the course syllabus on the LMS from which a unique course identifier can be extracted
      • start: 2018-02-01T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course starts
      • end: 2018-02-28T06:00:00Z (string, optional) - ISO 8601 date, when this session of the course ends
      • enrollment_start: 2018-01-01T06:00:00Z (string, optional) - ISO 8601 date, when enrollment @@ -19,7 +19,7 @@ containing the digest of the utf-8 encoded json representation of the submitted data for the given secret key and SHA256 digest algorithm (see [synchronizing-course-runs] for an example).
    • Body

        {
      "resource_link": "https://lms.example.com/courses/course-v1:001+001+001/info",
      "start": "2021-02-01T00:00:00Z",
      "end": "2021-02-31T23:59:59Z",
      "enrollment_start": "2021-01-01T00:00:00Z",
      "enrollment_end": "2021-01-31T23:59:59Z",
      "languages": ["en", "fr"]
      }
  • Response 200 (application/json)

    • Body

        {
      "success": True
      }
  • - - + + \ No newline at end of file diff --git a/docs/next/building-the-frontend/index.html b/docs/next/building-the-frontend/index.html index 6b5661ddd6..5d6d49e1e9 100644 --- a/docs/next/building-the-frontend/index.html +++ b/docs/next/building-the-frontend/index.html @@ -4,13 +4,13 @@ Building Richie's frontend in your own project | Richie - - + +
    -
    Version: Next

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    - - +
    Version: Next

    Building Richie's frontend in your own project

    Richie offers plenty of opportunities to customize the way it works and make it suit the needs of your own project. Most of these go through Django settings.

    Part of Richie is a React frontend however. If you want to change how it works in ways that cannot be changed from the Django settings, you will need to build your own frontend.

    Installing richie-education

    If you have not already, you should create a directory for the frontend in your project. We recommend you mirror Richie's file structure so it's easier to keep track of the changes you make.

    mkdir -p src/frontend

    Then, you need to bootstrap your own frontend project in this new directory.

    cd src/frontend
    yarn init

    With each version of Richie, we build and publish an NPM package to enable Richie users to build their own Javascript and CSS. You're now ready to install it.

    yarn add richie-education

    In your package.json file, you should see it in the list of dependencies. Also, there's a node_modules directory where the package and its dependencies are actually installed.

    "dependencies": {
    "richie-education": "1.12.0"
    },

    Building the Javascript bundle

    You are now ready to run your own frontend build. We'll just be using webpack directly.

    yarn webpack --config node_modules/richie-education/webpack.config.js --output-path ./build --richie-dependent-build

    Here is everything that is happening:

    • yarn webpack — run the webpack CLI;
    • --config node_modules/richie-education/webpack.config.js — point webpack to richie-education's webpack config file;
    • --output-path ./build — make sure we get our output where we need it to be;
    • --richie-dependent-build — enable some affordances with import paths. We pre-configured Richie's webpack to be able to run it from a dependent project.

    You can now run your build to change frontend settings or override frontend components with your own.

    Building the CSS

    If you want to change styles in Richie, or add new styles for components & templates you develop yourself, you can run the SASS/CSS build yourself.

    Start by creating your own main file. The _ underscore at the beginning is there to prevent sass from auto-compiling the file.

    mkdir -p src/frontend/scss
    touch src/frontend/scss/_mains.scss

    Start by importing Richie's main scss file. If you prefer, you can also directly import any files you want to include — in effect re-doing Richie's _main.scss on your own.

    @import "richie-education/scss/main";

    You are now ready to run the CSS build:

    cd src/frontend
    yarn build-sass

    This gives you one output CSS file that you can put in the static files directory of your project and use to override Richie's style or add your own parts.

    + + \ No newline at end of file diff --git a/docs/next/contributing-guide/index.html b/docs/next/contributing-guide/index.html index 3d688aa955..179e750cf8 100644 --- a/docs/next/contributing-guide/index.html +++ b/docs/next/contributing-guide/index.html @@ -4,19 +4,19 @@ Contributing guide | Richie - - + +
    -
    Version: Next

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations +

    Version: Next

    Contributing guide

    This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design decisions.

    We try to raise our code quality standards and expect contributors to follow the recommandations from our handbook.

    Checking your code

    We use strict flake8, pylint, isort and black linters to check the validity of our backend code:

    $ make lint-back

    We use strict eslint and prettier to check the validity of our frontend code:

    $ make lint-front

    Running tests

    On the backend, we use pytest to run our test suite:

    $ make test-back

    On the frontend, we use karma to run our test suite:

    $ make test-front

    Running migrations

    The first time you start the project with make bootstrap, the db container automatically creates a fresh database named richie and performs database migrations. Each time a new database migration is added to the code, you can synchronize the database schema by running:

    $ make migrate

    Handling new dependencies

    Each time you add new front-end or back-end dependencies, you will need to rebuild the application. We recommend to use:

    $ make bootstrap

    Going further

    To see all available commands, run:

    $ make

    We also provide shortcuts for docker-compose commands as sugar scripts in the bin/ directory:

    bin
    ├── exec
    ├── pylint
    ├── pytest
    └── run

    More details and tips & tricks can be found in our development with Docker documentation

    - - + + \ No newline at end of file diff --git a/docs/next/cookiecutter/index.html b/docs/next/cookiecutter/index.html index 5bc07c2667..f81e03eb34 100644 --- a/docs/next/cookiecutter/index.html +++ b/docs/next/cookiecutter/index.html @@ -4,17 +4,17 @@ Start your own site | Richie - - + +
    -
    Version: Next

    Start your own site

    We use Cookiecutter to help you +

    Version: Next

    Start your own site

    We use Cookiecutter to help you set up a production-ready learning portal website based on Richie in seconds.

    Run Cookiecutter

    There are 2 options to run Cookiecutter:

    While you think of it, navigate to the directory in which you want to create your site factory:

    cd /path/to/your/code/directory

    If you chose to install Cookiecutter, you can now run it against our -template as follows:

    cookiecutter gh:openfun/richie --directory cookiecutter  --checkout v2.21.0

    If you didn't want to install it on your machine, we provide a Docker image -built with our own repository that you can use as follows:

    docker run --rm -it -u $(id -u):$(id -g) -v $PWD:/app \
    fundocker/cookiecutter gh:openfun/richie --directory cookiecutter --checkout v2.21.0

    The --directory option is to indicate that our Cookiecutter template is in +template as follows:

    cookiecutter gh:openfun/richie --directory cookiecutter  --checkout v2.21.1

    If you didn't want to install it on your machine, we provide a Docker image +built with our own repository that you can use as follows:

    docker run --rm -it -u $(id -u):$(id -g) -v $PWD:/app \
    fundocker/cookiecutter gh:openfun/richie --directory cookiecutter --checkout v2.21.1

    The --directory option is to indicate that our Cookiecutter template is in a cookiecutter directory inside our git repository and not at the root.

    You will be prompted to enter an organization name, which will determine the name of your repository. For example, if you choose "foo" as organization name, your repository will be named foo-richie-site-factory. It's @@ -29,8 +29,8 @@ factory by replaying Cookiecutter. This will override your files in the project's scaffolding but, don't worry, it will respect all the sites you will have created in the sites directory:

    cookiecutter --overwrite-if-exists gh:openfun/richie --directory=cookiecutter

    Help us improve this project

    After starting your project, please submit an issue let us know how it went and -what other features we should add to make it better.

    - - +what other features we should add to make it better.

    + + \ No newline at end of file diff --git a/docs/next/css-guidelines/index.html b/docs/next/css-guidelines/index.html index d85fbb28a3..4789e055dd 100644 --- a/docs/next/css-guidelines/index.html +++ b/docs/next/css-guidelines/index.html @@ -4,13 +4,13 @@ CSS Guidelines | Richie - - + +
    -
    Version: Next

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    - - +
    Version: Next

    CSS Guidelines

    The purpose of these CSS guidelines is to make our CSS as easy as possible to maintain, prune and/or modify over time. To that end, they forgo some of the unwanted parts of CSS. They also require the use of a CSS preprocessor (we picked SASS) to be used effortlessly.

    Our approach is two-pronged. First, we put every piece of CSS as close as we can to the place it is used in a template or component. Second, we use strict class naming rules that act as a replacement to CSS selector combinations.

    File structuration

    Rules should be placed where their purpose is most apparent, and where they are easiest to find.

    Generally, this means CSS rules should live as close as possible to the place they are used. For example, the selectors and rules that define the look for a component should live in a .scss file in the same folder as the JS file for this component. This goes for templates too. Such files can only contain rules that are specific to this component/template and this one only

    Only general base rules, utility rules, site layout rules as well as our custom variables should live in the central app/static/scss folder.

    Code structuration

    In order to understand what classes are about at a glance and avoid collisions, naming conventions must be enforced for classes.

    Following the BEM naming convention, we will write our classes as follows :

    .block {}
    .block__element {}
    .block--modifier {}
    • .block represents the higher level of an abstraction or component.
    • .block__element represents a descendent of .block that helps form .block as a whole.
    • .block--modifier represents a different state or version of .block.

    We use double hyphens and double underscores as delimiters so that names themselves can be hyphen-delimited (e.g. .site-search__field--full).

    Yes, this notation is ugly. However, it allows our classes to express what they are doing. Both our CSS and our markup become more meaningful. It allows us to easily see what classes are related to others, and how they are related, when we look at the markup.

    Quick pointers

    • In general, do not use IDs. They can cause specificity wars and are not supposed to be reusable, and are therefore not very useful.
    • Do not nest selectors unnecessarily. It will increase specificity and affect where else you can use your styles.
    • Do not qualify selectors unnecessarily. It will impact the number of different elements you can apply styles to.
    • Comment profusely, whenever you think the CSS is getting complex or it would not be easy to understand its intent.
    • Use !important proactively. !important is a very useful tool when used proactively to make a state or a very specific rule on a tightly-scoped selector stronger. It is however to be avoided at all costs as an easy solution to specificity issues, reactively.

    (Direct) child selectors can sometimes be useful. Please remember that the key selector to determine performance is the rightmost one. i.e. div > #example is A LOT more efficient than #example > div although it may appear otherwise at first glance. Browsers parse multi part selectors from the right. See CSS Wizardry for more details.

    + + \ No newline at end of file diff --git a/docs/next/discover/index.html b/docs/next/discover/index.html index 8297dc3efb..cc3ab0ceb9 100644 --- a/docs/next/discover/index.html +++ b/docs/next/discover/index.html @@ -4,12 +4,12 @@ Discover Richie | Richie - - + +
    -
    Version: Next

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online +

    Version: Next

    Discover Richie

    Learning Management Systems (LMS) are great tools for hosting and playing interactive online courses and MOOCs.

    However, if you need to build a complete website with flexible content to aggregate your courses, in several languages and from different sources, you will soon need a CMS.

    At "France Université Numérique", we wanted to build an OpenSource portal with Python and Django. That's why we built Richie on top of DjangoCMS, one of @@ -21,7 +21,7 @@ OpenEdX Docker.

    Two users are available for testing:

    • admin: admin@example.com/admin
    • student: edx@example.com/edx

    The database is regularly flushed.

    Start your own site

    The next step after discovering Richie on the demo is to start your own project. We provide a production-ready template based on Cookiecutter that allows you to generate your project in seconds.

    Follow the guide on starting your own Richie site with Cookiecutter.

    Once you created a new site, you will be able to fully customize it:

    - - + + \ No newline at end of file diff --git a/docs/next/displaying-connection-status/index.html b/docs/next/displaying-connection-status/index.html index 66eba7ee23..36ae87333a 100644 --- a/docs/next/displaying-connection-status/index.html +++ b/docs/next/displaying-connection-status/index.html @@ -4,12 +4,12 @@ Displaying OpenEdX connection status in Richie | Richie - - + +
    -
    Version: Next

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status +

    Version: Next

    Displaying OpenEdX connection status in Richie

    This guide explains how to configure Richie and OpenEdX to share the OpenEdX connection status and display profile information for the logged-in user in Richie.

    In Richie, the only users that are actually authenticated on the DjangoCMS instance producing the site, are editors and staff users. Your instructors and learners will not have user accounts on Richie, but authentication is delegated to a remote service that can be OpenEdX, KeyCloack, or @@ -26,7 +26,7 @@ set for the above authentication delegation BASE_URL setting.

    If you need to bind user data into a url, wrap the property between brackets. For example, the link configured above for the profile page {base_url:s}/u/(username) would point to https://lms.example.com/u/johndoe for a user carrying the username johndoe.

    - - + + \ No newline at end of file diff --git a/docs/next/django-react-interop/index.html b/docs/next/django-react-interop/index.html index 7e0b41c1b5..8ca95e8593 100644 --- a/docs/next/django-react-interop/index.html +++ b/docs/next/django-react-interop/index.html @@ -4,13 +4,13 @@ Connecting React components with Django | Richie - - + +
    -
    Version: Next

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    - - +
    Version: Next

    Connecting React components with Django

    richie is a hybrid app, that relies on both HTML pages generated by the backend (Django/DjangoCMS) based on templates, and React components rendered on the frontend for parts of these HTML pages.

    Rendering components

    We needed a convention that enables us to easily mark those areas of the page that React needs to take control of, and to tell React which component to load there.

    We decided to use a specific CSS class name along with its modifiers. We reserve the richie-react class and its modified children for this purpose.

    Additionally, components including internationalized data or strings need to know which locale to use. They will pick up the locale specified through the lang attribute of the <html> element, which is a requirement to have an accessible page anyway.

    They use the BCP47/RFC5646 format.

    <html lang="en-US">

    Example

    Here is how we would call a <FeaturedCourses /> component from a template, a plugin or a snippet:

    <div
    class="richie-react richie-react--featured-courses"
    ></div>

    When our JS is loaded, it will recognize this as an element it must take over, and render the FeaturedCourses component in this element.

    Passing properties to components

    Some of Richie's React components, and some of those you might want to write, require arguments or "props" to be passed to them. We could work around that by adding API routes to fetch these props, but that would add complexity and reduce performance.

    Instead, we decided to normalize a simpler way for components in Richie to accept input from the Django template that is adding them to the DOM.

    We can add a data-props attribute on the element with the richie-react class and write a JSON object as the value for this attribute. Each key-value pair in this object will be passed as a propName={propValue} to the React component.

    Example

    Here is how we would pass a categories={[ "sociology", "anthropology" ]} prop to our <FeaturedCourses /> component:

    <div
    class="richie-react richie-react--featured-courses"
    data-props='{"categories": ["sociology", "anthropology"]}'
    ></div>

    When the component is rendered, it will be passed a categories prop with the relevant categories.

    Built-in components

    Here are the React component that Richie comes with and uses out of the box.

    <RootSearchSuggestField />

    Renders a course search bar, like the one that appears in the default Search page.

    Interactions will send the user to the courseSearchPageUrl url passed in the props, including the selected filter and/or search terms.

    It also autocompletes user input with course names and allows users to go directly to the course page if they select a course name among the selected results.

    Props:

    • courseSearchPageUrl [required] — URL for the course search page users should be sent to when they select a suggestion that is not a course, or launch a search with text terms.
    • context [required] — see context.

    <Search />

    Renders the full-page course search engine interface, including the search results, and filters pane, but not the suggest field (which can be added separately with <SearchSuggestField />) nor the page title.

    NB: the Search Django template basically renders just this page. If you need this, use it instead. It is included here for completeness' sake.

    Props:

    • context [required] — see context.

    <SearchSuggestField />

    Renders the course search bar that interacts directly with <Search />.

    It automatically communicates with <Search /> through browser history APIs and a shared React provider. This one, unlike <RootSearchSuggestField />, is meant to be used in combination with <Search /> (on the same page).

    Props:

    • context [required] — see context.

    <UserLogin />

    Renders a component that uses the /users/whoami endpoint to determine if the user is logged in and show them the appropriate interface: Signup/Login buttons or their name along with a Logout button.

    Props:

    • loginUrl [required] — the URL where the user is sent when they click on "Log in";
    • logoutUrl [required] — a link that logs the user out and redirects them (can be the standard django logout URL);
    • signupUrl [required] — the URL where the user is sent when they click on "Sign up".

    Context

    All built-in components for Richie accept a context prop, that may be required or optional, depending on the component.

    It is used to pass app-wide contextual information pertaining to the current instance, deployment or theme of Richie.

    Here is the expected shape for this object:

    {
    assets: {
    // SVG sprite used throughout Richie
    icons: "/path/to/icons/sprite.svg"
    }
    }

    Note that it might be expanded in further versions of Richie.

    + + \ No newline at end of file diff --git a/docs/next/docker-development/index.html b/docs/next/docker-development/index.html index 9a1385dfe1..0c19b6d219 100644 --- a/docs/next/docker-development/index.html +++ b/docs/next/docker-development/index.html @@ -4,12 +4,12 @@ Developing Richie with Docker | Richie - - + +
    -
    Version: Next

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django +

    Version: Next

    Developing Richie with Docker

    Now that you have Richie up and running, you can start working with it.

    Settings

    Settings are defined using Django Configurations for different environments:

    • Development: settings for development on developers' local environment,
    • Test: settings used to run our test suite,
    • ContinousIntegration: settings used on the continuous integration platform,
    • Feature: settings for deployment of each developers' feature branches,
    • Staging: settings for deployment to the staging environment,
    • PreProduction: settings for deployment to the pre-production environment,
    • Production: settings for deployment to the production environment.

    The Development environment is defined as the default environment.

    Front-end tools

    If you intend to work on the front-end development of the CMS, we also have sweet candies for you! 🤓

    # Start the Sass watcher
    $ make watch-sass

    # In a new terminal or session, start the TypeScript watcher
    $ make watch-ts

    Container control

    You can stop/start/restart a container:

    $ docker-compose [stop|start|restart] [app|postgresql|mysql|elasticsearch]

    or stop/start/restart all containers in one command:

    $ docker-compose [stop|start|restart]

    Debugging

    You can easily see the latest logs for a container:

    $ docker-compose logs [app|postgresql|mysql|elasticsearch]

    Or follow the stream of logs:

    $ docker-compose logs --follow [app|postgresql|mysql|elasticsearch]

    If you need to debug a running container, you can open a Linux shell with the @@ -29,7 +29,7 @@ remember to periodically clean the unused docker images and containers by running:

    $ docker image prune
    $ docker container prune

    Troubleshooting

    ElasticSearch service is always down

    If your elasticsearch container fails at booting, checkout the logs via:

    $ docker-compose logs elasticsearch

    You may see entries similar to:

    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

    In this case, increase virtual memory as follows (UNIX systems):

    $ sudo sysctl -w vm/max_map_count=262144

    This fix will apply to your current session. To make it permanent on your system, edit the /etc/sysctl.conf file and add the following line:

    vm.max_map_count=262144
    - - + + \ No newline at end of file diff --git a/docs/next/filters-customization/index.html b/docs/next/filters-customization/index.html index 5acf06a902..f17c69a331 100644 --- a/docs/next/filters-customization/index.html +++ b/docs/next/filters-customization/index.html @@ -4,12 +4,12 @@ Customizing search filters | Richie - - + +
    -
    Version: Next

    Customizing search filters

    You may want to customize the filters on the left side bar of the search page.

    Richie makes it easy to choose which filters you want to display among the existing filters +

    Version: Next

    Customizing search filters

    You may want to customize the filters on the left side bar of the search page.

    Richie makes it easy to choose which filters you want to display among the existing filters and in which order. You can also configure the existing filters to change their title or the way they behave. Lastly, you can completely override a filter or create your own custom filter from scratch.

    Filters configuration

    Filters must first be defined in the FILTERS_CONFIGURATION setting. It is a dictionary defining @@ -48,7 +48,7 @@ trivial, was given much care and includes many comments in an attempt to help writing new custom filters. Of course, don't hesitate to ask for help by opening an issue!

    - - + + \ No newline at end of file diff --git a/docs/next/frontend-overrides/index.html b/docs/next/frontend-overrides/index.html index 0ca2441907..2d41146bed 100644 --- a/docs/next/frontend-overrides/index.html +++ b/docs/next/frontend-overrides/index.html @@ -4,13 +4,13 @@ Overriding frontend components | Richie - - + +
    -
    Version: Next

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    - - +
    Version: Next

    Overriding frontend components

    Once you are able to build the frontend in your project (see previous section), you can override some parts of the frontend with a drop-in replacement you built yourself.

    This enables you to customize Richie to your own needs in the same way you could do it with backend templates by overriding templates or blocks which do not suit your needs.

    Defining your overrides

    Create a json settings files somewhere in your project. You'll use it to declare the overrides for your custom Richie build.

    Currently, it is only possible to override components. Richie's build is only set up to handle them.

    Inside, create an object with only one key: "overrides". This is an object, whose key-value pairs is the name of a component as a key and the path to the drop-in replacement as the value.

    {
    "overrides": {
    "CourseGlimpse": "src/richie/components/CustomCourseGlimpse.tsx"
    }
    }

    Building a component override

    As overrides are supposed to be drop-in replacements, directly processed by the bundler instead of the original file, they need to expose the same API.

    For example, if our component to override was the following:

    export interface CourseGlimpseProps {
    course: Course;
    context: { someProp: string };
    }

    export const CourseGlimpse: React.FC<CourseGlimpseProps> = ({ course, context }) => {
    // Whatever happens in this component
    return <p>The glimpse</p>;
    };

    Then, your override needs to provide the same exports, explicitly a named CourseGlimpseProps interface and a named CourseGlimpse component.

    You also need to respect the assumptions made by other components that use your overridden version, if you are not overriding a root component.

    For example returning null might break a layout if the original component never returned such a value, etc. You also need to make sure to avoid conflict with the parameters accepted by the original component.

    Override translation

    When you create an application based on richie, you can encounter two cases about translations:

    1. You created or overrode a react component and created new translation keys
    2. You just want to override a translation in an existing richie component

    Create new translation keys

    Once you created your new component with its translation keys, you have to extract them with the following command:

      formatjs extract './**/*.ts*' --ignore ./node_modules --ignore './**/*.d.ts' --out-file './i18n/frontend.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format crowdin

    This command extracts all translations defined in your typescript files then generates a frontend.json file in i18n/ directory. This file is like a pot file, this is the base to create your translations in any language you want.

    As --format option indicates, this command generates a file compatible with crowdin. If you want to customize this command to fit your needs, read the formatjs/cli documentation.

    Once translations keys are extracted and your local translations are ready, you need to compile these translations. In fact, the compilation process first aggregates all translation files found from provided paths then merges them with richie translations according their filename and finally generates an output formatted for react-intl. Below, here is an example of a compilation command:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/locales/*.json

    This command looks for all translation files in i18n/locales directory then merges files found with richie translation files. You can pass several path patterns. You can also use an --ignore argument to ignore a particular path.

    Override an existing translation key

    As explain above, the compilation process aggregates translations files then merges them according their filename. That means if you want override for example the english translation, you just have to create a en-US.json file and redefine translation keys used by Richie.

    Richie uses one file per language. Currently 4 languages supported:

    • English: filename is en-US.json
    • French: filename is fr-FR.json
    • Canadian french: filename is fr-CA.json
    • Spanish: filename is es-ES.json

    For example, richie uses the translation key components.UserLogin.logIn for the Log in button. If you want to change this label for the english translation, you just have to create a translation file en-US.json which redefines this translation key:

    {
    "components.UserLogin.logIn": {
    "description": "Overriden text for the login button.",
    "message": "Authentication"
    },
    }

    Then, for example if you put your overridden translation in i18n/overrides directory, you have to launch the compilation command below:

      node-modules/richie-education/i18n/compile-translations.js ./i18n/overrides/*.json

    In this way, "Authentication" will be displayed as label for login button instead of "Sign in".

    + + \ No newline at end of file diff --git a/docs/next/installation/index.html b/docs/next/installation/index.html index c46f4d5be1..65afec4b6a 100644 --- a/docs/next/installation/index.html +++ b/docs/next/installation/index.html @@ -4,12 +4,12 @@ Installing Richie for development | Richie - - + +
    -
    Version: Next

    Installing Richie for development

    Richie is a container-native application but can also be installed +

    Version: Next

    Installing Richie for development

    Richie is a container-native application but can also be installed on your machine.

    For development, the project is defined using a docker-compose file and consists of:

    • 3 running services:

      • database: postgresql or mysql at your preference,
      • elasticsearch: the search engine,
      • app: the actual DjangoCMS project with all our application code.
    • 2 containers for building purposes:

    - - + + \ No newline at end of file diff --git a/docs/next/internationalization/index.html b/docs/next/internationalization/index.html index 345f2aa33d..2d73048391 100644 --- a/docs/next/internationalization/index.html +++ b/docs/next/internationalization/index.html @@ -4,12 +4,12 @@ Internationalization | Richie - - + +
    -
    Version: Next

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. +

    Version: Next

    Internationalization

    richie has built-in localization and internationalization:

    • On the backend and CMS, i18n is built on the shoulders of Django and DjangoCMS,
    • On the frontend, we use React Intl.

    Contributing as a translator or proof-reader

    We use the Crowdin web platform to translate Richie to different languages. All translations are hosted at https://i18n.richie.education, which allows translators and proof-readers to contribute on translations in the languages they master.

    Sign-up on Crowdin

    If you don't have an account on Crowdin already, go to https://accounts.crowdin.com/register and fill out the form to create a free account.

    Join the Richie project

    Now that you have an account on Crowdin, @@ -22,7 +22,7 @@ release.

    Before asking for a new language, make sure it does not already exist. If your language already exists in another variant (e.g. Brazilian portuguese vs Portugal portuguese), you may consider contributing on the existing language if your resources to contribute are limited.

    - - + + \ No newline at end of file diff --git a/docs/next/joanie-connection/index.html b/docs/next/joanie-connection/index.html index bab288bba9..efb1cd2126 100644 --- a/docs/next/joanie-connection/index.html +++ b/docs/next/joanie-connection/index.html @@ -4,12 +4,12 @@ Joanie Connection | Richie - - + +
    -
    Version: Next

    Joanie Connection

    Joanie delivers an API able to manage course +

    Version: Next

    Joanie Connection

    Joanie delivers an API able to manage course enrollment/subscription, payment and certificates delivery. Richie can be configured to display course runs and micro-credentials managed through Joanie.

    In fact, Richie treats Joanie almost like a LMS backend that's why settings are similars.

    Configuring Joanie

    All settings related to Joanie have to be declared in the JOANIE_BACKEND dictionnary @@ -40,7 +40,7 @@ authentication server is using djangorestframework-simplejwt to generate the access token, its lifetime is 5 minutes by default.

    Technical support

    If you encounter an issue with this documentation, please open an issue on our repository.

    - - + + \ No newline at end of file diff --git a/docs/next/lms-backends/index.html b/docs/next/lms-backends/index.html index 69a3dbbaa9..2a241e0f21 100644 --- a/docs/next/lms-backends/index.html +++ b/docs/next/lms-backends/index.html @@ -4,12 +4,12 @@ Configuring LMS Backends | Richie - - + +
    -
    Version: Next

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless +

    Version: Next

    Configuring LMS Backends

    Richie can be connected to one or more OpenEdX Learning Management Systems (LMS) for a seamless experience between browsing the course catalog on Richie, enrolling to a course and following the course itself on the LMS.

    It is possible to do the same with Moodle or any other LMS exposing an enrollment API, at the cost of writing a custom LMS handler backend.

    Prerequisites

    This connection requires that Richie and OpenEdX be hosted on sibling domains i.e. domains that @@ -36,7 +36,7 @@ value other then manual.

    • Type: enum(string)
    • Required: No
    • Value: for example ["languages"]

    Technical support

    If you encounter an issue with this documentation or the backends included in Richie, please open an issue on our repository.

    If you need a custom backend, you can submit a PR or open an issue and we will consider adding it.

    - - + + \ No newline at end of file diff --git a/docs/next/lms-connection/index.html b/docs/next/lms-connection/index.html index c52cc15b81..e8adec022f 100644 --- a/docs/next/lms-connection/index.html +++ b/docs/next/lms-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie with one or more LMS | Richie - - + +
    -
    Version: Next

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated +

    Version: Next

    Connecting Richie with one or more LMS

    Connecting Richie to an LMS

    Richie can be connected to an LMS in several ways, ranging from SSO to a fully integrated seamless experience.

    As of today, each approach has been implemented for OpenEdX but the same could be done for other LMSes like Moodle, at the cost of minor adaptations.

    1. Displaying connection status

    OpenEdX can be configured to allow CORS requests. Doing so allows Richie to retrieve a user's connection status from OpenEdx and display the user's profile information directly on the Richie @@ -31,7 +31,7 @@ docker-compose.

    If you want to activate seamless enrollment locally for development, you will need to set up TLS domains for both Richie and OpenEdX. To do this, head over to our guide on setting-up TLS connections for Richie and OpenEdX.

    - - + + \ No newline at end of file diff --git a/docs/next/native-installation/index.html b/docs/next/native-installation/index.html index c51b622245..be63e47c65 100644 --- a/docs/next/native-installation/index.html +++ b/docs/next/native-installation/index.html @@ -4,12 +4,12 @@ Installing Richie on your machine | Richie - - + +
    -
    Version: Next

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie +

    Version: Next

    Installing Richie on your machine

    This document aims to list all needed steps to have a working Richie installation on your laptop.

    A better approach is to use Docker as explained in our guide for container-native installation instructions.

    Installing a fresh server

    Version

    You need a Ubuntu 18.04 Bionic Beaver (the latest LTS version) fresh installation.

    If you are using another operating system or distribution, you can use @@ -34,7 +34,7 @@ folder we're serving.

    npm run sass

    Run server

    Make sure your database is up-to-date before running the application the first time and after each modification to your models:

    python sandbox/manage.py migrate

    You can create a superuser account:

    python sandbox/manage.py createsuperuser

    Run the tests

    python sandbox/manage.py test

    You should now be able to start Django and view the site at localhost:8000

    python sandbox/manage.py runserver
    - - + + \ No newline at end of file diff --git a/docs/next/synchronizing-course-runs/index.html b/docs/next/synchronizing-course-runs/index.html index 570aedb019..c61ccdebde 100644 --- a/docs/next/synchronizing-course-runs/index.html +++ b/docs/next/synchronizing-course-runs/index.html @@ -4,12 +4,12 @@ Synchronizing course runs between Richie and OpenEdX | Richie - - + +
    -
    Version: Next

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: Next

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -29,7 +29,7 @@ course run is modified and published.

    Or you can use the Richie Open edX Synchronization which is based on the following code sample and also includes the enrollment count.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - + + \ No newline at end of file diff --git a/docs/next/tls-connection/index.html b/docs/next/tls-connection/index.html index 4184265d9e..4410aff528 100644 --- a/docs/next/tls-connection/index.html +++ b/docs/next/tls-connection/index.html @@ -4,12 +4,12 @@ Connecting Richie and OpenEdX over TLS for development | Richie - - + +
    -
    Version: Next

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: Next

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -32,7 +32,7 @@ to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - + + \ No newline at end of file diff --git a/docs/next/web-analytics/index.html b/docs/next/web-analytics/index.html index 905a3009dc..75c85c2ee8 100644 --- a/docs/next/web-analytics/index.html +++ b/docs/next/web-analytics/index.html @@ -4,19 +4,19 @@ Add web analytics to your site | Richie - - + +
    -
    Version: Next

    Add web analytics to your site

    Richie has native support to Google Universal Analytics and Google Tag Manager Web Analytics solutions. +

    Version: Next

    Add web analytics to your site

    Richie has native support to Google Universal Analytics and Google Tag Manager Web Analytics solutions. The purpose of this file is to explain how you can enable one of the supported Web Analytics providers and how you can extend Richie with an alternative solution.

    Google Universal Analytics

    Next, it is described how you can configure the Google Universal Analytics on your Richie site.

    Add the WEB_ANALYTICS setting, with the Google Universal Analytics configuration. From the next example replace TRACKING_ID with your tracking id code.

    {
    'google_universal_analytics': {
    'tracking_id': 'TRACKING_ID',
    }
    }

    The current Google Universal Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Universal Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Google Tag

    It is possible to configure the Google Tag, gtag.js, on your Richie site.

    Add the WEB_ANALYTICS setting, with the Google Tag configuration like for example:

    {
    'google_tag': {
    'tracking_id': 'TRACKING_ID',
    }
    }

    And don't forget to replace the TRACKING_ID with your tracking id/code from Google Ads, Google Analytics, or other Google product compatible with the gtag.js.

    The Google Tag is initialized with custom dimensions like the Google Universal Analytics.

    Google Tag Manager

    Next, it is described how you can configure the Google Tag Manager, gtm.js, on your Richie site.

    Add the WEB_ANALYTICS setting, with the Google Tag Manager configuration, for example:

    {
    'google_tag_manager': {
    'tracking_id': 'TRACKING_ID',
    }
    }

    And don't forget to replace the TRACKING_ID with your GTM tracking id/code.

    The current Google Tag Manager implementation also defines a custom dimensions like the Google Universal Analytics.

    If you want to use the Environments feature of the Google Tag Manager, you need to include the environment key with its value on google_tag_manager dict inside the WEB_ANALYTICS setting.

    The environments feature in Google Tag Manager is ideal for organizations that want to preview their container changes in a test environment before those changes are published.

    {
    'google_tag_manager': {
    'tracking_id': 'TRACKING_ID',
    'environment': '&gtm_auth=aaaaaaaaaaaaaaaa&gtm_preview=env-99&gtm_cookies_win=x';
    }
    }

    Multiple Web Analytics at the same time

    It is possible to configure several web analytics solutions at the same time or the same solution with different tracking identifications.

    WEB_ANALYTICS setting example to have both Google Universal Analytics and Google Tag Manager:

    {
    'google_universal_analytics': {
    'tracking_id': 'UA-TRACKING_ID',
    },
    'google_tag_manager': {
    'tracking_id': 'GTM-TRACKING_ID',
    }
    }

    Location of the web analytics javascript

    Each web analytics js code can be put on the footer (default value), to put the Javascript on HTML body footer, or header, to put the Javascript code at the end of the HTML head.

    Update the WEB_ANALYTICS setting, like:

    {
    'google_universal_analytics': {
    'tracking_id': 'UA-TRACKING_ID',
    'location': 'footer,
    },
    }

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • define the WEB_ANALYTICS setting with your tracking identification
    • optionally change location with footer (default) or head value
    {
    'my-custom-web-analytics-software': {
    'tracking_id': 'MY_CUSTOM_TRACKING_ID',
    'location': 'footer,
    },
    }
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% extends "richie/web_analytics.html" %}
    {% block web_analytics_additional_providers %}
    {% if provider == "my_custom_web_analytics_software_provider" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endblock web_analytics_additional_providers %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>

    The frontend code also sends events to the web analytics provider. Richie sends events when the user is enrolled on a course run. To support different providers, you need to create a similar file of src/frontend/js/utils/api/web-analytics/google_universal_analytics.ts and change the src/frontend/js/utils/api/web-analytics/index.ts file to include that newer provider.

    - - + + \ No newline at end of file diff --git a/docs/synchronizing-course-runs/index.html b/docs/synchronizing-course-runs/index.html index cc4a2c665d..2f47cba415 100644 --- a/docs/synchronizing-course-runs/index.html +++ b/docs/synchronizing-course-runs/index.html @@ -1,15 +1,15 @@ - + -Synchronizing course runs between Richie and OpenEdX | Richie - - +Synchronizing course runs between Richie and OpenEdX | Richie + +
    -
    Version: 2.21.0

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the +

    Version: 2.21.1

    Synchronizing course runs between Richie and OpenEdX

    Richie can receive automatic course runs updates on a dedicated API endpoint.

    Configure a shared secret

    In order to activate the course run synchronization API endpoint, you first need to configure the RICHIE_COURSE_RUN_SYNC_SECRETS setting with one or more secrets:

    RICHIE_COURSE_RUN_SYNC_SECRETS = ["SharedSecret", "OtherSharedSecret"]

    This setting collects several secrets in order to allow rotating them without any downtime. Any of the secrets listed in this setting can be used to sign your queries.

    Your secret should be shared with the LMS or distant system that needs to synchronize its course runs with the Richie instance. Richie will try the declared secrets one by one until it finds @@ -28,8 +28,8 @@ should run on the post_publish signal emitted by the OpenEdX cms application each time a course run is modified and published.

    Or you can use the Richie Open edX Synchronization which is based on the following code sample and also includes the enrollment count.

    Given a COURSE_HOOK setting defined as follows in your OpenEdX instance:

    COURSE_HOOK = {
    "secret": "SharedSecret",
    "url": "https://richie.example.com/api/v1.0/course-runs-sync/",
    }

    The code for the synchronization function in OpenEdX could look like this:

    import hashlib
    import hmac
    import json

    from django.conf import settings

    from microsite_configuration import microsite
    import requests
    from xmodule.modulestore.django import modulestore


    def update_course(course_key, *args, **kwargs):
    """Synchronize an OpenEdX course, identified by its course key, with a Richie instance."""
    course = modulestore().get_course(course_key)
    edxapp_domain = microsite.get_value("site_domain", settings.LMS_BASE)

    data = {
    "resource_link": "https://{:s}/courses/{!s}/info".format(
    edxapp_domain, course_key
    ),
    "start": course.start and course.start.isoformat(),
    "end": course.end and course.end.isoformat(),
    "enrollment_start": course.enrollment_start and course.enrollment_start.isoformat(),
    "enrollment_end": course.enrollment_end and course.enrollment_end.isoformat(),
    "languages": [course.language or settings.LANGUAGE_CODE],
    }

    signature = hmac.new(
    setting.COURSE_HOOK["secret"].encode("utf-8"),
    msg=json.dumps(data).encode("utf-8"),
    digestmod=hashlib.sha256,
    ).hexdigest()

    response = requests.post(
    setting.COURSE_HOOK["url"],
    json=data,
    headers={"Authorization": "SIG-HMAC-SHA256 {:s}".format(signature)},
    )

    Thanks to the signal emitted in OpenEdX, this function can then be triggered each time a course -is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    - - +is modified and published:

    from django.dispatch import receiver
    from xmodule.modulestore.django import SignalHandler


    @receiver(SignalHandler.course_published, dispatch_uid='update_course_on_publish')
    def update_course_on_publish(sender, course_key, **kwargs):
    update_course(course_key)
    + + \ No newline at end of file diff --git a/docs/tls-connection/index.html b/docs/tls-connection/index.html index 5eb8f70a8b..d604df204a 100644 --- a/docs/tls-connection/index.html +++ b/docs/tls-connection/index.html @@ -1,15 +1,15 @@ - + -Connecting Richie and OpenEdX over TLS for development | Richie - - +Connecting Richie and OpenEdX over TLS for development | Richie + +
    -
    Version: 2.21.0

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 +

    Version: 2.21.1

    Connecting Richie and OpenEdX over TLS for development

    Purpose

    By default in the docker-compose environment for development, Richie is hosted on localhost:8070 and uses a fake LMS backend (base.BaseLMSBackend) as you can see if you check the RICHIE_LMS_BACKENDS setting in env.d/development.

    This base backend uses session storage to fake enrollments to course runs.

    If you want to test real enrollments to an OpenEdX instance hosted on an external domain, OpenEdX will need to generate a CORS CSRF Cookie. This cookie is flagged as secure, which implies that @@ -31,8 +31,8 @@ and Richie should respond on https://richie.local.dev:8070. The richie application should be able to share cookies with the OpenEdx application to allow CORS CSRF Protected XHR requests.

    4. Start Richie and OpenEdx over SSL

    Now, the OpenEdx application should respond on https://edx.local.dev:8073, and Richie on https://richie.local.dev:8070 without browser warning about the certificate validity.

    You need to follow these steps once. The next time you want to use SSL, you can run the following -command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    - - +command on both the Richie and OpenEdX projects:

    $ make run-ssl

    Of course, you can still run apps without ssl by using:

    $ make run
    + + \ No newline at end of file diff --git a/docs/web-analytics/index.html b/docs/web-analytics/index.html index 0a54686959..76bf3c03e3 100644 --- a/docs/web-analytics/index.html +++ b/docs/web-analytics/index.html @@ -1,22 +1,22 @@ - + -Add web analytics to your site | Richie - - +Add web analytics to your site | Richie + +
    -
    Version: 2.21.0

    Add web analytics to your site

    Richie has native support to Google Universal Analytics and Google Tag Manager Web Analytics solutions. +

    Version: 2.21.1

    Add web analytics to your site

    Richie has native support to Google Universal Analytics and Google Tag Manager Web Analytics solutions. The purpose of this file is to explain how you can enable one of the supported Web Analytics providers and how you can extend Richie with an alternative solution.

    Google Universal Analytics

    Next, it is described how you can configure the Google Universal Analytics on your Richie site.

    Add the WEB_ANALYTICS setting, with the Google Universal Analytics configuration. From the next example replace TRACKING_ID with your tracking id code.

    {
    'google_universal_analytics': {
    'tracking_id': 'TRACKING_ID',
    }
    }

    The current Google Universal Analytics implementation also includes custom dimensions. Those dimensions permit you to create further analyses on Google Universal Analytics or even use them to create custom reports. Custom dimensions with a value as example:

    • Organizations codes - UNIV_LISBON | UNIV_PORTO
    • Course code - COURSE_XPTO
    • Course runs titles - Summer edition | Winter edition
    • Course runs resource links - http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info
    • Page title - Introduction to Programming

    Google Tag

    It is possible to configure the Google Tag, gtag.js, on your Richie site.

    Add the WEB_ANALYTICS setting, with the Google Tag configuration like for example:

    {
    'google_tag': {
    'tracking_id': 'TRACKING_ID',
    }
    }

    And don't forget to replace the TRACKING_ID with your tracking id/code from Google Ads, Google Analytics, or other Google product compatible with the gtag.js.

    The Google Tag is initialized with custom dimensions like the Google Universal Analytics.

    Google Tag Manager

    Next, it is described how you can configure the Google Tag Manager, gtm.js, on your Richie site.

    Add the WEB_ANALYTICS setting, with the Google Tag Manager configuration, for example:

    {
    'google_tag_manager': {
    'tracking_id': 'TRACKING_ID',
    }
    }

    And don't forget to replace the TRACKING_ID with your GTM tracking id/code.

    The current Google Tag Manager implementation also defines a custom dimensions like the Google Universal Analytics.

    If you want to use the Environments feature of the Google Tag Manager, you need to include the environment key with its value on google_tag_manager dict inside the WEB_ANALYTICS setting.

    The environments feature in Google Tag Manager is ideal for organizations that want to preview their container changes in a test environment before those changes are published.

    {
    'google_tag_manager': {
    'tracking_id': 'TRACKING_ID',
    'environment': '&gtm_auth=aaaaaaaaaaaaaaaa&gtm_preview=env-99&gtm_cookies_win=x';
    }
    }

    Multiple Web Analytics at the same time

    It is possible to configure several web analytics solutions at the same time or the same solution with different tracking identifications.

    WEB_ANALYTICS setting example to have both Google Universal Analytics and Google Tag Manager:

    {
    'google_universal_analytics': {
    'tracking_id': 'UA-TRACKING_ID',
    },
    'google_tag_manager': {
    'tracking_id': 'GTM-TRACKING_ID',
    }
    }

    Location of the web analytics javascript

    Each web analytics js code can be put on the footer (default value), to put the Javascript on HTML body footer, or header, to put the Javascript code at the end of the HTML head.

    Update the WEB_ANALYTICS setting, like:

    {
    'google_universal_analytics': {
    'tracking_id': 'UA-TRACKING_ID',
    'location': 'footer,
    },
    }

    Add a new Web Analytics solution

    In this section it's described how you can add support to a different Web Analytics solution.

    • override the richie/web_analytics.html template
    • define the WEB_ANALYTICS setting with a value that represents your solution, eg. my-custom-web-analytics-software
    • define the WEB_ANALYTICS setting with your tracking identification
    • optionally change location with footer (default) or head value
    {
    'my-custom-web-analytics-software': {
    'tracking_id': 'MY_CUSTOM_TRACKING_ID',
    'location': 'footer,
    },
    }
    • Example of a richie/web_analytics.html file customization that prints to the browser console log the dimension keys and values:
    <script type="text/javascript">
    {% for dimension_key, dimension_value_list in WEB_ANALYTICS.DIMENSIONS.items %}
    console.log("dimension: index '{{forloop.counter}}' with key '{{ dimension_key }}' with value '{{ dimension_value_list|join:" | " }}'");
    {% endfor %}
    </script>

    Output:

    dimension: index '1' with key 'organizations_codes' with value 'COMPATIBLE-EVEN-KEELED-UTILIZATION-19 | FOCUSED-NEXT-GENERATION-FUNCTIONALITIES-22 | UNIVERSAL-MODULAR-LOCAL-AREA-NETWORK-23'
    dimension: index '2' with key 'course_code' with value '00017'
    dimension: index '3' with key 'course_runs_titles' with value 'Run 0'
    dimension: index '4' with key 'course_runs_resource_links' with value ''
    dimension: index '5' with key 'page_title' with value 'Business-focused zero-defect application'

    But you can also contribute to Richie by creating a pull request to add support for a different web analytics solution. In this last case, you have to edit directly the richie/web_analytics.html template.

    Example of an override of the richie/web_analytics.html file:

    {% extends "richie/web_analytics.html" %}
    {% block web_analytics_additional_providers %}
    {% if provider == "my_custom_web_analytics_software_provider" %}
    <script type="text/javascript" src="{% static 'myapp/js/custom_web_analytics_software.js' %}">
    <script type="text/javascript">
    // javascript code that startups the custom web analytics software
    </script>
    {% endif %}
    {% endblock web_analytics_additional_providers %}

    The web analytics dimensions are being added to the django context using the WEB_ANALYTICS.DIMENSIONS dictionary. Because each dimension value could have multiple values, then each dictionary value is a list. Web analytics dimensions dictionary keys:

    • organizations_codes
    • course_code
    • course_runs_titles
    • course_runs_resource_links
    • page_title

    Example, if you only need the organization codes on your custom richie/web_analytics.html file:

    <script type="text/javascript">
    console.log("organization codes: '{{ WEB_ANALYTICS.DIMENSIONS.organizations_codes |join:" | " }}");
    </script>

    The frontend code also sends events to the web analytics provider. Richie sends events when the user is enrolled on a course run. To support different providers, you need to create a similar file -of src/frontend/js/utils/api/web-analytics/google_universal_analytics.ts and change the src/frontend/js/utils/api/web-analytics/index.ts file to include that newer provider.

    - - +of src/frontend/js/utils/api/web-analytics/google_universal_analytics.ts and change the src/frontend/js/utils/api/web-analytics/index.ts file to include that newer provider.

    + + \ No newline at end of file diff --git a/help/index.html b/help/index.html index e7775aa16e..fe9054687d 100644 --- a/help/index.html +++ b/help/index.html @@ -4,13 +4,13 @@ Richie - - + +
    -

    Need help?

    If your questions are not answered in the docs and various readmes, reach out to us through Github Issues or by email at fun.dev@fun-mooc.fr.

    We also have a regular video-chat meetup with the stakeholders of Richie, (some) Thursdays in the afternoon, UTC time. Reach out to us to know when the next one takes place and come introduce yourself!

    Browse Docs

    Learn more in the documentation. Please tell us if anything is missing or out-of-date.

    Stay up to date

    Keep up with the latest updates on Richie by reading the changelog.

    Join the community

    This project is maintained by a dedicated group of people led by the team at France Université Numérique.

    - - +

    Need help?

    If your questions are not answered in the docs and various readmes, reach out to us through Github Issues or by email at fun.dev@fun-mooc.fr.

    We also have a regular video-chat meetup with the stakeholders of Richie, (some) Thursdays in the afternoon, UTC time. Reach out to us to know when the next one takes place and come introduce yourself!

    Browse Docs

    Learn more in the documentation. Please tell us if anything is missing or out-of-date.

    Stay up to date

    Keep up with the latest updates on Richie by reading the changelog.

    Join the community

    This project is maintained by a dedicated group of people led by the team at France Université Numérique.

    + + \ No newline at end of file diff --git a/index.html b/index.html index fdeba8c9dd..a911570210 100644 --- a/index.html +++ b/index.html @@ -4,13 +4,13 @@ Richie - - + +
    -

    Richie helps educators create rich online learning portals

    A CMS for Open Education

    Richie helps educators create online learning portals.

    Build websites including online course catalogs in days with Richie's content management system.

    Get started

    Multilingual by Design

    From the ground up, Richie is localized and handles multilingual content.

    Built for Search

    Richie integrates a powerful course search engine with autosuggestion and advanced filtering options.

    Fully Customizable

    Personalize course catalogs by swapping colors and styles, or dive deep to customize the built-in search engine.

    Fully Open Source

    Built with Django CMS, Django, and React - everything is in the open. Richie is available under the MIT license.

    Users can modify and distribute documentation freely. Start contributing today.

    View code

    What Richie brings you

    An LMS-agnostic Education Portal

    Course catalogs can synchronize with one or more LMS instances running different software, such as Open edX or Moodle. Richie aggregates it all for your users.

    Author-first

    Content authors do not have to rely on software engineers to create and update all materials in Richie. Instead, authors use a rich editor interface to maintain content.

    Advanced Access Rights and Moderation

    Everything is managed through comprehensive access rights from CMS content structured objects like organizations, courses, and categories. Rights scale from individual users to enterprise-wide.

    A Multilingual Website

    Richie is available in more than one language, and you can add yours by talking to us. All the content can be added and managed in as many languages as you need. Richie is available in English, French, Spanish, and more. Want to add yours? Reach out! Richie supports content creation and management in as many languages as you need.

    An Extensible Platform

    Richie is a Django application with a NPM package. You can install it as a third-party app to build learning platforms.

    Join the Community

    Project stakeholders regularly check in through virtual meetups in English. Discussions take place in the #richie channel of the DjangoCMS Slack instance

    We encourage potential and new contributors to introduce themselves and get help.

    Who is Using Richie?

    France Université NumériqueNAUEDUlib
    View demo
    - - +

    Richie helps educators create rich online learning portals

    A CMS for Open Education

    Richie helps educators create online learning portals.

    Build websites including online course catalogs in days with Richie's content management system.

    Get started

    Multilingual by Design

    From the ground up, Richie is localized and handles multilingual content.

    Built for Search

    Richie integrates a powerful course search engine with autosuggestion and advanced filtering options.

    Fully Customizable

    Personalize course catalogs by swapping colors and styles, or dive deep to customize the built-in search engine.

    Fully Open Source

    Built with Django CMS, Django, and React - everything is in the open. Richie is available under the MIT license.

    Users can modify and distribute documentation freely. Start contributing today.

    View code

    What Richie brings you

    An LMS-agnostic Education Portal

    Course catalogs can synchronize with one or more LMS instances running different software, such as Open edX or Moodle. Richie aggregates it all for your users.

    Author-first

    Content authors do not have to rely on software engineers to create and update all materials in Richie. Instead, authors use a rich editor interface to maintain content.

    Advanced Access Rights and Moderation

    Everything is managed through comprehensive access rights from CMS content structured objects like organizations, courses, and categories. Rights scale from individual users to enterprise-wide.

    A Multilingual Website

    Richie is available in more than one language, and you can add yours by talking to us. All the content can be added and managed in as many languages as you need. Richie is available in English, French, Spanish, and more. Want to add yours? Reach out! Richie supports content creation and management in as many languages as you need.

    An Extensible Platform

    Richie is a Django application with a NPM package. You can install it as a third-party app to build learning platforms.

    Join the Community

    Project stakeholders regularly check in through virtual meetups in English. Discussions take place in the #richie channel of the DjangoCMS Slack instance

    We encourage potential and new contributors to introduce themselves and get help.

    Who is Using Richie?

    France Université NumériqueNAUEDUlib
    View demo
    + + \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml index d184486aad..507c5fd156 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1 +1 @@ -https://richie.education/helpweekly0.5https://richie.education/usersweekly0.5https://richie.education/versionsweekly0.5https://richie.education/docs/1.12/contributing-guideweekly0.5https://richie.education/docs/1.12/css-guidelinesweekly0.5https://richie.education/docs/1.12/discoverweekly0.5https://richie.education/docs/1.12/django-react-interopweekly0.5https://richie.education/docs/1.12/docker-developmentweekly0.5https://richie.education/docs/1.12/native-installationweekly0.5https://richie.education/docs/1.13/building-the-frontendweekly0.5https://richie.education/docs/1.13/contributing-guideweekly0.5https://richie.education/docs/1.13/css-guidelinesweekly0.5https://richie.education/docs/1.13/discoverweekly0.5https://richie.education/docs/1.13/django-react-interopweekly0.5https://richie.education/docs/1.13/docker-developmentweekly0.5https://richie.education/docs/1.13/native-installationweekly0.5https://richie.education/docs/1.14/building-the-frontendweekly0.5https://richie.education/docs/1.14/contributing-guideweekly0.5https://richie.education/docs/1.14/css-guidelinesweekly0.5https://richie.education/docs/1.14/discoverweekly0.5https://richie.education/docs/1.14/django-react-interopweekly0.5https://richie.education/docs/1.14/docker-developmentweekly0.5https://richie.education/docs/1.14/native-installationweekly0.5https://richie.education/docs/1.15/building-the-frontendweekly0.5https://richie.education/docs/1.15/contributing-guideweekly0.5https://richie.education/docs/1.15/css-guidelinesweekly0.5https://richie.education/docs/1.15/discoverweekly0.5https://richie.education/docs/1.15/django-react-interopweekly0.5https://richie.education/docs/1.15/docker-developmentweekly0.5https://richie.education/docs/1.15/native-installationweekly0.5https://richie.education/docs/1.16/accessibility-testingweekly0.5https://richie.education/docs/1.16/building-the-frontendweekly0.5https://richie.education/docs/1.16/contributing-guideweekly0.5https://richie.education/docs/1.16/css-guidelinesweekly0.5https://richie.education/docs/1.16/discoverweekly0.5https://richie.education/docs/1.16/django-react-interopweekly0.5https://richie.education/docs/1.16/docker-developmentweekly0.5https://richie.education/docs/1.16/native-installationweekly0.5https://richie.education/docs/1.17/accessibility-testingweekly0.5https://richie.education/docs/1.17/building-the-frontendweekly0.5https://richie.education/docs/1.17/contributing-guideweekly0.5https://richie.education/docs/1.17/css-guidelinesweekly0.5https://richie.education/docs/1.17/discoverweekly0.5https://richie.education/docs/1.17/django-react-interopweekly0.5https://richie.education/docs/1.17/docker-developmentweekly0.5https://richie.education/docs/1.17/native-installationweekly0.5https://richie.education/docs/2.0.0/accessibility-testingweekly0.5https://richie.education/docs/2.0.0/building-the-frontendweekly0.5https://richie.education/docs/2.0.0/contributing-guideweekly0.5https://richie.education/docs/2.0.0/css-guidelinesweekly0.5https://richie.education/docs/2.0.0/discoverweekly0.5https://richie.education/docs/2.0.0/django-react-interopweekly0.5https://richie.education/docs/2.0.0/docker-developmentweekly0.5https://richie.education/docs/2.0.0/frontend-overridesweekly0.5https://richie.education/docs/2.0.0/lms-connectionweekly0.5https://richie.education/docs/2.0.0/native-installationweekly0.5https://richie.education/docs/2.0.1/accessibility-testingweekly0.5https://richie.education/docs/2.0.1/building-the-frontendweekly0.5https://richie.education/docs/2.0.1/contributing-guideweekly0.5https://richie.education/docs/2.0.1/css-guidelinesweekly0.5https://richie.education/docs/2.0.1/discoverweekly0.5https://richie.education/docs/2.0.1/django-react-interopweekly0.5https://richie.education/docs/2.0.1/docker-developmentweekly0.5https://richie.education/docs/2.0.1/frontend-overridesweekly0.5https://richie.education/docs/2.0.1/lms-connectionweekly0.5https://richie.education/docs/2.0.1/native-installationweekly0.5https://richie.education/docs/2.1.0/accessibility-testingweekly0.5https://richie.education/docs/2.1.0/building-the-frontendweekly0.5https://richie.education/docs/2.1.0/contributing-guideweekly0.5https://richie.education/docs/2.1.0/css-guidelinesweekly0.5https://richie.education/docs/2.1.0/discoverweekly0.5https://richie.education/docs/2.1.0/django-react-interopweekly0.5https://richie.education/docs/2.1.0/docker-developmentweekly0.5https://richie.education/docs/2.1.0/frontend-overridesweekly0.5https://richie.education/docs/2.1.0/lms-connectionweekly0.5https://richie.education/docs/2.1.0/native-installationweekly0.5https://richie.education/docs/2.10.0/accessibility-testingweekly0.5https://richie.education/docs/2.10.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.10.0/building-the-frontendweekly0.5https://richie.education/docs/2.10.0/contributing-guideweekly0.5https://richie.education/docs/2.10.0/css-guidelinesweekly0.5https://richie.education/docs/2.10.0/discoverweekly0.5https://richie.education/docs/2.10.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.10.0/django-react-interopweekly0.5https://richie.education/docs/2.10.0/docker-developmentweekly0.5https://richie.education/docs/2.10.0/frontend-overridesweekly0.5https://richie.education/docs/2.10.0/internationalizationweekly0.5https://richie.education/docs/2.10.0/lms-backendsweekly0.5https://richie.education/docs/2.10.0/lms-connectionweekly0.5https://richie.education/docs/2.10.0/native-installationweekly0.5https://richie.education/docs/2.10.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.10.0/tls-connectionweekly0.5https://richie.education/docs/2.10.0/web-analyticsweekly0.5https://richie.education/docs/2.11.0/accessibility-testingweekly0.5https://richie.education/docs/2.11.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.11.0/building-the-frontendweekly0.5https://richie.education/docs/2.11.0/contributing-guideweekly0.5https://richie.education/docs/2.11.0/css-guidelinesweekly0.5https://richie.education/docs/2.11.0/discoverweekly0.5https://richie.education/docs/2.11.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.11.0/django-react-interopweekly0.5https://richie.education/docs/2.11.0/docker-developmentweekly0.5https://richie.education/docs/2.11.0/frontend-overridesweekly0.5https://richie.education/docs/2.11.0/internationalizationweekly0.5https://richie.education/docs/2.11.0/lms-backendsweekly0.5https://richie.education/docs/2.11.0/lms-connectionweekly0.5https://richie.education/docs/2.11.0/native-installationweekly0.5https://richie.education/docs/2.11.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.11.0/tls-connectionweekly0.5https://richie.education/docs/2.11.0/web-analyticsweekly0.5https://richie.education/docs/2.12.0/accessibility-testingweekly0.5https://richie.education/docs/2.12.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.12.0/building-the-frontendweekly0.5https://richie.education/docs/2.12.0/contributing-guideweekly0.5https://richie.education/docs/2.12.0/css-guidelinesweekly0.5https://richie.education/docs/2.12.0/discoverweekly0.5https://richie.education/docs/2.12.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.12.0/django-react-interopweekly0.5https://richie.education/docs/2.12.0/docker-developmentweekly0.5https://richie.education/docs/2.12.0/frontend-overridesweekly0.5https://richie.education/docs/2.12.0/internationalizationweekly0.5https://richie.education/docs/2.12.0/lms-backendsweekly0.5https://richie.education/docs/2.12.0/lms-connectionweekly0.5https://richie.education/docs/2.12.0/native-installationweekly0.5https://richie.education/docs/2.12.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.12.0/tls-connectionweekly0.5https://richie.education/docs/2.12.0/web-analyticsweekly0.5https://richie.education/docs/2.13.0/accessibility-testingweekly0.5https://richie.education/docs/2.13.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.13.0/building-the-frontendweekly0.5https://richie.education/docs/2.13.0/contributing-guideweekly0.5https://richie.education/docs/2.13.0/css-guidelinesweekly0.5https://richie.education/docs/2.13.0/discoverweekly0.5https://richie.education/docs/2.13.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.13.0/django-react-interopweekly0.5https://richie.education/docs/2.13.0/docker-developmentweekly0.5https://richie.education/docs/2.13.0/frontend-overridesweekly0.5https://richie.education/docs/2.13.0/internationalizationweekly0.5https://richie.education/docs/2.13.0/lms-backendsweekly0.5https://richie.education/docs/2.13.0/lms-connectionweekly0.5https://richie.education/docs/2.13.0/native-installationweekly0.5https://richie.education/docs/2.13.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.13.0/tls-connectionweekly0.5https://richie.education/docs/2.13.0/web-analyticsweekly0.5https://richie.education/docs/2.14.0/accessibility-testingweekly0.5https://richie.education/docs/2.14.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.14.0/building-the-frontendweekly0.5https://richie.education/docs/2.14.0/contributing-guideweekly0.5https://richie.education/docs/2.14.0/css-guidelinesweekly0.5https://richie.education/docs/2.14.0/discoverweekly0.5https://richie.education/docs/2.14.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.14.0/django-react-interopweekly0.5https://richie.education/docs/2.14.0/docker-developmentweekly0.5https://richie.education/docs/2.14.0/frontend-overridesweekly0.5https://richie.education/docs/2.14.0/internationalizationweekly0.5https://richie.education/docs/2.14.0/lms-backendsweekly0.5https://richie.education/docs/2.14.0/lms-connectionweekly0.5https://richie.education/docs/2.14.0/native-installationweekly0.5https://richie.education/docs/2.14.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.14.0/tls-connectionweekly0.5https://richie.education/docs/2.14.0/web-analyticsweekly0.5https://richie.education/docs/2.14.1/accessibility-testingweekly0.5https://richie.education/docs/2.14.1/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.14.1/building-the-frontendweekly0.5https://richie.education/docs/2.14.1/contributing-guideweekly0.5https://richie.education/docs/2.14.1/cookiecutterweekly0.5https://richie.education/docs/2.14.1/css-guidelinesweekly0.5https://richie.education/docs/2.14.1/discoverweekly0.5https://richie.education/docs/2.14.1/displaying-connection-statusweekly0.5https://richie.education/docs/2.14.1/django-react-interopweekly0.5https://richie.education/docs/2.14.1/docker-developmentweekly0.5https://richie.education/docs/2.14.1/frontend-overridesweekly0.5https://richie.education/docs/2.14.1/installationweekly0.5https://richie.education/docs/2.14.1/internationalizationweekly0.5https://richie.education/docs/2.14.1/joanie-connectionweekly0.5https://richie.education/docs/2.14.1/lms-backendsweekly0.5https://richie.education/docs/2.14.1/lms-connectionweekly0.5https://richie.education/docs/2.14.1/native-installationweekly0.5https://richie.education/docs/2.14.1/synchronizing-course-runsweekly0.5https://richie.education/docs/2.14.1/tls-connectionweekly0.5https://richie.education/docs/2.14.1/web-analyticsweekly0.5https://richie.education/docs/2.15.0/accessibility-testingweekly0.5https://richie.education/docs/2.15.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.15.0/building-the-frontendweekly0.5https://richie.education/docs/2.15.0/contributing-guideweekly0.5https://richie.education/docs/2.15.0/cookiecutterweekly0.5https://richie.education/docs/2.15.0/css-guidelinesweekly0.5https://richie.education/docs/2.15.0/discoverweekly0.5https://richie.education/docs/2.15.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.15.0/django-react-interopweekly0.5https://richie.education/docs/2.15.0/docker-developmentweekly0.5https://richie.education/docs/2.15.0/frontend-overridesweekly0.5https://richie.education/docs/2.15.0/installationweekly0.5https://richie.education/docs/2.15.0/internationalizationweekly0.5https://richie.education/docs/2.15.0/joanie-connectionweekly0.5https://richie.education/docs/2.15.0/lms-backendsweekly0.5https://richie.education/docs/2.15.0/lms-connectionweekly0.5https://richie.education/docs/2.15.0/native-installationweekly0.5https://richie.education/docs/2.15.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.15.0/tls-connectionweekly0.5https://richie.education/docs/2.15.0/web-analyticsweekly0.5https://richie.education/docs/2.15.1/accessibility-testingweekly0.5https://richie.education/docs/2.15.1/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.15.1/building-the-frontendweekly0.5https://richie.education/docs/2.15.1/contributing-guideweekly0.5https://richie.education/docs/2.15.1/cookiecutterweekly0.5https://richie.education/docs/2.15.1/css-guidelinesweekly0.5https://richie.education/docs/2.15.1/discoverweekly0.5https://richie.education/docs/2.15.1/displaying-connection-statusweekly0.5https://richie.education/docs/2.15.1/django-react-interopweekly0.5https://richie.education/docs/2.15.1/docker-developmentweekly0.5https://richie.education/docs/2.15.1/frontend-overridesweekly0.5https://richie.education/docs/2.15.1/installationweekly0.5https://richie.education/docs/2.15.1/internationalizationweekly0.5https://richie.education/docs/2.15.1/joanie-connectionweekly0.5https://richie.education/docs/2.15.1/lms-backendsweekly0.5https://richie.education/docs/2.15.1/lms-connectionweekly0.5https://richie.education/docs/2.15.1/native-installationweekly0.5https://richie.education/docs/2.15.1/synchronizing-course-runsweekly0.5https://richie.education/docs/2.15.1/tls-connectionweekly0.5https://richie.education/docs/2.15.1/web-analyticsweekly0.5https://richie.education/docs/2.16.0/accessibility-testingweekly0.5https://richie.education/docs/2.16.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.16.0/building-the-frontendweekly0.5https://richie.education/docs/2.16.0/contributing-guideweekly0.5https://richie.education/docs/2.16.0/cookiecutterweekly0.5https://richie.education/docs/2.16.0/css-guidelinesweekly0.5https://richie.education/docs/2.16.0/discoverweekly0.5https://richie.education/docs/2.16.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.16.0/django-react-interopweekly0.5https://richie.education/docs/2.16.0/docker-developmentweekly0.5https://richie.education/docs/2.16.0/frontend-overridesweekly0.5https://richie.education/docs/2.16.0/installationweekly0.5https://richie.education/docs/2.16.0/internationalizationweekly0.5https://richie.education/docs/2.16.0/joanie-connectionweekly0.5https://richie.education/docs/2.16.0/lms-backendsweekly0.5https://richie.education/docs/2.16.0/lms-connectionweekly0.5https://richie.education/docs/2.16.0/native-installationweekly0.5https://richie.education/docs/2.16.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.16.0/tls-connectionweekly0.5https://richie.education/docs/2.16.0/web-analyticsweekly0.5https://richie.education/docs/2.17.0/accessibility-testingweekly0.5https://richie.education/docs/2.17.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.17.0/building-the-frontendweekly0.5https://richie.education/docs/2.17.0/contributing-guideweekly0.5https://richie.education/docs/2.17.0/cookiecutterweekly0.5https://richie.education/docs/2.17.0/css-guidelinesweekly0.5https://richie.education/docs/2.17.0/discoverweekly0.5https://richie.education/docs/2.17.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.17.0/django-react-interopweekly0.5https://richie.education/docs/2.17.0/docker-developmentweekly0.5https://richie.education/docs/2.17.0/filters-customizationweekly0.5https://richie.education/docs/2.17.0/frontend-overridesweekly0.5https://richie.education/docs/2.17.0/installationweekly0.5https://richie.education/docs/2.17.0/internationalizationweekly0.5https://richie.education/docs/2.17.0/joanie-connectionweekly0.5https://richie.education/docs/2.17.0/lms-backendsweekly0.5https://richie.education/docs/2.17.0/lms-connectionweekly0.5https://richie.education/docs/2.17.0/native-installationweekly0.5https://richie.education/docs/2.17.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.17.0/tls-connectionweekly0.5https://richie.education/docs/2.17.0/web-analyticsweekly0.5https://richie.education/docs/2.18.0/accessibility-testingweekly0.5https://richie.education/docs/2.18.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.18.0/building-the-frontendweekly0.5https://richie.education/docs/2.18.0/contributing-guideweekly0.5https://richie.education/docs/2.18.0/cookiecutterweekly0.5https://richie.education/docs/2.18.0/css-guidelinesweekly0.5https://richie.education/docs/2.18.0/discoverweekly0.5https://richie.education/docs/2.18.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.18.0/django-react-interopweekly0.5https://richie.education/docs/2.18.0/docker-developmentweekly0.5https://richie.education/docs/2.18.0/filters-customizationweekly0.5https://richie.education/docs/2.18.0/frontend-overridesweekly0.5https://richie.education/docs/2.18.0/installationweekly0.5https://richie.education/docs/2.18.0/internationalizationweekly0.5https://richie.education/docs/2.18.0/joanie-connectionweekly0.5https://richie.education/docs/2.18.0/lms-backendsweekly0.5https://richie.education/docs/2.18.0/lms-connectionweekly0.5https://richie.education/docs/2.18.0/native-installationweekly0.5https://richie.education/docs/2.18.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.18.0/tls-connectionweekly0.5https://richie.education/docs/2.18.0/web-analyticsweekly0.5https://richie.education/docs/2.19.0/accessibility-testingweekly0.5https://richie.education/docs/2.19.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.19.0/building-the-frontendweekly0.5https://richie.education/docs/2.19.0/contributing-guideweekly0.5https://richie.education/docs/2.19.0/cookiecutterweekly0.5https://richie.education/docs/2.19.0/css-guidelinesweekly0.5https://richie.education/docs/2.19.0/discoverweekly0.5https://richie.education/docs/2.19.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.19.0/django-react-interopweekly0.5https://richie.education/docs/2.19.0/docker-developmentweekly0.5https://richie.education/docs/2.19.0/filters-customizationweekly0.5https://richie.education/docs/2.19.0/frontend-overridesweekly0.5https://richie.education/docs/2.19.0/installationweekly0.5https://richie.education/docs/2.19.0/internationalizationweekly0.5https://richie.education/docs/2.19.0/joanie-connectionweekly0.5https://richie.education/docs/2.19.0/lms-backendsweekly0.5https://richie.education/docs/2.19.0/lms-connectionweekly0.5https://richie.education/docs/2.19.0/native-installationweekly0.5https://richie.education/docs/2.19.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.19.0/tls-connectionweekly0.5https://richie.education/docs/2.19.0/web-analyticsweekly0.5https://richie.education/docs/2.2.0/accessibility-testingweekly0.5https://richie.education/docs/2.2.0/building-the-frontendweekly0.5https://richie.education/docs/2.2.0/contributing-guideweekly0.5https://richie.education/docs/2.2.0/css-guidelinesweekly0.5https://richie.education/docs/2.2.0/discoverweekly0.5https://richie.education/docs/2.2.0/django-react-interopweekly0.5https://richie.education/docs/2.2.0/docker-developmentweekly0.5https://richie.education/docs/2.2.0/frontend-overridesweekly0.5https://richie.education/docs/2.2.0/internationalizationweekly0.5https://richie.education/docs/2.2.0/lms-connectionweekly0.5https://richie.education/docs/2.2.0/native-installationweekly0.5https://richie.education/docs/2.20.0/accessibility-testingweekly0.5https://richie.education/docs/2.20.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.20.0/building-the-frontendweekly0.5https://richie.education/docs/2.20.0/contributing-guideweekly0.5https://richie.education/docs/2.20.0/cookiecutterweekly0.5https://richie.education/docs/2.20.0/css-guidelinesweekly0.5https://richie.education/docs/2.20.0/discoverweekly0.5https://richie.education/docs/2.20.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.20.0/django-react-interopweekly0.5https://richie.education/docs/2.20.0/docker-developmentweekly0.5https://richie.education/docs/2.20.0/filters-customizationweekly0.5https://richie.education/docs/2.20.0/frontend-overridesweekly0.5https://richie.education/docs/2.20.0/installationweekly0.5https://richie.education/docs/2.20.0/internationalizationweekly0.5https://richie.education/docs/2.20.0/joanie-connectionweekly0.5https://richie.education/docs/2.20.0/lms-backendsweekly0.5https://richie.education/docs/2.20.0/lms-connectionweekly0.5https://richie.education/docs/2.20.0/native-installationweekly0.5https://richie.education/docs/2.20.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.20.0/tls-connectionweekly0.5https://richie.education/docs/2.20.0/web-analyticsweekly0.5https://richie.education/docs/2.20.1/accessibility-testingweekly0.5https://richie.education/docs/2.20.1/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.20.1/building-the-frontendweekly0.5https://richie.education/docs/2.20.1/contributing-guideweekly0.5https://richie.education/docs/2.20.1/cookiecutterweekly0.5https://richie.education/docs/2.20.1/css-guidelinesweekly0.5https://richie.education/docs/2.20.1/discoverweekly0.5https://richie.education/docs/2.20.1/displaying-connection-statusweekly0.5https://richie.education/docs/2.20.1/django-react-interopweekly0.5https://richie.education/docs/2.20.1/docker-developmentweekly0.5https://richie.education/docs/2.20.1/filters-customizationweekly0.5https://richie.education/docs/2.20.1/frontend-overridesweekly0.5https://richie.education/docs/2.20.1/installationweekly0.5https://richie.education/docs/2.20.1/internationalizationweekly0.5https://richie.education/docs/2.20.1/joanie-connectionweekly0.5https://richie.education/docs/2.20.1/lms-backendsweekly0.5https://richie.education/docs/2.20.1/lms-connectionweekly0.5https://richie.education/docs/2.20.1/native-installationweekly0.5https://richie.education/docs/2.20.1/synchronizing-course-runsweekly0.5https://richie.education/docs/2.20.1/tls-connectionweekly0.5https://richie.education/docs/2.20.1/web-analyticsweekly0.5https://richie.education/docs/2.3.0/accessibility-testingweekly0.5https://richie.education/docs/2.3.0/building-the-frontendweekly0.5https://richie.education/docs/2.3.0/contributing-guideweekly0.5https://richie.education/docs/2.3.0/css-guidelinesweekly0.5https://richie.education/docs/2.3.0/discoverweekly0.5https://richie.education/docs/2.3.0/django-react-interopweekly0.5https://richie.education/docs/2.3.0/docker-developmentweekly0.5https://richie.education/docs/2.3.0/frontend-overridesweekly0.5https://richie.education/docs/2.3.0/internationalizationweekly0.5https://richie.education/docs/2.3.0/lms-connectionweekly0.5https://richie.education/docs/2.3.0/native-installationweekly0.5https://richie.education/docs/2.3.1/accessibility-testingweekly0.5https://richie.education/docs/2.3.1/building-the-frontendweekly0.5https://richie.education/docs/2.3.1/contributing-guideweekly0.5https://richie.education/docs/2.3.1/css-guidelinesweekly0.5https://richie.education/docs/2.3.1/discoverweekly0.5https://richie.education/docs/2.3.1/django-react-interopweekly0.5https://richie.education/docs/2.3.1/docker-developmentweekly0.5https://richie.education/docs/2.3.1/frontend-overridesweekly0.5https://richie.education/docs/2.3.1/internationalizationweekly0.5https://richie.education/docs/2.3.1/lms-connectionweekly0.5https://richie.education/docs/2.3.1/native-installationweekly0.5https://richie.education/docs/2.3.2/accessibility-testingweekly0.5https://richie.education/docs/2.3.2/building-the-frontendweekly0.5https://richie.education/docs/2.3.2/contributing-guideweekly0.5https://richie.education/docs/2.3.2/css-guidelinesweekly0.5https://richie.education/docs/2.3.2/discoverweekly0.5https://richie.education/docs/2.3.2/django-react-interopweekly0.5https://richie.education/docs/2.3.2/docker-developmentweekly0.5https://richie.education/docs/2.3.2/frontend-overridesweekly0.5https://richie.education/docs/2.3.2/internationalizationweekly0.5https://richie.education/docs/2.3.2/lms-connectionweekly0.5https://richie.education/docs/2.3.2/native-installationweekly0.5https://richie.education/docs/2.3.3/accessibility-testingweekly0.5https://richie.education/docs/2.3.3/building-the-frontendweekly0.5https://richie.education/docs/2.3.3/contributing-guideweekly0.5https://richie.education/docs/2.3.3/css-guidelinesweekly0.5https://richie.education/docs/2.3.3/discoverweekly0.5https://richie.education/docs/2.3.3/django-react-interopweekly0.5https://richie.education/docs/2.3.3/docker-developmentweekly0.5https://richie.education/docs/2.3.3/frontend-overridesweekly0.5https://richie.education/docs/2.3.3/internationalizationweekly0.5https://richie.education/docs/2.3.3/lms-connectionweekly0.5https://richie.education/docs/2.3.3/native-installationweekly0.5https://richie.education/docs/2.4.0/accessibility-testingweekly0.5https://richie.education/docs/2.4.0/building-the-frontendweekly0.5https://richie.education/docs/2.4.0/contributing-guideweekly0.5https://richie.education/docs/2.4.0/css-guidelinesweekly0.5https://richie.education/docs/2.4.0/discoverweekly0.5https://richie.education/docs/2.4.0/django-react-interopweekly0.5https://richie.education/docs/2.4.0/docker-developmentweekly0.5https://richie.education/docs/2.4.0/frontend-overridesweekly0.5https://richie.education/docs/2.4.0/internationalizationweekly0.5https://richie.education/docs/2.4.0/lms-connectionweekly0.5https://richie.education/docs/2.4.0/native-installationweekly0.5https://richie.education/docs/2.5.0/accessibility-testingweekly0.5https://richie.education/docs/2.5.0/building-the-frontendweekly0.5https://richie.education/docs/2.5.0/contributing-guideweekly0.5https://richie.education/docs/2.5.0/css-guidelinesweekly0.5https://richie.education/docs/2.5.0/discoverweekly0.5https://richie.education/docs/2.5.0/django-react-interopweekly0.5https://richie.education/docs/2.5.0/docker-developmentweekly0.5https://richie.education/docs/2.5.0/frontend-overridesweekly0.5https://richie.education/docs/2.5.0/internationalizationweekly0.5https://richie.education/docs/2.5.0/lms-connectionweekly0.5https://richie.education/docs/2.5.0/native-installationweekly0.5https://richie.education/docs/2.6.0/accessibility-testingweekly0.5https://richie.education/docs/2.6.0/building-the-frontendweekly0.5https://richie.education/docs/2.6.0/contributing-guideweekly0.5https://richie.education/docs/2.6.0/css-guidelinesweekly0.5https://richie.education/docs/2.6.0/discoverweekly0.5https://richie.education/docs/2.6.0/django-react-interopweekly0.5https://richie.education/docs/2.6.0/docker-developmentweekly0.5https://richie.education/docs/2.6.0/frontend-overridesweekly0.5https://richie.education/docs/2.6.0/internationalizationweekly0.5https://richie.education/docs/2.6.0/lms-connectionweekly0.5https://richie.education/docs/2.6.0/native-installationweekly0.5https://richie.education/docs/2.7.0/accessibility-testingweekly0.5https://richie.education/docs/2.7.0/building-the-frontendweekly0.5https://richie.education/docs/2.7.0/contributing-guideweekly0.5https://richie.education/docs/2.7.0/css-guidelinesweekly0.5https://richie.education/docs/2.7.0/discoverweekly0.5https://richie.education/docs/2.7.0/django-react-interopweekly0.5https://richie.education/docs/2.7.0/docker-developmentweekly0.5https://richie.education/docs/2.7.0/frontend-overridesweekly0.5https://richie.education/docs/2.7.0/internationalizationweekly0.5https://richie.education/docs/2.7.0/lms-connectionweekly0.5https://richie.education/docs/2.7.0/native-installationweekly0.5https://richie.education/docs/2.7.1/accessibility-testingweekly0.5https://richie.education/docs/2.7.1/building-the-frontendweekly0.5https://richie.education/docs/2.7.1/contributing-guideweekly0.5https://richie.education/docs/2.7.1/css-guidelinesweekly0.5https://richie.education/docs/2.7.1/discoverweekly0.5https://richie.education/docs/2.7.1/django-react-interopweekly0.5https://richie.education/docs/2.7.1/docker-developmentweekly0.5https://richie.education/docs/2.7.1/frontend-overridesweekly0.5https://richie.education/docs/2.7.1/internationalizationweekly0.5https://richie.education/docs/2.7.1/lms-connectionweekly0.5https://richie.education/docs/2.7.1/native-installationweekly0.5https://richie.education/docs/2.8.0/accessibility-testingweekly0.5https://richie.education/docs/2.8.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.8.0/building-the-frontendweekly0.5https://richie.education/docs/2.8.0/contributing-guideweekly0.5https://richie.education/docs/2.8.0/css-guidelinesweekly0.5https://richie.education/docs/2.8.0/discoverweekly0.5https://richie.education/docs/2.8.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.8.0/django-react-interopweekly0.5https://richie.education/docs/2.8.0/docker-developmentweekly0.5https://richie.education/docs/2.8.0/frontend-overridesweekly0.5https://richie.education/docs/2.8.0/internationalizationweekly0.5https://richie.education/docs/2.8.0/lms-backendsweekly0.5https://richie.education/docs/2.8.0/lms-connectionweekly0.5https://richie.education/docs/2.8.0/native-installationweekly0.5https://richie.education/docs/2.8.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.8.0/tls-connectionweekly0.5https://richie.education/docs/2.8.0/web-analyticsweekly0.5https://richie.education/docs/2.8.1/accessibility-testingweekly0.5https://richie.education/docs/2.8.1/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.8.1/building-the-frontendweekly0.5https://richie.education/docs/2.8.1/contributing-guideweekly0.5https://richie.education/docs/2.8.1/css-guidelinesweekly0.5https://richie.education/docs/2.8.1/discoverweekly0.5https://richie.education/docs/2.8.1/displaying-connection-statusweekly0.5https://richie.education/docs/2.8.1/django-react-interopweekly0.5https://richie.education/docs/2.8.1/docker-developmentweekly0.5https://richie.education/docs/2.8.1/frontend-overridesweekly0.5https://richie.education/docs/2.8.1/internationalizationweekly0.5https://richie.education/docs/2.8.1/lms-backendsweekly0.5https://richie.education/docs/2.8.1/lms-connectionweekly0.5https://richie.education/docs/2.8.1/native-installationweekly0.5https://richie.education/docs/2.8.1/synchronizing-course-runsweekly0.5https://richie.education/docs/2.8.1/tls-connectionweekly0.5https://richie.education/docs/2.8.1/web-analyticsweekly0.5https://richie.education/docs/2.8.2/accessibility-testingweekly0.5https://richie.education/docs/2.8.2/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.8.2/building-the-frontendweekly0.5https://richie.education/docs/2.8.2/contributing-guideweekly0.5https://richie.education/docs/2.8.2/css-guidelinesweekly0.5https://richie.education/docs/2.8.2/discoverweekly0.5https://richie.education/docs/2.8.2/displaying-connection-statusweekly0.5https://richie.education/docs/2.8.2/django-react-interopweekly0.5https://richie.education/docs/2.8.2/docker-developmentweekly0.5https://richie.education/docs/2.8.2/frontend-overridesweekly0.5https://richie.education/docs/2.8.2/internationalizationweekly0.5https://richie.education/docs/2.8.2/lms-backendsweekly0.5https://richie.education/docs/2.8.2/lms-connectionweekly0.5https://richie.education/docs/2.8.2/native-installationweekly0.5https://richie.education/docs/2.8.2/synchronizing-course-runsweekly0.5https://richie.education/docs/2.8.2/tls-connectionweekly0.5https://richie.education/docs/2.8.2/web-analyticsweekly0.5https://richie.education/docs/2.9.0/accessibility-testingweekly0.5https://richie.education/docs/2.9.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.9.0/building-the-frontendweekly0.5https://richie.education/docs/2.9.0/contributing-guideweekly0.5https://richie.education/docs/2.9.0/css-guidelinesweekly0.5https://richie.education/docs/2.9.0/discoverweekly0.5https://richie.education/docs/2.9.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.9.0/django-react-interopweekly0.5https://richie.education/docs/2.9.0/docker-developmentweekly0.5https://richie.education/docs/2.9.0/frontend-overridesweekly0.5https://richie.education/docs/2.9.0/internationalizationweekly0.5https://richie.education/docs/2.9.0/lms-backendsweekly0.5https://richie.education/docs/2.9.0/lms-connectionweekly0.5https://richie.education/docs/2.9.0/native-installationweekly0.5https://richie.education/docs/2.9.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.9.0/tls-connectionweekly0.5https://richie.education/docs/2.9.0/web-analyticsweekly0.5https://richie.education/docs/2.9.1/accessibility-testingweekly0.5https://richie.education/docs/2.9.1/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.9.1/building-the-frontendweekly0.5https://richie.education/docs/2.9.1/contributing-guideweekly0.5https://richie.education/docs/2.9.1/css-guidelinesweekly0.5https://richie.education/docs/2.9.1/discoverweekly0.5https://richie.education/docs/2.9.1/displaying-connection-statusweekly0.5https://richie.education/docs/2.9.1/django-react-interopweekly0.5https://richie.education/docs/2.9.1/docker-developmentweekly0.5https://richie.education/docs/2.9.1/frontend-overridesweekly0.5https://richie.education/docs/2.9.1/internationalizationweekly0.5https://richie.education/docs/2.9.1/lms-backendsweekly0.5https://richie.education/docs/2.9.1/lms-connectionweekly0.5https://richie.education/docs/2.9.1/native-installationweekly0.5https://richie.education/docs/2.9.1/synchronizing-course-runsweekly0.5https://richie.education/docs/2.9.1/tls-connectionweekly0.5https://richie.education/docs/2.9.1/web-analyticsweekly0.5https://richie.education/docs/next/accessibility-testingweekly0.5https://richie.education/docs/next/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/next/building-the-frontendweekly0.5https://richie.education/docs/next/contributing-guideweekly0.5https://richie.education/docs/next/cookiecutterweekly0.5https://richie.education/docs/next/css-guidelinesweekly0.5https://richie.education/docs/next/discoverweekly0.5https://richie.education/docs/next/displaying-connection-statusweekly0.5https://richie.education/docs/next/django-react-interopweekly0.5https://richie.education/docs/next/docker-developmentweekly0.5https://richie.education/docs/next/filters-customizationweekly0.5https://richie.education/docs/next/frontend-overridesweekly0.5https://richie.education/docs/next/installationweekly0.5https://richie.education/docs/next/internationalizationweekly0.5https://richie.education/docs/next/joanie-connectionweekly0.5https://richie.education/docs/next/lms-backendsweekly0.5https://richie.education/docs/next/lms-connectionweekly0.5https://richie.education/docs/next/native-installationweekly0.5https://richie.education/docs/next/synchronizing-course-runsweekly0.5https://richie.education/docs/next/tls-connectionweekly0.5https://richie.education/docs/next/web-analyticsweekly0.5https://richie.education/docs/accessibility-testingweekly0.5https://richie.education/docs/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/building-the-frontendweekly0.5https://richie.education/docs/contributing-guideweekly0.5https://richie.education/docs/cookiecutterweekly0.5https://richie.education/docs/css-guidelinesweekly0.5https://richie.education/docs/discoverweekly0.5https://richie.education/docs/displaying-connection-statusweekly0.5https://richie.education/docs/django-react-interopweekly0.5https://richie.education/docs/docker-developmentweekly0.5https://richie.education/docs/filters-customizationweekly0.5https://richie.education/docs/frontend-overridesweekly0.5https://richie.education/docs/installationweekly0.5https://richie.education/docs/internationalizationweekly0.5https://richie.education/docs/joanie-connectionweekly0.5https://richie.education/docs/lms-backendsweekly0.5https://richie.education/docs/lms-connectionweekly0.5https://richie.education/docs/native-installationweekly0.5https://richie.education/docs/synchronizing-course-runsweekly0.5https://richie.education/docs/tls-connectionweekly0.5https://richie.education/docs/web-analyticsweekly0.5https://richie.education/weekly0.5 \ No newline at end of file +https://richie.education/helpweekly0.5https://richie.education/usersweekly0.5https://richie.education/versionsweekly0.5https://richie.education/docs/1.12/contributing-guideweekly0.5https://richie.education/docs/1.12/css-guidelinesweekly0.5https://richie.education/docs/1.12/discoverweekly0.5https://richie.education/docs/1.12/django-react-interopweekly0.5https://richie.education/docs/1.12/docker-developmentweekly0.5https://richie.education/docs/1.12/native-installationweekly0.5https://richie.education/docs/1.13/building-the-frontendweekly0.5https://richie.education/docs/1.13/contributing-guideweekly0.5https://richie.education/docs/1.13/css-guidelinesweekly0.5https://richie.education/docs/1.13/discoverweekly0.5https://richie.education/docs/1.13/django-react-interopweekly0.5https://richie.education/docs/1.13/docker-developmentweekly0.5https://richie.education/docs/1.13/native-installationweekly0.5https://richie.education/docs/1.14/building-the-frontendweekly0.5https://richie.education/docs/1.14/contributing-guideweekly0.5https://richie.education/docs/1.14/css-guidelinesweekly0.5https://richie.education/docs/1.14/discoverweekly0.5https://richie.education/docs/1.14/django-react-interopweekly0.5https://richie.education/docs/1.14/docker-developmentweekly0.5https://richie.education/docs/1.14/native-installationweekly0.5https://richie.education/docs/1.15/building-the-frontendweekly0.5https://richie.education/docs/1.15/contributing-guideweekly0.5https://richie.education/docs/1.15/css-guidelinesweekly0.5https://richie.education/docs/1.15/discoverweekly0.5https://richie.education/docs/1.15/django-react-interopweekly0.5https://richie.education/docs/1.15/docker-developmentweekly0.5https://richie.education/docs/1.15/native-installationweekly0.5https://richie.education/docs/1.16/accessibility-testingweekly0.5https://richie.education/docs/1.16/building-the-frontendweekly0.5https://richie.education/docs/1.16/contributing-guideweekly0.5https://richie.education/docs/1.16/css-guidelinesweekly0.5https://richie.education/docs/1.16/discoverweekly0.5https://richie.education/docs/1.16/django-react-interopweekly0.5https://richie.education/docs/1.16/docker-developmentweekly0.5https://richie.education/docs/1.16/native-installationweekly0.5https://richie.education/docs/1.17/accessibility-testingweekly0.5https://richie.education/docs/1.17/building-the-frontendweekly0.5https://richie.education/docs/1.17/contributing-guideweekly0.5https://richie.education/docs/1.17/css-guidelinesweekly0.5https://richie.education/docs/1.17/discoverweekly0.5https://richie.education/docs/1.17/django-react-interopweekly0.5https://richie.education/docs/1.17/docker-developmentweekly0.5https://richie.education/docs/1.17/native-installationweekly0.5https://richie.education/docs/2.0.0/accessibility-testingweekly0.5https://richie.education/docs/2.0.0/building-the-frontendweekly0.5https://richie.education/docs/2.0.0/contributing-guideweekly0.5https://richie.education/docs/2.0.0/css-guidelinesweekly0.5https://richie.education/docs/2.0.0/discoverweekly0.5https://richie.education/docs/2.0.0/django-react-interopweekly0.5https://richie.education/docs/2.0.0/docker-developmentweekly0.5https://richie.education/docs/2.0.0/frontend-overridesweekly0.5https://richie.education/docs/2.0.0/lms-connectionweekly0.5https://richie.education/docs/2.0.0/native-installationweekly0.5https://richie.education/docs/2.0.1/accessibility-testingweekly0.5https://richie.education/docs/2.0.1/building-the-frontendweekly0.5https://richie.education/docs/2.0.1/contributing-guideweekly0.5https://richie.education/docs/2.0.1/css-guidelinesweekly0.5https://richie.education/docs/2.0.1/discoverweekly0.5https://richie.education/docs/2.0.1/django-react-interopweekly0.5https://richie.education/docs/2.0.1/docker-developmentweekly0.5https://richie.education/docs/2.0.1/frontend-overridesweekly0.5https://richie.education/docs/2.0.1/lms-connectionweekly0.5https://richie.education/docs/2.0.1/native-installationweekly0.5https://richie.education/docs/2.1.0/accessibility-testingweekly0.5https://richie.education/docs/2.1.0/building-the-frontendweekly0.5https://richie.education/docs/2.1.0/contributing-guideweekly0.5https://richie.education/docs/2.1.0/css-guidelinesweekly0.5https://richie.education/docs/2.1.0/discoverweekly0.5https://richie.education/docs/2.1.0/django-react-interopweekly0.5https://richie.education/docs/2.1.0/docker-developmentweekly0.5https://richie.education/docs/2.1.0/frontend-overridesweekly0.5https://richie.education/docs/2.1.0/lms-connectionweekly0.5https://richie.education/docs/2.1.0/native-installationweekly0.5https://richie.education/docs/2.10.0/accessibility-testingweekly0.5https://richie.education/docs/2.10.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.10.0/building-the-frontendweekly0.5https://richie.education/docs/2.10.0/contributing-guideweekly0.5https://richie.education/docs/2.10.0/css-guidelinesweekly0.5https://richie.education/docs/2.10.0/discoverweekly0.5https://richie.education/docs/2.10.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.10.0/django-react-interopweekly0.5https://richie.education/docs/2.10.0/docker-developmentweekly0.5https://richie.education/docs/2.10.0/frontend-overridesweekly0.5https://richie.education/docs/2.10.0/internationalizationweekly0.5https://richie.education/docs/2.10.0/lms-backendsweekly0.5https://richie.education/docs/2.10.0/lms-connectionweekly0.5https://richie.education/docs/2.10.0/native-installationweekly0.5https://richie.education/docs/2.10.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.10.0/tls-connectionweekly0.5https://richie.education/docs/2.10.0/web-analyticsweekly0.5https://richie.education/docs/2.11.0/accessibility-testingweekly0.5https://richie.education/docs/2.11.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.11.0/building-the-frontendweekly0.5https://richie.education/docs/2.11.0/contributing-guideweekly0.5https://richie.education/docs/2.11.0/css-guidelinesweekly0.5https://richie.education/docs/2.11.0/discoverweekly0.5https://richie.education/docs/2.11.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.11.0/django-react-interopweekly0.5https://richie.education/docs/2.11.0/docker-developmentweekly0.5https://richie.education/docs/2.11.0/frontend-overridesweekly0.5https://richie.education/docs/2.11.0/internationalizationweekly0.5https://richie.education/docs/2.11.0/lms-backendsweekly0.5https://richie.education/docs/2.11.0/lms-connectionweekly0.5https://richie.education/docs/2.11.0/native-installationweekly0.5https://richie.education/docs/2.11.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.11.0/tls-connectionweekly0.5https://richie.education/docs/2.11.0/web-analyticsweekly0.5https://richie.education/docs/2.12.0/accessibility-testingweekly0.5https://richie.education/docs/2.12.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.12.0/building-the-frontendweekly0.5https://richie.education/docs/2.12.0/contributing-guideweekly0.5https://richie.education/docs/2.12.0/css-guidelinesweekly0.5https://richie.education/docs/2.12.0/discoverweekly0.5https://richie.education/docs/2.12.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.12.0/django-react-interopweekly0.5https://richie.education/docs/2.12.0/docker-developmentweekly0.5https://richie.education/docs/2.12.0/frontend-overridesweekly0.5https://richie.education/docs/2.12.0/internationalizationweekly0.5https://richie.education/docs/2.12.0/lms-backendsweekly0.5https://richie.education/docs/2.12.0/lms-connectionweekly0.5https://richie.education/docs/2.12.0/native-installationweekly0.5https://richie.education/docs/2.12.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.12.0/tls-connectionweekly0.5https://richie.education/docs/2.12.0/web-analyticsweekly0.5https://richie.education/docs/2.13.0/accessibility-testingweekly0.5https://richie.education/docs/2.13.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.13.0/building-the-frontendweekly0.5https://richie.education/docs/2.13.0/contributing-guideweekly0.5https://richie.education/docs/2.13.0/css-guidelinesweekly0.5https://richie.education/docs/2.13.0/discoverweekly0.5https://richie.education/docs/2.13.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.13.0/django-react-interopweekly0.5https://richie.education/docs/2.13.0/docker-developmentweekly0.5https://richie.education/docs/2.13.0/frontend-overridesweekly0.5https://richie.education/docs/2.13.0/internationalizationweekly0.5https://richie.education/docs/2.13.0/lms-backendsweekly0.5https://richie.education/docs/2.13.0/lms-connectionweekly0.5https://richie.education/docs/2.13.0/native-installationweekly0.5https://richie.education/docs/2.13.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.13.0/tls-connectionweekly0.5https://richie.education/docs/2.13.0/web-analyticsweekly0.5https://richie.education/docs/2.14.0/accessibility-testingweekly0.5https://richie.education/docs/2.14.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.14.0/building-the-frontendweekly0.5https://richie.education/docs/2.14.0/contributing-guideweekly0.5https://richie.education/docs/2.14.0/css-guidelinesweekly0.5https://richie.education/docs/2.14.0/discoverweekly0.5https://richie.education/docs/2.14.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.14.0/django-react-interopweekly0.5https://richie.education/docs/2.14.0/docker-developmentweekly0.5https://richie.education/docs/2.14.0/frontend-overridesweekly0.5https://richie.education/docs/2.14.0/internationalizationweekly0.5https://richie.education/docs/2.14.0/lms-backendsweekly0.5https://richie.education/docs/2.14.0/lms-connectionweekly0.5https://richie.education/docs/2.14.0/native-installationweekly0.5https://richie.education/docs/2.14.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.14.0/tls-connectionweekly0.5https://richie.education/docs/2.14.0/web-analyticsweekly0.5https://richie.education/docs/2.14.1/accessibility-testingweekly0.5https://richie.education/docs/2.14.1/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.14.1/building-the-frontendweekly0.5https://richie.education/docs/2.14.1/contributing-guideweekly0.5https://richie.education/docs/2.14.1/cookiecutterweekly0.5https://richie.education/docs/2.14.1/css-guidelinesweekly0.5https://richie.education/docs/2.14.1/discoverweekly0.5https://richie.education/docs/2.14.1/displaying-connection-statusweekly0.5https://richie.education/docs/2.14.1/django-react-interopweekly0.5https://richie.education/docs/2.14.1/docker-developmentweekly0.5https://richie.education/docs/2.14.1/frontend-overridesweekly0.5https://richie.education/docs/2.14.1/installationweekly0.5https://richie.education/docs/2.14.1/internationalizationweekly0.5https://richie.education/docs/2.14.1/joanie-connectionweekly0.5https://richie.education/docs/2.14.1/lms-backendsweekly0.5https://richie.education/docs/2.14.1/lms-connectionweekly0.5https://richie.education/docs/2.14.1/native-installationweekly0.5https://richie.education/docs/2.14.1/synchronizing-course-runsweekly0.5https://richie.education/docs/2.14.1/tls-connectionweekly0.5https://richie.education/docs/2.14.1/web-analyticsweekly0.5https://richie.education/docs/2.15.0/accessibility-testingweekly0.5https://richie.education/docs/2.15.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.15.0/building-the-frontendweekly0.5https://richie.education/docs/2.15.0/contributing-guideweekly0.5https://richie.education/docs/2.15.0/cookiecutterweekly0.5https://richie.education/docs/2.15.0/css-guidelinesweekly0.5https://richie.education/docs/2.15.0/discoverweekly0.5https://richie.education/docs/2.15.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.15.0/django-react-interopweekly0.5https://richie.education/docs/2.15.0/docker-developmentweekly0.5https://richie.education/docs/2.15.0/frontend-overridesweekly0.5https://richie.education/docs/2.15.0/installationweekly0.5https://richie.education/docs/2.15.0/internationalizationweekly0.5https://richie.education/docs/2.15.0/joanie-connectionweekly0.5https://richie.education/docs/2.15.0/lms-backendsweekly0.5https://richie.education/docs/2.15.0/lms-connectionweekly0.5https://richie.education/docs/2.15.0/native-installationweekly0.5https://richie.education/docs/2.15.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.15.0/tls-connectionweekly0.5https://richie.education/docs/2.15.0/web-analyticsweekly0.5https://richie.education/docs/2.15.1/accessibility-testingweekly0.5https://richie.education/docs/2.15.1/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.15.1/building-the-frontendweekly0.5https://richie.education/docs/2.15.1/contributing-guideweekly0.5https://richie.education/docs/2.15.1/cookiecutterweekly0.5https://richie.education/docs/2.15.1/css-guidelinesweekly0.5https://richie.education/docs/2.15.1/discoverweekly0.5https://richie.education/docs/2.15.1/displaying-connection-statusweekly0.5https://richie.education/docs/2.15.1/django-react-interopweekly0.5https://richie.education/docs/2.15.1/docker-developmentweekly0.5https://richie.education/docs/2.15.1/frontend-overridesweekly0.5https://richie.education/docs/2.15.1/installationweekly0.5https://richie.education/docs/2.15.1/internationalizationweekly0.5https://richie.education/docs/2.15.1/joanie-connectionweekly0.5https://richie.education/docs/2.15.1/lms-backendsweekly0.5https://richie.education/docs/2.15.1/lms-connectionweekly0.5https://richie.education/docs/2.15.1/native-installationweekly0.5https://richie.education/docs/2.15.1/synchronizing-course-runsweekly0.5https://richie.education/docs/2.15.1/tls-connectionweekly0.5https://richie.education/docs/2.15.1/web-analyticsweekly0.5https://richie.education/docs/2.16.0/accessibility-testingweekly0.5https://richie.education/docs/2.16.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.16.0/building-the-frontendweekly0.5https://richie.education/docs/2.16.0/contributing-guideweekly0.5https://richie.education/docs/2.16.0/cookiecutterweekly0.5https://richie.education/docs/2.16.0/css-guidelinesweekly0.5https://richie.education/docs/2.16.0/discoverweekly0.5https://richie.education/docs/2.16.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.16.0/django-react-interopweekly0.5https://richie.education/docs/2.16.0/docker-developmentweekly0.5https://richie.education/docs/2.16.0/frontend-overridesweekly0.5https://richie.education/docs/2.16.0/installationweekly0.5https://richie.education/docs/2.16.0/internationalizationweekly0.5https://richie.education/docs/2.16.0/joanie-connectionweekly0.5https://richie.education/docs/2.16.0/lms-backendsweekly0.5https://richie.education/docs/2.16.0/lms-connectionweekly0.5https://richie.education/docs/2.16.0/native-installationweekly0.5https://richie.education/docs/2.16.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.16.0/tls-connectionweekly0.5https://richie.education/docs/2.16.0/web-analyticsweekly0.5https://richie.education/docs/2.17.0/accessibility-testingweekly0.5https://richie.education/docs/2.17.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.17.0/building-the-frontendweekly0.5https://richie.education/docs/2.17.0/contributing-guideweekly0.5https://richie.education/docs/2.17.0/cookiecutterweekly0.5https://richie.education/docs/2.17.0/css-guidelinesweekly0.5https://richie.education/docs/2.17.0/discoverweekly0.5https://richie.education/docs/2.17.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.17.0/django-react-interopweekly0.5https://richie.education/docs/2.17.0/docker-developmentweekly0.5https://richie.education/docs/2.17.0/filters-customizationweekly0.5https://richie.education/docs/2.17.0/frontend-overridesweekly0.5https://richie.education/docs/2.17.0/installationweekly0.5https://richie.education/docs/2.17.0/internationalizationweekly0.5https://richie.education/docs/2.17.0/joanie-connectionweekly0.5https://richie.education/docs/2.17.0/lms-backendsweekly0.5https://richie.education/docs/2.17.0/lms-connectionweekly0.5https://richie.education/docs/2.17.0/native-installationweekly0.5https://richie.education/docs/2.17.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.17.0/tls-connectionweekly0.5https://richie.education/docs/2.17.0/web-analyticsweekly0.5https://richie.education/docs/2.18.0/accessibility-testingweekly0.5https://richie.education/docs/2.18.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.18.0/building-the-frontendweekly0.5https://richie.education/docs/2.18.0/contributing-guideweekly0.5https://richie.education/docs/2.18.0/cookiecutterweekly0.5https://richie.education/docs/2.18.0/css-guidelinesweekly0.5https://richie.education/docs/2.18.0/discoverweekly0.5https://richie.education/docs/2.18.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.18.0/django-react-interopweekly0.5https://richie.education/docs/2.18.0/docker-developmentweekly0.5https://richie.education/docs/2.18.0/filters-customizationweekly0.5https://richie.education/docs/2.18.0/frontend-overridesweekly0.5https://richie.education/docs/2.18.0/installationweekly0.5https://richie.education/docs/2.18.0/internationalizationweekly0.5https://richie.education/docs/2.18.0/joanie-connectionweekly0.5https://richie.education/docs/2.18.0/lms-backendsweekly0.5https://richie.education/docs/2.18.0/lms-connectionweekly0.5https://richie.education/docs/2.18.0/native-installationweekly0.5https://richie.education/docs/2.18.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.18.0/tls-connectionweekly0.5https://richie.education/docs/2.18.0/web-analyticsweekly0.5https://richie.education/docs/2.19.0/accessibility-testingweekly0.5https://richie.education/docs/2.19.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.19.0/building-the-frontendweekly0.5https://richie.education/docs/2.19.0/contributing-guideweekly0.5https://richie.education/docs/2.19.0/cookiecutterweekly0.5https://richie.education/docs/2.19.0/css-guidelinesweekly0.5https://richie.education/docs/2.19.0/discoverweekly0.5https://richie.education/docs/2.19.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.19.0/django-react-interopweekly0.5https://richie.education/docs/2.19.0/docker-developmentweekly0.5https://richie.education/docs/2.19.0/filters-customizationweekly0.5https://richie.education/docs/2.19.0/frontend-overridesweekly0.5https://richie.education/docs/2.19.0/installationweekly0.5https://richie.education/docs/2.19.0/internationalizationweekly0.5https://richie.education/docs/2.19.0/joanie-connectionweekly0.5https://richie.education/docs/2.19.0/lms-backendsweekly0.5https://richie.education/docs/2.19.0/lms-connectionweekly0.5https://richie.education/docs/2.19.0/native-installationweekly0.5https://richie.education/docs/2.19.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.19.0/tls-connectionweekly0.5https://richie.education/docs/2.19.0/web-analyticsweekly0.5https://richie.education/docs/2.2.0/accessibility-testingweekly0.5https://richie.education/docs/2.2.0/building-the-frontendweekly0.5https://richie.education/docs/2.2.0/contributing-guideweekly0.5https://richie.education/docs/2.2.0/css-guidelinesweekly0.5https://richie.education/docs/2.2.0/discoverweekly0.5https://richie.education/docs/2.2.0/django-react-interopweekly0.5https://richie.education/docs/2.2.0/docker-developmentweekly0.5https://richie.education/docs/2.2.0/frontend-overridesweekly0.5https://richie.education/docs/2.2.0/internationalizationweekly0.5https://richie.education/docs/2.2.0/lms-connectionweekly0.5https://richie.education/docs/2.2.0/native-installationweekly0.5https://richie.education/docs/2.20.0/accessibility-testingweekly0.5https://richie.education/docs/2.20.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.20.0/building-the-frontendweekly0.5https://richie.education/docs/2.20.0/contributing-guideweekly0.5https://richie.education/docs/2.20.0/cookiecutterweekly0.5https://richie.education/docs/2.20.0/css-guidelinesweekly0.5https://richie.education/docs/2.20.0/discoverweekly0.5https://richie.education/docs/2.20.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.20.0/django-react-interopweekly0.5https://richie.education/docs/2.20.0/docker-developmentweekly0.5https://richie.education/docs/2.20.0/filters-customizationweekly0.5https://richie.education/docs/2.20.0/frontend-overridesweekly0.5https://richie.education/docs/2.20.0/installationweekly0.5https://richie.education/docs/2.20.0/internationalizationweekly0.5https://richie.education/docs/2.20.0/joanie-connectionweekly0.5https://richie.education/docs/2.20.0/lms-backendsweekly0.5https://richie.education/docs/2.20.0/lms-connectionweekly0.5https://richie.education/docs/2.20.0/native-installationweekly0.5https://richie.education/docs/2.20.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.20.0/tls-connectionweekly0.5https://richie.education/docs/2.20.0/web-analyticsweekly0.5https://richie.education/docs/2.20.1/accessibility-testingweekly0.5https://richie.education/docs/2.20.1/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.20.1/building-the-frontendweekly0.5https://richie.education/docs/2.20.1/contributing-guideweekly0.5https://richie.education/docs/2.20.1/cookiecutterweekly0.5https://richie.education/docs/2.20.1/css-guidelinesweekly0.5https://richie.education/docs/2.20.1/discoverweekly0.5https://richie.education/docs/2.20.1/displaying-connection-statusweekly0.5https://richie.education/docs/2.20.1/django-react-interopweekly0.5https://richie.education/docs/2.20.1/docker-developmentweekly0.5https://richie.education/docs/2.20.1/filters-customizationweekly0.5https://richie.education/docs/2.20.1/frontend-overridesweekly0.5https://richie.education/docs/2.20.1/installationweekly0.5https://richie.education/docs/2.20.1/internationalizationweekly0.5https://richie.education/docs/2.20.1/joanie-connectionweekly0.5https://richie.education/docs/2.20.1/lms-backendsweekly0.5https://richie.education/docs/2.20.1/lms-connectionweekly0.5https://richie.education/docs/2.20.1/native-installationweekly0.5https://richie.education/docs/2.20.1/synchronizing-course-runsweekly0.5https://richie.education/docs/2.20.1/tls-connectionweekly0.5https://richie.education/docs/2.20.1/web-analyticsweekly0.5https://richie.education/docs/2.21.0/accessibility-testingweekly0.5https://richie.education/docs/2.21.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.21.0/building-the-frontendweekly0.5https://richie.education/docs/2.21.0/contributing-guideweekly0.5https://richie.education/docs/2.21.0/cookiecutterweekly0.5https://richie.education/docs/2.21.0/css-guidelinesweekly0.5https://richie.education/docs/2.21.0/discoverweekly0.5https://richie.education/docs/2.21.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.21.0/django-react-interopweekly0.5https://richie.education/docs/2.21.0/docker-developmentweekly0.5https://richie.education/docs/2.21.0/filters-customizationweekly0.5https://richie.education/docs/2.21.0/frontend-overridesweekly0.5https://richie.education/docs/2.21.0/installationweekly0.5https://richie.education/docs/2.21.0/internationalizationweekly0.5https://richie.education/docs/2.21.0/joanie-connectionweekly0.5https://richie.education/docs/2.21.0/lms-backendsweekly0.5https://richie.education/docs/2.21.0/lms-connectionweekly0.5https://richie.education/docs/2.21.0/native-installationweekly0.5https://richie.education/docs/2.21.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.21.0/tls-connectionweekly0.5https://richie.education/docs/2.21.0/web-analyticsweekly0.5https://richie.education/docs/2.3.0/accessibility-testingweekly0.5https://richie.education/docs/2.3.0/building-the-frontendweekly0.5https://richie.education/docs/2.3.0/contributing-guideweekly0.5https://richie.education/docs/2.3.0/css-guidelinesweekly0.5https://richie.education/docs/2.3.0/discoverweekly0.5https://richie.education/docs/2.3.0/django-react-interopweekly0.5https://richie.education/docs/2.3.0/docker-developmentweekly0.5https://richie.education/docs/2.3.0/frontend-overridesweekly0.5https://richie.education/docs/2.3.0/internationalizationweekly0.5https://richie.education/docs/2.3.0/lms-connectionweekly0.5https://richie.education/docs/2.3.0/native-installationweekly0.5https://richie.education/docs/2.3.1/accessibility-testingweekly0.5https://richie.education/docs/2.3.1/building-the-frontendweekly0.5https://richie.education/docs/2.3.1/contributing-guideweekly0.5https://richie.education/docs/2.3.1/css-guidelinesweekly0.5https://richie.education/docs/2.3.1/discoverweekly0.5https://richie.education/docs/2.3.1/django-react-interopweekly0.5https://richie.education/docs/2.3.1/docker-developmentweekly0.5https://richie.education/docs/2.3.1/frontend-overridesweekly0.5https://richie.education/docs/2.3.1/internationalizationweekly0.5https://richie.education/docs/2.3.1/lms-connectionweekly0.5https://richie.education/docs/2.3.1/native-installationweekly0.5https://richie.education/docs/2.3.2/accessibility-testingweekly0.5https://richie.education/docs/2.3.2/building-the-frontendweekly0.5https://richie.education/docs/2.3.2/contributing-guideweekly0.5https://richie.education/docs/2.3.2/css-guidelinesweekly0.5https://richie.education/docs/2.3.2/discoverweekly0.5https://richie.education/docs/2.3.2/django-react-interopweekly0.5https://richie.education/docs/2.3.2/docker-developmentweekly0.5https://richie.education/docs/2.3.2/frontend-overridesweekly0.5https://richie.education/docs/2.3.2/internationalizationweekly0.5https://richie.education/docs/2.3.2/lms-connectionweekly0.5https://richie.education/docs/2.3.2/native-installationweekly0.5https://richie.education/docs/2.3.3/accessibility-testingweekly0.5https://richie.education/docs/2.3.3/building-the-frontendweekly0.5https://richie.education/docs/2.3.3/contributing-guideweekly0.5https://richie.education/docs/2.3.3/css-guidelinesweekly0.5https://richie.education/docs/2.3.3/discoverweekly0.5https://richie.education/docs/2.3.3/django-react-interopweekly0.5https://richie.education/docs/2.3.3/docker-developmentweekly0.5https://richie.education/docs/2.3.3/frontend-overridesweekly0.5https://richie.education/docs/2.3.3/internationalizationweekly0.5https://richie.education/docs/2.3.3/lms-connectionweekly0.5https://richie.education/docs/2.3.3/native-installationweekly0.5https://richie.education/docs/2.4.0/accessibility-testingweekly0.5https://richie.education/docs/2.4.0/building-the-frontendweekly0.5https://richie.education/docs/2.4.0/contributing-guideweekly0.5https://richie.education/docs/2.4.0/css-guidelinesweekly0.5https://richie.education/docs/2.4.0/discoverweekly0.5https://richie.education/docs/2.4.0/django-react-interopweekly0.5https://richie.education/docs/2.4.0/docker-developmentweekly0.5https://richie.education/docs/2.4.0/frontend-overridesweekly0.5https://richie.education/docs/2.4.0/internationalizationweekly0.5https://richie.education/docs/2.4.0/lms-connectionweekly0.5https://richie.education/docs/2.4.0/native-installationweekly0.5https://richie.education/docs/2.5.0/accessibility-testingweekly0.5https://richie.education/docs/2.5.0/building-the-frontendweekly0.5https://richie.education/docs/2.5.0/contributing-guideweekly0.5https://richie.education/docs/2.5.0/css-guidelinesweekly0.5https://richie.education/docs/2.5.0/discoverweekly0.5https://richie.education/docs/2.5.0/django-react-interopweekly0.5https://richie.education/docs/2.5.0/docker-developmentweekly0.5https://richie.education/docs/2.5.0/frontend-overridesweekly0.5https://richie.education/docs/2.5.0/internationalizationweekly0.5https://richie.education/docs/2.5.0/lms-connectionweekly0.5https://richie.education/docs/2.5.0/native-installationweekly0.5https://richie.education/docs/2.6.0/accessibility-testingweekly0.5https://richie.education/docs/2.6.0/building-the-frontendweekly0.5https://richie.education/docs/2.6.0/contributing-guideweekly0.5https://richie.education/docs/2.6.0/css-guidelinesweekly0.5https://richie.education/docs/2.6.0/discoverweekly0.5https://richie.education/docs/2.6.0/django-react-interopweekly0.5https://richie.education/docs/2.6.0/docker-developmentweekly0.5https://richie.education/docs/2.6.0/frontend-overridesweekly0.5https://richie.education/docs/2.6.0/internationalizationweekly0.5https://richie.education/docs/2.6.0/lms-connectionweekly0.5https://richie.education/docs/2.6.0/native-installationweekly0.5https://richie.education/docs/2.7.0/accessibility-testingweekly0.5https://richie.education/docs/2.7.0/building-the-frontendweekly0.5https://richie.education/docs/2.7.0/contributing-guideweekly0.5https://richie.education/docs/2.7.0/css-guidelinesweekly0.5https://richie.education/docs/2.7.0/discoverweekly0.5https://richie.education/docs/2.7.0/django-react-interopweekly0.5https://richie.education/docs/2.7.0/docker-developmentweekly0.5https://richie.education/docs/2.7.0/frontend-overridesweekly0.5https://richie.education/docs/2.7.0/internationalizationweekly0.5https://richie.education/docs/2.7.0/lms-connectionweekly0.5https://richie.education/docs/2.7.0/native-installationweekly0.5https://richie.education/docs/2.7.1/accessibility-testingweekly0.5https://richie.education/docs/2.7.1/building-the-frontendweekly0.5https://richie.education/docs/2.7.1/contributing-guideweekly0.5https://richie.education/docs/2.7.1/css-guidelinesweekly0.5https://richie.education/docs/2.7.1/discoverweekly0.5https://richie.education/docs/2.7.1/django-react-interopweekly0.5https://richie.education/docs/2.7.1/docker-developmentweekly0.5https://richie.education/docs/2.7.1/frontend-overridesweekly0.5https://richie.education/docs/2.7.1/internationalizationweekly0.5https://richie.education/docs/2.7.1/lms-connectionweekly0.5https://richie.education/docs/2.7.1/native-installationweekly0.5https://richie.education/docs/2.8.0/accessibility-testingweekly0.5https://richie.education/docs/2.8.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.8.0/building-the-frontendweekly0.5https://richie.education/docs/2.8.0/contributing-guideweekly0.5https://richie.education/docs/2.8.0/css-guidelinesweekly0.5https://richie.education/docs/2.8.0/discoverweekly0.5https://richie.education/docs/2.8.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.8.0/django-react-interopweekly0.5https://richie.education/docs/2.8.0/docker-developmentweekly0.5https://richie.education/docs/2.8.0/frontend-overridesweekly0.5https://richie.education/docs/2.8.0/internationalizationweekly0.5https://richie.education/docs/2.8.0/lms-backendsweekly0.5https://richie.education/docs/2.8.0/lms-connectionweekly0.5https://richie.education/docs/2.8.0/native-installationweekly0.5https://richie.education/docs/2.8.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.8.0/tls-connectionweekly0.5https://richie.education/docs/2.8.0/web-analyticsweekly0.5https://richie.education/docs/2.8.1/accessibility-testingweekly0.5https://richie.education/docs/2.8.1/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.8.1/building-the-frontendweekly0.5https://richie.education/docs/2.8.1/contributing-guideweekly0.5https://richie.education/docs/2.8.1/css-guidelinesweekly0.5https://richie.education/docs/2.8.1/discoverweekly0.5https://richie.education/docs/2.8.1/displaying-connection-statusweekly0.5https://richie.education/docs/2.8.1/django-react-interopweekly0.5https://richie.education/docs/2.8.1/docker-developmentweekly0.5https://richie.education/docs/2.8.1/frontend-overridesweekly0.5https://richie.education/docs/2.8.1/internationalizationweekly0.5https://richie.education/docs/2.8.1/lms-backendsweekly0.5https://richie.education/docs/2.8.1/lms-connectionweekly0.5https://richie.education/docs/2.8.1/native-installationweekly0.5https://richie.education/docs/2.8.1/synchronizing-course-runsweekly0.5https://richie.education/docs/2.8.1/tls-connectionweekly0.5https://richie.education/docs/2.8.1/web-analyticsweekly0.5https://richie.education/docs/2.8.2/accessibility-testingweekly0.5https://richie.education/docs/2.8.2/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.8.2/building-the-frontendweekly0.5https://richie.education/docs/2.8.2/contributing-guideweekly0.5https://richie.education/docs/2.8.2/css-guidelinesweekly0.5https://richie.education/docs/2.8.2/discoverweekly0.5https://richie.education/docs/2.8.2/displaying-connection-statusweekly0.5https://richie.education/docs/2.8.2/django-react-interopweekly0.5https://richie.education/docs/2.8.2/docker-developmentweekly0.5https://richie.education/docs/2.8.2/frontend-overridesweekly0.5https://richie.education/docs/2.8.2/internationalizationweekly0.5https://richie.education/docs/2.8.2/lms-backendsweekly0.5https://richie.education/docs/2.8.2/lms-connectionweekly0.5https://richie.education/docs/2.8.2/native-installationweekly0.5https://richie.education/docs/2.8.2/synchronizing-course-runsweekly0.5https://richie.education/docs/2.8.2/tls-connectionweekly0.5https://richie.education/docs/2.8.2/web-analyticsweekly0.5https://richie.education/docs/2.9.0/accessibility-testingweekly0.5https://richie.education/docs/2.9.0/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.9.0/building-the-frontendweekly0.5https://richie.education/docs/2.9.0/contributing-guideweekly0.5https://richie.education/docs/2.9.0/css-guidelinesweekly0.5https://richie.education/docs/2.9.0/discoverweekly0.5https://richie.education/docs/2.9.0/displaying-connection-statusweekly0.5https://richie.education/docs/2.9.0/django-react-interopweekly0.5https://richie.education/docs/2.9.0/docker-developmentweekly0.5https://richie.education/docs/2.9.0/frontend-overridesweekly0.5https://richie.education/docs/2.9.0/internationalizationweekly0.5https://richie.education/docs/2.9.0/lms-backendsweekly0.5https://richie.education/docs/2.9.0/lms-connectionweekly0.5https://richie.education/docs/2.9.0/native-installationweekly0.5https://richie.education/docs/2.9.0/synchronizing-course-runsweekly0.5https://richie.education/docs/2.9.0/tls-connectionweekly0.5https://richie.education/docs/2.9.0/web-analyticsweekly0.5https://richie.education/docs/2.9.1/accessibility-testingweekly0.5https://richie.education/docs/2.9.1/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/2.9.1/building-the-frontendweekly0.5https://richie.education/docs/2.9.1/contributing-guideweekly0.5https://richie.education/docs/2.9.1/css-guidelinesweekly0.5https://richie.education/docs/2.9.1/discoverweekly0.5https://richie.education/docs/2.9.1/displaying-connection-statusweekly0.5https://richie.education/docs/2.9.1/django-react-interopweekly0.5https://richie.education/docs/2.9.1/docker-developmentweekly0.5https://richie.education/docs/2.9.1/frontend-overridesweekly0.5https://richie.education/docs/2.9.1/internationalizationweekly0.5https://richie.education/docs/2.9.1/lms-backendsweekly0.5https://richie.education/docs/2.9.1/lms-connectionweekly0.5https://richie.education/docs/2.9.1/native-installationweekly0.5https://richie.education/docs/2.9.1/synchronizing-course-runsweekly0.5https://richie.education/docs/2.9.1/tls-connectionweekly0.5https://richie.education/docs/2.9.1/web-analyticsweekly0.5https://richie.education/docs/next/accessibility-testingweekly0.5https://richie.education/docs/next/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/next/building-the-frontendweekly0.5https://richie.education/docs/next/contributing-guideweekly0.5https://richie.education/docs/next/cookiecutterweekly0.5https://richie.education/docs/next/css-guidelinesweekly0.5https://richie.education/docs/next/discoverweekly0.5https://richie.education/docs/next/displaying-connection-statusweekly0.5https://richie.education/docs/next/django-react-interopweekly0.5https://richie.education/docs/next/docker-developmentweekly0.5https://richie.education/docs/next/filters-customizationweekly0.5https://richie.education/docs/next/frontend-overridesweekly0.5https://richie.education/docs/next/installationweekly0.5https://richie.education/docs/next/internationalizationweekly0.5https://richie.education/docs/next/joanie-connectionweekly0.5https://richie.education/docs/next/lms-backendsweekly0.5https://richie.education/docs/next/lms-connectionweekly0.5https://richie.education/docs/next/native-installationweekly0.5https://richie.education/docs/next/synchronizing-course-runsweekly0.5https://richie.education/docs/next/tls-connectionweekly0.5https://richie.education/docs/next/web-analyticsweekly0.5https://richie.education/docs/accessibility-testingweekly0.5https://richie.education/docs/api/course-run-synchronization-apiweekly0.5https://richie.education/docs/building-the-frontendweekly0.5https://richie.education/docs/contributing-guideweekly0.5https://richie.education/docs/cookiecutterweekly0.5https://richie.education/docs/css-guidelinesweekly0.5https://richie.education/docs/discoverweekly0.5https://richie.education/docs/displaying-connection-statusweekly0.5https://richie.education/docs/django-react-interopweekly0.5https://richie.education/docs/docker-developmentweekly0.5https://richie.education/docs/filters-customizationweekly0.5https://richie.education/docs/frontend-overridesweekly0.5https://richie.education/docs/installationweekly0.5https://richie.education/docs/internationalizationweekly0.5https://richie.education/docs/joanie-connectionweekly0.5https://richie.education/docs/lms-backendsweekly0.5https://richie.education/docs/lms-connectionweekly0.5https://richie.education/docs/native-installationweekly0.5https://richie.education/docs/synchronizing-course-runsweekly0.5https://richie.education/docs/tls-connectionweekly0.5https://richie.education/docs/web-analyticsweekly0.5https://richie.education/weekly0.5 \ No newline at end of file diff --git a/users/index.html b/users/index.html index 6bc3e853df..06f5f3024d 100644 --- a/users/index.html +++ b/users/index.html @@ -4,13 +4,13 @@ Richie - - + + - - +

    Who is Using This?

    This project is used by many folks

    France Université NumériqueNAUEDUlib

    Are you using this project?

    Add your company
    + + \ No newline at end of file diff --git a/versions/index.html b/versions/index.html index a4d53ce190..bf6c8229d6 100644 --- a/versions/index.html +++ b/versions/index.html @@ -4,13 +4,13 @@ Richie - - + +
    -

    Richie versions and documentation

    New versions of this project are shipped regularly. Every new version includes its own version of the documentation.

    Versions below 1.12.0 did not have a dedicated documentation website.

    Current version (Stable)

    2.21.0DocumentationRelease Notes

    Pre-release versions

    masterDocumentationSource Code

    Past Versions

    Here you can find previous versions of the documentation.

    2.20.1DocumentationRelease Notes
    2.20.0DocumentationRelease Notes
    2.19.0DocumentationRelease Notes
    2.18.0DocumentationRelease Notes
    2.17.0DocumentationRelease Notes
    2.16.0DocumentationRelease Notes
    2.15.1DocumentationRelease Notes
    2.15.0DocumentationRelease Notes
    2.14.1DocumentationRelease Notes
    2.14.0DocumentationRelease Notes
    2.13.0DocumentationRelease Notes
    2.12.0DocumentationRelease Notes
    2.11.0DocumentationRelease Notes
    2.10.0DocumentationRelease Notes
    2.9.1DocumentationRelease Notes
    2.9.0DocumentationRelease Notes
    2.8.2DocumentationRelease Notes
    2.8.1DocumentationRelease Notes
    2.8.0DocumentationRelease Notes
    2.7.1DocumentationRelease Notes
    2.7.0DocumentationRelease Notes
    2.6.0DocumentationRelease Notes
    2.5.0DocumentationRelease Notes
    2.4.0DocumentationRelease Notes
    2.3.3DocumentationRelease Notes
    2.3.2DocumentationRelease Notes
    2.3.1DocumentationRelease Notes
    2.3.0DocumentationRelease Notes
    2.2.0DocumentationRelease Notes
    2.1.0DocumentationRelease Notes
    2.0.1DocumentationRelease Notes
    2.0.0DocumentationRelease Notes
    1.17DocumentationRelease Notes
    1.16DocumentationRelease Notes
    1.15DocumentationRelease Notes
    1.14DocumentationRelease Notes
    1.13DocumentationRelease Notes
    1.12DocumentationRelease Notes

    You can find past versions of this project on GitHub.

    - - +

    Richie versions and documentation

    New versions of this project are shipped regularly. Every new version includes its own version of the documentation.

    Versions below 1.12.0 did not have a dedicated documentation website.

    Current version (Stable)

    2.21.1DocumentationRelease Notes

    Pre-release versions

    masterDocumentationSource Code

    Past Versions

    Here you can find previous versions of the documentation.

    2.21.0DocumentationRelease Notes
    2.20.1DocumentationRelease Notes
    2.20.0DocumentationRelease Notes
    2.19.0DocumentationRelease Notes
    2.18.0DocumentationRelease Notes
    2.17.0DocumentationRelease Notes
    2.16.0DocumentationRelease Notes
    2.15.1DocumentationRelease Notes
    2.15.0DocumentationRelease Notes
    2.14.1DocumentationRelease Notes
    2.14.0DocumentationRelease Notes
    2.13.0DocumentationRelease Notes
    2.12.0DocumentationRelease Notes
    2.11.0DocumentationRelease Notes
    2.10.0DocumentationRelease Notes
    2.9.1DocumentationRelease Notes
    2.9.0DocumentationRelease Notes
    2.8.2DocumentationRelease Notes
    2.8.1DocumentationRelease Notes
    2.8.0DocumentationRelease Notes
    2.7.1DocumentationRelease Notes
    2.7.0DocumentationRelease Notes
    2.6.0DocumentationRelease Notes
    2.5.0DocumentationRelease Notes
    2.4.0DocumentationRelease Notes
    2.3.3DocumentationRelease Notes
    2.3.2DocumentationRelease Notes
    2.3.1DocumentationRelease Notes
    2.3.0DocumentationRelease Notes
    2.2.0DocumentationRelease Notes
    2.1.0DocumentationRelease Notes
    2.0.1DocumentationRelease Notes
    2.0.0DocumentationRelease Notes
    1.17DocumentationRelease Notes
    1.16DocumentationRelease Notes
    1.15DocumentationRelease Notes
    1.14DocumentationRelease Notes
    1.13DocumentationRelease Notes
    1.12DocumentationRelease Notes

    You can find past versions of this project on GitHub.

    + + \ No newline at end of file