EdupageAPI / edupage-api

A python library for accessing your Edupage account
https://edupageapi.github.io/edupage-api/
GNU General Public License v3.0
66 stars 13 forks source link

[Feature request] Webpage editor #57

Open patwork opened 1 year ago

patwork commented 1 year ago

Is there support for editing the school website in the library expansion plans? I am looking for the ability to modify:

ivanhrabcak commented 1 year ago

I think it would definetly be possible. I will investigate the details and give you an update if I find a smart way to implement/test this.

patwork commented 1 year ago

Thanks! I guess file upload support is already in edupage_api/cloud.py but I didn't find the ability to read the file list and create folders.

I looked at the news edit page (/news/?akcia=save) and I see that the data sent in POST is compressed using https://github.com/imaya/zlib.js and converted to Base64. I don't know if zlib libraries from python will be compatible with zlib.js?

This page decodes data sent by the news editor: https://jgraph.github.io/drawio-tools/tools/convert.html

ivanhrabcak commented 1 year ago

To my knowledge, there is no way in the Edupage's website itself to upload folders (only .zip files that contain folders), or to browse the files you (or someone else uploaded). Can you do that? Did I not notice something?

patwork commented 1 year ago

I mean creating new empty directories. On the /customize/files.php page, in the lower right corner, there is a button with a directory icon (class "newFolderBtn").

As for reading the list of files, it should be doable but requires parsing the HTML returned by files.php (POST cmd=FilesBrowser akcia=getTab).

ivanhrabcak commented 1 year ago

Seems pretty hard to implement:/. I've written some code, but nothing complete. I am putting this feature into my backlist and I will work on it when I have more time.

It would be very helpful if you could provide at least some code or example requests (or you can specify what exactly you need).

patwork commented 1 year ago

Hi, thanks for the info.

In the end, I decided to use javascript directly in the browser console window. This way I can access some of the edupage functions directly and not have to write them from scratch.

My goal was to move the news content from the existing joomla site to the edupage site. This was more or less successful, although I still have my doubts that the news entered manually doesn't display a little differently than the imported ones. However, this may be the result of different text formatting in joomla.

ivanhrabcak commented 1 year ago

Would it be possible for you to provide the code you used? (The javascript you run in the browser would be enough)

patwork commented 1 year ago

Key scripts are:

The newsItemEditor.js script handles the saving and publishing of news. You can find there an object with list of public functions:

var actionFuncs = {}; ... actionFuncs.save = function() ... actionFuncs.publish = function()

In addition to this, the key element is the substituted POST support from jQuery in the edubarUtils.js file:

$j.origPost = $j.post; ... $j.post = function(url, data, success, dataType, eqav)

The save() function from newsItemEditor retrieves the data from the editor form on the page, prepares the data structure and sends it using a substituted $.post in edubarUtils which compresses the entire query and sends it to the backend.

The way my code works is that it prepares an analogous data structure, but before sending it to $.post it substitutes the HTML content with data exported from joomla.

IMPORTANT: the assumption is that my script runs from the console and only when the news edit dialog is open in the browser.

First, I'm querying for:

const mainElem = $('.ui-dialog-content').first().children().first();
const mainElemId = mainElem.attr('id');
const editorWidget = mainElem.find('.simple-rte-editor').first();
const editorWidgetFuncs = editorWidget.data('publicFuncs');
const jwid = mainElemId.split('_')[0];

Creating url for posting data:

const url = {
  jwgc: 'NewEditDialog',
  jwid: jwid,
  asDialog: 1,
  maxNewsCount: 22,
  akcia: 'save',
};
url['ak_' + jwid] = 'save';
const formurl = '/news/?' + new URLSearchParams(url).toString();

News data structure (notice the use of the external getData function directly from the editor on the page):

const newData = {
  textdata: editorWidgetFuncs.getData(),
  datefrom: '',
  dateto: '',
  image: '',
  albumVisible: false,
  addToSlider: false,
  stav: 'o',
  addTimeline: '',
};

Next, I'm parsing returned html and looking for first text field.

const domParser = new DOMParser();
const html = domParser.parseFromString(
    newData.textdata.html,
    'text/html'
);
const divs = html.body.getElementsByClassName('erte-text-inner');

Substitution (sorry about those widgets.widgets... mess):

divs[0].innerHTML = HERE_GOES_NEW_HTML_FROM_JOOMLA;
newData.textdata.rtedata.widgets[0].widgets[0].widgets[0].widgets[0].props.text = divs[0].innerHTML;

News title:

  newData.title = TITLE_STRING_FROM_JOOMLA;

Yet another structure, this time for edubarUtils' post:

const postData = {
  newid: HERE_GOES_ID_OF_THE_NEWS_IN_EDUPAGE,
  newData: JSON.stringify(newData),
};

And now we are ready to send postData structure to edubarUtils' post (accessible by $j.post):

  $j.post(formurl, postData, (res) => console.log(res), 'json');
ivanhrabcak commented 1 year ago

Thank you very much!