Skip to content
Snippets Groups Projects
  • Robert Raposa's avatar
    remove studio signin and signup pages · 2202545a
    Robert Raposa authored
    This completes the work started in https://github.com/edx/edx-platform/pull/19453
    to use the LMS login and registration for Studio, rather than Studio
    providing its own implementation.
    
    LMS login/registration are being used for the following reasons:
    1. LMS logistration properly handles all SSO integrations.
    2. A single logistration is simpler to maintain and understand.
    3. Allows Studio to work more like all other IDAs that use LMS
    logistration.
    
    The original switch to use LMS logistration for Studio also added the
    toggle `DISABLE_STUDIO_SSO_OVER_LMS` to provide the community some
    additional time for switching. This commit removes this toggle, which
    at this point means all deployments will use the LMS logistration.
    
    This change requires sharing cookies across LMS and Studio. Should that
    prove to be a problem for certain Open edX instances, there are
    discussions of possible alternative solutions.
    See https://github.com/edx/edx-platform/pull/19845#issuecomment-559154256
    
    Detailed changes:
    * Fix some Studio links that still went to old Studio signin and signup.
    * Remove DISABLE_STUDIO_SSO_OVER_LMS feature toggle.
    * Remove old studio signin and signup pages and templates.
    * Fix url name "login", which had different meanings for Studio and LMS.
    * Use the following settings: LOGIN_URL, FRONTEND_LOGIN_URL,
    FRONTEND_LOGOUT_URL, and FRONTEND_REGISTER_URL.
    * Redirect /signin and /signup to the LMS logistration.
    * Add custom metric `uses_pattern_library`.
    * Add custom metric `student_activate_account`.
    * Add Django Settings to allow /signin, /signup, and /login_post to be
    disabled once ready.
    
    This work also relates to ARCH-218 and DEPR-6.
    
    ARCH-1253
    2202545a
webpack.common.config.js 18.98 KiB
/* eslint-env node */

'use strict';

var path = require('path');
var webpack = require('webpack');
var BundleTracker = require('webpack-bundle-tracker');
var StringReplace = require('string-replace-webpack-plugin');
var Merge = require('webpack-merge');

var files = require('./webpack-config/file-lists.js');
var xmoduleJS = require('./common/static/xmodule/webpack.xmodule.config.js');

var filesWithRequireJSBlocks = [
    path.resolve(__dirname, 'common/static/common/js/components/utils/view_utils.js'),
    /descriptors\/js/,
    /modules\/js/,
    /common\/lib\/xmodule\/xmodule\/js\/src\//
];

var defineHeader = /\(function ?\(((define|require|requirejs|\$)(, )?)+\) ?\{/;
var defineCallFooter = /\}\)\.call\(this, ((define|require)( \|\| RequireJS\.(define|require))?(, )?)+?\);/;
var defineDirectFooter = /\}\(((window\.)?(RequireJS\.)?(requirejs|define|require|jQuery)(, )?)+\)\);/;
var defineFancyFooter = /\}\).call\(\s*this(\s|.)*define(\s|.)*\);/;
var defineFooter = new RegExp('(' + defineCallFooter.source + ')|('
                             + defineDirectFooter.source + ')|('
                             + defineFancyFooter.source + ')', 'm');

var workerConfig = function() {
    try {
        return {
            webworker: {
                target: 'webworker',
                context: __dirname,
                entry: require('../workers.json'),
                output: {
                    filename: '[name].js',
                    path: path.resolve(__dirname, 'common/static/bundles')
                },
                plugins: [
                    new BundleTracker({
                        path: process.env.STATIC_ROOT_LMS,
                        filename: 'webpack-worker-stats.json'
                    })
                ],
                module: {
                    rules: [
                        {
                            test: /\.(js|jsx)$/,
                            include: [
                                /node_modules\//
                            ],
                            use: 'babel-loader'
                        }
                    ]
                },
                resolve: {
                    extensions: ['.js']
                }
            }
        }
    } catch (err) {
        return null;
    }
};

module.exports = Merge.smart({
    web: {
        context: __dirname,
        entry: {
            // Studio
            Import: './cms/static/js/features/import/factories/import.js',
            CourseOrLibraryListing: './cms/static/js/features_jsx/studio/CourseOrLibraryListing.jsx',
            'js/factories/textbooks': './cms/static/js/factories/textbooks.js',
            'js/factories/container': './cms/static/js/factories/container.js',
            'js/factories/context_course': './cms/static/js/factories/context_course.js',
            'js/factories/library': './cms/static/js/factories/library.js',
            'js/factories/xblock_validation': './cms/static/js/factories/xblock_validation.js',
            'js/factories/edit_tabs': './cms/static/js/factories/edit_tabs.js',
            'js/sock': './cms/static/js/sock.js',

            // LMS
            SingleSupportForm: './lms/static/support/jsx/single_support_form.jsx',
            AlertStatusBar: './lms/static/js/accessible_components/StatusBarAlert.jsx',
            EntitlementSupportPage: './lms/djangoapps/support/static/support/jsx/entitlements/index.jsx',
            LinkProgramEnrollmentsSupportPage: './lms/djangoapps/support/static/support/jsx/' +
                                               'program_enrollments/index.jsx',
            PasswordResetConfirmation: './lms/static/js/student_account/components/PasswordResetConfirmation.jsx',
            StudentAccountDeletion: './lms/static/js/student_account/components/StudentAccountDeletion.jsx',
            StudentAccountDeletionInitializer: './lms/static/js/student_account/StudentAccountDeletionInitializer.js',
            ProblemBrowser: './lms/djangoapps/instructor/static/instructor/ProblemBrowser/index.jsx',
            CustomUserMenuLinks: './lms/static/js/custom_user_menu_links/CustomUserMenuLinks.js',
            EnterpriseLearnerPortalBanner: './lms/static/js/learner_dashboard/EnterpriseLearnerPortalBanner.jsx',

            // Learner Dashboard
            EntitlementFactory: './lms/static/js/learner_dashboard/course_entitlement_factory.js',
            EntitlementUnenrollmentFactory: './lms/static/js/learner_dashboard/entitlement_unenrollment_factory.js',
            ProgramDetailsFactory: './lms/static/js/learner_dashboard/program_details_factory.js',
            ProgramListFactory: './lms/static/js/learner_dashboard/program_list_factory.js',
            UnenrollmentFactory: './lms/static/js/learner_dashboard/unenrollment_factory.js',
            CompletionOnViewService: './lms/static/completion/js/CompletionOnViewService.js',

            // Features
            CourseGoals: './openedx/features/course_experience/static/course_experience/js/CourseGoals.js',
            CourseHome: './openedx/features/course_experience/static/course_experience/js/CourseHome.js',
            CourseOutline: './openedx/features/course_experience/static/course_experience/js/CourseOutline.js',
            CourseSock: './openedx/features/course_experience/static/course_experience/js/CourseSock.js',
            CourseTalkReviews: './openedx/features/course_experience/static/course_experience/js/CourseTalkReviews.js',
            Currency: './openedx/features/course_experience/static/course_experience/js/currency.js',
            Enrollment: './openedx/features/course_experience/static/course_experience/js/Enrollment.js',
            LatestUpdate: './openedx/features/course_experience/static/course_experience/js/LatestUpdate.js',
            WelcomeMessage: './openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js',

            AnnouncementsView: './openedx/features/announcements/static/announcements/jsx/Announcements.jsx',
            CookiePolicyBanner: './common/static/js/src/CookiePolicyBanner.jsx',

            // Common
            ReactRenderer: './common/static/js/src/ReactRenderer.jsx',
            XModuleShim: 'xmodule/js/src/xmodule.js',
            VerticalStudentView: './common/lib/xmodule/xmodule/assets/vertical/public/js/vertical_student_view.js',
            commons: 'babel-polyfill'
        },

        output: {
            path: path.resolve(__dirname, 'common/static/bundles'),
            libraryTarget: 'window'
        },

        plugins: [
            new webpack.NoEmitOnErrorsPlugin(),
            new webpack.NamedModulesPlugin(),
            new BundleTracker({
                path: process.env.STATIC_ROOT_CMS,
                filename: 'webpack-stats.json'
            }),
            new BundleTracker({
                path: process.env.STATIC_ROOT_LMS,
                filename: 'webpack-stats.json'
            }),
            new webpack.ProvidePlugin({
                _: 'underscore',
                $: 'jquery',
                jQuery: 'jquery',
                'window.jQuery': 'jquery',
                Popper: 'popper.js', // used by bootstrap
                CodeMirror: 'codemirror',
                'edx.HtmlUtils': 'edx-ui-toolkit/js/utils/html-utils',
                AjaxPrefix: 'ajax_prefix',
                // This is used by some XModules/XBlocks, which don't have
                // any other way to declare that dependency.
                $script: 'scriptjs'
            }),

            // Note: Until karma-webpack releases v3, it doesn't play well with
            // the CommonsChunkPlugin. We have a kludge in karma.common.conf.js
            // that dynamically removes this plugin from webpack config when
            // running those tests (the details are in that file). This is a
            // recommended workaround, as this plugin is just an optimization. But
            // because of this, we really don't want to get too fancy with how we
            // invoke this plugin until we can upgrade karma-webpack.
            new webpack.optimize.CommonsChunkPlugin({
                // If the value below changes, update the render_bundle call in
                // common/djangoapps/pipeline_mako/templates/static_content.html
                name: 'commons',
                filename: 'commons.js',
                minChunks: 3
            })
        ],

        module: {
            noParse: [
                // See sinon/webpack interaction weirdness:
                // https://github.com/webpack/webpack/issues/304#issuecomment-272150177
                // (I've tried every other suggestion solution on that page, this
                // was the only one that worked.)
                /\/sinon\.js|codemirror-compressed\.js|hls\.js|tinymce\.full\.min\.js/
            ],
            rules: [
                {
                    test: files.namespacedRequire.concat(files.textBangUnderscore, filesWithRequireJSBlocks),
                    loader: StringReplace.replace(
                        ['babel-loader'],
                        {
                            replacements: [
                                {
                                    pattern: defineHeader,
                                    replacement: function() { return ''; }
                                },
                                {
                                    pattern: defineFooter,
                                    replacement: function() { return ''; }
                                },
                                {
                                    pattern: /(\/\* RequireJS) \*\//g,
                                    replacement: function(match, p1) { return p1; }
                                },
                                {
                                    pattern: /\/\* Webpack/g,
                                    replacement: function(match) { return match + ' */'; }
                                },
                                {
                                    pattern: /text!(.*?\.underscore)/g,
                                    replacement: function(match, p1) { return p1; }
                                },
                                {
                                    pattern: /RequireJS.require/g,
                                    replacement: function() {
                                        return 'require';
                                    }
                                }
                            ]
                        }
                    )
                },
                {
                    test: /\.(js|jsx)$/,
                    exclude: [
                        /node_modules/,
                        files.namespacedRequire,
                        files.textBangUnderscore,
                        filesWithRequireJSBlocks
                    ],
                    use: 'babel-loader'
                },
                {
                    test: /\.(js|jsx)$/,
                    include: [
                        /paragon/
                    ],
                    use: 'babel-loader'
                },
                {
                    test: path.resolve(__dirname, 'common/static/js/src/ajax_prefix.js'),
                    use: [
                        'babel-loader',
                        {
                            loader: 'exports-loader',
                            options: {
                                'this.AjaxPrefix': true
                            }
                        }
                    ]
                },
                {
                    test: /\.underscore$/,
                    use: 'raw-loader'
                },
                {
                    // This file is used by both RequireJS and Webpack and depends on window globals
                    // This is a dirty hack and shouldn't be replicated for other files.
                    test: path.resolve(__dirname, 'cms/static/cms/js/main.js'),
                    loader: StringReplace.replace(
                        ['babel-loader'],
                        {
                            replacements: [
                                {
                                    pattern: /\(function\(AjaxPrefix\) {/,
                                    replacement: function() { return ''; }
                                },
                                {
                                    pattern: /], function\(domReady, \$, str, Backbone, gettext, NotificationView\) {/,
                                    replacement: function() {
                                        // eslint-disable-next-line
                                        return '], function(domReady, $, str, Backbone, gettext, NotificationView, AjaxPrefix) {';
                                    }
                                },
                                {
                                    pattern: /'..\/..\/common\/js\/components\/views\/feedback_notification',/,
                                    replacement: function() {
                                        return "'../../common/js/components/views/feedback_notification'," +
                                               "'AjaxPrefix',";
                                    }
                                },
                                {
                                    pattern: /}\).call\(this, AjaxPrefix\);/,
                                    replacement: function() { return ''; }
                                },
                                {
                                    pattern: /'..\/..\/common\/js\/components\/views\/feedback_notification',/,
                                    replacement: function() {
                                        return "'../../common/js/components/views/feedback_notification'," +
                                               "'AjaxPrefix',";
                                    }
                                }
                            ]
                        }
                    )
                },
                {
                    test: /\.(woff2?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
                    loader: 'file-loader'
                },
                {
                    test: /\.svg$/,
                    loader: 'svg-inline-loader'
                },
                {
                    test: /xblock\/core/,
                    loader: 'exports-loader?window.XBlock!' +
                            'imports-loader?jquery,jquery.immediateDescendents,this=>window'
                },
                {
                    test: /xblock\/runtime.v1/,
                    loader: 'exports-loader?window.XBlock!imports-loader?XBlock=xblock/core,this=>window'
                },
                {
                    test: /descriptors\/js/,
                    loader: 'imports-loader?this=>window'
                },
                {
                    test: /modules\/js/,
                    loader: 'imports-loader?this=>window'
                },
                {
                    test: /codemirror/,
                    loader: 'exports-loader?window.CodeMirror'
                },
                {
                    test: /tinymce/,
                    loader: 'imports-loader?this=>window'
                },
                {
                    test: /xmodule\/js\/src\/xmodule/,
                    loader: 'exports-loader?window.XModule!imports-loader?this=>window'
                },
                {
                    test: /mock-ajax/,
                    loader: 'imports-loader?exports=>false'
                },
                {
                    test: /d3.min/,
                    use: [
                        'babel-loader',
                        {
                            loader: 'exports-loader',
                            options: {
                                d3: true
                            }
                        }
                    ]
                },
                {
                    test: /logger/,
                    loader: 'imports-loader?this=>window'
                }
            ]
        },

        resolve: {
            extensions: ['.js', '.jsx', '.json'],
            alias: {
                AjaxPrefix: 'ajax_prefix',
                accessibility: 'accessibility_tools',
                codemirror: 'codemirror-compressed',
                datepair: 'timepicker/datepair',
                'edx-ui-toolkit': 'edx-ui-toolkit/src/',  // @TODO: some paths in toolkit are not valid relative paths
                ieshim: 'ie_shim',
                jquery: 'jquery/src/jquery',  // Use the non-diqst form of jQuery for better debugging + optimization
                'jquery.flot': 'flot/jquery.flot.min',
                'jquery.ui': 'jquery-ui.min',
                'jquery.tinymce': 'jquery.tinymce.min',
                'jquery.inputnumber': 'html5-input-polyfills/number-polyfill',
                'jquery.qtip': 'jquery.qtip.min',
                'jquery.smoothScroll': 'jquery.smooth-scroll.min',
                'jquery.timepicker': 'timepicker/jquery.timepicker',
                'backbone.associations': 'backbone-associations/backbone-associations-min',
                squire: 'Squire',
                tinymce: 'tinymce.full.min',

                // See sinon/webpack interaction weirdness:
                // https://github.com/webpack/webpack/issues/304#issuecomment-272150177
                // (I've tried every other suggestion solution on that page, this
                // was the only one that worked.)
                sinon: __dirname + '/node_modules/sinon/pkg/sinon.js',
                hls: 'hls.js/dist/hls.js'
            },
            modules: [
                'cms/djangoapps/pipeline_js/js',
                'cms/static',
                'cms/static/cms/js',
                'cms/templates/js',
                'lms/static',
                'common/lib/xmodule',
                'common/lib/xmodule/xmodule/js/src',
                'common/lib/xmodule/xmodule/assets/word_cloud/src/js',
                'common/static',
                'common/static/coffee/src',
                'common/static/common/js',
                'common/static/common/js/vendor/',
                'common/static/common/js/components',
                'common/static/js/src',
                'common/static/js/vendor/',
                'common/static/js/vendor/jQuery-File-Upload/js/',
                'common/static/js/vendor/tinymce/js/tinymce',
                'node_modules',
                'common/static/xmodule'
            ]
        },

        resolveLoader: {
            alias: {
                text: 'raw-loader'  // Compatibility with RequireJSText's text! loader, uses raw-loader under the hood
            }
        },

        externals: {
            $: 'jQuery',
            backbone: 'Backbone',
            canvas: 'canvas',
            coursetalk: 'CourseTalk',
            gettext: 'gettext',
            jquery: 'jQuery',
            logger: 'Logger',
            underscore: '_',
            URI: 'URI',
            XBlockToXModuleShim: 'XBlockToXModuleShim',
            XModule: 'XModule'
        },
        watchOptions: {
            poll: true
        },

        node: {
            fs: 'empty'
        }

    }
}, {web: xmoduleJS}, workerConfig());