Krotimo Googlov oblak
Zanimiva nova zmožnost spletnih pisarn je programiranje. Ob pomoči skriptne kode in pripravljenih predmetov lahko sestavimo najrazličnejše avtomatizirane postopke, ki ohranjajo vse prednosti dela v oblaku - preprosta raba ob kateremkoli času, s katerekoli naprave, ki ponuja povezljivost v splet in dovolj sodoben spletni brskalnik.
Vse več naših vsakdanjih dejavnosti se seli v splet. Vse bolj tudi dokumenti. Zadnje čase različni ponudniki kar tekmujejo v tem, kdo bo ponudil več brezplačnega prostora v oblaku, številni pa ponujajo tudi možnost urejanja dokumentov kar v spletnem brskalniku, ne da bi potrebovali kakršnokoli dodatno programsko opremo. Eden izmed pionirjev pisarne v oblaku je seveda Google, ki ga zanima prav vse, povezano s spletom (in kopičenjem informacij o uporabnikih). Njegova storitev Google Docs se je nedavno preimenovala v Google Drive in ponuja možnost brezplačnega izkoriščanja do 5 GB prostora v oblaku (po ugodni ceni lahko zakupimo še veliko, veliko več). Ta prostor lahko izkoristimo za hrambo česarkoli, če pa bomo tam shranjevali tudi dokumente Googlove pisarne v oblaku, se nam razpoložljivi prostor zaradi tega ne bo manjšal. Seveda lahko take dokumente urejamo kar v spletnem brskalniku, ta prispevek pa bomo posvetili še veliko bolj vznemirljivi možnosti - Google namreč omogoča, da delo z dokumenti tudi avtomatiziramo ob pomoči skriptne kode.
Skripta za oblak
Google je za programiranje dokumentne avtomatizacije izbral kar javascript. A to je le skladnja, ta javascript je precej drugačen od našega znanca iz spletnih brskalnikov. Najbolj očitna razlika je, da se izvaja kar v Googlovih strežnikih. Zaradi tega ima nekatere zanimive možnosti, še pomembnejše pa so najrazličnejše omejitve, ki jih vsiljuje okolje tako zaradi varnosti kot zaradi zagotavljanja ustrezne zmogljivosti. Žal so trenutno nastavitve še precej omejujoče, kot bomo podrobneje spoznali v nadaljevanju.
Ključ zmogljivosti skriptne kode se skriva v predmetih, ki jih je Google omogočil za rabo. Med drugim imamo najrazličnejše predmetne modele za ponazoritev dokumentnih aplikacij in vsebine, ki jo v njih urejamo. Na voljo so tudi številni pomočniki, npr. za časovno nadzorovanje izvajanja. Ob tem je vsa moč skriptne kode seveda lahko združena s funkcijami, ki jih podpirajo preglednice, kjer najdemo preprost zajem drugih spletnih virov HTML, XML ali JSON.
Tako tudi ne čudi, da skriptno kodo pišemo kot del Googlovih preglednic v oblaku (Spreadsheet). Ta del svojih storitev Google pospešeno razvija in skoraj vsak teden je predstavljena kakšna novost. Da so razvijalci novo podlago kar dobro sprejeli, priča tudi to, da so nedavno vzpostavili javni semafor, ki prikazuje zdravje vseh storitev, ki so lahko zajete v skriptne programe. Ta semafor najdemo na naslovu: https://docs.google.com/macros/dashboard. Storitev v semaforju so neposredno povezane z referenčno pomočjo ustreznega premeta. Nas bosta npr. v nadaljevanju zanimala predmeta SpreadsheetApp (https://developers.google.com/apps-script/service_spreadsheet) in GmailApp (https://developers.google.com/apps-script/service_gmail).
Za več informacij o skriptnem programiranju Googlovega oblaka lahko obiščemo še naslov https://developers.google.com/apps-script/, razvijalcem, ki začenjajo spoznavati programiranja spletne pisarne, pa je namenjeno poglavje
https://developers.google.com/apps-script/guide_getting_started.
Spletišče za skriptne razvijalce (https://developers.google.com/apps-script/).
Nad e-pošto
Uporabnikov spletne pošte Gmail ne manjka. Storitev ima nekatere zanimive posebnosti, kot je pregled skupine sporočil kot enotni pogovor, možnost takojšnjega sporočanja, po novem so v Gmail vpletli celo kroge iz Google+. No, kakorkoli že, Gmailu manjkata pomembni zmožnosti: urejanje sporočil po velikosti in možnost odstranjevanja velikih priponk, ki nam ne pomenijo več kaj dosti, oz. smo jih že shranili na disk, zdaj pa nam odžirajo dragoceni prostor v nabiralniku. Storitev Google Drive resda obeta, da bo nekoč morda le prišla možnost shranjevanja priponk neposredno tja in s tem razbremenjevanje nabiralnika, a kdo ve, kako dolgo jo bomo še čakali. Če se torej naši nabiralniki za e-pošto nevarno polnijo, nam lahko pomaga prav Google Apps Script.
Na srečo bomo med pomočniki za skriptno kodo našli tudi predmet GmailApp, ki omogoča dostop do programsko dosegljivih storitev Gmaila. Z nekaj truda si lahko pripravimo skript, ki nam bo izbrskal sporočila z največjimi priponkami. S tem bomo v prepolne nabiralnike lahko vnesli nekaj več reda, ali z brisanjem sporočil ali pa z dodatno zvijačo, ki nam bo ponudila celo odstranjevanje priponke, ne da bi zbrisali sporočilo.
Postopek
Ravno med nastajanjem tega članka smo v spletu našli podobno rešitev, ki smo jo zaradi nekoliko večje uporabniške prijaznosti posvojili in prilagodili naši rešitvi. Če vas zanima še en pogled na iskanje prevelikih sporočil, si v spletu oglejte tale naslov: http://www.labnol.org/internet/sort-gmail-by-size/21191/. Za nas je seveda pomembno, da si na zgledu ogledamo, kaj vse skript zmore, in damo nekaj napotkov, kako lahko zmogljivosti kode še izboljšamo. S tem želimo navdihniti čim več uporabnikov, da bi se programiranja s skriptno kodo lotili tudi sami.
Če želite, lahko končni izdelek tega prispevka najdete tudi v spletu, na naslovu: http://goo.gl/Mlxhr. Odpremo ga lahko le v načinu za pregled, a nič zato, za delo tako ali tako potrebujemo lastno kopijo. Moramo se prijaviti s svojim računom Google (ali Gmail, če se že nismo) in za tem z menuja File izbrati ukaz Make a copy ... Navodila so sicer zapisana tudi v stolpcu F te preglednice.
Če se bomo dela lotili sami, najprej potrebujemo novo preglednico. V storitvi Google Drive izberemo Create | Spreadsheet. Najbolje bo, da jo takoj preimenujemo, s klikom imena ali z ukazom File | Rename... Lahko ji damo npr. ime "Gmail velikosti". V preglednici nas bo zanimal urejevalnik skript, ki ga najdemo na menuju Tools | Script Editor... Gre za kar zmogljiv urejevalnik in razhroščevalnik, na voljo neposredno v spletnem brskalniku. Zelo hitro si lahko pripravimo ogrodje našega programčka. Zbrišimo morebitno kodo in za začetek napišimo tri funkcije, le eno izmed njih polno:
/*
* Izvedi ob odpiranju preglednice
* - doda nov meni
* - opozori uporabnika
*/
function onOpen() {
var dok =
SpreadsheetApp.getActiveSpreadsheet();
var meni = [];
meni.push({
name: "Preglej nabiralnik",
functionName: "gmPregled"
});
meni.push({
name: "Počisti list",
functionName: "gmPocisti"
});
dok.addMenu(
"Gmail (izberi!)",
meni
);
dok.toast(
"Izberite akcijo v novem meniju 'Gmail'",
"Vzpostavljen"
);
}
function gmPocisti() {}
function gmPregled() {}
Vneseno kodo moramo shraniti, da jo Googlov oblak analizira in prepozna. Ob prvem shranjevanju bomo morali poimenovati tudi skriptni projekt, lahko mu damo ime, enako preglednici. Shranimo ga z ukazom File | Save, na voljo pa je tudi bližnjica s kombinacijo tipk Ctrl+S oz. gumb v orodjarni.
Če ni napak, se bo seznam v orodjarni napolnil z imeni funkcij v naši kodi. Na morebitne napake nas urejevalnik opozori in nam ponudi vrstico, v kateri se skriva, tako da lahko hitro popravimo skladnjo programa. Za preverjanje pravilnosti delovanja bo seveda potreben vsaj en poskusni zagon. Na srečo imamo na voljo tudi razhroščevalnik, ki ga aktiviramo z menuja ali iz orodjarne.
Zagon zahteva avtorizacijo kode. To moramo prav gotovo izvesti ob prvem zagonu, lahko pa se prikaže tudi po vsakem popravku kode, če vpletemo kakšno novo storitev ali predmet iz Googlovega nabora. Z avtorizacijo se seveda prepreči možnost, da bi nam kdo podtaknil preglednico, ki bi nam takoj ob odprtju npr. pokradla vse naslove prijateljev ali zbrisala dokumente. Morda je nekoliko sitna, a je nedvomno potrebna in koristna. Poleg tega jo lahko opravimo z nekaj kliki, vendar seveda previdno, kadar nas zahteva po avtorizaciji doleti pri preglednicah, ki niso naše!
Naš program skriva začetno funkcionalnost v funkciji s posebnim imenom. Če jo poimenujemo onOpen(), se pokliče samodejno, kadarkoli uporabnik preglednico odpre. V naši kodi poskrbimo za dodajanje nove izbire na menu in prikaz opozorila (toast), ki izskoči iz vrstice stanja. Vse skupaj dosežemo ob pomoči že pripravljenih predmetov, na nas je le, da pokličemo ustrezne funkcije (.addMenu() in .toast()) .
Novi menujski izbiri smo že povezali s praznima funkcijama v kodi: gmPocisti() in gmPregled(), na nas je še, da ju ustrezno izpopolnimo.
Manj zahtevna je funkcija čiščenja preglednice, ki bo omogočala svež zagon pregledovanja sporočil. Preglednico bomo izkoristili tudi za uporabniški vmesnik našega programa. Prvo vrstico bomo izkoristili za pojasnila vrednosti, ki jih bomo kasneje programsko dodajali. Tako se vrnemo na preglednico (verjetno je še vedno odprta v kakšnem zavihku brskalnika) in v prvo vrstico, v celice od A1 do E1 vnesemo pojasnila:
Datum / Poslal / Naziv / Velikost (MB) / Vez
Videz preglednice lahko po želji preoblikujemo.
Nazaj v urejevalniku kode bomo izpolnili funkcijo gmPocisti():
/*
* Počisti delovno površino preglednice
*/
function gmPocisti() {
UserProperties.setProperty("pregled", "0");
var list = SpreadsheetApp.getActiveSheet();
list
.getRange(2, 1, list.getLastRow(), 5)
.clearContent();
SpreadsheetApp
.getActiveSpreadsheet()
.toast(
"Izberite 'Preglej nabiralnik'",
"Vzpostavljen",
-1
);
}
Skriptna koda se praviloma izvaja kratek čas, zato moramo poskrbeti za shranjevanje informacije, ki jo potrebujemo ob kasnejših zagonih. Za to sicer lahko izkoristimo celice na preglednici, vendar so s tem izpostavljene uporabniku. Skriptna koda nam omogoča trajno hranjenje različnih lastnosti v globalni shrambi, ki se vzdržuje tudi po koncu izvajanja. Vanjo sicer ne moremo shranjevati velikih količin podatkov, vendar je za naš zgled kakor nalašč. Uporaba je preprosta, izberemo ključ (enolično besedilo) in vrednost (tudi besedilo, ki pa ga lahko kasneje pretvorimo). Za nas bo pomembna informacija, koliko sporočil smo že pregledali. To vzpostavimo v globalni shrambi pod ključem "pregled". V nadaljevanju kode vidimo, kako lahko ugotovimo zadnjo izpolnjeno vrstico (.getLastRow()), kar nam pomaga pri tem, da počistimo delovno površino lista, od druge vrstice naprej, a le v prvih petih stolpcih. Na koncu še obvestimo uporabnika (že znani .toast(), ki ima tokrat še tretji parameter z vrednostjo -1, ki določa, da obvestilo vztraja na zaslonu, dokler ga ne skrije sam uporabnik.
Ostala nam je še najpomembnejša funkcija, pregled nabiralnika in iskanje sporočil z velikimi priponkami. Najprej si bomo pripravili dve "konstanti":
/*
* Pregled nabiralnika
*/
function gmPregled() {
// koliko niti naenkrat
var MSG_NUM = 100;
// mejna velikost v MB
var MSG_SIZE = 2;
Določata, koliko niti bomo obdelali v enem prehodu, in mejno velikost. Če posamezno sporočilo to velikost doseže ali preseže, ga bomo zapisali v preglednico.
Zatem preberemo ali vzpostavimo globalno shrambo, ki šteje, koliko smo že pregledali v prejšnjih zagonih skripta:
// globalna lastnost, do kje smo pregledali
// - če je še ni, jo vzpostavimo
if (!UserProperties.getProperty("pregled")) {
UserProperties
.setProperty("pregled", "0");
}
// - preberemo stanje globalnega števca
var pregled =
parseInt(UserProperties.getProperty("pregled"));
Pregled vrednosti v globalni shrambi lahko prikličemo z ukazom File |Project properties... Skrivajo se pod jezičkom User properties, kjer jih lahko tudi urejamo.
V kodi nadaljujemo delo z iskanjem prazne vrstice na delovni površini brskalnika, da lahko nadaljujemo, ne da bi prekrivali že vstavljene vrstice:
var list = SpreadsheetApp
.getActiveSheet();
var dok = SpreadsheetApp
.getActiveSpreadsheet()
// najdemo prvo prazno vrstico
// preglednice
var vrednosti =
dok.getRange('A:A').getValues();
var vrstica = 2;
while ( vrednosti[vrstica][0] != "" ) {
vrstica++;
}
Ključna storitev je iskanje sporočil. Na voljo je predmet s posebno funkcijo:
// najdimo nekaj niti sporočil,
// ki imajo priponke
var niti = GmailApp.search(
"has:attachment",
pregled, MSG_NUM
);
Gmail sporočila združuje v pogovore (conversations, tehnično tudi niti - threads). Ob pomoči funkcije .search() lahko najdemo vse niti, ki ustrezajo iskalnemu pogoju. Tega vnesemo enako, kot da bi bili v Gmailu. Iskani izraz "has:attachment" najde vse niti, ki vsebujejo priponke. Ker je lahko vrnjena količina sporočil zelo velika, imamo možnost omejiti število zadetkov. Mi smo izbrali za MSG_NUM niti (torej 100 glede na kodo od prej), začenši s shranjenim stanjem, ki je v spremenljivki pregled.
Izid iskanja bo v polju niti. Če je polje prazno, smo prišli do dna nabiralnika in se lahko vrnemo iz funkcije ter s tem preprečimo nadaljnjo obdelavo:
// smo prišli do dna nabiralnika?
if (niti.length == 0) {
dok.toast(
"Pregledal " + pregled +
" sporočil.",
"Zaključeno", -1
);
return;
}
Če smo kaj niti le našli, moramo napisati dve zanki, prva se sprehaja prek vseh sporočil v niti, druga pa sešteva velikost vseh priponk v sporočilu, ki jih ima:
for (var i=0; i<niti.length; i++) {
// posamezna sporočila so del niti
var posta = niti[i].getMessages();
// za vsa sporočila v niti
for (var m=0; m<posta.length; m++) {
// skupna velikost bo
// seštevek priponk
var velikost = 0;
var priponke = posta[m]
.getAttachments();
for (var j=0; j<priponke.length; j++) {
// prištevamo št. bajtov
velikost += priponke[j]
.getBytes().length;
}
// bajti v megabajte z dvema decimalkama
velikost = Math
.round(velikost*100/(1024*1024))/100;
Tako končno pridemo do velikosti, ki bo odločila, ali smo našli "veliko ribo":
// zabeležimo velikost >= MSG_SIZE MB
if (velikost >= MSG_SIZE) {
list.getRange(vrstica,1)
.setValue(
Utilities.formatDate(
posta[m].getDate(),
"CET", "dd.MM.yyyy"
)
);
list.getRange(vrstica,2)
.setValue(posta[m].getFrom());
list.getRange(vrstica,3)
.setValue(posta[m].getSubject());
list.getRange(vrstica,4)
.setValue(velikost);
list.getRange(vrstica,5)
.setFormula(
"=hyperlink("
+ "\"https://mail.google.com/"
+ "mail/u/0/#all/"
+ posta[m].getId() + "\""
+ ";\"Poglej\")"
);
vrstica++;
} // if
Z vrsto klicev funkcije .getRange() pridemo do ustrezne celice, ki jo zapolnimo ali z .setValue() ali z .setFormula(). Enolična številka vsakega sporočila nam omogoča sestavo povezave do tistega sporočila.
Na koncu še popravimo globalni števec, da bomo naslednjič znali nadaljevati s pravega mesta:
// premaknemo globalni števec pregledanih niti
pregled++;
UserProperties
.setProperty("pregled", pregled);
Dodamo še pavzo:
// da ne sprožimo opozorila
// "Service invoked too many times in short time"
Utilities.sleep(1000);
Skript se izvaja v strežniku, ki vsiljuje določene omejitve. Ne pusti predolgega izvajanja, prav tako omejuje število klicev na sekundo do nekaterih ključnih storitev. V našo kodo smo zato dodali zakasnitev s funkcijo .sleep(), da ne izzovemo (prehitro) sporočila o napaki zaradi presežene kvote klicev. Ta se sicer še vedno lahko pripeti, zato tudi skript pišemo na način, ki omogoča poljubno število zaporednih zagonov.
Če kodo pišemo sami, poskrbimo še za zapiranje vseh odprtih blokov ({...}). Če nam slučajno nikakor ne bo uspelo sestaviti kode, ki bi delovala brez napak, vedno lahko odpremo že dokončan zgled. Kot smo omenili zgoraj, je na voljo na naslovu http://goo.gl/Mlxhr.
Pregled zdravja skriptnih storitev in razpoložljive kvote uporabe (https://docs.google.com/macros/dashboard).
Kako naprej
S tem uporabnim zgledom smo seveda šele popraskali po površini. Že kratek sprehod po menujih urejevalnika kode nam razkriva zanimive možnosti nadaljnjega raziskovanja:
Vsekakor nam možnosti za raziskovanje ne bo zmanjkalo.
Skript med delom polni preglednico s podatki o najobsežnejših sporočilih.
Zvijače
Seveda bo koristno izvedeti tudi, kako nam pridobljeni seznam lahko pomaga pri obvladovanju prepolnega nabiralnika. Za začetek ga lahko uredimo po velikosti priponk. Preglednica je za to kot naročena, kliknemo priročni menu stolpca D (simbol prevrnjenega trikotnika) in izberemo Sort sheet Z -> A.
Kot smo videli, nam skript pripravi tudi neposredno vez do sporočila z obsežno priponko ali priponkami. Klik te vezi nam sporočilo odpre. Ena možnost je, da izbrišemo celotno nit, a to pogosto ne pride v poštev. Kaj torej storiti, da si sprostimo nekaj prostora? Lahko se znebimo samo enega sporočila v niti, vsako sporočilo v Gmailu ima še priročni menu, skriva se v desnem zgornjem vogalu, pod navzdol obrnjenim trikotnikom. V njem lahko najdemo tudi ukaz Delete this message. Tako bomo ohranili celotno nit, razen omenjenega sporočila. Kaj pa, če se nam zdi pomembna tudi vsebina tega sporočila, radi bi se znebili le priponke? Zgolj v Gmailu je samo možnost, da sporočilo posredujemo in pri posredovanju izklopimo priponke. S tega priročnega menuja izberemo Forward, sporočilo naslovimo nase in izklopimo stikala poleg priponk. Vsebino lahko še popravimo, morda z opombo, da smo odstranili priponko iz izvirnika in sporočilo pošljemo sami sebi. V nit se bo dodalo novo sporočilo, tokrat brez priponk. Zdaj lahko odstranimo izvirnik.
Če se želimo ukvarjati z zunanjimi pripomočki, pa bo najbolje, da kritična sporočila označimo z ustrezno oznako. Gre tudi s skriptno kodo, le oznake morajo biti že pripravljene, saj skriptna koda (še) ne more dodajati novih. Če si tako npr. pripravimo oznako "Požeruhi", jo lahko na najdena sporočila preprosto dodamo:
// oznaka
var oznaka = GmailApp
.getUserLabelByName("Požeruhi");
Ko najdemo sporočilo, ustrezno označimo njegovo nit:
niti[i].addLabel(oznaka);
S tem bomo vsa velika sporočila zbrali tudi pod ustrezno oznako. Tako jih lahko hitro prikličemo iz Gmaila, še bolje pa je, da lahko zdaj samo to oznako sinhroniziramo z zunanjimi odjemalci. V Gmailu moramo najprej omogočiti dostop IMAP (več tu: http://goo.gl/fwXkz), potem lahko uporabimo zunanjega odjemalca, kot je npr. IMAPSize (http://www.broobles.com/imapsize/index.php), ki omogoča sinhroniziranje samo izbranih map (za Gmail so to oznake). Ta odjemalec podpira tudi odstranjevanje priponke. Izvede ga tako, da prenese izvirno sporočilo, odstrani in shrani oznako, naloži novo sporočilo z enakimi atributi kot izvirnik, le brez priponke, in na koncu izbriše izvirnik. Postopek zna biti dolgotrajen, zato je še kako priročno, da so kritična sporočila že označena in s tem v eni sami mapi IMAP.