diff --git a/.flowconfig b/.flowconfig index 6d284f4209..c8f07e8cff 100644 --- a/.flowconfig +++ b/.flowconfig @@ -7,6 +7,10 @@ [libs] ./static/js/flow/declarations.js +node_modules/iflow-lodash/index.js.flow +node_modules/iflow-moment/index.js.flow +node_modules/iflow-react-router/index.js.flow +node_modules/iflow-redux/index.js.flow [options] esproposal.class_static_fields=enable diff --git a/.gitignore b/.gitignore index 87d31e8092..142dbc1298 100644 --- a/.gitignore +++ b/.gitignore @@ -88,3 +88,4 @@ codekit-config.json staticfiles/ .venv +release-notes-checklist diff --git a/README.md b/README.md index 325c468046..842e1aae44 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# MicroMaster’s -Portal for learners and course teams to access MITx MicroMaster’s programs +# MicroMasters +Portal for learners and course teams to access MITx MicroMasters programs ## Major Dependencies - Docker @@ -26,7 +26,7 @@ with the edX instance. ## Running edX devstack locally _(optional, but recommended)_ -MicroMaster’s can work with a live instance of edX, but it's recommended that +MicroMasters can work with a live instance of edX, but it's recommended that you get it running locally. It's obviously more configurable that way, and you'll likely need to run it locally for other projects in the future. @@ -93,17 +93,18 @@ new Application. Fill in the values as follows: - **User**: Use the lookup (magnifying glass) to find your superuser - **Redirect uris**: The URL where MicroMaster’s will be running, followed by "/complete/edxorg/". -If you're running it via Docker, run ``docker-machine ip`` from the host machine to get the -container IP. MicroMaster’s runs on port ``8079`` by default, so this value should be something -like ``http://192.168.99.100:8079/complete/edxorg/`` + **Linux users:** the MicroMaster’s URL will be `http://localhost:8079`. **OSX users:** The MicroMaster's + IP can be found by running ``docker-machine ip `` from the host machine. MicroMaster’s runs on port + ``8079`` by default, so the full URL should be something like + ``http://192.168.99.100:8079/complete/edxorg/`` - **Client type**: Set to '_Confidential_'. - **Authorization grant type**: Set to '_Authorization Code_'. - **Name**: Anything you want. Something like 'mm-local' would do fine here. -#### 5) Copy relevant values to use in the MicroMaster’s .env file +#### 5) Copy relevant values to use in the MicroMasters .env file -The MicroMaster’s codebase contains a ``.env.sample`` file which will be used as -a template to create your ``.env`` file. For MicroMaster’s to work, it needs 3 values: +The MicroMasters codebase contains a ``.env.sample`` file which will be used as +a template to create your ``.env`` file. For MicroMasters to work, it needs 3 values: - ``EDXORG_BASE_URL`` @@ -174,7 +175,7 @@ For first-time container start-up, start it with a full build: docker-compose up --build -In another terminal tab, navigate the the MicroMaster’s directory +In another terminal tab, navigate the the MicroMasters directory and add a superuser in the now-running Docker container: docker-compose run web python3 manage.py createsuperuser @@ -184,8 +185,8 @@ param: ``docker-compose up`` You should now be able to do the following: -1. Visit MicroMaster’s in your browser on port `8079`. _(OSX Only)_ Docker auto-assigns - the container IP. Run ``docker-machine ip`` to see it. Your MicroMaster’s URL will +1. Visit MicroMasters in your browser on port `8079`. _(OSX Only)_ Docker auto-assigns + the container IP. Run ``docker-machine ip`` to see it. Your MicroMasters URL will be something like this: ``192.168.99.100:8079``. 1. Click "Sign in with edX.org" and sign in by authorizing an edX client. If you're running edX locally, this will be the client you created in the steps above. @@ -193,7 +194,7 @@ You should now be able to do the following: ## Running Commands and Testing As shown above, manage commands can be executed on the Docker-contained -MicroMaster’s app. For example, you can run a Python shell with the following command: +MicroMasters app. For example, you can run a Python shell with the following command: docker-compose run web python3 manage.py shell @@ -211,3 +212,5 @@ Tests should be run in the Docker container, not the host machine. They can be r docker-compose run watch npm test /path/to/test.js # Run the JS linter docker-compose run watch npm run-script lint + # Run JS type-checking + docker-compose run watch npm run-script flow diff --git a/RELEASE.rst b/RELEASE.rst index f66de4b522..dfb8ebe71a 100644 --- a/RELEASE.rst +++ b/RELEASE.rst @@ -1,6 +1,63 @@ Release Notes ============= +Version 0.12.0 +-------------- + +- Added ErrorMessage to UserPage +- Changed dateFields to disallow non-numerical input (#641) +- Added deadline for upgrade +- Removed some (now) useless cases in constants +- Modified FAQ field to have rich text +- FAQ collapsed by default +- Added spinner and error message for profile page (#661) +- Added user page link to dropdown +- Changed field of study select to match anywhere in string w/ highlighted text +- Removed routing from profile flow +- added docstring +- fixed MORE unit tests +- fixed js test +- refactored error page code and fixed unit tests +- nevermind. tabs changed to spaces in base_error.html +- changed base_error.html to match tab/space style, which is apparently mixed +- Added user page link to dropdown +- Added thumbnail to wagtail CMS (#625) +- Redirected to 404 if user goes to a missing user page (#629) +- Added spinner for dashboard (#646) +- Removed x's from text fields (#642) +- Tests fixed +- Removed upgrade logic from the frontend +- Changed the label of settings button +- Added settings page +- Added link to home page on program page logo (#645) +- Added text to JumboTron for terms of service (#644) +- Updated validation text (#643) +- Added resumeOrder to education entries +- Updated edx-api-client requirement +- Removed padding from date field (#631) +- Removed UI validators from PrivacyTab validator callback +- Raised 404 exception when user wants to access someones profile whose privacy mode is set tp private +- Fixed filtering text to remain if textbox clicked (#628) +- Made FieldsOfStudySelectField wider +- Added new types for Course, CourseRun, added flow to many files +- Added react-virtualized to AutoComplete (#568) +- Fixed style regression (#624) +- Link opens in the same page +- Added possibility to link external program pages +- Added custom 500 page +- Added 'confirm delete all entries' when closing switches +- Sorted employment entries in resume order +- Updated documentation to reflect edX changes +- First working version +- Removed apostrophe from MicroMaster's (#560) +- Updated to redux-asserts 0.0.8 and fixed related test failures (#616) +- Fixed bug with preferred name not updating on Jumbotron +- Added babel-polyfill to support IE11 (#611) +- Swapped courses and faq in program page +- Upgraded to wagtail 1.5.2 +- Fixed spinner positioning (#563) +- Bumped django version + Version 0.11.0 -------------- diff --git a/cms/migrations/0012_programpage_external_program_page_url.py b/cms/migrations/0012_programpage_external_program_page_url.py new file mode 100644 index 0000000000..5f6ab3244a --- /dev/null +++ b/cms/migrations/0012_programpage_external_program_page_url.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-06-22 20:59 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cms', '0011_programpage_title_over_image'), + ] + + operations = [ + migrations.AddField( + model_name='programpage', + name='external_program_page_url', + field=models.URLField(blank=True, help_text='Use this field to directly link an external web page for this program.', null=True), + ), + ] diff --git a/cms/migrations/0013_programpage_thumbnail_image.py b/cms/migrations/0013_programpage_thumbnail_image.py new file mode 100644 index 0000000000..64732bf253 --- /dev/null +++ b/cms/migrations/0013_programpage_thumbnail_image.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-06-22 15:41 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailimages', '0012_copy_image_permissions_to_collections'), + ('cms', '0012_programpage_external_program_page_url'), + ] + + operations = [ + migrations.AddField( + model_name='programpage', + name='thumbnail_image', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.Image'), + ), + ] diff --git a/cms/migrations/0014_html_in_faq_answers.py b/cms/migrations/0014_html_in_faq_answers.py new file mode 100644 index 0000000000..ca71199085 --- /dev/null +++ b/cms/migrations/0014_html_in_faq_answers.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-06-29 16:12 +from __future__ import unicode_literals + +from django.db import migrations +import wagtail.wagtailcore.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('cms', '0013_programpage_thumbnail_image'), + ] + + operations = [ + migrations.AlterField( + model_name='frequentlyaskedquestion', + name='answer', + field=wagtail.wagtailcore.fields.RichTextField(), + ), + ] diff --git a/cms/models.py b/cms/models.py index 5e2f57ceac..a33a91231e 100644 --- a/cms/models.py +++ b/cms/models.py @@ -63,6 +63,11 @@ class ProgramPage(Page): """ description = RichTextField(blank=True) program = models.OneToOneField('courses.Program', null=True, on_delete=models.SET_NULL) + external_program_page_url = models.URLField( + blank=True, + null=True, + help_text="Use this field to directly link an external web page for this program." + ) background_image = models.ForeignKey( Image, null=True, @@ -73,14 +78,24 @@ class ProgramPage(Page): contact_us = RichTextField(blank=True) title_over_image = RichTextField(blank=True) + thumbnail_image = models.ForeignKey( + Image, + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name='+' + ) + content_panels = Page.content_panels + [ FieldPanel('description', classname="full"), FieldPanel('program'), + FieldPanel('thumbnail_image'), + FieldPanel('external_program_page_url'), FieldPanel('background_image'), FieldPanel('contact_us'), FieldPanel('title_over_image'), + InlinePanel('courses', label='Program Courses'), InlinePanel('faqs', label='Frequently Asked Questions'), - InlinePanel('courses', label='Program Courses') ] def get_context(self, request): @@ -128,7 +143,7 @@ class FrequentlyAskedQuestion(Orderable): """ program_page = ParentalKey(ProgramPage, related_name='faqs') question = models.TextField() - answer = models.TextField() + answer = RichTextField() content_panels = [ MultiFieldPanel( diff --git a/cms/templates/cms/home_page.html b/cms/templates/cms/home_page.html index 2165bcd263..9dbbead591 100644 --- a/cms/templates/cms/home_page.html +++ b/cms/templates/cms/home_page.html @@ -6,7 +6,7 @@ {% wagtailuserbar %} {% block body_class %}template-programpage{% endblock %} -{% block title %}{% trans "MIT MicroMaster’s" %}{% endblock %} +{% block title %}{% trans "MIT MicroMasters" %}{% endblock %} {% block content %} @@ -15,7 +15,7 @@