1. TIM Plugin määritys
Dokumentissa määritellään TIMin ja pluginien välinen rajapinta ja niiden välinen vuorovaikutus.
2. Toimintaperiaate
Yllä olevassa kuvassa on esitetty TIMin ja pluginien välinen toiminta tilanteessa, jossa käyttäjä avaa tehtäväplugineja (yhden tai useampia) sisältävän dokumentin sekä lähettää vastauksen yhteen niistä. Kuvassa tapahtuu seuraavaa:
Selain lähettää pyynnön osoitteeseen
/view/1
, mikä tarkoittaa, että ollaan avaamassa dokumenttia, jonka id on 1.TIM kysyy kaikilta sivun plugineilta, mitä CSS- ja JavaScript-tiedostoja sekä Angular-moduuleja se tarvitsee ja pitää ne muistissa.
- TIM pyytää jokaiselta pluginilta HTML-palan, joka tullaan viemään selaimelle. Tämä tapahtuu lähettämällä pluginin
/html
-reittiin seuraavat tiedot:markup
: dokumentissa oleva plugin-lohkon sisältö JSON-muodossastate
: tilatieto siitä, mihin tilaan käyttäjä on viimeksi pluginin saattanuttaskID
: pluginin tehtävän id, jossa siis on mukana dokumentin id. Esimerkiksi123.tehtava1
. Jos plugin-instanssi ei ole tehtävä (esim. kuvannäyttöplugin), niin tämä kenttä on määrittelemätön, eli sen arvoa ei pidä katsoa (TODO: ei pitäisi lähettää tätä kenttää ollenkaan, jos plugin ei ole tehtävä).taskIDExt
: Laajennettu tehtävän id. Tämä kenttä lähetetään aina ja se on muotoa<dokumentin id>.<tehtävän nimi tai tyhjä>.<kappaleen id>
.doLazy
: True, jos halutaan, että plugin latautuu laiskasti, ts. vasta sitten, kun hiiri koskettaa sitä. Tällä voidaan välttää hitaiden laitteiden työtä isoa dokumenttia ladattaessa. (TODO: Voisi olla infon sisällä.)preview
: True, jos pluginia ollaan renderöimässä esikatseluna muokatessa. (TODO: Voisi olla infon sisällä.)anonymous
: True, jos käyttäjä ei ole kirjautunut. (TODO: Voisi olla infon sisällä.)info
: sisältää seuraavat metatiedot:earlier_answers
: aikaisempien vastausten lukumäärämax_answers
: vastausten sallittu enimmäismäärä tähän tehtävääncurrent_user_id
: kirjautuneen käyttäjän käyttäjätunnususer_id
: sama kuin edellinen (TODO: pitäisi olla vastauksen tekijä(t), josstate
kin on olemassa)look_answer
: ainafalse
, TODO: tätä ei tarvitsisi olla lainkaan HTML-reitissävalid
: onko viimeisin vastaus validi vai ei, TODO: pitäisi voida olla myösnull
, jos yhtään vastausta ei ole
Pluginit palauttavat TIMille parametreja vastaavaa HTML:ää.
TIM lähettää dokumentin plugineineen selaimelle.
- Plugin lataa mahdolliset muut tarvitsemansa resurssit reittiensä avulla.
- Käyttäjä painaa selaimeen renderöidyn tehtävän tallennuspainiketta, minkä johdosta selain (pluginin JavaScript) tekee HTTP-pyynnön
/answer
-reittiin. Pyynnön formaatti on JSON, joka sisältääinput
-nimisen kentän. Tämä kenttä voi sisältää mitä tahansa tietoa, jonka TIM lähettää eteenpäin pluginille. TIM kutsuu siis pluginin answer-reittiä seuraavin tiedoin:input
: selaimelta tullut datamarkup
: ks. yllästate
: ks. yllätaskID
: ks. ylläinfo
: sama kuin yllä seuraavin eroin:look_answer
voi ollatrue
, jos opettaja on vain katsomassa jonkun käyttäjän vastaustauser_id
sisältää puolipisteellä erotettuina niiden käyttäjien tunnukset, jotka ovat vastaamassa tehtäväänvalid
on alustava arvo nyt lähetetyn vastauksen validiudelle. Se siis voi ollafalse
esim. silloin, jos TIM huomaa, että tehtävän vastausaikaraja on umpeutunut.
- Plugin palauttaa
/answer
-reitistä JSONin, jossa on seuraavat kentät:web
: Pakollinen. Tämän TIM lähettää selaimelle osana answer-reitin vastaustasave
: Valinnainen. Jos kenttä on mitä tahansa muuta kuinnull
, TIM tallentaa sen sisällön tietokantaan käyttäen avaimena käyttäjän sisäistä tunnistetta jataskID
:tä. TODO: Pitäisikö myösnull
tallentaa ja vaatia, etteisave
-kenttää ole lainkaan, jos ei ole tallennettavaa?tim_info
: Valinnainen. Voi sisältää seuraavia kenttiä:points
: Valinnainen. Pluginin antamat pisteet käyttäjän vastauksesta. Voi olla mikä tahansa liukuluku, myös negatiivinen.notValid
: Valinnainen. Jos muu kuinnull
, vastaus merkitään tietokantaan ei-validiksi. Huomaa, että vastaus saatetaan merkitä muustakin syystä ei-validiksi (esim. umpeutunut aikaraja).
- TIM lähettää selaimelle vastauksen JSONina, jossa on seuraavat kentät:
web
: Pakollinen. Sama kuin pluginin palauttamaweb
-kenttä.savedNew
: Pakollinen. Tallennetun vastauksen id tietokannassa, jos vastaus tallennettiin, muulloinnull
.error
: Valinnainen. Virhettä kuvaava merkkijono. Tämä kenttä palautetaan silloin, kun answer-reitin aikana tapahtuu jokin virhe tai jos vastaus todettiin epävalidiksi.
2.1 Pluginin markup
Pluginin markup-lohkot ovat YAML-muotoista tekstiä, joissa voi esiintyä makroja (kuten tavallisissakin kappaleissa), jotka oletuksena menevät kaksien prosenttimerkkien (%%...%%) sisälle. Nämä makrot korvataan arvoillaan, minkä jälkeen YAML parsii tekstin ja syntynyt YAML lähetetään pluginille JSONiksi muutettuna.
Pluginin markup kirjoitetaan koodilohkoon, jolla on plugin
-attribuutti. Esimerkiksi:
```{#tehtava1 plugin=csPlugin}
type: console
file: https://svn.cc.jyu.fi/srv/svn/ohj1/luentomonistecs/esimerkit/Pohja/Pohja/Pohja.cs
replace: "Console "
byCode: |
Console.WriteLine("Moi 1");
Console.WriteLine("Moi 2");
```
Toistaiseksi ei ole olemassa erityisesti pluginkappaleille tarkoitettuja makroja. Yleiset makrot on kuvattu ohjeissa.
2.1.1 Erityiskentät
Markupissa voi esiintyä kenttiä, joilla on tietty erityismerkitys ja joita TIM käyttää. Plugin ei saa määritellä näitä kenttiä eri tavalla omaan tarkoitukseensa. Kentät ovat seuraavat:
starttime
: Tätä aikaleimaa aiemmin tehtävään ei voi vastata.deadline
: Tätä aikaleimaa myöhemmin tehtävään ei voi vastata.pointsRule
: Pisteytyssääntö tehtävälle. Tämä voi sisältää seuraavia kenttiä:allowUserMin
: Minimipistemäärä, jonka käyttäjä voi itse määritellä vastaukselleen.allowUserMax
: Maksimipistemäärä, jonka käyttäjä voi itse määritellä vastaukselleen.maxPoints
: Kuvaus tehtävän maksimipistemäärästä. Voi olla mikä tahansa merkkijono.
answerLimit
: Vastausten enimmäismäärä per käyttäjä. Tämän rajan ylittäneet vastaukset merkitään epävalideiksi.lazy
: True, jos plugin pitäisi renderöidä laiskana. Tämä ylikirjoittaa ylätasondoLazy
-määrityksen.
2.2 Pluginin renderöinti selaimeen
Pluginin tuottamaan HTML:ään liittyy usein skriptejä, joiden pitää tietää, miten pluginille voidaan lähettää pyyntöjä. Tämän mahdollistamiseksi TIM sijoittaa pluginin tuottaman HTML:n metatieto-divin sisään:
<div id="{taskIDExt}"
data-plugin="{URL, jota pitkin voi tehdä pyyntöjä pluginille}">
{pluginin HTML}
</div>
Tämän jälkeen pluginiin liittyvät skriptit voivat lukea yo. divistä riittävät metatiedot toimiakseen.
Pluginilta voidaan pyytää myös "laiska" (lazy) HTML-muoto, jolloin plugin näytetään "pelkistettynä" siihen asti, kunnes käyttäjä koskee pluginiin. Tällä voidaan välttää merkittävästi hitaiden laitteiden työtä isoa dokumenttia ladattaessa. Vastausselain vaihtaa pluginin sisällön sitten, kun siihen kosketaan.
Lazy-muodossa pluginin tulee sulkea laiskasti latautuva koodi HTML-kommenttien <!--lazy ... lazy-->
sisään. Esimerkki:
<!--lazy <cs-console>...</cs-console> lazy-->
Heti tämän kommentin perään pluginin tulee antaa itsestään HTML:nä pelkistetty sisältö - siis se, joka näytetään ennen pluginiin koskemista.
2.3 Pluginin kanssa kommunikointi skriptistä
Skripti voi kommunikoida pluginin kanssa hakemalla parent-elementtinsä data-plugin
arvon ja tekemällä pyyntöjä sinne. Osa reiteistä on standardeja ja speksattu tämän dokumentin lopussa, mutta pluginin kirjoittaja voi määritellä myös omia reittejään. Näiden reittien kohdalla TIM vain forwardoi pyynnöt sellaisenaan pluginille.
3. Pluginin tila (state
)
Pluginin tila tallennetaan aina sellaisena kuin plugin sen antaa save
-kentässä. Tila voi sisältää mitä tahansa dataa. Sen ei tarvitse olla JSONia (TODO: pitäisikö?), mutta TIM oletuksena yrittää parsia sen JSONina lähetettäessä pyyntöä html- ja answer-reittiin. Mikäli se onnistuu, state
-kentän arvoksi asetetaan saatu JSON-olio. Muulloin arvoksi asetetaan data sellaisenaan.
4. Reitit
4.1 Pluginien tarjoamat reitit
Kaikki POST- ja PUT-reitit ottavat parametrit JSON-muodossa.
4.1.1 /plugin/html/ [POST]
- SYÖTE: ks. yllä luku 2
- PALAUTTAA: HTML:ksi renderöidyn pluginin
- kutsutaan joka kerta, kun plugin renderöidään
- optio, tehtävä jos ei toteuta
/iframe
(voi olla molemmat)
4.1.2 /plugin/multihtml/ [POST]
SYÖTE: Lista
/html
-reitin vaatimista parametreistaPALAUTTAA: JSON lista HTML:ksi renderöidyt pluginit
esimerkiksi syöte:
[ {"taskID": "25.Writeline", "state": null, "markup": {"user_id": "mikkalle", "byCode": "koodia"}}, {"taskID": "25.puolipistevaarin", "doLazy": true, "state": null, "markup": {"lazy": false, "user_id": "mikkalle", "byCode": "koodia"}}, {"taskID": "25.virheita", "doLazy": true,"state": null, "markup": {"maxrows": 10, "header": "Teht\u00e4v\u00e4 4", "user_id": "mikkalle", "stem": "stem-teksti", "byCode": "koodia"}} ]
johon vastaus on JSON-taulukko, csPluginin tapauksessa tyyliin
[ "<cs-runner>xxxHEXJSONxxx7b226...heksalukuja...</cs-runner>", "<cs-runner>xxxHEXJSONxxx7b226...heksalukuja...</cs-runner>", "<!--lazy <cs-runner>xxxHEXJSONxxx7b226...heksalukuja...</cs-runner> lazy--><div class="csRunDiv"><h4>Tehtävä 4...PLUGININ LAZY HTML...</div> ]
Jos plugin ei halua, että se on lazy-muotoinen pyynnöistä huolimatta, se voi liittää jonon
<!--nolazy-->
lähettämänsä HTML:n alkuun.
kutsutaan kerran per dokumentti per plugintyyppi, jotta dokumentin latausta saadaan nopeutettua
optio; reitin olemassaolo kerrotaan
/plugin/reqs
-reitin avulla, ks. alempana
- säännöt sille, milloin lazy-tehdään Python-koodina yleisissä tapauksissa (jossa
GenericHtmlModel
on muoto, joka sisältää pluginin markupit):
def is_lazy(q: GenericHtmlModel) -> bool: """Determines if the server should render a lazy version of the plugin.""" if q.doLazy == Laziness.Never: return False if q.markup.lazy: return True if q.markup.lazy is False: return False if q.doLazy == Laziness.Yes: return True return False
gitlab linkki http_params.py -tiedostoon ei toimi. Tiedostorakennetta muutettu gitlabin sisällä
DZ: Joo, tuota kooditiedostoa ei olekaan enää olemassa. Nyt on korjattu tilalle "yleinen" logiikka. Tämän logiikan tosin jokainen plugin voi määriittää itse.
—4.1.3 /plugin/iframe/ [POST]
- optio, tehtävä jos ei toteuta reittiä
/html
- muuten kuten
/html
- tuottaa
<iframe source="...."></iframe>
-sisällön
4.1.4 /plugin/reqs/ [GET]
- antaa listan tarvituista CSS, JS etc. tiedostoista sekä tiedon siitä, tuetaanko
multihtml
-reittiä - pluginilla voi olla kolme eri tyyppiä:
embedded
,simpleEmbedded
jaiframe
- alla 3 eri paluuesimerkkiä kunkin tyypin mukaan
PALAUTTAA: (yleisin tapaus)
{ "type": "embedded", "js": ["munSkripti1.js", "http://path/to/js.js"], "css": ["munStyylit.css", "http://path/to/css.css"], "multihtml": true, "canGiveTask": true, "text": ["Mun plugin"], "templates": [[{"text":"Mun eka","file":"munEka","expl":"Ekat ominaisuudet"}, {"file":"munToka"}]] }
type
(embedded/iframe/simpleEmbedded
oletus:embedded
). Pluginin tyyppi.- embedded tyyppi (oletus), html kääritään
<div>
in sisään, jossataskId
japluginURL
- embedded tyyppi (oletus), html kääritään
js
: lista javascripteistä joita plugin tarvitseecss
: lista css-tiedostoista joita plugin tarvitseemultihtml
:true/false
(oletus=false
), vastaako plugin multihtml-reittiincanGiveTask
: plugin voi vastata answer reittiin jos siellä on parametrigetTask: true
. Tälläin mitään ei tallenneta ja annetaan "pienen" mahdollinen vastaus niin että itse tehtävä saadaan näkyviin. Tämä liittyy tehtäviin, joita ei nopeussyistä voidahtml
taimultihtlm
vastauksissa laitata mukaan. Oletus onfalse
ja parametria ei anneta.text
: taulukko tekstejä, joilla plugin esittelee itsensä esimerkiksi editorin tab-listaan, oletus on pluginin nimi. Jos taulukossa on monta nimeä on niille vastaavat tiedot vastaavassa indeksissätemplates
taulukossa.templates
: Taulukko taulukoista. Ulomassa taulukossa on taulukko kutakintext
kohdassa olevaa nimeä varten.
Useimmissa tapauksissa sisempiä taulukkoja on vain yksi. Kukin sisempi taulukko on lista yhteen tabiin tulevista template-tiedostoista joita plugin tarjoaa. Template on tekstitiedosto, jonka sisällön editori kopioi tekstiin kun ko. template listään. Jos file puuttuu, niin oletus on file=template
, tekstille text=<pluginin nimi>
. Jos templates-kohdassa puuttuu expl, niin se on tyhjä. Jos plugin ei halua julkaista templateja, se ei palautatemplates
-attribuuttia tai palauttaa"templates": []"
tai"templates": [[]]"
.text
: teksti jolla template näytetään mm. editorin listassafile
: tiedoston nimi, jolla TIMin editori pyytää ko. templatea jos käyttäjä valitsee templaten lisättäväksiexpl
: editori voi laittaa tämän tekstin vaikka hoverilla templaten valinnan (text
) kohdalle.
- HUOMAA että kaikki templates-tiedostot pitää olla kirjoitettu UTF8-koodauksella.
PALAUTTAA:
{"type":"iframe"}
- jos plugin palauttaa html-kutsusta iframen, niin sitä ei tarvitse kääriä
<div>
in sisään.
- jos plugin palauttaa html-kutsusta iframen, niin sitä ei tarvitse kääriä
PALAUTTAA:
{"type":"simpleEmbedded","css":["munStyylit.css"]}
- plugin tuottaa pelkän HTML, mutta voi tarvita JSS tai CSS:ää (silloin ne ovat tuossa mukana). Ei tarvitse kääriä
<div>
in sisään. Plugin ei kommunikoi TIMin kanssa HTML:än antamisen jälkeen.
- plugin tuottaa pelkän HTML, mutta voi tarvita JSS tai CSS:ää (silloin ne ovat tuossa mukana). Ei tarvitse kääriä
- Jos url alkaa
http://
, niin TIM tulkitsee sen absoluuttiseksi urliksi, mutta muuten url on suhteellinen pluginin osoitteeseen.
4.1.5 /plugin/template/ [GET]
- SYÖTE:
file
: templaten nimiidx
: templaten indeksitemplates
-listassa. Eli samalla indeksi sille, monenteenko pluginin ilmoittamaan tabiin sisältö liittyy. Oletus 0, jos puuttuu.
- PALAUTTAA: templaten tekstimuodossa
Esimerkin tapauksessa idx
ei muuta voisi ollakkaan kuin 0, koska plugin ilmoitti sisältöä vain yhteen tabiin.
Esimerkki csPlugin palautuksista:
4.1.6 /plugin/answer/ [PUT]
- SYÖTE: ks. luku 2.
- PALAUTTAA: ks. luku 2.
5. Templateiden lisääminen
Tässä luvussa template
-sanalla tarkoitetaan tekstinpätkää, joka lisääntyy editorissa kun vastaava template valitaan Plugins
-tabin alta.
Toistaiseksi vain pluginit: csPlugin
ja svn
tukevat templateja. Tosin niiden tukea voidaan käyttää hyväksi templetejen lisäämiseksi muidenkin pohjatekstien syöttämiseksi.
5.1 Template rakenne svn-pluginissa
Esimerkiksi svn
-pluginissa on kolmen pluginin palvelu: svn
, image
ja video
. csPlugin
alla on vastaava rakenne. Templateja varten on hakemistot:
/opt/tim/timApp/modules/svn/templates
svn
0
image
0
video
0
5.1.1 Hymiöt tabin lisääminen
Noiden kolmen hakemiston alle voi lisätä tarvittaessa omia templateja vaikka seuraavasti (uutta hakemistoa EI voi tehdä):
Lisätään editoriin Plugins
-kohdan alle Video
-tabin viereen tab Hymiöt
jonka alle tulee kaksi valintaa Nauru
ja Itku
:
Programs Questions Others Image Video Hymiöt
Itku
Nauru
Close menu
Lisätään hakemiston (joka on siis oltava joku noista kolmesta, koska se on kovakoodattu svn
-pluginiin)
/opt/tim/timApp/modules/svn/templates/video
tiedostoon
tabs.txt
uusi "tabin" nimi vaikkapa Hymiöt
lisäämällä uusi rivi:
Video
Hymiöt
Sitten tehdään tämän indeksiä vastaava hakemisto 1
(hakemiston nimi pitää olla sama indeksi kuin monenellako rivillä ko. tabin nimi on) ja sen alle tarvitava määrä tiedostoja vapaasti valittavilla nimillä tyyliin:
nauru
Nauru
Naurava hymiö
:-)
itku
Itku
Itkevä hymiö
;-(
Tiedostot listautuvat tabin alle niiden nimien mukaisessa aakkosjärjestyksessä. Mikäli nauru
haluttaisiin listaan ennen itku
-riviä, pitäisi tiedostot nimetä esim:
0-nauru
1-itku
Tiedostojen nimet eivät näy mitenkään käyttöliittymään.
Eli itse mallitiedostossa (esim nauru
, nimessä ei saa olla pistettä) on rivit:
- Tabin alla näkyvä teksti
- tekstille tuleva tootip
- loput rivit tulevat sellaisenaan editoriin kun template valitaan
Muutosten jälkeen rakenne on siis:
/opt/tim/timApp/modules/svn/templates/video
tabs.txt
0 - hakemisto video tempateille
1 - hakemisto hymiö tempateille
itku
nauru
Kun muutokset on tehty, pitää (toistaiseksi) itse tim
-kontti käynnistää uudelleen:
/opt/tim$ ./restart.sh tim
Mikäli itse template-tiedostoja nauru
tai itku
muutetaan 3:sta rivistä eteenpäin, ei tarvitse käynistään uudelleen. Mutta jos tiedostoja lisätään, silloin uudelleenkäynistys tarvitaan, koska templatejen menurakenne on cachessa.
5.1.2 Templaten tekstiosa
Itse templaten tekstiosassa voi olla mitä tahansa, mikä lisätään editoriin kun template valitaan. Esimerkiksi listamuotoista videota varten template-tiedosto on
List video
Video as a list item
``` {plugin="showVideo"}
type: list
stem: "Mistä aliohjelmille parametrejä"
videoname: Luento 3
doctext: 6. Aliohjelmat
doclink: "https://tim.jyu.fi/view/1#aliohjelmat"
start: 39:00
end: 1:19:15
width: 400
height: 300
file: "http://kurssit.it.jyu.fi/ITKP102/2015s/luento/luento03a.mp4"
```
5.1.3 Templaten kyselyosa
Templaten tekstiosan alkuun voi lisätä kyselyitä tyyliin:
Tehtävän numero
Sijoittaa tehtävän
- {"what": "TEHTNRO", "text": "Tehtävän numero", "default": "1", "pattern": "[0-9]+", "error": "Pitää olla luku!"}
``` {#tehtavaTEHTNRO plugin="csPlugin"}
...
Kun tällainen template lisätään, niin ennen lisäämistä kysellään dialogilla noiden
- {"what":
alkuisten rivien mukaan arvot korvattaville parametreille. Huomattavaa että rivin pitää alkaa juuri noin ja niiden pitää olla peräkkäin jos on monta korvattavaa kysymystä. Sitten kaikki korvattavat vaihdetaan annettuun arvoon. Mikäli jonkin kysymykseen vastataan Cancel
, mitään ei sijoiteta editoriin.
Parametrien merkitys:
what
- mitä tekstiä etsitään tekstistä ja korvataan kysymyksen vastauksella, regexptext
- kysymyksessä näytettävä tekstidefault
- oletusarvo kysymyksellepattern
- regexp jolla vastauksen oikeellisuus tarkistetaanerror
- teksti joka näytetään, mikäli vastaus ei "mätsää" regexpiinflags
- mitätext
regexp lippuja käytetään korvauksessa. Oletus tyhjä joswhat
puuttuu, muuten "gm".
5.1.4 addTemplateAbove
#- {.removePre nocache="true"}
[Lisää HT-aihe]{.addTemplateAbove .timButton .removePre}
- {"what": "#1", "text": "Syötä työn nimi:", "default": "Työn nimi"}
- {"what": "#2", "text": "Syötä työn Koko:", "default": "10"}
- [Anonymous](./Anonymous) - Ryhmä: Anonymous, #1/#2,
[git](https://gitlab.jyu.fi/Anonymous/ohj1.git)
5.2 Template-tabit
Mikäli useampi plugin tarjoaa templateja saman tab-nimen alla (esim. Programs
) lisää TIM niitä saman tabin alle siinä järjestyksessä missä itse pluginit on TIMille esitelty.
6. Muuta plugineista
- csPluginien tiedosto-cachen tyhjennys mikäli muuttaa sellaisia tiedostoja, joita se hakee
- svnPluginien tiedosto-cachen tyhjennys mikäli muuttaa sellaisia tiedostoja, joita se hakee
These are the current permissions for this document; please modify if needed. You can always modify these permissions from the manage page.