forumfunction.inc.php 246 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. use Chamilo\CourseBundle\Entity\CForumPost;
  4. use Chamilo\CourseBundle\Entity\CForumThread;
  5. use Chamilo\UserBundle\Entity\User;
  6. use ChamiloSession as Session;
  7. use Doctrine\Common\Collections\Criteria;
  8. /**
  9. * These files are a complete rework of the forum. The database structure is
  10. * based on phpBB but all the code is rewritten. A lot of new functionalities
  11. * are added:
  12. * - forum categories and forums can be sorted up or down, locked or made invisible
  13. * - consistent and integrated forum administration
  14. * - forum options: are students allowed to edit their post?
  15. * moderation of posts (approval)
  16. * reply only forums (students cannot create new threads)
  17. * multiple forums per group
  18. * - sticky messages
  19. * - new view option: nested view
  20. * - quoting a message.
  21. *
  22. * @package chamilo.forum
  23. *
  24. * @todo convert into a class
  25. */
  26. define('FORUM_NEW_POST', 0);
  27. getNotificationsPerUser();
  28. $htmlHeadXtra[] = api_get_jquery_libraries_js(['jquery-ui', 'jquery-upload']);
  29. $htmlHeadXtra[] = '<script>
  30. function check_unzip() {
  31. if (document.upload.unzip.checked){
  32. document.upload.if_exists[0].disabled=true;
  33. document.upload.if_exists[1].checked=true;
  34. document.upload.if_exists[2].disabled=true;
  35. } else {
  36. document.upload.if_exists[0].checked=true;
  37. document.upload.if_exists[0].disabled=false;
  38. document.upload.if_exists[2].disabled=false;
  39. }
  40. }
  41. function setFocus() {
  42. $("#title_file").focus();
  43. }
  44. </script>';
  45. // The next javascript script is to manage ajax upload file
  46. $htmlHeadXtra[] = api_get_jquery_libraries_js(['jquery-ui', 'jquery-upload']);
  47. // Recover Thread ID, will be used to generate delete attachment URL to do ajax
  48. $threadId = isset($_REQUEST['thread']) ? intval($_REQUEST['thread']) : 0;
  49. $forumId = isset($_REQUEST['forum']) ? intval($_REQUEST['forum']) : 0;
  50. $ajaxUrl = api_get_path(WEB_AJAX_PATH).'forum.ajax.php?'.api_get_cidreq();
  51. // The next javascript script is to delete file by ajax
  52. $htmlHeadXtra[] = '<script>
  53. $(function () {
  54. $(document).on("click", ".deleteLink", function(e) {
  55. e.preventDefault();
  56. e.stopPropagation();
  57. var l = $(this);
  58. var id = l.closest("tr").attr("id");
  59. var filename = l.closest("tr").find(".attachFilename").html();
  60. if (confirm("'.get_lang('Are you sure to delete').'", filename)) {
  61. $.ajax({
  62. type: "POST",
  63. url: "'.$ajaxUrl.'&a=delete_file&attachId=" + id +"&thread='.$threadId.'&forum='.$forumId.'",
  64. dataType: "json",
  65. success: function(data) {
  66. if (data.error == false) {
  67. l.closest("tr").remove();
  68. if ($(".files td").length < 1) {
  69. $(".files").closest(".control-group").hide();
  70. }
  71. }
  72. }
  73. })
  74. }
  75. });
  76. });
  77. </script>';
  78. /**
  79. * This function handles all the forum and forum categories actions. This is a wrapper for the
  80. * forum and forum categories. All this code code could go into the section where this function is
  81. * called but this make the code there cleaner.
  82. *
  83. * @param int $lp_id Learning path Id
  84. *
  85. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  86. * @author Juan Carlos Raña Trabado (return to lp_id)
  87. *
  88. * @version may 2011, Chamilo 1.8.8
  89. */
  90. function handle_forum_and_forumcategories($lp_id = null)
  91. {
  92. $action_forum_cat = isset($_GET['action']) ? $_GET['action'] : '';
  93. $get_content = isset($_GET['content']) ? $_GET['content'] : '';
  94. $post_submit_cat = isset($_POST['SubmitForumCategory']) ? true : false;
  95. $post_submit_forum = isset($_POST['SubmitForum']) ? true : false;
  96. $get_id = isset($_GET['id']) ? (int) $_GET['id'] : 0;
  97. $forum_categories_list = get_forum_categories();
  98. // Verify if forum category exists
  99. if (empty($forum_categories_list)) {
  100. $get_content = 'forumcategory';
  101. }
  102. $content = '';
  103. // Adding a forum category
  104. if (($action_forum_cat === 'add' && $get_content === 'forumcategory') || $post_submit_cat) {
  105. $content = show_add_forumcategory_form([], $lp_id); //$lp_id when is called from learning path
  106. }
  107. // Adding a forum
  108. if ((($action_forum_cat === 'add' || $action_forum_cat === 'edit') && $get_content === 'forum') ||
  109. $post_submit_forum
  110. ) {
  111. $inputvalues = [];
  112. if ($action_forum_cat === 'edit' && $get_id || $post_submit_forum) {
  113. $inputvalues = get_forums($get_id);
  114. }
  115. $content = show_add_forum_form($inputvalues, $lp_id);
  116. }
  117. // Edit a forum category
  118. if (($action_forum_cat === 'edit' && $get_content === 'forumcategory') ||
  119. (isset($_POST['SubmitEditForumCategory'])) ? true : false
  120. ) {
  121. $forum_category = get_forum_categories($get_id);
  122. $content = show_edit_forumcategory_form($forum_category);
  123. }
  124. // Delete a forum category
  125. if ($action_forum_cat === 'delete') {
  126. $list_threads = get_threads($get_id);
  127. for ($i = 0; $i < count($list_threads); $i++) {
  128. deleteForumCategoryThread('thread', $list_threads[$i]['thread_id']);
  129. $link_info = GradebookUtils::isResourceInCourseGradebook(
  130. api_get_course_id(),
  131. 5,
  132. $list_threads[$i]['thread_id'],
  133. api_get_session_id()
  134. );
  135. if ($link_info !== false) {
  136. GradebookUtils::remove_resource_from_course_gradebook($link_info['id']);
  137. }
  138. }
  139. deleteForumCategoryThread($get_content, $get_id);
  140. }
  141. // Change visibility of a forum or a forum category.
  142. if ($action_forum_cat === 'invisible' || $action_forum_cat === 'visible') {
  143. $return_message = change_visibility($get_content, $get_id, $action_forum_cat);
  144. Display::addFlash(
  145. Display::return_message($return_message, 'confirmation', false)
  146. );
  147. }
  148. // Change lock status of a forum or a forum category.
  149. if ($action_forum_cat === 'lock' || $action_forum_cat === 'unlock') {
  150. $return_message = change_lock_status($get_content, $get_id, $action_forum_cat);
  151. Display::addFlash(
  152. Display::return_message($return_message, 'confirmation', false)
  153. );
  154. }
  155. // Move a forum or a forum category.
  156. if ($action_forum_cat === 'move' && isset($_GET['direction'])) {
  157. $return_message = move_up_down($get_content, $_GET['direction'], $get_id);
  158. Display::addFlash(
  159. Display::return_message($return_message, 'confirmation', false)
  160. );
  161. }
  162. return $content;
  163. }
  164. /**
  165. * This function displays the form that is used to add a forum category.
  166. *
  167. * @param array $inputvalues (deprecated, set to null when calling)
  168. * @param int $lp_id Learning path ID
  169. *
  170. * @return string
  171. *
  172. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  173. * @author Juan Carlos Raña Trabado (return to lp_id)
  174. *
  175. * @version may 2011, Chamilo 1.8.8
  176. */
  177. function show_add_forumcategory_form($inputvalues = [], $lp_id)
  178. {
  179. $form = new FormValidator(
  180. 'forumcategory',
  181. 'post',
  182. 'index.php?'.api_get_cidreq()
  183. );
  184. // hidden field if from learning path
  185. $form->addElement('hidden', 'lp_id', $lp_id);
  186. // Setting the form elements.
  187. $form->addElement('header', get_lang('Add forum category'));
  188. $form->addElement('text', 'forum_category_title', get_lang('Title'), ['autofocus']);
  189. $form->addElement(
  190. 'html_editor',
  191. 'forum_category_comment',
  192. get_lang('Description'),
  193. null,
  194. ['ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200']
  195. );
  196. $extraField = new ExtraField('forum_category');
  197. $returnParams = $extraField->addElements(
  198. $form,
  199. null,
  200. [], //exclude
  201. false, // filter
  202. false, // tag as select
  203. [], //show only fields
  204. [], // order fields
  205. [] // extra data
  206. );
  207. $form->addButtonCreate(get_lang('Create category'), 'SubmitForumCategory');
  208. // Setting the rules.
  209. $form->addRule('forum_category_title', get_lang('Required field'), 'required');
  210. // The validation or display
  211. if ($form->validate()) {
  212. $check = Security::check_token('post');
  213. if ($check) {
  214. $values = $form->exportValues();
  215. store_forumcategory($values);
  216. }
  217. Security::clear_token();
  218. } else {
  219. $token = Security::get_token();
  220. $form->addElement('hidden', 'sec_token');
  221. $form->setConstants(['sec_token' => $token]);
  222. return $form->returnForm();
  223. }
  224. }
  225. /**
  226. * This function displays the form that is used to add a forum category.
  227. *
  228. * @param array $inputvalues
  229. * @param int $lp_id
  230. *
  231. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  232. * @author Juan Carlos Raña Trabado (return to lp_id)
  233. *
  234. * @version may 2011, Chamilo 1.8.8
  235. */
  236. function show_add_forum_form($inputvalues = [], $lp_id)
  237. {
  238. $_course = api_get_course_info();
  239. $form = new FormValidator('forumcategory', 'post', 'index.php?'.api_get_cidreq());
  240. // The header for the form
  241. $form_title = get_lang('Add a forum');
  242. if (!empty($inputvalues)) {
  243. $form_title = get_lang('Edit forum');
  244. }
  245. $form->addHeader($form_title);
  246. // We have a hidden field if we are editing.
  247. if (!empty($inputvalues) && is_array($inputvalues)) {
  248. $my_forum_id = isset($inputvalues['forum_id']) ? $inputvalues['forum_id'] : null;
  249. $form->addElement('hidden', 'forum_id', $my_forum_id);
  250. }
  251. $lp_id = (int) $lp_id;
  252. // hidden field if from learning path
  253. $form->addElement('hidden', 'lp_id', $lp_id);
  254. // The title of the forum
  255. $form->addElement('text', 'forum_title', get_lang('Title'), ['autofocus']);
  256. // The comment of the forum.
  257. $form->addElement(
  258. 'html_editor',
  259. 'forum_comment',
  260. get_lang('Description'),
  261. null,
  262. ['ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200']
  263. );
  264. // Dropdown list: Forum categories
  265. $forum_categories = get_forum_categories();
  266. foreach ($forum_categories as $key => $value) {
  267. $forum_categories_titles[$value['cat_id']] = $value['cat_title'];
  268. }
  269. $form->addElement(
  270. 'select',
  271. 'forum_category',
  272. get_lang('Create in category'),
  273. $forum_categories_titles
  274. );
  275. $form->applyFilter('forum_category', 'html_filter');
  276. if ($_course['visibility'] == COURSE_VISIBILITY_OPEN_WORLD) {
  277. // This is for horizontal
  278. $group = [];
  279. $group[] = $form->createElement('radio', 'allow_anonymous', null, get_lang('Yes'), 1);
  280. $group[] = $form->createElement('radio', 'allow_anonymous', null, get_lang('No'), 0);
  281. $form->addGroup($group, 'allow_anonymous_group', get_lang('Allow anonymous posts?'));
  282. }
  283. $form->addButtonAdvancedSettings('advanced_params');
  284. $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
  285. $form->addDateTimePicker(
  286. 'start_time',
  287. [get_lang('Public access (access authorized to any member of the course)ation date'), get_lang('Public access (access authorized to any member of the course)ation dateComment')],
  288. ['id' => 'start_time']
  289. );
  290. $form->addDateTimePicker(
  291. 'end_time',
  292. [get_lang('Closing date'), get_lang('Closing dateComment')],
  293. ['id' => 'end_time']
  294. );
  295. $form->addRule(
  296. ['start_time', 'end_time'],
  297. get_lang('Start date must be before the end date'),
  298. 'compare_datetime_text',
  299. '< allow_empty'
  300. );
  301. $group = [];
  302. $group[] = $form->createElement('radio', 'moderated', null, get_lang('Yes'), 1);
  303. $group[] = $form->createElement('radio', 'moderated', null, get_lang('No'), 0);
  304. $form->addGroup($group, 'moderated', get_lang('Moderated forum'));
  305. $group = [];
  306. $group[] = $form->createElement('radio', 'students_can_edit', null, get_lang('Yes'), 1);
  307. $group[] = $form->createElement('radio', 'students_can_edit', null, get_lang('No'), 0);
  308. $form->addGroup($group, 'students_can_edit_group', get_lang('Can learners edit their own posts?'));
  309. $group = [];
  310. $group[] = $form->createElement('radio', 'approval_direct', null, get_lang('Approval'), 1);
  311. $group[] = $form->createElement('radio', 'approval_direct', null, get_lang('Direct'), 0);
  312. $group = [];
  313. $group[] = $form->createElement('radio', 'allow_attachments', null, get_lang('Yes'), 1);
  314. $group[] = $form->createElement('radio', 'allow_attachments', null, get_lang('No'), 0);
  315. $group = [];
  316. $group[] = $form->createElement('radio', 'allow_new_threads', null, get_lang('Yes'), 1);
  317. $group[] = $form->createElement('radio', 'allow_new_threads', null, get_lang('No'), 0);
  318. $form->addGroup($group, 'allow_new_threads_group', get_lang('Allow users to start new threads'));
  319. $group = [];
  320. $group[] = $form->createElement('radio', 'default_view_type', null, get_lang('Flat'), 'flat');
  321. $group[] = $form->createElement('radio', 'default_view_type', null, get_lang('Threaded'), 'threaded');
  322. $group[] = $form->createElement('radio', 'default_view_type', null, get_lang('Nested'), 'nested');
  323. $form->addGroup($group, 'default_view_type_group', get_lang('Default view type'));
  324. // Drop down list: Groups
  325. $groups = GroupManager::get_group_list();
  326. $groups_titles[0] = get_lang('Not a group forum');
  327. foreach ($groups as $key => $value) {
  328. $groups_titles[$value['id']] = $value['name'];
  329. }
  330. $form->addElement('select', 'group_forum', get_lang('For Group'), $groups_titles);
  331. // Public or private group forum
  332. $group = [];
  333. $group[] = $form->createElement('radio', 'public_private_group_forum', null, get_lang('Public access (access authorized to any member of the course)'), 'public');
  334. $group[] = $form->createElement('radio', 'public_private_group_forum', null, get_lang('Private access (access authorized to group members only)'), 'private');
  335. $form->addGroup($group, 'public_private_group_forum_group', get_lang('Public access (access authorized to any member of the course)Private access (access authorized to group members only)GroupForum'));
  336. // Forum image
  337. $form->addProgress();
  338. if (!empty($inputvalues['forum_image'])) {
  339. $baseImagePath = api_get_course_path().'/upload/forum/images/'.$inputvalues['forum_image'];
  340. $image_path = api_get_path(WEB_COURSE_PATH).$baseImagePath;
  341. $sysImagePath = api_get_path(SYS_COURSE_PATH).$baseImagePath;
  342. if (file_exists($sysImagePath)) {
  343. $show_preview_image = Display::img(
  344. $image_path,
  345. null,
  346. ['class' => 'img-responsive']
  347. );
  348. $form->addElement('label', get_lang('Preview image'), $show_preview_image);
  349. $form->addElement('checkbox', 'remove_picture', null, get_lang('Remove picture'));
  350. }
  351. }
  352. $forum_image = isset($inputvalues['forum_image']) ? $inputvalues['forum_image'] : '';
  353. $form->addElement('file', 'picture', ($forum_image != '' ? get_lang('Update Image') : get_lang('Add image')));
  354. $form->addRule(
  355. 'picture',
  356. get_lang('Only PNG, JPG or GIF images allowed'),
  357. 'filetype',
  358. ['jpg', 'jpeg', 'png', 'gif']
  359. );
  360. //$forumId = isset($_GET['id']) ? (int) $_GET['id'] : 0;
  361. //$skillList = Skill::addSkillsToForm($form, ITEM_TYPE_FORUM, $forumId);
  362. $form->addElement('html', '</div>');
  363. // The OK button
  364. if (isset($_GET['id']) && $_GET['action'] == 'edit') {
  365. $form->addButtonUpdate(get_lang('Edit forum'), 'SubmitForum');
  366. } else {
  367. $form->addButtonCreate(get_lang('Create forum'), 'SubmitForum');
  368. }
  369. // setting the rules
  370. $form->addRule('forum_title', get_lang('Required field'), 'required');
  371. $form->addRule('forum_category', get_lang('Required field'), 'required');
  372. $defaultSettingAllowNewThreads = api_get_default_tool_setting('forum', 'allow_new_threads', 0);
  373. // Settings the defaults
  374. if (empty($inputvalues) || !is_array($inputvalues)) {
  375. $defaults['moderated']['moderated'] = 0;
  376. $defaults['allow_anonymous_group']['allow_anonymous'] = 0;
  377. $defaults['students_can_edit_group']['students_can_edit'] = 0;
  378. $defaults['approval_direct_group']['approval_direct'] = 0;
  379. $defaults['allow_attachments_group']['allow_attachments'] = 1;
  380. $defaults['allow_new_threads_group']['allow_new_threads'] = $defaultSettingAllowNewThreads;
  381. $defaults['default_view_type_group']['default_view_type'] = api_get_setting('default_forum_view');
  382. $defaults['public_private_group_forum_group']['public_private_group_forum'] = 'public';
  383. if (isset($_GET['forumcategory'])) {
  384. $defaults['forum_category'] = Security::remove_XSS($_GET['forumcategory']);
  385. }
  386. } else {
  387. // the default values when editing = the data in the table
  388. $defaults['forum_id'] = isset($inputvalues['forum_id']) ? $inputvalues['forum_id'] : null;
  389. $defaults['forum_title'] = prepare4display(isset($inputvalues['forum_title']) ? $inputvalues['forum_title'] : null);
  390. $defaults['forum_comment'] = prepare4display(isset($inputvalues['forum_comment']) ? $inputvalues['forum_comment'] : null);
  391. $defaults['start_time'] = isset($inputvalues['start_time']) ? api_get_local_time($inputvalues['start_time']) : null;
  392. $defaults['end_time'] = isset($inputvalues['end_time']) ? api_get_local_time($inputvalues['end_time']) : null;
  393. $defaults['moderated']['moderated'] = isset($inputvalues['moderated']) ? $inputvalues['moderated'] : 0;
  394. $defaults['forum_category'] = isset($inputvalues['forum_category']) ? $inputvalues['forum_category'] : null;
  395. $defaults['allow_anonymous_group']['allow_anonymous'] = isset($inputvalues['allow_anonymous']) ? $inputvalues['allow_anonymous'] : null;
  396. $defaults['students_can_edit_group']['students_can_edit'] = isset($inputvalues['allow_edit']) ? $inputvalues['allow_edit'] : null;
  397. $defaults['approval_direct_group']['approval_direct'] = isset($inputvalues['approval_direct_post']) ? $inputvalues['approval_direct_post'] : null;
  398. $defaults['allow_attachments_group']['allow_attachments'] = isset($inputvalues['allow_attachments']) ? $inputvalues['allow_attachments'] : null;
  399. $defaults['allow_new_threads_group']['allow_new_threads'] = isset($inputvalues['allow_new_threads']) ? $inputvalues['allow_new_threads'] : $defaultSettingAllowNewThreads;
  400. $defaults['default_view_type_group']['default_view_type'] = isset($inputvalues['default_view']) ? $inputvalues['default_view'] : null;
  401. $defaults['public_private_group_forum_group']['public_private_group_forum'] = isset($inputvalues['forum_group_public_private']) ? $inputvalues['forum_group_public_private'] : null;
  402. $defaults['group_forum'] = isset($inputvalues['forum_of_group']) ? $inputvalues['forum_of_group'] : null;
  403. }
  404. $form->setDefaults($defaults);
  405. // Validation or display
  406. if ($form->validate()) {
  407. $check = Security::check_token('post');
  408. if ($check) {
  409. $values = $form->getSubmitValues();
  410. $forumId = store_forum($values, '', true);
  411. if ($forumId) {
  412. // Skill::saveSkills($form, ITEM_TYPE_FORUM, $forumId);
  413. if (isset($values['forum_id'])) {
  414. Display::addFlash(Display::return_message(get_lang('The forum has been modified'), 'confirmation'));
  415. } else {
  416. Display::addFlash(Display::return_message(get_lang('The forum has been added'), 'confirmation'));
  417. }
  418. }
  419. }
  420. Security::clear_token();
  421. } else {
  422. $token = Security::get_token();
  423. $form->addElement('hidden', 'sec_token');
  424. $form->setConstants(['sec_token' => $token]);
  425. return $form->returnForm();
  426. }
  427. }
  428. /**
  429. * This function deletes the forum image if exists.
  430. *
  431. * @param int forum id
  432. *
  433. * @return bool true if success
  434. *
  435. * @author Julio Montoya <gugli100@gmail.com>
  436. *
  437. * @version february 2006, dokeos 1.8
  438. */
  439. function delete_forum_image($forum_id)
  440. {
  441. $table_forums = Database::get_course_table(TABLE_FORUM);
  442. $course_id = api_get_course_int_id();
  443. $forum_id = intval($forum_id);
  444. $sql = "SELECT forum_image FROM $table_forums
  445. WHERE forum_id = $forum_id AND c_id = $course_id";
  446. $result = Database::query($sql);
  447. $row = Database::fetch_array($result);
  448. if ($row['forum_image'] != '') {
  449. $file = api_get_path(SYS_COURSE_PATH).api_get_course_path().'/upload/forum/images/'.$row['forum_image'];
  450. if (file_exists($file)) {
  451. unlink($file);
  452. }
  453. return true;
  454. } else {
  455. return false;
  456. }
  457. }
  458. /**
  459. * This function displays the form that is used to edit a forum category.
  460. *
  461. * @param array
  462. *
  463. * @return string
  464. *
  465. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  466. *
  467. * @version february 2006, dokeos 1.8
  468. */
  469. function show_edit_forumcategory_form($inputvalues = [])
  470. {
  471. $categoryId = $inputvalues['cat_id'];
  472. $form = new FormValidator('forumcategory', 'post', 'index.php?'.api_get_cidreq().'&id='.$categoryId);
  473. // Setting the form elements.
  474. $form->addElement('header', '', get_lang('Edit forumCategory'));
  475. $form->addElement('hidden', 'forum_category_id');
  476. $form->addElement('text', 'forum_category_title', get_lang('Title'));
  477. $form->addElement(
  478. 'html_editor',
  479. 'forum_category_comment',
  480. get_lang('Comment'),
  481. null,
  482. ['ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200']
  483. );
  484. $extraField = new ExtraField('forum_category');
  485. $returnParams = $extraField->addElements(
  486. $form,
  487. $categoryId,
  488. [], //exclude
  489. false, // filter
  490. false, // tag as select
  491. [], //show only fields
  492. [], // order fields
  493. [] // extra data
  494. );
  495. $form->addButtonUpdate(get_lang('Edit category'), 'SubmitEdit forumCategory');
  496. // Setting the default values.
  497. $defaultvalues['forum_category_id'] = $inputvalues['cat_id'];
  498. $defaultvalues['forum_category_title'] = $inputvalues['cat_title'];
  499. $defaultvalues['forum_category_comment'] = $inputvalues['cat_comment'];
  500. $form->setDefaults($defaultvalues);
  501. // Setting the rules.
  502. $form->addRule('forum_category_title', get_lang('Required field'), 'required');
  503. // Validation or display
  504. if ($form->validate()) {
  505. $check = Security::check_token('post');
  506. if ($check) {
  507. $values = $form->exportValues();
  508. store_forumcategory($values);
  509. }
  510. Security::clear_token();
  511. } else {
  512. $token = Security::get_token();
  513. $form->addElement('hidden', 'sec_token');
  514. $form->setConstants(['sec_token' => $token]);
  515. return $form->returnForm();
  516. }
  517. }
  518. /**
  519. * This function stores the forum category in the database.
  520. * The new category is added to the end.
  521. *
  522. * @param array $values
  523. * @param array $courseInfo
  524. * @param bool $showMessage
  525. *
  526. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  527. *
  528. * @version february 2006, dokeos 1.8
  529. */
  530. function store_forumcategory($values, $courseInfo = [], $showMessage = true)
  531. {
  532. $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
  533. $course_id = $courseInfo['real_id'];
  534. $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
  535. // Find the max cat_order. The new forum category is added at the end => max cat_order + &
  536. $sql = "SELECT MAX(cat_order) as sort_max
  537. FROM $table_categories
  538. WHERE c_id = $course_id";
  539. $result = Database::query($sql);
  540. $row = Database::fetch_array($result);
  541. $new_max = $row['sort_max'] + 1;
  542. $session_id = api_get_session_id();
  543. $clean_cat_title = $values['forum_category_title'];
  544. $last_id = null;
  545. if (isset($values['forum_category_id'])) {
  546. // Storing after edition.
  547. $params = [
  548. 'cat_title' => $clean_cat_title,
  549. 'cat_comment' => isset($values['forum_category_comment']) ? $values['forum_category_comment'] : '',
  550. ];
  551. Database::update(
  552. $table_categories,
  553. $params,
  554. [
  555. 'c_id = ? AND cat_id = ?' => [
  556. $course_id,
  557. $values['forum_category_id'],
  558. ],
  559. ]
  560. );
  561. api_item_property_update(
  562. $courseInfo,
  563. TOOL_FORUM_CATEGORY,
  564. $values['forum_category_id'],
  565. 'ForumCategoryUpdated',
  566. api_get_user_id()
  567. );
  568. $return_message = get_lang('The forum category has been modified');
  569. $logInfo = [
  570. 'tool' => TOOL_FORUM,
  571. 'tool_id' => 0,
  572. 'tool_id_detail' => 0,
  573. 'action' => 'update-forumcategory',
  574. 'action_details' => 'forumcategory',
  575. 'info' => $clean_cat_title,
  576. ];
  577. Event::registerLog($logInfo);
  578. $values['item_id'] = $values['forum_category_id'];
  579. } else {
  580. $params = [
  581. 'c_id' => $course_id,
  582. 'cat_title' => $clean_cat_title,
  583. 'cat_comment' => isset($values['forum_category_comment']) ? $values['forum_category_comment'] : '',
  584. 'cat_order' => $new_max,
  585. 'session_id' => $session_id,
  586. 'locked' => 0,
  587. 'cat_id' => 0,
  588. ];
  589. $last_id = Database::insert($table_categories, $params);
  590. if ($last_id > 0) {
  591. $sql = "UPDATE $table_categories SET cat_id = $last_id WHERE iid = $last_id";
  592. Database::query($sql);
  593. api_item_property_update(
  594. $courseInfo,
  595. TOOL_FORUM_CATEGORY,
  596. $last_id,
  597. 'ForumCategoryAdded',
  598. api_get_user_id()
  599. );
  600. api_set_default_visibility(
  601. $last_id,
  602. TOOL_FORUM_CATEGORY,
  603. 0,
  604. $courseInfo
  605. );
  606. }
  607. $return_message = get_lang('The forum category has been added');
  608. $logInfo = [
  609. 'tool' => TOOL_FORUM,
  610. 'tool_id' => 0,
  611. 'tool_id_detail' => 0,
  612. 'action' => 'new-forumcategory',
  613. 'action_details' => 'forumcategory',
  614. 'info' => $clean_cat_title,
  615. ];
  616. Event::registerLog($logInfo);
  617. $values['item_id'] = $last_id;
  618. }
  619. $extraFieldValue = new ExtraFieldValue('forum_category');
  620. $extraFieldValue->saveFieldValues($values);
  621. if ($showMessage) {
  622. Display::addFlash(Display::return_message($return_message, 'confirmation'));
  623. }
  624. return $last_id;
  625. }
  626. /**
  627. * This function stores the forum in the database. The new forum is added to the end.
  628. *
  629. * @param array $values
  630. * @param array $courseInfo
  631. * @param bool $returnId
  632. *
  633. * @return string language variable
  634. *
  635. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  636. *
  637. * @version february 2006, dokeos 1.8
  638. */
  639. function store_forum($values, $courseInfo = [], $returnId = false)
  640. {
  641. $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
  642. $courseId = $courseInfo['real_id'];
  643. $session_id = api_get_session_id();
  644. $group_id = api_get_group_id();
  645. if (isset($values['group_id']) && !empty($values['group_id'])) {
  646. $group_id = $values['group_id'];
  647. }
  648. $groupInfo = [];
  649. if (!empty($group_id)) {
  650. $groupInfo = GroupManager::get_group_properties($group_id);
  651. }
  652. $table_forums = Database::get_course_table(TABLE_FORUM);
  653. // Find the max forum_order for the given category. The new forum is added at the end => max cat_order + &
  654. if (is_null($values['forum_category'])) {
  655. $new_max = null;
  656. } else {
  657. $sql = "SELECT MAX(forum_order) as sort_max
  658. FROM $table_forums
  659. WHERE
  660. c_id = $courseId AND
  661. forum_category='".Database::escape_string($values['forum_category'])."'";
  662. $result = Database::query($sql);
  663. $row = Database::fetch_array($result);
  664. $new_max = $row['sort_max'] + 1;
  665. }
  666. // Forum images
  667. $has_attachment = false;
  668. $image_moved = true;
  669. if (!empty($_FILES['picture']['name'])) {
  670. $upload_ok = process_uploaded_file($_FILES['picture']);
  671. $has_attachment = true;
  672. }
  673. // Remove existing picture if it was requested.
  674. if (!empty($_POST['remove_picture'])) {
  675. delete_forum_image($values['forum_id']);
  676. }
  677. $new_file_name = '';
  678. if (isset($upload_ok)) {
  679. if ($has_attachment) {
  680. $course_dir = $courseInfo['path'].'/upload/forum/images';
  681. $sys_course_path = api_get_path(SYS_COURSE_PATH);
  682. $updir = $sys_course_path.$course_dir;
  683. // Try to add an extension to the file if it hasn't one.
  684. $new_file_name = add_ext_on_mime(
  685. Database::escape_string($_FILES['picture']['name']),
  686. $_FILES['picture']['type']
  687. );
  688. if (!filter_extension($new_file_name)) {
  689. //Display::addFlash(Display::return_message(get_lang('File upload failed: this file extension or file type is prohibited'), 'error'));
  690. $image_moved = false;
  691. } else {
  692. $file_extension = explode('.', $_FILES['picture']['name']);
  693. $file_extension = strtolower($file_extension[sizeof($file_extension) - 1]);
  694. $new_file_name = uniqid('').'.'.$file_extension;
  695. $new_path = $updir.'/'.$new_file_name;
  696. $result = @move_uploaded_file($_FILES['picture']['tmp_name'], $new_path);
  697. // Storing the attachments if any
  698. if ($result) {
  699. $image_moved = true;
  700. }
  701. }
  702. }
  703. }
  704. if (isset($values['forum_id'])) {
  705. // Storing after edition.
  706. $params = [
  707. 'forum_title' => $values['forum_title'],
  708. 'forum_comment' => isset($values['forum_comment']) ? $values['forum_comment'] : null,
  709. 'forum_category' => isset($values['forum_category']) ? $values['forum_category'] : null,
  710. 'allow_anonymous' => isset($values['allow_anonymous_group']['allow_anonymous']) ? $values['allow_anonymous_group']['allow_anonymous'] : null,
  711. 'allow_edit' => isset($values['students_can_edit_group']['students_can_edit']) ? $values['students_can_edit_group']['students_can_edit'] : null,
  712. 'approval_direct_post' => isset($values['approval_direct_group']['approval_direct']) ? $values['approval_direct_group']['approval_direct'] : null,
  713. 'allow_attachments' => isset($values['allow_attachments_group']['allow_attachments']) ? $values['allow_attachments_group']['allow_attachments'] : null,
  714. 'allow_new_threads' => isset($values['allow_new_threads_group']['allow_new_threads']) ? $values['allow_new_threads_group']['allow_new_threads'] : null,
  715. 'default_view' => isset($values['default_view_type_group']['default_view_type']) ? $values['default_view_type_group']['default_view_type'] : null,
  716. 'forum_of_group' => isset($values['group_forum']) ? $values['group_forum'] : null,
  717. 'forum_group_public_private' => isset($values['public_private_group_forum_group']['public_private_group_forum']) ? $values['public_private_group_forum_group']['public_private_group_forum'] : null,
  718. 'moderated' => $values['moderated']['moderated'],
  719. 'start_time' => !empty($values['start_time']) ? api_get_utc_datetime($values['start_time']) : null,
  720. 'end_time' => !empty($values['end_time']) ? api_get_utc_datetime($values['end_time']) : null,
  721. 'session_id' => $session_id,
  722. 'lp_id' => isset($values['lp_id']) ? intval($values['lp_id']) : 0,
  723. ];
  724. if (isset($upload_ok)) {
  725. if ($has_attachment) {
  726. $params['forum_image'] = $new_file_name;
  727. }
  728. }
  729. if (isset($values['remove_picture']) && $values['remove_picture'] == 1) {
  730. $params['forum_image'] = '';
  731. delete_forum_image($values['forum_id']);
  732. }
  733. // Move groups from one group to another
  734. if (isset($values['group_forum'])) {
  735. $forumData = get_forums($values['forum_id']);
  736. $currentGroupId = $forumData['forum_of_group'];
  737. if ($currentGroupId != $values['group_forum']) {
  738. $threads = get_threads($values['forum_id']);
  739. $toGroupId = 'NULL';
  740. if (!empty($values['group_forum'])) {
  741. $toGroupId = $values['group_forum'];
  742. }
  743. $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
  744. foreach ($threads as $thread) {
  745. $sql = "UPDATE $tableItemProperty
  746. SET to_group_id = $toGroupId
  747. WHERE
  748. tool = '".TOOL_FORUM_THREAD."' AND
  749. ref = ".$thread['thread_id']." AND
  750. c_id = ".$courseId;
  751. Database::query($sql);
  752. $posts = getPosts(
  753. $forumData,
  754. $thread['thread_id']
  755. );
  756. foreach ($posts as $post) {
  757. $postId = $post['post_id'];
  758. $attachMentList = getAllAttachment($postId);
  759. if (!empty($attachMentList)) {
  760. foreach ($attachMentList as $attachMent) {
  761. $sql = "UPDATE $tableItemProperty
  762. SET to_group_id = $toGroupId
  763. WHERE
  764. tool = '".TOOL_FORUM_ATTACH."' AND
  765. ref = ".$attachMent['iid']." AND
  766. c_id = ".$courseId;
  767. Database::query($sql);
  768. }
  769. }
  770. $sql = "UPDATE $tableItemProperty
  771. SET to_group_id = $toGroupId
  772. WHERE
  773. tool = '".TOOL_FORUM_POST."' AND
  774. ref = $postId AND
  775. c_id = $courseId";
  776. Database::query($sql);
  777. }
  778. }
  779. }
  780. }
  781. Database::update(
  782. $table_forums,
  783. $params,
  784. ['c_id = ? AND forum_id = ?' => [$courseId, $values['forum_id']]]
  785. );
  786. api_item_property_update(
  787. $courseInfo,
  788. TOOL_FORUM,
  789. Database::escape_string($values['forum_id']),
  790. 'ForumUpdated',
  791. api_get_user_id(),
  792. $groupInfo
  793. );
  794. $return_message = get_lang('The forum has been modified');
  795. $forumId = $values['forum_id'];
  796. $logInfo = [
  797. 'tool' => TOOL_FORUM,
  798. 'tool_id' => $values['forum_id'],
  799. 'action' => 'update-forum',
  800. 'action_details' => 'forum',
  801. 'info' => $values['forum_title'],
  802. ];
  803. Event::registerLog($logInfo);
  804. } else {
  805. if ($image_moved) {
  806. $new_file_name = isset($new_file_name) ? $new_file_name : '';
  807. }
  808. $params = [
  809. 'c_id' => $courseId,
  810. 'forum_title' => $values['forum_title'],
  811. 'forum_image' => $new_file_name,
  812. 'forum_comment' => isset($values['forum_comment']) ? $values['forum_comment'] : null,
  813. 'forum_category' => isset($values['forum_category']) ? $values['forum_category'] : null,
  814. 'allow_anonymous' => isset($values['allow_anonymous_group']['allow_anonymous']) ? $values['allow_anonymous_group']['allow_anonymous'] : null,
  815. 'allow_edit' => isset($values['students_can_edit_group']['students_can_edit']) ? $values['students_can_edit_group']['students_can_edit'] : null,
  816. 'approval_direct_post' => isset($values['approval_direct_group']['approval_direct']) ? $values['approval_direct_group']['approval_direct'] : null,
  817. 'allow_attachments' => isset($values['allow_attachments_group']['allow_attachments']) ? $values['allow_attachments_group']['allow_attachments'] : null,
  818. 'allow_new_threads' => isset($values['allow_new_threads_group']['allow_new_threads']) ? $values['allow_new_threads_group']['allow_new_threads'] : null,
  819. 'default_view' => isset($values['default_view_type_group']['default_view_type']) ? $values['default_view_type_group']['default_view_type'] : null,
  820. 'forum_of_group' => isset($values['group_forum']) ? $values['group_forum'] : null,
  821. 'forum_group_public_private' => isset($values['public_private_group_forum_group']['public_private_group_forum']) ? $values['public_private_group_forum_group']['public_private_group_forum'] : null,
  822. 'moderated' => isset($values['moderated']['moderated']) ? (int) $values['moderated']['moderated'] : 0,
  823. 'start_time' => !empty($values['start_time']) ? api_get_utc_datetime($values['start_time']) : null,
  824. 'end_time' => !empty($values['end_time']) ? api_get_utc_datetime($values['end_time']) : null,
  825. 'forum_order' => isset($new_max) ? $new_max : null,
  826. 'session_id' => $session_id,
  827. 'lp_id' => isset($values['lp_id']) ? (int) $values['lp_id'] : 0,
  828. 'locked' => 0,
  829. 'forum_id' => 0,
  830. ];
  831. $forumId = Database::insert($table_forums, $params);
  832. if ($forumId > 0) {
  833. $sql = "UPDATE $table_forums SET forum_id = iid WHERE iid = $forumId";
  834. Database::query($sql);
  835. $courseCode = $courseInfo['code'];
  836. $subscribe = (int) api_get_course_setting('subscribe_users_to_forum_notifications');
  837. $status = STUDENT;
  838. if (!empty($session_id)) {
  839. $status = 0;
  840. }
  841. if ($subscribe === 1) {
  842. $userList = CourseManager::get_user_list_from_course_code(
  843. $courseCode,
  844. $session_id,
  845. null,
  846. null,
  847. $status
  848. );
  849. foreach ($userList as $userInfo) {
  850. set_notification('forum', $forumId, false, $userInfo, $courseInfo);
  851. }
  852. }
  853. api_item_property_update(
  854. $courseInfo,
  855. TOOL_FORUM,
  856. $forumId,
  857. 'ForumAdded',
  858. api_get_user_id(),
  859. $groupInfo
  860. );
  861. api_set_default_visibility(
  862. $forumId,
  863. TOOL_FORUM,
  864. $group_id,
  865. $courseInfo
  866. );
  867. $logInfo = [
  868. 'tool' => TOOL_FORUM,
  869. 'tool_id' => $forumId,
  870. 'action' => 'new-forum',
  871. 'action_details' => 'forum',
  872. 'info' => $values['forum_title'],
  873. ];
  874. Event::registerLog($logInfo);
  875. }
  876. $return_message = get_lang('The forum has been added');
  877. }
  878. if ($returnId) {
  879. return $forumId;
  880. }
  881. return $return_message;
  882. }
  883. /**
  884. * This function deletes a forum or a forum category
  885. * This function currently does not delete the forums inside the category,
  886. * nor the threads and replies inside these forums.
  887. * For the moment this is the easiest method and it has the advantage that it
  888. * allows to recover fora that were acidently deleted
  889. * when the forum category got deleted.
  890. *
  891. * @param $content = what we are deleting (a forum or a forum category)
  892. * @param $id the id of the forum category that has to be deleted
  893. *
  894. * @todo write the code for the cascading deletion of the forums inside a
  895. * forum category and also the threads and replies inside these forums
  896. * @todo config setting for recovery or not
  897. * (see also the documents tool: real delete or not).
  898. *
  899. * @return string
  900. *
  901. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  902. *
  903. * @version february 2006, dokeos 1.8
  904. */
  905. function deleteForumCategoryThread($content, $id)
  906. {
  907. $_course = api_get_course_info();
  908. $table_forums = Database::get_course_table(TABLE_FORUM);
  909. $table_forums_post = Database::get_course_table(TABLE_FORUM_POST);
  910. $table_forum_thread = Database::get_course_table(TABLE_FORUM_THREAD);
  911. $course_id = api_get_course_int_id();
  912. $groupId = api_get_group_id();
  913. $groupInfo = GroupManager::get_group_properties($groupId);
  914. $userId = api_get_user_id();
  915. $id = (int) $id;
  916. // Delete all attachment file about this tread id.
  917. $sql = "SELECT post_id FROM $table_forums_post
  918. WHERE c_id = $course_id AND thread_id = '".$id."' ";
  919. $res = Database::query($sql);
  920. while ($poster_id = Database::fetch_row($res)) {
  921. delete_attachment($poster_id[0]);
  922. }
  923. $tool_constant = null;
  924. $return_message = '';
  925. if ($content === 'forumcategory') {
  926. $tool_constant = TOOL_FORUM_CATEGORY;
  927. $return_message = get_lang('Forum category deleted');
  928. if (!empty($forum_list)) {
  929. $sql = "SELECT forum_id FROM $table_forums
  930. WHERE c_id = $course_id AND forum_category='".$id."'";
  931. $result = Database::query($sql);
  932. $row = Database::fetch_array($result);
  933. foreach ($row as $arr_forum) {
  934. $forum_id = $arr_forum['forum_id'];
  935. api_item_property_update(
  936. $_course,
  937. 'forum',
  938. $forum_id,
  939. 'delete',
  940. api_get_user_id()
  941. );
  942. }
  943. }
  944. }
  945. if ($content === 'forum') {
  946. $tool_constant = TOOL_FORUM;
  947. $return_message = get_lang('Forum deleted');
  948. if (!empty($number_threads)) {
  949. $sql = "SELECT thread_id FROM $table_forum_thread
  950. WHERE c_id = $course_id AND forum_id = $id ";
  951. $result = Database::query($sql);
  952. $row = Database::fetch_array($result);
  953. foreach ($row as $arr_forum) {
  954. $forum_id = $arr_forum['thread_id'];
  955. api_item_property_update(
  956. $_course,
  957. 'forum_thread',
  958. $forum_id,
  959. 'delete',
  960. api_get_user_id()
  961. );
  962. }
  963. }
  964. }
  965. if ($content === 'thread') {
  966. $tool_constant = TOOL_FORUM_THREAD;
  967. $return_message = get_lang('Thread deleted');
  968. Skill::deleteSkillsFromItem($id, ITEM_TYPE_FORUM_THREAD);
  969. }
  970. api_item_property_update(
  971. $_course,
  972. $tool_constant,
  973. $id,
  974. 'delete',
  975. $userId,
  976. $groupInfo
  977. );
  978. // Check if this returns a true and if so => return $return_message, if not => return false;
  979. if (!empty($return_message)) {
  980. Display::addFlash(Display::return_message($return_message, 'confirmation', false));
  981. }
  982. return $return_message;
  983. }
  984. /**
  985. * This function deletes a forum post. This separate function is needed because forum posts do not appear
  986. * in the item_property table (yet)
  987. * and because deleting a post also has consequence on the posts that have this post as parent_id
  988. * (they are also deleted).
  989. * an alternative would be to store the posts also in item_property and mark this post as deleted (visibility = 2).
  990. * We also have to decrease the number of replies in the thread table.
  991. *
  992. * @param $post_id the id of the post that will be deleted
  993. *
  994. * @todo write recursive function that deletes all the posts that have this message as parent
  995. *
  996. * @return string language variable
  997. *
  998. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  999. * @author Hubert Borderiou Function cleanead and fixed
  1000. *
  1001. * @version february 2006
  1002. */
  1003. function delete_post($post_id)
  1004. {
  1005. $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
  1006. $post_id = intval($post_id);
  1007. $course_id = api_get_course_int_id();
  1008. $em = Database::getManager();
  1009. $post = $em
  1010. ->getRepository('ChamiloCourseBundle:CForumPost')
  1011. ->findOneBy(['cId' => $course_id, 'postId' => $post_id]);
  1012. if ($post) {
  1013. $em
  1014. ->createQuery('
  1015. UPDATE ChamiloCourseBundle:CForumPost p
  1016. SET p.postParentId = :parent_of_deleted_post
  1017. WHERE
  1018. p.cId = :course AND
  1019. p.postParentId = :post AND
  1020. p.threadId = :thread_of_deleted_post AND
  1021. p.forumId = :forum_of_deleted_post
  1022. ')
  1023. ->execute([
  1024. 'parent_of_deleted_post' => $post->getPostParentId(),
  1025. 'course' => $course_id,
  1026. 'post' => $post->getPostId(),
  1027. 'thread_of_deleted_post' => $post->getThread() ? $post->getThread()->getIid() : 0,
  1028. 'forum_of_deleted_post' => $post->getForumId(),
  1029. ]);
  1030. $em->remove($post);
  1031. $em->flush();
  1032. // Delete attachment file about this post id.
  1033. delete_attachment($post_id);
  1034. }
  1035. $last_post_of_thread = check_if_last_post_of_thread($_GET['thread']);
  1036. if (is_array($last_post_of_thread)) {
  1037. // Decreasing the number of replies for this thread and also changing the last post information.
  1038. $sql = "UPDATE $table_threads
  1039. SET
  1040. thread_replies = thread_replies - 1,
  1041. thread_last_post = ".intval($last_post_of_thread['post_id']).",
  1042. thread_date='".Database::escape_string($last_post_of_thread['post_date'])."'
  1043. WHERE c_id = $course_id AND thread_id = ".intval($_GET['thread']);
  1044. Database::query($sql);
  1045. return 'PostDeleted';
  1046. }
  1047. if (!$last_post_of_thread) {
  1048. // We deleted the very single post of the thread so we need to delete the entry in the thread table also.
  1049. $sql = "DELETE FROM $table_threads
  1050. WHERE c_id = $course_id AND thread_id = ".intval($_GET['thread']);
  1051. Database::query($sql);
  1052. return 'PostDeletedSpecial';
  1053. }
  1054. }
  1055. /**
  1056. * This function gets the all information of the last (=most recent) post of the thread
  1057. * This can be done by sorting the posts that have the field thread_id=$thread_id and sort them by post_date.
  1058. *
  1059. * @param $thread_id the id of the thread we want to know the last post of
  1060. *
  1061. * @return an array or bool if there is a last post found, false if there is
  1062. * no post entry linked to that thread => thread will be deleted
  1063. *
  1064. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  1065. *
  1066. * @version february 2006, dokeos 1.8
  1067. */
  1068. function check_if_last_post_of_thread($thread_id)
  1069. {
  1070. $table_posts = Database::get_course_table(TABLE_FORUM_POST);
  1071. $course_id = api_get_course_int_id();
  1072. $sql = "SELECT * FROM $table_posts
  1073. WHERE c_id = $course_id AND thread_id = ".intval($thread_id)."
  1074. ORDER BY post_date DESC";
  1075. $result = Database::query($sql);
  1076. if (Database::num_rows($result) > 0) {
  1077. $row = Database::fetch_array($result);
  1078. return $row;
  1079. } else {
  1080. return false;
  1081. }
  1082. }
  1083. /**
  1084. * @param string $content Type of content forum category, forum, thread, post
  1085. * @param int $id the id of the content we want to make invisible
  1086. * @param int $current_visibility_status what is the current status of the visibility (0 = invisible, 1 = visible)
  1087. * @param array $additional_url_parameters
  1088. *
  1089. * @return string HTML
  1090. */
  1091. function return_visible_invisible_icon(
  1092. $content,
  1093. $id,
  1094. $current_visibility_status,
  1095. $additional_url_parameters = ''
  1096. ) {
  1097. $html = '';
  1098. $id = (int) $id;
  1099. $current_visibility_status = (int) $current_visibility_status;
  1100. if ($current_visibility_status == 1) {
  1101. $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
  1102. if (is_array($additional_url_parameters)) {
  1103. foreach ($additional_url_parameters as $key => $value) {
  1104. $html .= $key.'='.$value.'&';
  1105. }
  1106. }
  1107. $html .= 'action=invisible&content='.$content.'&id='.$id.'">'.
  1108. Display::return_icon('visible.png', get_lang('Make invisible'), [], ICON_SIZE_SMALL).'</a>';
  1109. }
  1110. if ($current_visibility_status == 0) {
  1111. $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
  1112. if (is_array($additional_url_parameters)) {
  1113. foreach ($additional_url_parameters as $key => $value) {
  1114. $html .= $key.'='.$value.'&';
  1115. }
  1116. }
  1117. $html .= 'action=visible&content='.$content.'&id='.$id.'">'.
  1118. Display::return_icon('invisible.png', get_lang('Make Visible'), [], ICON_SIZE_SMALL).'</a>';
  1119. }
  1120. return $html;
  1121. }
  1122. /**
  1123. * @param $content
  1124. * @param $id
  1125. * @param $current_lock_status
  1126. * @param string $additional_url_parameters
  1127. *
  1128. * @return string
  1129. */
  1130. function return_lock_unlock_icon($content, $id, $current_lock_status, $additional_url_parameters = '')
  1131. {
  1132. $html = '';
  1133. $id = intval($id);
  1134. //check if the forum is blocked due
  1135. if ($content == 'thread') {
  1136. if (api_resource_is_locked_by_gradebook($id, LINK_FORUM_THREAD)) {
  1137. $html .= Display::return_icon(
  1138. 'lock_na.png',
  1139. get_lang('This option is not available because this activity is contained by an assessment, which is currently locked. To unlock the assessment, ask your platform administrator.'),
  1140. [],
  1141. ICON_SIZE_SMALL
  1142. );
  1143. return $html;
  1144. }
  1145. }
  1146. if ($current_lock_status == '1') {
  1147. $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
  1148. if (is_array($additional_url_parameters)) {
  1149. foreach ($additional_url_parameters as $key => $value) {
  1150. $html .= $key.'='.$value.'&';
  1151. }
  1152. }
  1153. $html .= 'action=unlock&content='.$content.'&id='.$id.'">'.
  1154. Display::return_icon('lock.png', get_lang('Unlock'), [], ICON_SIZE_SMALL).'</a>';
  1155. }
  1156. if ($current_lock_status == '0') {
  1157. $html .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&';
  1158. if (is_array($additional_url_parameters)) {
  1159. foreach ($additional_url_parameters as $key => $value) {
  1160. $html .= $key.'='.$value.'&';
  1161. }
  1162. }
  1163. $html .= 'action=lock&content='.$content.'&id='.$id.'">'.
  1164. Display::return_icon('unlock.png', get_lang('Lock'), [], ICON_SIZE_SMALL).'</a>';
  1165. }
  1166. return $html;
  1167. }
  1168. /**
  1169. * This function takes care of the display of the up and down icon.
  1170. *
  1171. * @param string $content what is it that we want to make (in)visible: forum category, forum, thread, post
  1172. * @param int $id is the id of the item we want to display the icons for
  1173. * @param array $list is an array of all the items. All items in this list should have
  1174. * an up and down icon except for the first (no up icon) and the last (no down icon)
  1175. * The key of this $list array is the id of the item.
  1176. *
  1177. * @return string HTML
  1178. */
  1179. function return_up_down_icon($content, $id, $list)
  1180. {
  1181. $id = (int) $id;
  1182. $total_items = count($list);
  1183. $position = 0;
  1184. $internal_counter = 0;
  1185. $forumCategory = isset($_GET['forumcategory']) ? Security::remove_XSS($_GET['forumcategory']) : null;
  1186. if (is_array($list)) {
  1187. foreach ($list as $key => $listitem) {
  1188. $internal_counter++;
  1189. if ($id == $key) {
  1190. $position = $internal_counter;
  1191. }
  1192. }
  1193. }
  1194. if ($position > 1) {
  1195. $return_value = '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=move&direction=up&content='.$content.'&forumcategory='.$forumCategory.'&id='.$id.'" title="'.get_lang('Move up').'">'.
  1196. Display::return_icon('up.png', get_lang('Move up'), [], ICON_SIZE_SMALL).'</a>';
  1197. } else {
  1198. $return_value = Display::return_icon('up_na.png', '-', [], ICON_SIZE_SMALL);
  1199. }
  1200. if ($position < $total_items) {
  1201. $return_value .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=move&direction=down&content='.$content.'&forumcategory='.$forumCategory.'&id='.$id.'" title="'.get_lang('Move down').'" >'.
  1202. Display::return_icon('down.png', get_lang('Move down'), [], ICON_SIZE_SMALL).'</a>';
  1203. } else {
  1204. $return_value .= Display::return_icon('down_na.png', '-', [], ICON_SIZE_SMALL);
  1205. }
  1206. return $return_value;
  1207. }
  1208. /**
  1209. * This function changes the visibility in the database (item_property).
  1210. *
  1211. * @param string $content what is it that we want to make (in)visible: forum category, forum, thread, post
  1212. * @param int $id the id of the content we want to make invisible
  1213. * @param string $target_visibility what is the current status of the visibility (0 = invisible, 1 = visible)
  1214. *
  1215. * @todo change the get parameter so that it matches the tool constants.
  1216. * @todo check if api_item_property_update returns true or false => returnmessage depends on it.
  1217. * @todo move to itemmanager
  1218. *
  1219. * @return string language variable
  1220. *
  1221. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  1222. *
  1223. * @version february 2006, dokeos 1.8
  1224. */
  1225. function change_visibility($content, $id, $target_visibility)
  1226. {
  1227. $_course = api_get_course_info();
  1228. $constants = [
  1229. 'forumcategory' => TOOL_FORUM_CATEGORY,
  1230. 'forum' => TOOL_FORUM,
  1231. 'thread' => TOOL_FORUM_THREAD,
  1232. ];
  1233. api_item_property_update(
  1234. $_course,
  1235. $constants[$content],
  1236. $id,
  1237. $target_visibility,
  1238. api_get_user_id()
  1239. );
  1240. if ($target_visibility == 'visible') {
  1241. handle_mail_cue($content, $id);
  1242. }
  1243. return get_lang('The visibility has been changed.');
  1244. }
  1245. /**
  1246. * This function changes the lock status in the database.
  1247. *
  1248. * @param string $content what is it that we want to (un)lock: forum category, forum, thread, post
  1249. * @param int $id the id of the content we want to (un)lock
  1250. * @param string $action do we lock (=>locked value in db = 1) or unlock (=> locked value in db = 0)
  1251. *
  1252. * @return string language variable
  1253. *
  1254. * @todo move to item manager
  1255. *
  1256. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  1257. *
  1258. * @version february 2006, dokeos 1.8
  1259. */
  1260. function change_lock_status($content, $id, $action)
  1261. {
  1262. $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
  1263. $table_forums = Database::get_course_table(TABLE_FORUM);
  1264. $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
  1265. // Determine the relevant table.
  1266. if ($content == 'forumcategory') {
  1267. $table = $table_categories;
  1268. $id_field = 'cat_id';
  1269. } elseif ($content == 'forum') {
  1270. $table = $table_forums;
  1271. $id_field = 'forum_id';
  1272. } elseif ($content == 'thread') {
  1273. $table = $table_threads;
  1274. $id_field = 'thread_id';
  1275. } else {
  1276. return get_lang('Error');
  1277. }
  1278. // Determine what we are doing => defines the value for the database and the return message.
  1279. if ($action == 'lock') {
  1280. $db_locked = 1;
  1281. $return_message = get_lang('Locked: students can no longer post new messages in this forum category, forum or thread but they can still read the messages that were already posted');
  1282. } elseif ($action == 'unlock') {
  1283. $db_locked = 0;
  1284. $return_message = get_lang('Unlocked: learners can post new messages in this forum category, forum or thread');
  1285. } else {
  1286. return get_lang('Error');
  1287. }
  1288. $course_id = api_get_course_int_id();
  1289. // Doing the change in the database
  1290. $sql = "UPDATE $table SET locked='".Database::escape_string($db_locked)."'
  1291. WHERE c_id = $course_id AND $id_field='".Database::escape_string($id)."'";
  1292. if (Database::query($sql)) {
  1293. return $return_message;
  1294. } else {
  1295. return get_lang('Error');
  1296. }
  1297. }
  1298. /**
  1299. * This function moves a forum or a forum category up or down.
  1300. *
  1301. * @param $content what is it that we want to make (in)visible: forum category, forum, thread, post
  1302. * @param $direction do we want to move it up or down
  1303. * @param $id the id of the content we want to make invisible
  1304. *
  1305. * @todo consider removing the table_item_property calls here but this can
  1306. * prevent unwanted side effects when a forum does not have an entry in
  1307. * the item_property table but does have one in the forum table.
  1308. *
  1309. * @return string language variable
  1310. *
  1311. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  1312. *
  1313. * @version february 2006, dokeos 1.8
  1314. */
  1315. function move_up_down($content, $direction, $id)
  1316. {
  1317. $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
  1318. $table_forums = Database::get_course_table(TABLE_FORUM);
  1319. $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
  1320. $course_id = api_get_course_int_id();
  1321. $id = intval($id);
  1322. // Determine which field holds the sort order.
  1323. if ($content == 'forumcategory') {
  1324. $table = $table_categories;
  1325. $sort_column = 'cat_order';
  1326. $id_column = 'cat_id';
  1327. $sort_column = 'cat_order';
  1328. } elseif ($content == 'forum') {
  1329. $table = $table_forums;
  1330. $sort_column = 'forum_order';
  1331. $id_column = 'forum_id';
  1332. $sort_column = 'forum_order';
  1333. // We also need the forum_category of this forum.
  1334. $sql = "SELECT forum_category FROM $table_forums
  1335. WHERE c_id = $course_id AND forum_id = ".intval($id);
  1336. $result = Database::query($sql);
  1337. $row = Database::fetch_array($result);
  1338. $forum_category = $row['forum_category'];
  1339. } else {
  1340. return get_lang('Error');
  1341. }
  1342. // Determine the need for sorting ascending or descending order.
  1343. if ($direction == 'down') {
  1344. $sort_direction = 'ASC';
  1345. } elseif ($direction == 'up') {
  1346. $sort_direction = 'DESC';
  1347. } else {
  1348. return get_lang('Error');
  1349. }
  1350. // The SQL statement
  1351. if ($content == 'forumcategory') {
  1352. $sql = "SELECT *
  1353. FROM $table_categories forum_categories, $table_item_property item_properties
  1354. WHERE
  1355. forum_categories.c_id = $course_id AND
  1356. item_properties.c_id = $course_id AND
  1357. forum_categories.cat_id=item_properties.ref AND
  1358. item_properties.tool='".TOOL_FORUM_CATEGORY."'
  1359. ORDER BY forum_categories.cat_order $sort_direction";
  1360. }
  1361. if ($content == 'forum') {
  1362. $sql = "SELECT *
  1363. FROM $table
  1364. WHERE
  1365. c_id = $course_id AND
  1366. forum_category='".Database::escape_string($forum_category)."'
  1367. ORDER BY forum_order $sort_direction";
  1368. }
  1369. // Finding the items that need to be switched.
  1370. $result = Database::query($sql);
  1371. $found = false;
  1372. while ($row = Database::fetch_array($result)) {
  1373. if ($found) {
  1374. $next_id = $row[$id_column];
  1375. $next_sort = $row[$sort_column];
  1376. $found = false;
  1377. }
  1378. if ($id == $row[$id_column]) {
  1379. $this_id = $id;
  1380. $this_sort = $row[$sort_column];
  1381. $found = true;
  1382. }
  1383. }
  1384. // Committing the switch.
  1385. // We do an extra check if we do not have illegal values. If your remove this if statement you will
  1386. // be able to mess with the sorting by refreshing the page over and over again.
  1387. if ($this_sort != '' && $next_sort != '' && $next_id != '' && $this_id != '') {
  1388. $sql = "UPDATE $table SET $sort_column='".Database::escape_string($this_sort)."'
  1389. WHERE c_id = $course_id AND $id_column='".Database::escape_string($next_id)."'";
  1390. Database::query($sql);
  1391. $sql = "UPDATE $table SET $sort_column='".Database::escape_string($next_sort)."'
  1392. WHERE c_id = $course_id AND $id_column='".Database::escape_string($this_id)."'";
  1393. Database::query($sql);
  1394. }
  1395. return get_lang(ucfirst($content).'Moved');
  1396. }
  1397. /**
  1398. * Retrieve all the information off the forum categories (or one specific) for the current course.
  1399. * The categories are sorted according to their sorting order (cat_order.
  1400. *
  1401. * @param int|string $id default ''. When an id is passed we only find the information
  1402. * about that specific forum category. If no id is passed we get all the forum categories.
  1403. * @param int $courseId Optional. The course ID
  1404. * @param int $sessionId Optional. The session ID
  1405. *
  1406. * @return array containing all the information about all the forum categories
  1407. *
  1408. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  1409. *
  1410. * @version february 2006, dokeos 1.8
  1411. */
  1412. function get_forum_categories($id = '', $courseId = 0, $sessionId = 0)
  1413. {
  1414. $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
  1415. $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
  1416. // Condition for the session
  1417. $session_id = $sessionId ?: api_get_session_id();
  1418. $course_id = $courseId ?: api_get_course_int_id();
  1419. $condition_session = api_get_session_condition(
  1420. $session_id,
  1421. true,
  1422. true,
  1423. 'forum_categories.session_id'
  1424. );
  1425. $condition_session .= " AND forum_categories.c_id = $course_id AND item_properties.c_id = $course_id";
  1426. if (empty($id)) {
  1427. $sql = "SELECT *
  1428. FROM $table_item_property item_properties
  1429. INNER JOIN $table_categories forum_categories
  1430. ON (
  1431. forum_categories.cat_id = item_properties.ref AND
  1432. item_properties.c_id = forum_categories.c_id
  1433. )
  1434. WHERE
  1435. item_properties.visibility = 1 AND
  1436. item_properties.tool = '".TOOL_FORUM_CATEGORY."'
  1437. $condition_session
  1438. ORDER BY forum_categories.cat_order ASC";
  1439. if (api_is_allowed_to_edit()) {
  1440. $sql = "SELECT *
  1441. FROM $table_item_property item_properties
  1442. INNER JOIN $table_categories forum_categories
  1443. ON (
  1444. forum_categories.cat_id = item_properties.ref AND
  1445. item_properties.c_id = forum_categories.c_id
  1446. )
  1447. WHERE
  1448. item_properties.visibility<>2 AND
  1449. item_properties.tool='".TOOL_FORUM_CATEGORY."'
  1450. $condition_session
  1451. ORDER BY forum_categories.cat_order ASC";
  1452. }
  1453. } else {
  1454. $sql = "SELECT *
  1455. FROM $table_item_property item_properties
  1456. INNER JOIN $table_categories forum_categories
  1457. ON (
  1458. forum_categories.cat_id = item_properties.ref AND
  1459. item_properties.c_id = forum_categories.c_id
  1460. )
  1461. WHERE
  1462. item_properties.tool='".TOOL_FORUM_CATEGORY."' AND
  1463. forum_categories.cat_id = ".intval($id)."
  1464. $condition_session
  1465. ORDER BY forum_categories.cat_order ASC";
  1466. }
  1467. $result = Database::query($sql);
  1468. $forum_categories_list = [];
  1469. $extraFieldValue = new ExtraFieldValue('forum_category');
  1470. while ($row = Database::fetch_assoc($result)) {
  1471. $row['extra_fields'] = $extraFieldValue->getAllValuesByItem($row['cat_id']);
  1472. if (empty($id)) {
  1473. $forum_categories_list[$row['cat_id']] = $row;
  1474. } else {
  1475. $forum_categories_list = $row;
  1476. }
  1477. }
  1478. return $forum_categories_list;
  1479. }
  1480. /**
  1481. * This function retrieves all the fora in a given forum category.
  1482. *
  1483. * @param int $cat_id the id of the forum category
  1484. * @param int $courseId Optional. The course ID
  1485. *
  1486. * @return array containing all the information about the forums (regardless of their category)
  1487. *
  1488. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  1489. *
  1490. * @version february 2006, dokeos 1.8
  1491. */
  1492. function get_forums_in_category($cat_id, $courseId = 0)
  1493. {
  1494. $table_forums = Database::get_course_table(TABLE_FORUM);
  1495. $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
  1496. $forum_list = [];
  1497. $course_id = $courseId ?: api_get_course_int_id();
  1498. $cat_id = (int) $cat_id;
  1499. $sql = "SELECT * FROM $table_forums forum
  1500. INNER JOIN $table_item_property item_properties
  1501. ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
  1502. WHERE
  1503. forum.forum_category = '".$cat_id."' AND
  1504. item_properties.visibility = 1 AND
  1505. forum.c_id = $course_id AND
  1506. item_properties.c_id = $course_id AND
  1507. item_properties.tool = '".TOOL_FORUM."'
  1508. ORDER BY forum.forum_order ASC";
  1509. if (api_is_allowed_to_edit()) {
  1510. $sql = "SELECT * FROM $table_forums forum
  1511. INNER JOIN $table_item_property item_properties
  1512. ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
  1513. WHERE
  1514. forum.forum_category = '".$cat_id."' AND
  1515. item_properties.visibility <> 2 AND
  1516. item_properties.tool = '".TOOL_FORUM."' AND
  1517. item_properties.c_id = $course_id AND
  1518. forum.c_id = $course_id
  1519. ORDER BY forum_order ASC";
  1520. }
  1521. $result = Database::query($sql);
  1522. while ($row = Database::fetch_array($result)) {
  1523. $forum_list[$row['forum_id']] = $row;
  1524. }
  1525. return $forum_list;
  1526. }
  1527. /**
  1528. * Retrieve all the forums (regardless of their category) or of only one.
  1529. * The forums are sorted according to the forum_order.
  1530. * Since it does not take the forum category into account there probably
  1531. * will be two or more forums that have forum_order=1, ...
  1532. *
  1533. * @param int $id forum id
  1534. * @param string $course_code
  1535. * @param bool $includeGroupsForum
  1536. * @param int $sessionId
  1537. *
  1538. * @return array an array containing all the information about the forums (regardless of their category)
  1539. *
  1540. * @todo check $sql4 because this one really looks fishy.
  1541. *
  1542. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  1543. *
  1544. * @version february 2006, dokeos 1.8
  1545. */
  1546. function get_forums(
  1547. $id = 0,
  1548. $course_code = '',
  1549. $includeGroupsForum = true,
  1550. $sessionId = 0
  1551. ) {
  1552. $id = (int) $id;
  1553. $course_info = api_get_course_info($course_code);
  1554. $table_forums = Database::get_course_table(TABLE_FORUM);
  1555. $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
  1556. $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
  1557. // Condition for the session
  1558. $session_id = intval($sessionId) ?: api_get_session_id();
  1559. $sessionIdLink = $session_id === 0 ? '' : ' AND threads.session_id = item_properties.session_id';
  1560. $condition_session = api_get_session_condition(
  1561. $session_id,
  1562. true,
  1563. false,
  1564. 'item_properties.session_id'
  1565. );
  1566. $course_id = $course_info['real_id'];
  1567. $forum_list = [];
  1568. $includeGroupsForumSelect = '';
  1569. if (!$includeGroupsForum) {
  1570. $includeGroupsForumSelect = " AND (forum_of_group = 0 OR forum_of_group IS NULL) ";
  1571. }
  1572. $allowToEdit = api_is_allowed_to_edit();
  1573. if (empty($id)) {
  1574. // Student
  1575. // Select all the forum information of all forums (that are visible to students).
  1576. $sql = "SELECT item_properties.*, forum.*
  1577. FROM $table_forums forum
  1578. INNER JOIN $table_item_property item_properties
  1579. ON (
  1580. forum.forum_id = item_properties.ref AND
  1581. forum.c_id = item_properties.c_id
  1582. )
  1583. WHERE
  1584. item_properties.visibility = 1 AND
  1585. item_properties.tool = '".TOOL_FORUM."'
  1586. $condition_session AND
  1587. forum.c_id = $course_id AND
  1588. item_properties.c_id = $course_id
  1589. $includeGroupsForumSelect
  1590. ORDER BY forum.forum_order ASC";
  1591. // Select the number of threads of the forums (only the threads that are visible).
  1592. $sql2 = "SELECT count(*) AS number_of_threads, threads.forum_id
  1593. FROM $table_threads threads
  1594. INNER JOIN $table_item_property item_properties
  1595. ON (
  1596. threads.thread_id = item_properties.ref AND
  1597. threads.c_id = item_properties.c_id
  1598. $sessionIdLink
  1599. )
  1600. WHERE
  1601. item_properties.visibility=1 AND
  1602. item_properties.tool='".TOOL_FORUM_THREAD."' AND
  1603. threads.c_id = $course_id AND
  1604. item_properties.c_id = $course_id
  1605. GROUP BY threads.forum_id";
  1606. // Course Admin
  1607. if ($allowToEdit) {
  1608. // Select all the forum information of all forums (that are not deleted).
  1609. $sql = "SELECT item_properties.*, forum.*
  1610. FROM $table_forums forum
  1611. INNER JOIN $table_item_property item_properties
  1612. ON (
  1613. forum.forum_id = item_properties.ref AND
  1614. forum.c_id = item_properties.c_id
  1615. )
  1616. WHERE
  1617. item_properties.visibility <> 2 AND
  1618. item_properties.tool = '".TOOL_FORUM."'
  1619. $condition_session AND
  1620. forum.c_id = $course_id AND
  1621. item_properties.c_id = $course_id
  1622. $includeGroupsForumSelect
  1623. ORDER BY forum_order ASC";
  1624. // Select the number of threads of the forums (only the threads that are not deleted).
  1625. $sql2 = "SELECT count(*) AS number_of_threads, threads.forum_id
  1626. FROM $table_threads threads
  1627. INNER JOIN $table_item_property item_properties
  1628. ON (
  1629. threads.thread_id = item_properties.ref AND
  1630. threads.c_id = item_properties.c_id
  1631. $sessionIdLink
  1632. )
  1633. WHERE
  1634. item_properties.visibility<>2 AND
  1635. item_properties.tool='".TOOL_FORUM_THREAD."' AND
  1636. threads.c_id = $course_id AND
  1637. item_properties.c_id = $course_id
  1638. GROUP BY threads.forum_id";
  1639. }
  1640. } else {
  1641. // GETTING ONE SPECIFIC FORUM
  1642. /* We could do the splitup into student and course admin also but we want
  1643. to have as much as information about a certain forum as possible
  1644. so we do not take too much information into account. This function
  1645. (or this section of the function) is namely used to fill the forms
  1646. when editing a forum (and for the moment it is the only place where
  1647. we use this part of the function) */
  1648. // Select all the forum information of the given forum (that is not deleted).
  1649. $sql = "SELECT * FROM $table_item_property item_properties
  1650. INNER JOIN $table_forums forum
  1651. ON (forum.forum_id = item_properties.ref AND forum.c_id = item_properties.c_id)
  1652. WHERE
  1653. forum.forum_id = $id AND
  1654. forum.c_id = $course_id AND
  1655. item_properties.visibility != 2 AND
  1656. item_properties.tool = '".TOOL_FORUM."'
  1657. ORDER BY forum_order ASC";
  1658. // Select the number of threads of the forum.
  1659. $sql2 = "SELECT count(*) AS number_of_threads, forum_id
  1660. FROM $table_threads
  1661. WHERE
  1662. forum_id = $id
  1663. GROUP BY forum_id";
  1664. }
  1665. // Handling all the forum information.
  1666. $result = Database::query($sql);
  1667. while ($row = Database::fetch_assoc($result)) {
  1668. if (empty($id)) {
  1669. $forum_list[$row['forum_id']] = $row;
  1670. } else {
  1671. $forum_list = $row;
  1672. }
  1673. }
  1674. // Handling the thread count information.
  1675. $result2 = Database::query($sql2);
  1676. while ($row2 = Database::fetch_array($result2)) {
  1677. if (empty($id)) {
  1678. $forum_list[$row2['forum_id']]['number_of_threads'] = $row2['number_of_threads'];
  1679. } else {
  1680. $forum_list['number_of_threads'] = $row2['number_of_threads'];
  1681. }
  1682. }
  1683. /* Finding the last post information
  1684. (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname)*/
  1685. if (empty($id)) {
  1686. if (is_array($forum_list)) {
  1687. foreach ($forum_list as $key => $value) {
  1688. $lastPost = get_last_post_information(
  1689. $key,
  1690. $allowToEdit,
  1691. $course_id
  1692. );
  1693. if ($lastPost) {
  1694. $forum_list[$key]['last_post_id'] = $lastPost['last_post_id'];
  1695. $forum_list[$key]['last_poster_id'] = $lastPost['last_poster_id'];
  1696. $forum_list[$key]['last_post_date'] = $lastPost['last_post_date'];
  1697. $forum_list[$key]['last_poster_name'] = $lastPost['last_poster_name'];
  1698. $forum_list[$key]['last_poster_lastname'] = $lastPost['last_poster_lastname'];
  1699. $forum_list[$key]['last_poster_firstname'] = $lastPost['last_poster_firstname'];
  1700. $forum_list[$key]['last_post_title'] = $lastPost['last_post_title'];
  1701. $forum_list[$key]['last_post_text'] = $lastPost['last_post_text'];
  1702. }
  1703. }
  1704. } else {
  1705. $forum_list = [];
  1706. }
  1707. } else {
  1708. $lastPost = get_last_post_information(
  1709. $id,
  1710. $allowToEdit,
  1711. $course_id
  1712. );
  1713. if ($lastPost) {
  1714. $forum_list['last_post_id'] = $lastPost['last_post_id'];
  1715. $forum_list['last_poster_id'] = $lastPost['last_poster_id'];
  1716. $forum_list['last_post_date'] = $lastPost['last_post_date'];
  1717. $forum_list['last_poster_name'] = $lastPost['last_poster_name'];
  1718. $forum_list['last_poster_lastname'] = $lastPost['last_poster_lastname'];
  1719. $forum_list['last_poster_firstname'] = $lastPost['last_poster_firstname'];
  1720. $forum_list['last_post_title'] = $lastPost['last_post_title'];
  1721. $forum_list['last_post_text'] = $lastPost['last_post_text'];
  1722. }
  1723. }
  1724. return $forum_list;
  1725. }
  1726. /**
  1727. * @param int $course_id
  1728. * @param int $thread_id
  1729. * @param int $forum_id
  1730. * @param bool $show_visible
  1731. *
  1732. * @return array|bool
  1733. */
  1734. function get_last_post_by_thread($course_id, $thread_id, $forum_id, $show_visible = true)
  1735. {
  1736. if (empty($thread_id) || empty($forum_id) || empty($course_id)) {
  1737. return false;
  1738. }
  1739. $thread_id = intval($thread_id);
  1740. $forum_id = intval($forum_id);
  1741. $course_id = intval($course_id);
  1742. $table_posts = Database::get_course_table(TABLE_FORUM_POST);
  1743. $sql = "SELECT * FROM $table_posts
  1744. WHERE
  1745. c_id = $course_id AND
  1746. thread_id = $thread_id AND
  1747. forum_id = $forum_id";
  1748. if ($show_visible == false) {
  1749. $sql .= " AND visible = 1 ";
  1750. }
  1751. $sql .= " ORDER BY post_id DESC LIMIT 1";
  1752. $result = Database::query($sql);
  1753. if (Database::num_rows($result)) {
  1754. return Database::fetch_array($result, 'ASSOC');
  1755. } else {
  1756. return false;
  1757. }
  1758. }
  1759. /**
  1760. * This function gets all the last post information of a certain forum.
  1761. *
  1762. * @param int $forum_id the id of the forum we want to know the last post information of
  1763. * @param bool $show_invisibles
  1764. * @param string course db name
  1765. * @param int $sessionId Optional. The session id
  1766. *
  1767. * @return array containing all the information about the last post
  1768. * (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname)
  1769. *
  1770. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  1771. *
  1772. * @version february 2006, dokeos 1.8
  1773. */
  1774. function get_last_post_information($forum_id, $show_invisibles = false, $course_id = null, $sessionId = 0)
  1775. {
  1776. if (!isset($course_id)) {
  1777. $course_id = api_get_course_int_id();
  1778. } else {
  1779. $course_id = intval($course_id);
  1780. }
  1781. $sessionId = $sessionId ? intval($sessionId) : api_get_session_id();
  1782. $table_posts = Database::get_course_table(TABLE_FORUM_POST);
  1783. $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
  1784. $table_users = Database::get_main_table(TABLE_MAIN_USER);
  1785. $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
  1786. $forum_id = intval($forum_id);
  1787. $return_array = [];
  1788. // First get the threads to make sure there is no inconsistency in the
  1789. // database between forum and thread
  1790. $sql = "SELECT thread_id FROM $table_threads
  1791. WHERE
  1792. forum_id = $forum_id AND
  1793. c_id = $course_id AND
  1794. session_id = $sessionId";
  1795. $result = Database::query($sql);
  1796. if (Database::num_rows($result) == 0) {
  1797. // If there are no threads in this forum, then there are no posts
  1798. return [];
  1799. }
  1800. $threads = [];
  1801. while ($row = Database::fetch_row($result)) {
  1802. $threads[] = $row[0];
  1803. }
  1804. $threadsList = implode(',', $threads);
  1805. // Now get the posts that are linked to these threads
  1806. $sql = "SELECT
  1807. post.post_id,
  1808. post.forum_id,
  1809. post.poster_id,
  1810. post.poster_name,
  1811. post.post_date,
  1812. users.lastname,
  1813. users.firstname,
  1814. post.visible,
  1815. thread_properties.visibility AS thread_visibility,
  1816. forum_properties.visibility AS forum_visibility,
  1817. post.post_title,
  1818. post.post_text
  1819. FROM
  1820. $table_posts post,
  1821. $table_users users,
  1822. $table_item_property thread_properties,
  1823. $table_item_property forum_properties
  1824. WHERE
  1825. post.forum_id = $forum_id
  1826. AND post.thread_id IN ($threadsList)
  1827. AND post.poster_id = users.user_id
  1828. AND post.thread_id = thread_properties.ref
  1829. AND thread_properties.tool='".TOOL_FORUM_THREAD."'
  1830. AND post.forum_id=forum_properties.ref
  1831. AND forum_properties.tool='".TOOL_FORUM."'
  1832. AND post.c_id = $course_id AND
  1833. thread_properties.c_id = $course_id AND
  1834. forum_properties.c_id = $course_id
  1835. ORDER BY post.post_id DESC";
  1836. $result = Database::query($sql);
  1837. if ($show_invisibles) {
  1838. $row = Database::fetch_array($result);
  1839. $return_array['last_post_id'] = $row['post_id'];
  1840. $return_array['last_poster_id'] = $row['poster_id'];
  1841. $return_array['last_post_date'] = $row['post_date'];
  1842. $return_array['last_poster_name'] = $row['poster_name'];
  1843. $return_array['last_poster_lastname'] = $row['lastname'];
  1844. $return_array['last_poster_firstname'] = $row['firstname'];
  1845. $return_array['last_post_title'] = $row['post_title'];
  1846. $return_array['last_post_text'] = $row['post_text'];
  1847. return $return_array;
  1848. } else {
  1849. // We have to loop through the results to find the first one that is
  1850. // actually visible to students (forum_category, forum, thread AND post are visible).
  1851. while ($row = Database::fetch_array($result)) {
  1852. if ($row['visible'] == '1' && $row['thread_visibility'] == '1' && $row['forum_visibility'] == '1') {
  1853. $return_array['last_post_id'] = $row['post_id'];
  1854. $return_array['last_poster_id'] = $row['poster_id'];
  1855. $return_array['last_post_date'] = $row['post_date'];
  1856. $return_array['last_poster_name'] = $row['poster_name'];
  1857. $return_array['last_poster_lastname'] = $row['lastname'];
  1858. $return_array['last_poster_firstname'] = $row['firstname'];
  1859. $return_array['last_post_title'] = $row['post_title'];
  1860. $return_array['last_post_text'] = $row['post_text'];
  1861. return $return_array;
  1862. }
  1863. }
  1864. }
  1865. }
  1866. /**
  1867. * Retrieve all the threads of a given forum.
  1868. *
  1869. * @param int $forum_id
  1870. * @param int|null $courseId Optional If is null then it is considered the current course
  1871. * @param int|null $sessionId Optional. If is null then it is considered the current session
  1872. *
  1873. * @return array containing all the information about the threads
  1874. *
  1875. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  1876. *
  1877. * @version february 2006, dokeos 1.8
  1878. */
  1879. function get_threads($forum_id, $courseId = null, $sessionId = null)
  1880. {
  1881. $groupId = api_get_group_id();
  1882. $sessionId = $sessionId !== null ? (int) $sessionId : api_get_session_id();
  1883. $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
  1884. $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
  1885. $table_users = Database::get_main_table(TABLE_MAIN_USER);
  1886. $courseId = $courseId !== null ? (int) $courseId : api_get_course_int_id();
  1887. $groupInfo = GroupManager::get_group_properties($groupId);
  1888. $groupCondition = '';
  1889. if (!empty($groupInfo)) {
  1890. $groupIid = $groupInfo['iid'];
  1891. $groupCondition = " AND item_properties.to_group_id = '$groupIid' ";
  1892. }
  1893. $sessionCondition = api_get_session_condition(
  1894. $sessionId,
  1895. true,
  1896. false,
  1897. 'item_properties.session_id'
  1898. );
  1899. // important note: it might seem a little bit awkward that we have 'thread.locked as locked' in the sql statement
  1900. // because we also have thread.* in it. This is because thread has a field locked and post also has the same field
  1901. // since we are merging these we would have the post.locked value but in fact we want the thread.locked value
  1902. // This is why it is added to the end of the field selection
  1903. $sql = "SELECT DISTINCT
  1904. item_properties.*,
  1905. users.firstname,
  1906. users.lastname,
  1907. users.user_id,
  1908. thread.locked as locked,
  1909. thread.*
  1910. FROM $table_threads thread
  1911. INNER JOIN $table_item_property item_properties
  1912. ON
  1913. thread.thread_id = item_properties.ref AND
  1914. item_properties.c_id = thread.c_id AND
  1915. item_properties.tool = '".TABLE_FORUM_THREAD."'
  1916. $groupCondition
  1917. $sessionCondition
  1918. LEFT JOIN $table_users users
  1919. ON thread.thread_poster_id = users.user_id
  1920. WHERE
  1921. item_properties.visibility='1' AND
  1922. thread.forum_id = ".intval($forum_id)." AND
  1923. thread.c_id = $courseId
  1924. ORDER BY thread.thread_sticky DESC, thread.thread_date DESC";
  1925. if (api_is_allowed_to_edit()) {
  1926. $sql = "SELECT DISTINCT
  1927. item_properties.*,
  1928. users.firstname,
  1929. users.lastname,
  1930. users.user_id,
  1931. thread.locked as locked,
  1932. thread.*
  1933. FROM $table_threads thread
  1934. INNER JOIN $table_item_property item_properties
  1935. ON
  1936. thread.thread_id = item_properties.ref AND
  1937. item_properties.c_id = thread.c_id AND
  1938. item_properties.tool = '".TABLE_FORUM_THREAD."'
  1939. $groupCondition
  1940. $sessionCondition
  1941. LEFT JOIN $table_users users
  1942. ON thread.thread_poster_id=users.user_id
  1943. WHERE
  1944. item_properties.visibility<>2 AND
  1945. thread.forum_id = ".intval($forum_id)." AND
  1946. thread.c_id = $courseId
  1947. ORDER BY thread.thread_sticky DESC, thread.thread_date DESC";
  1948. }
  1949. $result = Database::query($sql);
  1950. $list = [];
  1951. $alreadyAdded = [];
  1952. while ($row = Database::fetch_array($result, 'ASSOC')) {
  1953. if (in_array($row['thread_id'], $alreadyAdded)) {
  1954. continue;
  1955. }
  1956. $list[] = $row;
  1957. $alreadyAdded[] = $row['thread_id'];
  1958. }
  1959. return $list;
  1960. }
  1961. /**
  1962. * Get a thread by Id and course id.
  1963. *
  1964. * @param int $threadId the thread Id
  1965. * @param int $cId the course id
  1966. *
  1967. * @return array containing all the information about the thread
  1968. */
  1969. function getThreadInfo($threadId, $cId)
  1970. {
  1971. $repo = Database::getManager()->getRepository('ChamiloCourseBundle:CForumThread');
  1972. $forumThread = $repo->findOneBy(['threadId' => $threadId, 'cId' => $cId]);
  1973. $thread = [];
  1974. if ($forumThread) {
  1975. $thread['threadId'] = $forumThread->getThreadId();
  1976. $thread['threadTitle'] = $forumThread->getThreadTitle();
  1977. $thread['forumId'] = $forumThread->getForum() ? $forumThread->getForum()->getIid() : 0;
  1978. $thread['sessionId'] = $forumThread->getSessionId();
  1979. $thread['threadSticky'] = $forumThread->getThreadSticky();
  1980. $thread['locked'] = $forumThread->getLocked();
  1981. $thread['threadTitleQualify'] = $forumThread->getThreadTitleQualify();
  1982. $thread['threadQualifyMax'] = $forumThread->getThreadQualifyMax();
  1983. $thread['threadCloseDate'] = $forumThread->getThreadCloseDate();
  1984. $thread['threadWeight'] = $forumThread->getThreadWeight();
  1985. $thread['threadPeerQualify'] = $forumThread->isThreadPeerQualify();
  1986. }
  1987. return $thread;
  1988. }
  1989. /**
  1990. * Retrieve all posts of a given thread.
  1991. *
  1992. * @param array $forumInfo
  1993. * @param int $threadId The thread ID
  1994. * @param string $orderDirection Optional. The direction for sort the posts
  1995. * @param bool $recursive Optional. If the list is recursive
  1996. * @param int $postId Optional. The post ID for recursive list
  1997. * @param int $depth Optional. The depth to indicate the indent
  1998. *
  1999. * @todo move to a repository
  2000. *
  2001. * @return array containing all the information about the posts of a given thread
  2002. */
  2003. function getPosts(
  2004. $forumInfo,
  2005. $threadId,
  2006. $orderDirection = 'ASC',
  2007. $recursive = false,
  2008. $postId = null,
  2009. $depth = -1
  2010. ) {
  2011. $em = Database::getManager();
  2012. if (api_is_allowed_to_edit(false, true)) {
  2013. $visibleCriteria = Criteria::expr()->neq('visible', 2);
  2014. } else {
  2015. $visibleCriteria = Criteria::expr()->eq('visible', 1);
  2016. }
  2017. $criteria = Criteria::create();
  2018. $criteria
  2019. ->where(Criteria::expr()->eq('thread', $threadId))
  2020. ->andWhere(Criteria::expr()->eq('cId', $forumInfo['c_id']))
  2021. ->andWhere($visibleCriteria)
  2022. ;
  2023. $groupId = api_get_group_id();
  2024. $groupInfo = GroupManager::get_group_properties($groupId);
  2025. $filterModerated = true;
  2026. if (empty($groupId)) {
  2027. if (api_is_allowed_to_edit()) {
  2028. $filterModerated = false;
  2029. }
  2030. } else {
  2031. if (GroupManager::is_tutor_of_group(api_get_user_id(), $groupInfo) ||
  2032. api_is_allowed_to_edit(false, true)
  2033. ) {
  2034. $filterModerated = false;
  2035. }
  2036. }
  2037. if ($recursive) {
  2038. $criteria->andWhere(Criteria::expr()->eq('postParentId', $postId));
  2039. }
  2040. $qb = $em->getRepository('ChamiloCourseBundle:CForumPost')->createQueryBuilder('p');
  2041. $qb->select('p')
  2042. ->addCriteria($criteria)
  2043. ->addOrderBy('p.postId', $orderDirection);
  2044. if ($filterModerated && $forumInfo['moderated'] == 1) {
  2045. if (!api_is_allowed_to_edit(false, true)) {
  2046. $userId = api_get_user_id();
  2047. $qb->andWhere(
  2048. "p.status = 1 OR
  2049. (p.status = ".CForumPost::STATUS_WAITING_MODERATION." AND p.posterId = $userId) OR
  2050. (p.status = ".CForumPost::STATUS_REJECTED." AND p.posterId = $userId) OR
  2051. (p.status IS NULL AND p.posterId = $userId)
  2052. "
  2053. );
  2054. }
  2055. }
  2056. $posts = $qb->getQuery()->getResult();
  2057. $depth++;
  2058. $list = [];
  2059. /** @var CForumPost $post */
  2060. foreach ($posts as $post) {
  2061. $postInfo = [
  2062. 'iid' => $post->getIid(),
  2063. 'c_id' => $post->getCId(),
  2064. 'post_id' => $post->getPostId(),
  2065. 'post_title' => $post->getPostTitle(),
  2066. 'post_text' => $post->getPostText(),
  2067. 'thread_id' => $post->getThread() ? $post->getThread()->getIid() : 0,
  2068. 'forum_id' => $post->getForumId(),
  2069. 'poster_id' => $post->getPosterId(),
  2070. 'poster_name' => $post->getPosterName(),
  2071. 'post_date' => $post->getPostDate(),
  2072. 'post_notification' => $post->getPostNotification(),
  2073. 'post_parent_id' => $post->getPostParentId(),
  2074. 'visible' => $post->getVisible(),
  2075. 'status' => $post->getStatus(),
  2076. 'indent_cnt' => $depth,
  2077. ];
  2078. $posterId = $post->getPosterId();
  2079. if (!empty($posterId)) {
  2080. $user = api_get_user_entity($posterId);
  2081. if ($user) {
  2082. $postInfo['user_id'] = $user->getUserId();
  2083. $postInfo['username'] = $user->getUsername();
  2084. $postInfo['username_canonical'] = $user->getUsernameCanonical();
  2085. $postInfo['lastname'] = $user->getLastname();
  2086. $postInfo['firstname'] = $user->getFirstname();
  2087. $postInfo['complete_name'] = UserManager::formatUserFullName($user);
  2088. }
  2089. }
  2090. $list[] = $postInfo;
  2091. if (!$recursive) {
  2092. continue;
  2093. }
  2094. $list = array_merge(
  2095. $list,
  2096. getPosts(
  2097. $forumInfo,
  2098. $threadId,
  2099. $orderDirection,
  2100. $recursive,
  2101. $post->getPostId(),
  2102. $depth
  2103. )
  2104. );
  2105. }
  2106. return $list;
  2107. }
  2108. /**
  2109. * This function retrieves all the information of a post.
  2110. *
  2111. * @param int $post_id integer that indicates the forum
  2112. *
  2113. * @return array returns
  2114. *
  2115. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  2116. *
  2117. * @version february 2006, dokeos 1.8
  2118. */
  2119. function get_post_information($post_id)
  2120. {
  2121. $table_posts = Database::get_course_table(TABLE_FORUM_POST);
  2122. $table_users = Database::get_main_table(TABLE_MAIN_USER);
  2123. $course_id = api_get_course_int_id();
  2124. $post_id = (int) $post_id;
  2125. if (empty($post_id)) {
  2126. return [];
  2127. }
  2128. $sql = "SELECT posts.*, email FROM ".$table_posts." posts, ".$table_users." users
  2129. WHERE
  2130. c_id = $course_id AND
  2131. posts.poster_id=users.user_id AND
  2132. posts.post_id = ".$post_id;
  2133. $result = Database::query($sql);
  2134. $row = Database::fetch_array($result, 'ASSOC');
  2135. return $row;
  2136. }
  2137. /**
  2138. * This function retrieves all the information of a thread.
  2139. *
  2140. * @param int $forumId
  2141. * @param $thread_id integer that indicates the forum
  2142. * @param int|null $sessionId Optional. If is null then it is considered the current session
  2143. *
  2144. * @return array returns
  2145. *
  2146. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  2147. *
  2148. * @version february 2006, dokeos 1.8
  2149. */
  2150. function get_thread_information($forumId, $thread_id, $sessionId = null)
  2151. {
  2152. $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
  2153. $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
  2154. $thread_id = intval($thread_id);
  2155. $sessionId = $sessionId !== null ? intval($sessionId) : api_get_session_id();
  2156. $sessionCondition = api_get_session_condition(
  2157. $sessionId,
  2158. true,
  2159. false,
  2160. 'threads.session_id'
  2161. );
  2162. $forumCondition = '';
  2163. if (!empty($forumId)) {
  2164. $forumId = (int) $forumId;
  2165. $forumCondition = " threads.forum_id = $forumId AND ";
  2166. }
  2167. $sql = "SELECT * FROM $table_item_property item_properties
  2168. INNER JOIN
  2169. $table_threads threads
  2170. ON (item_properties.ref = threads.thread_id AND threads.c_id = item_properties.c_id)
  2171. WHERE
  2172. $forumCondition
  2173. item_properties.tool= '".TOOL_FORUM_THREAD."' AND
  2174. threads.thread_id = $thread_id
  2175. $sessionCondition
  2176. ";
  2177. $result = Database::query($sql);
  2178. $row = Database::fetch_assoc($result);
  2179. return $row;
  2180. }
  2181. /**
  2182. * This function retrieves forum thread users details.
  2183. *
  2184. * @param int Thread ID
  2185. * @param string Course DB name (optional)
  2186. *
  2187. * @return Doctrine\DBAL\Driver\Statement|null array Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
  2188. *
  2189. * @author Christian Fasanando <christian.fasanando@dokeos.com>,
  2190. *
  2191. * @todo this function need to be improved
  2192. *
  2193. * @version octubre 2008, dokeos 1.8
  2194. */
  2195. function get_thread_users_details($thread_id)
  2196. {
  2197. $t_posts = Database::get_course_table(TABLE_FORUM_POST);
  2198. $t_users = Database::get_main_table(TABLE_MAIN_USER);
  2199. $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
  2200. $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
  2201. $course_id = api_get_course_int_id();
  2202. $is_western_name_order = api_is_western_name_order();
  2203. if ($is_western_name_order) {
  2204. $orderby = 'ORDER BY user.firstname, user.lastname ';
  2205. } else {
  2206. $orderby = 'ORDER BY user.lastname, user.firstname';
  2207. }
  2208. if (api_get_session_id()) {
  2209. $session_info = api_get_session_info(api_get_session_id());
  2210. $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
  2211. //not showing coaches
  2212. $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, thread_id
  2213. FROM $t_posts p, $t_users user, $t_session_rel_user session_rel_user_rel_course
  2214. WHERE
  2215. p.poster_id = user.id AND
  2216. user.id = session_rel_user_rel_course.user_id AND
  2217. session_rel_user_rel_course.status<>'2' AND
  2218. session_rel_user_rel_course.user_id NOT IN ($user_to_avoid) AND
  2219. p.thread_id = ".intval($thread_id)." AND
  2220. session_id = ".api_get_session_id()." AND
  2221. p.c_id = $course_id AND
  2222. session_rel_user_rel_course.c_id = ".$course_id." $orderby ";
  2223. } else {
  2224. $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, thread_id
  2225. FROM $t_posts p, $t_users user, $t_course_user course_user
  2226. WHERE
  2227. p.poster_id = user.id
  2228. AND user.id = course_user.user_id
  2229. AND course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH."
  2230. AND p.thread_id = ".intval($thread_id)."
  2231. AND course_user.status NOT IN('1') AND
  2232. p.c_id = $course_id AND
  2233. course_user.c_id = ".$course_id." $orderby";
  2234. }
  2235. $result = Database::query($sql);
  2236. return $result;
  2237. }
  2238. /**
  2239. * This function retrieves forum thread users qualify.
  2240. *
  2241. * @param int Thread ID
  2242. * @param string Course DB name (optional)
  2243. *
  2244. * @return Doctrine\DBAL\Driver\Statement|null Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
  2245. *
  2246. * @author Jhon Hinojosa
  2247. *
  2248. * @todo this function need to be improved
  2249. */
  2250. function get_thread_users_qualify($thread_id)
  2251. {
  2252. $t_posts = Database::get_course_table(TABLE_FORUM_POST);
  2253. $t_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
  2254. $t_users = Database::get_main_table(TABLE_MAIN_USER);
  2255. $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
  2256. $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
  2257. $course_id = api_get_course_int_id();
  2258. $sessionId = api_get_session_id();
  2259. $is_western_name_order = api_is_western_name_order();
  2260. if ($is_western_name_order) {
  2261. $orderby = 'ORDER BY user.firstname, user.lastname ';
  2262. } else {
  2263. $orderby = 'ORDER BY user.lastname, user.firstname';
  2264. }
  2265. if ($sessionId) {
  2266. $session_info = api_get_session_info($sessionId);
  2267. $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
  2268. //not showing coaches
  2269. $sql = "SELECT DISTINCT post.poster_id, user.lastname, user.firstname, post.thread_id,user.id,qualify.qualify
  2270. FROM $t_posts post , $t_users user, $t_session_rel_user scu, $t_qualify qualify
  2271. WHERE poster_id = user.id
  2272. AND post.poster_id = qualify.user_id
  2273. AND user.id = scu.user_id
  2274. AND scu.status<>'2'
  2275. AND scu.user_id NOT IN ($user_to_avoid)
  2276. AND qualify.thread_id = ".intval($thread_id)."
  2277. AND post.thread_id = ".intval($thread_id)."
  2278. AND scu.session_id = $sessionId
  2279. AND scu.c_id = ".$course_id." AND
  2280. qualify.c_id = $course_id AND
  2281. post.c_id = $course_id
  2282. $orderby ";
  2283. } else {
  2284. $sql = "SELECT DISTINCT post.poster_id, user.lastname, user.firstname, post.thread_id,user.id,qualify.qualify
  2285. FROM $t_posts post,
  2286. $t_qualify qualify,
  2287. $t_users user,
  2288. $t_course_user course_user
  2289. WHERE
  2290. post.poster_id = user.id
  2291. AND post.poster_id = qualify.user_id
  2292. AND user.id = course_user.user_id
  2293. AND course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH."
  2294. AND qualify.thread_id = ".intval($thread_id)."
  2295. AND post.thread_id = ".intval($thread_id)."
  2296. AND course_user.status not in('1')
  2297. AND course_user.c_id = $course_id
  2298. AND qualify.c_id = $course_id
  2299. AND post.c_id = $course_id
  2300. $orderby ";
  2301. }
  2302. $result = Database::query($sql);
  2303. return $result;
  2304. }
  2305. /**
  2306. * This function retrieves forum thread users not qualify.
  2307. *
  2308. * @param int Thread ID
  2309. * @param string Course DB name (optional)
  2310. *
  2311. * @return Doctrine\DBAL\Driver\Statement|null Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
  2312. *
  2313. * @author Jhon Hinojosa<jhon.hinojosa@dokeos.com>,
  2314. *
  2315. * @version oct 2008, dokeos 1.8
  2316. */
  2317. function get_thread_users_not_qualify($thread_id)
  2318. {
  2319. $t_posts = Database::get_course_table(TABLE_FORUM_POST);
  2320. $t_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
  2321. $t_users = Database::get_main_table(TABLE_MAIN_USER);
  2322. $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
  2323. $t_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
  2324. $is_western_name_order = api_is_western_name_order();
  2325. if ($is_western_name_order) {
  2326. $orderby = 'ORDER BY user.firstname, user.lastname ';
  2327. } else {
  2328. $orderby = 'ORDER BY user.lastname, user.firstname';
  2329. }
  2330. $course_id = api_get_course_int_id();
  2331. $sql1 = "SELECT user_id FROM $t_qualify
  2332. WHERE c_id = $course_id AND thread_id = '".$thread_id."'";
  2333. $result1 = Database::query($sql1);
  2334. $cad = '';
  2335. while ($row = Database::fetch_array($result1)) {
  2336. $cad .= $row['user_id'].',';
  2337. }
  2338. if ($cad == '') {
  2339. $cad = '0';
  2340. } else {
  2341. $cad = substr($cad, 0, strlen($cad) - 1);
  2342. }
  2343. if (api_get_session_id()) {
  2344. $session_info = api_get_session_info(api_get_session_id());
  2345. $user_to_avoid = "'".$session_info['id_coach']."', '".$session_info['session_admin_id']."'";
  2346. //not showing coaches
  2347. $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, post.thread_id
  2348. FROM $t_posts post , $t_users user, $t_session_rel_user session_rel_user_rel_course
  2349. WHERE poster_id = user.id
  2350. AND user.id NOT IN (".$cad.")
  2351. AND user.id = session_rel_user_rel_course.user_id
  2352. AND session_rel_user_rel_course.status<>'2'
  2353. AND session_rel_user_rel_course.user_id NOT IN ($user_to_avoid)
  2354. AND post.thread_id = ".intval($thread_id)."
  2355. AND session_id = ".api_get_session_id()."
  2356. AND session_rel_user_rel_course.c_id = $course_id AND post.c_id = $course_id $orderby ";
  2357. } else {
  2358. $sql = "SELECT DISTINCT user.id, user.lastname, user.firstname, post.thread_id
  2359. FROM $t_posts post, $t_users user,$t_course_user course_user
  2360. WHERE post.poster_id = user.id
  2361. AND user.id NOT IN (".$cad.")
  2362. AND user.id = course_user.user_id
  2363. AND course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH."
  2364. AND post.thread_id = ".intval($thread_id)."
  2365. AND course_user.status not in('1')
  2366. AND course_user.c_id = $course_id AND post.c_id = $course_id $orderby";
  2367. }
  2368. $result = Database::query($sql);
  2369. return $result;
  2370. }
  2371. /**
  2372. * This function retrieves all the information of a given forum_id.
  2373. *
  2374. * @param $forum_id integer that indicates the forum
  2375. *
  2376. * @return array returns
  2377. *
  2378. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  2379. *
  2380. * @version february 2006, dokeos 1.8
  2381. *
  2382. * @deprecated this functionality is now moved to get_forums($forum_id)
  2383. */
  2384. function get_forum_information($forum_id, $courseId = 0)
  2385. {
  2386. $table_forums = Database::get_course_table(TABLE_FORUM);
  2387. $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
  2388. $courseId = empty($courseId) ? api_get_course_int_id() : intval($courseId);
  2389. $forum_id = intval($forum_id);
  2390. $sql = "SELECT *
  2391. FROM $table_forums forums
  2392. INNER JOIN $table_item_property item_properties
  2393. ON (forums.c_id = item_properties.c_id)
  2394. WHERE
  2395. item_properties.tool = '".TOOL_FORUM."' AND
  2396. item_properties.ref = '".$forum_id."' AND
  2397. forums.forum_id = '".$forum_id."' AND
  2398. forums.c_id = ".$courseId."
  2399. ";
  2400. $result = Database::query($sql);
  2401. $row = Database::fetch_array($result, 'ASSOC');
  2402. $row['approval_direct_post'] = 0;
  2403. // We can't anymore change this option, so it should always be activated.
  2404. return $row;
  2405. }
  2406. /**
  2407. * This function retrieves all the information of a given forumcategory id.
  2408. *
  2409. * @param $cat_id integer that indicates the forum
  2410. *
  2411. * @return array returns if there are category or bool returns if there aren't category
  2412. *
  2413. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  2414. *
  2415. * @version february 2006, dokeos 1.8
  2416. */
  2417. function get_forumcategory_information($cat_id)
  2418. {
  2419. $table_categories = Database::get_course_table(TABLE_FORUM_CATEGORY);
  2420. $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
  2421. $course_id = api_get_course_int_id();
  2422. $sql = "SELECT *
  2423. FROM $table_categories forumcategories
  2424. INNER JOIN $table_item_property item_properties
  2425. ON (forumcategories.c_id = item_properties.c_id)
  2426. WHERE
  2427. forumcategories.c_id = $course_id AND
  2428. item_properties.c_id = $course_id AND
  2429. item_properties.tool='".TOOL_FORUM_CATEGORY."' AND
  2430. item_properties.ref='".Database::escape_string($cat_id)."' AND
  2431. forumcategories.cat_id='".Database::escape_string($cat_id)."'";
  2432. $result = Database::query($sql);
  2433. $row = Database::fetch_array($result);
  2434. return $row;
  2435. }
  2436. /**
  2437. * This function counts the number of forums inside a given category.
  2438. *
  2439. * @param int $cat_id the id of the forum category
  2440. *
  2441. * @todo an additional parameter that takes the visibility into account. For instance $countinvisible=0 would return the number
  2442. * of visible forums, $countinvisible=1 would return the number of visible and invisible forums
  2443. *
  2444. * @return int the number of forums inside the given category
  2445. *
  2446. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  2447. *
  2448. * @version february 2006, dokeos 1.8
  2449. */
  2450. function count_number_of_forums_in_category($cat_id)
  2451. {
  2452. $table_forums = Database::get_course_table(TABLE_FORUM);
  2453. $course_id = api_get_course_int_id();
  2454. $cat_id = (int) $cat_id;
  2455. $sql = "SELECT count(*) AS number_of_forums
  2456. FROM $table_forums
  2457. WHERE c_id = $course_id AND forum_category = $cat_id";
  2458. $result = Database::query($sql);
  2459. $row = Database::fetch_array($result);
  2460. return $row['number_of_forums'];
  2461. }
  2462. /**
  2463. * This function update a thread.
  2464. *
  2465. * @param array $values - The form Values
  2466. */
  2467. function updateThread($values)
  2468. {
  2469. if (!api_is_allowed_to_edit()) {
  2470. return '';
  2471. }
  2472. $logInfo = [
  2473. 'tool' => TOOL_FORUM,
  2474. 'tool_id' => $values['forum_id'],
  2475. 'tool_id_detail' => $values['thread_id'],
  2476. 'action' => 'edit-thread',
  2477. 'action_details' => 'thread',
  2478. 'info' => $values['thread_title'],
  2479. ];
  2480. Event::registerLog($logInfo);
  2481. $threadTable = Database::get_course_table(TABLE_FORUM_THREAD);
  2482. $courseId = api_get_course_int_id();
  2483. $courseCode = api_get_course_id();
  2484. $sessionId = api_get_session_id();
  2485. // Simple update + set gradebook values to null
  2486. $params = [
  2487. 'thread_title' => $values['thread_title'],
  2488. 'thread_sticky' => isset($values['thread_sticky']) ? $values['thread_sticky'] : 0,
  2489. ];
  2490. $where = ['c_id = ? AND thread_id = ?' => [$courseId, $values['thread_id']]];
  2491. Database::update($threadTable, $params, $where);
  2492. $id = $values['thread_id'];
  2493. $linkInfo = GradebookUtils::isResourceInCourseGradebook(
  2494. $courseCode,
  2495. LINK_FORUM_THREAD,
  2496. $id,
  2497. $sessionId
  2498. );
  2499. $linkId = $linkInfo['id'];
  2500. $em = Database::getManager();
  2501. $gradebookLink = null;
  2502. if (!empty($linkId)) {
  2503. $gradebookLink = $em->getRepository('ChamiloCoreBundle:GradebookLink')->find($linkId);
  2504. }
  2505. // values 1 or 0
  2506. $check = isset($values['thread_qualify_gradebook']) ? $values['thread_qualify_gradebook'] : false;
  2507. if ($check) {
  2508. $title = Security::remove_XSS(stripslashes($values['calification_notebook_title']));
  2509. $value = isset($values['numeric_calification']) ? intval($values['numeric_calification']) : 0;
  2510. $weight = isset($values['weight_calification']) ? floatval($values['weight_calification']) : 0;
  2511. $description = '';
  2512. // Update title
  2513. $params = [
  2514. 'thread_title_qualify' => $values['calification_notebook_title'],
  2515. 'thread_qualify_max' => api_float_val($values['numeric_calification']),
  2516. 'thread_weight' => api_float_val($values['weight_calification']),
  2517. 'thread_peer_qualify' => $values['thread_peer_qualify'],
  2518. ];
  2519. $where = ['c_id = ? AND thread_id = ?' => [$courseId, $values['thread_id']]];
  2520. Database::update($threadTable, $params, $where);
  2521. if (!$linkInfo) {
  2522. GradebookUtils::add_resource_to_course_gradebook(
  2523. $values['category_id'],
  2524. $courseCode,
  2525. LINK_FORUM_THREAD,
  2526. $id,
  2527. $title,
  2528. $weight,
  2529. $value,
  2530. $description,
  2531. 1,
  2532. $sessionId
  2533. );
  2534. } else {
  2535. if ($gradebookLink) {
  2536. $gradebookLink->setWeight($weight);
  2537. $em->persist($gradebookLink);
  2538. $em->flush();
  2539. }
  2540. }
  2541. } else {
  2542. $params = [
  2543. 'thread_title_qualify' => '',
  2544. 'thread_qualify_max' => 0,
  2545. 'thread_weight' => 0,
  2546. 'thread_peer_qualify' => 0,
  2547. ];
  2548. $where = ['c_id = ? AND thread_id = ?' => [$courseId, $values['thread_id']]];
  2549. Database::update($threadTable, $params, $where);
  2550. if (!empty($linkInfo)) {
  2551. if ($gradebookLink) {
  2552. $em->remove($gradebookLink);
  2553. $em->flush();
  2554. }
  2555. }
  2556. }
  2557. $message = get_lang('The post has been modified').'<br />';
  2558. Display::addFlash(Display::return_message($message, 'confirmation', false));
  2559. }
  2560. /**
  2561. * This function stores a new thread. This is done through an entry in the forum_thread table AND
  2562. * in the forum_post table because. The threads are also stored in the item_property table. (forum posts are not (yet)).
  2563. *
  2564. * @param array $current_forum
  2565. * @param array $values
  2566. * @param array $courseInfo
  2567. * @param bool $showMessage
  2568. * @param int $userId Optional. The user ID
  2569. * @param int $sessionId
  2570. *
  2571. * @return CForumThread
  2572. *
  2573. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  2574. *
  2575. * @version february 2006, dokeos 1.8
  2576. */
  2577. function store_thread(
  2578. $current_forum,
  2579. $values,
  2580. $courseInfo = [],
  2581. $showMessage = true,
  2582. $userId = 0,
  2583. $sessionId = 0
  2584. ) {
  2585. $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
  2586. $userId = $userId ?: api_get_user_id();
  2587. $course_id = $courseInfo['real_id'];
  2588. $courseCode = $courseInfo['code'];
  2589. $groupId = api_get_group_id();
  2590. $groupInfo = GroupManager::get_group_properties($groupId);
  2591. $sessionId = $sessionId ?: api_get_session_id();
  2592. $em = Database::getManager();
  2593. $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
  2594. $upload_ok = 1;
  2595. $has_attachment = false;
  2596. if (!empty($_FILES['user_upload']['name'])) {
  2597. $upload_ok = process_uploaded_file($_FILES['user_upload']);
  2598. $has_attachment = true;
  2599. }
  2600. if (!$upload_ok) {
  2601. if ($showMessage) {
  2602. Display::addFlash(
  2603. Display::return_message(
  2604. get_lang('No file was uploaded.'),
  2605. 'error',
  2606. false
  2607. )
  2608. );
  2609. }
  2610. return null;
  2611. }
  2612. $post_date = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
  2613. $visible = 1;
  2614. if ($current_forum['approval_direct_post'] == '1' && !api_is_allowed_to_edit(null, true)) {
  2615. $visible = 0; // The post has not been approved yet.
  2616. }
  2617. $clean_post_title = $values['post_title'];
  2618. $forum = $em->find('ChamiloCourseBundle:CForumForum', $values['forum_id']);
  2619. // We first store an entry in the forum_thread table because the thread_id is used in the forum_post table.
  2620. $lastThread = new CForumThread();
  2621. $lastThread
  2622. ->setCId($course_id)
  2623. ->setThreadTitle($clean_post_title)
  2624. ->setForum($forum)
  2625. ->setThreadPosterId($userId)
  2626. ->setThreadPosterName(isset($values['poster_name']) ? $values['poster_name'] : null)
  2627. ->setThreadDate($post_date)
  2628. ->setThreadSticky(isset($values['thread_sticky']) ? $values['thread_sticky'] : 0)
  2629. ->setThreadTitleQualify(
  2630. isset($values['calification_notebook_title']) ? $values['calification_notebook_title'] : null
  2631. )
  2632. ->setThreadQualifyMax(isset($values['numeric_calification']) ? (int) $values['numeric_calification'] : 0)
  2633. ->setThreadWeight(isset($values['weight_calification']) ? (int) $values['weight_calification'] : 0)
  2634. ->setThreadPeerQualify(isset($values['thread_peer_qualify']) ? (bool) $values['thread_peer_qualify'] : false)
  2635. ->setSessionId($sessionId)
  2636. ->setLpItemId(isset($values['lp_item_id']) ? (int) $values['lp_item_id'] : 0)
  2637. ->setThreadId(0)
  2638. ->setLocked(0)
  2639. ;
  2640. $em->persist($lastThread);
  2641. $em->flush();
  2642. // Add option gradebook qualify.
  2643. if (isset($values['thread_qualify_gradebook']) &&
  2644. 1 == $values['thread_qualify_gradebook']
  2645. ) {
  2646. // Add function gradebook.
  2647. $resourcename = stripslashes($values['calification_notebook_title']);
  2648. GradebookUtils::add_resource_to_course_gradebook(
  2649. $values['category_id'],
  2650. $courseCode,
  2651. 5,
  2652. $lastThread->getIid(),
  2653. $resourcename,
  2654. $values['weight_calification'],
  2655. $values['numeric_calification'],
  2656. '',
  2657. 0,
  2658. $sessionId
  2659. );
  2660. }
  2661. if ($lastThread->getIid()) {
  2662. $lastThread->setThreadId($lastThread->getIid());
  2663. $em->merge($lastThread);
  2664. $em->flush();
  2665. api_item_property_update(
  2666. $courseInfo,
  2667. TOOL_FORUM_THREAD,
  2668. $lastThread->getIid(),
  2669. 'ForumThreadAdded',
  2670. $userId,
  2671. $groupInfo,
  2672. null,
  2673. null,
  2674. null,
  2675. $sessionId
  2676. );
  2677. // If the forum properties tell that the posts have to be approved
  2678. // we have to put the whole thread invisible,
  2679. // because otherwise the students will see the thread and not the post
  2680. // in the thread.
  2681. // We also have to change $visible because the post itself has to be
  2682. // visible in this case (otherwise the teacher would have
  2683. // to make the thread visible AND the post.
  2684. // Default behaviour
  2685. api_set_default_visibility(
  2686. $lastThread->getIid(),
  2687. TOOL_FORUM_THREAD,
  2688. $groupId,
  2689. $courseInfo,
  2690. $sessionId,
  2691. $userId
  2692. );
  2693. if ($visible == 0) {
  2694. api_item_property_update(
  2695. $courseInfo,
  2696. TOOL_FORUM_THREAD,
  2697. $lastThread->getIid(),
  2698. 'invisible',
  2699. $userId,
  2700. $groupInfo
  2701. );
  2702. $visible = 1;
  2703. }
  2704. $logInfo = [
  2705. 'tool' => TOOL_FORUM,
  2706. 'tool_id' => $values['forum_id'],
  2707. 'tool_id_detail' => $lastThread->getIid(),
  2708. 'action' => 'new-thread',
  2709. 'action_details' => '',
  2710. 'info' => $clean_post_title,
  2711. ];
  2712. Event::registerLog($logInfo);
  2713. }
  2714. // We now store the content in the table_post table.
  2715. $lastPost = new CForumPost();
  2716. $lastPost
  2717. ->setCId($course_id)
  2718. ->setPostTitle($clean_post_title)
  2719. ->setPostText($values['post_text'])
  2720. ->setThread($lastThread)
  2721. ->setForumId($values['forum_id'])
  2722. ->setPosterId($userId)
  2723. ->setPosterName(isset($values['poster_name']) ? $values['poster_name'] : null)
  2724. ->setPostDate($post_date)
  2725. ->setPostNotification(isset($values['post_notification']) ? (int) $values['post_notification'] : null)
  2726. ->setPostParentId(null)
  2727. ->setVisible($visible)
  2728. ->setPostId(0)
  2729. ->setStatus(CForumPost::STATUS_VALIDATED);
  2730. if ($current_forum['moderated']) {
  2731. $lastPost->setStatus(
  2732. api_is_course_admin() ? CForumPost::STATUS_VALIDATED : CForumPost::STATUS_WAITING_MODERATION
  2733. );
  2734. }
  2735. $em->persist($lastPost);
  2736. $em->flush();
  2737. $lastPostId = $lastPost->getIid();
  2738. $lastThread->setThreadLastPost($lastPostId);
  2739. $em->merge($lastThread);
  2740. $em->flush();
  2741. $logInfo = [
  2742. 'tool' => TOOL_FORUM,
  2743. 'tool_id' => $values['forum_id'],
  2744. 'tool_id_detail' => $lastThread->getIid(),
  2745. 'action' => 'new-post',
  2746. 'info' => $clean_post_title,
  2747. ];
  2748. Event::registerLog($logInfo);
  2749. if ($lastPostId) {
  2750. $lastPost->setPostId($lastPostId);
  2751. $em->merge($lastPost);
  2752. $em->flush();
  2753. }
  2754. // Update attached files
  2755. if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
  2756. foreach ($_POST['file_ids'] as $key => $id) {
  2757. editAttachedFile(
  2758. [
  2759. 'comment' => $_POST['file_comments'][$key],
  2760. 'post_id' => $lastPostId,
  2761. ],
  2762. $id
  2763. );
  2764. }
  2765. }
  2766. // Now we have to update the thread table to fill the thread_last_post
  2767. // field (so that we know when the thread has been updated for the last time).
  2768. $sql = "UPDATE $table_threads
  2769. SET thread_last_post = '".Database::escape_string($lastPostId)."'
  2770. WHERE
  2771. c_id = $course_id AND
  2772. thread_id='".Database::escape_string($lastThread->getIid())."'";
  2773. $result = Database::query($sql);
  2774. $message = get_lang('The new thread has been added');
  2775. // Overwrite default message.
  2776. if ($current_forum['moderated'] &&
  2777. !api_is_allowed_to_edit(null, true)
  2778. ) {
  2779. $message = get_lang('Your message has to be approved before people can view it.');
  2780. }
  2781. // Storing the attachments if any.
  2782. if ($has_attachment) {
  2783. // Try to add an extension to the file if it hasn't one.
  2784. $new_file_name = add_ext_on_mime(
  2785. stripslashes($_FILES['user_upload']['name']),
  2786. $_FILES['user_upload']['type']
  2787. );
  2788. if (!filter_extension($new_file_name)) {
  2789. if ($showMessage) {
  2790. Display::addFlash(Display::return_message(
  2791. get_lang('File upload failed: this file extension or file type is prohibited'),
  2792. 'error'
  2793. ));
  2794. }
  2795. } else {
  2796. if ($result) {
  2797. add_forum_attachment_file(
  2798. isset($values['file_comment']) ? $values['file_comment'] : null,
  2799. $lastPostId
  2800. );
  2801. }
  2802. }
  2803. } else {
  2804. $message .= '<br />';
  2805. }
  2806. if ($current_forum['approval_direct_post'] == '1' &&
  2807. !api_is_allowed_to_edit(null, true)
  2808. ) {
  2809. $message .= get_lang('Your message has to be approved before people can view it.').'<br />';
  2810. $message .= get_lang('You can now return to the').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'">'.
  2811. get_lang('Forum').'</a><br />';
  2812. } else {
  2813. $message .= get_lang('You can now return to the').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'">'.
  2814. get_lang('Forum').'</a><br />';
  2815. $message .= get_lang('You can now return to the').' <a href="viewthread.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'&thread='.$lastThread->getIid().'">'.
  2816. get_lang('Message').'</a>';
  2817. }
  2818. $reply_info['new_post_id'] = $lastPostId;
  2819. $my_post_notification = isset($values['post_notification']) ? $values['post_notification'] : null;
  2820. if ($my_post_notification == 1) {
  2821. set_notification('thread', $lastThread->getIid(), true);
  2822. }
  2823. send_notification_mails(
  2824. $current_forum['forum_id'],
  2825. $lastThread->getIid(),
  2826. $reply_info,
  2827. $courseInfo['code']
  2828. );
  2829. Session::erase('formelements');
  2830. Session::erase('origin');
  2831. Session::erase('breadcrumbs');
  2832. Session::erase('addedresource');
  2833. Session::erase('addedresourceid');
  2834. if ($showMessage) {
  2835. Display::addFlash(Display::return_message($message, 'success', false));
  2836. }
  2837. return $lastThread;
  2838. }
  2839. /**
  2840. * This function displays the form that is used to add a post. This can be a new thread or a reply.
  2841. *
  2842. * @param array $current_forum
  2843. * @param string $action is the parameter that determines if we are
  2844. * 1. newthread: adding a new thread (both empty) => No I-frame
  2845. * 2. replythread: Replying to a thread ($action = replythread) => I-frame with the complete thread (if enabled)
  2846. * 3. replymessage: Replying to a message ($action =replymessage) => I-frame with the complete thread (if enabled)
  2847. * (I first thought to put and I-frame with the message only)
  2848. * 4. quote: Quoting a message ($action= quotemessage) => I-frame with the complete thread (if enabled).
  2849. * The message will be in the reply. (I first thought not to put an I-frame here)
  2850. * @param array $form_values
  2851. * @param bool $showPreview
  2852. *
  2853. * @return FormValidator
  2854. *
  2855. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  2856. *
  2857. * @version february 2006, dokeos 1.8
  2858. */
  2859. function show_add_post_form($current_forum, $action, $form_values = '', $showPreview = true)
  2860. {
  2861. $_user = api_get_user_info();
  2862. $action = isset($action) ? Security::remove_XSS($action) : '';
  2863. $myThread = isset($_GET['thread']) ? (int) $_GET['thread'] : '';
  2864. $forumId = isset($_GET['forum']) ? (int) $_GET['forum'] : '';
  2865. $my_post = isset($_GET['post']) ? (int) $_GET['post'] : '';
  2866. $giveRevision = isset($_GET['give_revision']) && $_GET['give_revision'] == 1;
  2867. $url = api_get_self().'?'.http_build_query(
  2868. [
  2869. 'action' => $action,
  2870. 'forum' => $forumId,
  2871. 'thread' => $myThread,
  2872. 'post' => $my_post,
  2873. ]
  2874. ).'&'.api_get_cidreq();
  2875. $form = new FormValidator(
  2876. 'thread',
  2877. 'post',
  2878. $url
  2879. );
  2880. $form->setConstants(['forum' => '5']);
  2881. // Setting the form elements.
  2882. $form->addElement('hidden', 'forum_id', $forumId);
  2883. $form->addElement('hidden', 'thread_id', $myThread);
  2884. $form->addElement('hidden', 'action', $action);
  2885. // If anonymous posts are allowed we also display a form to allow the user to put his name or username in.
  2886. if ($current_forum['allow_anonymous'] == 1 && !isset($_user['user_id'])) {
  2887. $form->addElement('text', 'poster_name', get_lang('Name'));
  2888. $form->applyFilter('poster_name', 'html_filter');
  2889. }
  2890. $form->addElement('text', 'post_title', get_lang('Title'));
  2891. $form->addHtmlEditor(
  2892. 'post_text',
  2893. get_lang('Text'),
  2894. true,
  2895. false,
  2896. api_is_allowed_to_edit(null, true) ? [
  2897. 'ToolbarSet' => 'Forum',
  2898. 'Width' => '100%',
  2899. 'Height' => '300',
  2900. ] : [
  2901. 'ToolbarSet' => 'ForumStudent',
  2902. 'Width' => '100%',
  2903. 'Height' => '300',
  2904. 'UserStatus' => 'student',
  2905. ]
  2906. );
  2907. $form->addRule('post_text', get_lang('Required field'), 'required');
  2908. if (in_array($action, ['newthread', 'replythread', 'replymessage', 'quote'])) {
  2909. $extraFields = new ExtraField('forum_post');
  2910. $extraFields->addElements(
  2911. $form,
  2912. null,
  2913. [], //exclude
  2914. false, // filter
  2915. false, // tag as select
  2916. ['ask_for_revision'], //show only fields
  2917. [], // order fields
  2918. [] // extra data);
  2919. );
  2920. }
  2921. $iframe = null;
  2922. if ($showPreview) {
  2923. $myThread = Security::remove_XSS($myThread);
  2924. if ($action != 'newthread' && !empty($myThread)) {
  2925. $iframe = "<iframe style=\"border: 1px solid black\" src=\"iframe_thread.php?".api_get_cidreq(
  2926. )."&forum=".$forumId."&thread=".$myThread."#".$my_post."\" width=\"100%\"></iframe>";
  2927. }
  2928. if (!empty($iframe)) {
  2929. $form->addElement('label', get_lang('Thread'), $iframe);
  2930. }
  2931. }
  2932. if (Gradebook::is_active() &&
  2933. (api_is_course_admin() || api_is_session_general_coach() || api_is_course_tutor()) && !($myThread)
  2934. ) {
  2935. $form->addElement('advanced_settings', 'advanced_params', get_lang('Advanced settings'));
  2936. $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
  2937. // Thread qualify
  2938. if (Gradebook::is_active()) {
  2939. //Loading gradebook select
  2940. GradebookUtils::load_gradebook_select_in_tool($form);
  2941. $form->addElement(
  2942. 'checkbox',
  2943. 'thread_qualify_gradebook',
  2944. '',
  2945. get_lang('Grade this thread'),
  2946. 'onclick="javascript:if(this.checked==true){document.getElementById(\'options_field\').style.display = \'block\';}else{document.getElementById(\'options_field\').style.display = \'none\';}"'
  2947. );
  2948. } else {
  2949. $form->addElement('hidden', 'thread_qualify_gradebook', false);
  2950. }
  2951. $form->addElement('html', '<div id="options_field" style="display:none">');
  2952. $form->addElement('text', 'numeric_calification', get_lang('Maximum score'));
  2953. $form->applyFilter('numeric_calification', 'html_filter');
  2954. $form->addElement('text', 'calification_notebook_title', get_lang('Column header in Competences Report'));
  2955. $form->applyFilter('calification_notebook_title', 'html_filter');
  2956. $form->addElement(
  2957. 'text',
  2958. 'weight_calification',
  2959. get_lang('Weight in Report'),
  2960. ['value' => '0.00', 'onfocus' => "javascript: this.select();"]
  2961. );
  2962. $form->applyFilter('weight_calification', 'html_filter');
  2963. $group = [];
  2964. $group[] = $form->createElement('radio', 'thread_peer_qualify', null, get_lang('Yes'), 1);
  2965. $group[] = $form->createElement('radio', 'thread_peer_qualify', null, get_lang('No'), 0);
  2966. $form->addGroup(
  2967. $group,
  2968. '',
  2969. [
  2970. get_lang('Thread scored by peers'),
  2971. get_lang('Thread scored by peersComment'),
  2972. ]
  2973. );
  2974. $form->addElement('html', '</div>');
  2975. $form->addElement('html', '</div>');
  2976. }
  2977. if ($action === 'newthread') {
  2978. Skill::addSkillsToForm($form, ITEM_TYPE_FORUM_THREAD, 0);
  2979. }
  2980. if (api_is_allowed_to_edit(null, true) && $action == 'newthread') {
  2981. $form->addElement('checkbox', 'thread_sticky', '', get_lang('This is a sticky message (appears always on top and has a special sticky icon)'));
  2982. }
  2983. if (in_array($action, ['quote', 'replymessage'])) {
  2984. $form->addFile('user_upload[]', get_lang('Attachment'));
  2985. $form->addButton(
  2986. 'add_attachment',
  2987. get_lang('Add attachment'),
  2988. 'paperclip',
  2989. 'default',
  2990. 'default',
  2991. null,
  2992. ['id' => 'reply-add-attachment']
  2993. );
  2994. } else {
  2995. $form->addFile('user_upload', get_lang('Attachment'));
  2996. }
  2997. if ($giveRevision) {
  2998. $hide = api_get_configuration_value('hide_forum_post_revision_language');
  2999. $form->addHidden('give_revision', 1);
  3000. if ($hide === false) {
  3001. $extraField = new ExtraField('forum_post');
  3002. $extraField->addElements(
  3003. $form,
  3004. null,
  3005. [], //exclude
  3006. false, // filter
  3007. false, // tag as select
  3008. ['revision_language'], //show only fields
  3009. [], // order fields
  3010. [] // extra data
  3011. );
  3012. } else {
  3013. $form->addHidden('extra_revision_language', 1);
  3014. }
  3015. }
  3016. // Setting the class and text of the form title and submit button.
  3017. if ($action == 'quote') {
  3018. $form->addButtonCreate(get_lang('Quote this message'), 'SubmitPost');
  3019. } elseif ($action == 'replythread') {
  3020. $form->addButtonCreate(get_lang('Reply to this thread'), 'SubmitPost');
  3021. } elseif ($action == 'replymessage') {
  3022. $form->addButtonCreate(get_lang('Reply to this message'), 'SubmitPost');
  3023. } else {
  3024. $form->addButtonCreate(get_lang('Create thread'), 'SubmitPost');
  3025. }
  3026. $defaults['thread_peer_qualify'] = 0;
  3027. if (!empty($form_values)) {
  3028. $defaults['post_title'] = prepare4display($form_values['post_title']);
  3029. $defaults['post_text'] = prepare4display($form_values['post_text']);
  3030. $defaults['post_notification'] = (int) $form_values['post_notification'];
  3031. $defaults['thread_sticky'] = (int) $form_values['thread_sticky'];
  3032. $defaults['thread_peer_qualify'] = (int) $form_values['thread_peer_qualify'];
  3033. }
  3034. // If we are quoting a message we have to retrieve the information of the post we are quoting so that
  3035. // we can add this as default to the textarea.
  3036. // We also need to put the parent_id of the post in a hidden form when
  3037. if (($action == 'quote' || $action == 'replymessage' || $giveRevision) && !empty($my_post)) {
  3038. // we are quoting or replying to a message (<> reply to a thread !!!)
  3039. $form->addHidden('post_parent_id', $my_post);
  3040. // If we are replying or are quoting then we display a default title.
  3041. $values = get_post_information($my_post);
  3042. $posterInfo = api_get_user_info($values['poster_id']);
  3043. $posterName = '';
  3044. if ($posterInfo) {
  3045. $posterName = $posterInfo['complete_name'];
  3046. }
  3047. $defaults['post_title'] = get_lang('Re:').api_html_entity_decode($values['post_title'], ENT_QUOTES);
  3048. // When we are quoting a message then we have to put that message into the wysiwyg editor.
  3049. // Note: The style has to be hardcoded here because using class="quote" didn't work.
  3050. if ($action == 'quote') {
  3051. $defaults['post_text'] = '<div>&nbsp;</div>
  3052. <div style="margin: 5px;">
  3053. <div style="font-size: 90%; font-style: italic;">'.
  3054. get_lang('Quoting').' '.$posterName.':</div>
  3055. <div style="color: #006600; font-size: 90%; font-style: italic; background-color: #FAFAFA; border: #D1D7DC 1px solid; padding: 3px;">'.
  3056. prepare4display($values['post_text']).'
  3057. </div>
  3058. </div>
  3059. <div>&nbsp;</div>
  3060. <div>&nbsp;</div>
  3061. ';
  3062. }
  3063. if ($giveRevision) {
  3064. $defaults['post_text'] = prepare4display($values['post_text']);
  3065. }
  3066. }
  3067. $form->setDefaults(isset($defaults) ? $defaults : []);
  3068. // The course admin can make a thread sticky (=appears with special icon and always on top).
  3069. $form->addRule('post_title', get_lang('Required field'), 'required');
  3070. if ($current_forum['allow_anonymous'] == 1 && !isset($_user['user_id'])) {
  3071. $form->addRule(
  3072. 'poster_name',
  3073. get_lang('Required field'),
  3074. 'required'
  3075. );
  3076. }
  3077. // Validation or display
  3078. if ($form->validate()) {
  3079. $check = Security::check_token('post');
  3080. if ($check) {
  3081. $values = $form->getSubmitValues();
  3082. if (isset($values['thread_qualify_gradebook']) &&
  3083. $values['thread_qualify_gradebook'] == '1' &&
  3084. empty($values['weight_calification'])
  3085. ) {
  3086. Display::addFlash(
  3087. Display::return_message(
  3088. get_lang('You must assign a score to this activity').'&nbsp;<a href="javascript:window.history.go(-1);">'.get_lang('Back').'</a>',
  3089. 'error',
  3090. false
  3091. )
  3092. );
  3093. return false;
  3094. }
  3095. $postId = 0;
  3096. $threadId = 0;
  3097. switch ($action) {
  3098. case 'newthread':
  3099. $myThread = store_thread($current_forum, $values);
  3100. if ($myThread) {
  3101. $threadId = $myThread->getIid();
  3102. Skill::saveSkills($form, ITEM_TYPE_FORUM_THREAD, $threadId);
  3103. $postId = $myThread->getThreadLastPost();
  3104. }
  3105. break;
  3106. case 'quote':
  3107. case 'replythread':
  3108. case 'replymessage':
  3109. $postId = store_reply($current_forum, $values);
  3110. break;
  3111. }
  3112. if ($postId) {
  3113. $postInfo = get_post_information($postId);
  3114. if ($postInfo) {
  3115. $threadId = $postInfo['thread_id'];
  3116. }
  3117. if (isset($values['give_revision']) && $values['give_revision'] == 1) {
  3118. $extraFieldValues = new ExtraFieldValue('forum_post');
  3119. $revisionLanguage = isset($values['extra_revision_language']) ? $values['extra_revision_language'] : '';
  3120. $params = [
  3121. 'item_id' => $postId,
  3122. 'extra_revision_language' => $revisionLanguage,
  3123. ];
  3124. $extraFieldValues->saveFieldValues(
  3125. $params,
  3126. false,
  3127. false,
  3128. ['revision_language']
  3129. );
  3130. }
  3131. if (in_array($action, ['newthread', 'replythread', 'replymessage', 'quote'])) {
  3132. $extraFieldValues = new ExtraFieldValue('forum_post');
  3133. $params = [
  3134. 'item_id' => $postId,
  3135. 'extra_ask_for_revision' => isset($values['extra_ask_for_revision']) ? $values['extra_ask_for_revision'] : '',
  3136. ];
  3137. $extraFieldValues->saveFieldValues(
  3138. $params,
  3139. false,
  3140. false,
  3141. ['ask_for_revision']
  3142. );
  3143. }
  3144. }
  3145. $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&'.http_build_query(
  3146. [
  3147. 'forum' => $forumId,
  3148. 'thread' => $threadId,
  3149. ]
  3150. );
  3151. Security::clear_token();
  3152. header('Location: '.$url);
  3153. exit;
  3154. }
  3155. } else {
  3156. $token = Security::get_token();
  3157. $form->addElement('hidden', 'sec_token');
  3158. $form->setConstants(['sec_token' => $token]);
  3159. // Delete from $_SESSION forum attachment from other posts
  3160. // and keep only attachments for new post
  3161. clearAttachedFiles(FORUM_NEW_POST);
  3162. // Get forum attachment ajax table to add it to form
  3163. $attachmentAjaxTable = getAttachmentsAjaxTable(0, $current_forum['forum_id']);
  3164. $ajaxHtml = $attachmentAjaxTable;
  3165. $form->addElement('html', $ajaxHtml);
  3166. return $form;
  3167. }
  3168. }
  3169. /**
  3170. * @param array $threadInfo
  3171. * @param int $user_id
  3172. * @param int $thread_id
  3173. * @param int $thread_qualify
  3174. * @param int $qualify_time
  3175. * @param int $session_id
  3176. *
  3177. * @return array optional
  3178. *
  3179. * @author Isaac Flores <isaac.flores@dokeos.com>, U.N.A.S University
  3180. *
  3181. * @version October 2008, dokeos 1.8.6
  3182. */
  3183. function saveThreadScore(
  3184. $threadInfo,
  3185. $user_id,
  3186. $thread_id,
  3187. $thread_qualify = 0,
  3188. $qualify_time,
  3189. $session_id = 0
  3190. ) {
  3191. $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
  3192. $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
  3193. $course_id = api_get_course_int_id();
  3194. $session_id = intval($session_id);
  3195. $currentUserId = api_get_user_id();
  3196. if ($user_id == strval(intval($user_id)) &&
  3197. $thread_id == strval(intval($thread_id)) &&
  3198. $thread_qualify == strval(floatval($thread_qualify))
  3199. ) {
  3200. // Testing
  3201. $sql = "SELECT thread_qualify_max FROM $table_threads
  3202. WHERE c_id = $course_id AND thread_id=".$thread_id;
  3203. $res_string = Database::query($sql);
  3204. $row_string = Database::fetch_array($res_string);
  3205. if ($thread_qualify <= $row_string[0]) {
  3206. if ($threadInfo['thread_peer_qualify'] == 0) {
  3207. $sql = "SELECT COUNT(*) FROM $table_threads_qualify
  3208. WHERE
  3209. c_id = $course_id AND
  3210. user_id = $user_id AND
  3211. thread_id = ".$thread_id;
  3212. } else {
  3213. $sql = "SELECT COUNT(*) FROM $table_threads_qualify
  3214. WHERE
  3215. c_id = $course_id AND
  3216. user_id = $user_id AND
  3217. qualify_user_id = $currentUserId AND
  3218. thread_id = ".$thread_id;
  3219. }
  3220. $result = Database::query($sql);
  3221. $row = Database::fetch_array($result);
  3222. if ($row[0] == 0) {
  3223. $sql = "INSERT INTO $table_threads_qualify (c_id, user_id, thread_id,qualify,qualify_user_id,qualify_time,session_id)
  3224. VALUES (".$course_id.", '".$user_id."','".$thread_id."',".(float) $thread_qualify.", '".$currentUserId."','".$qualify_time."','".$session_id."')";
  3225. Database::query($sql);
  3226. $insertId = Database::insert_id();
  3227. if ($insertId) {
  3228. $sql = "UPDATE $table_threads_qualify SET id = iid
  3229. WHERE iid = $insertId";
  3230. Database::query($sql);
  3231. }
  3232. return 'insert';
  3233. } else {
  3234. saveThreadScoreHistory(
  3235. '1',
  3236. $course_id,
  3237. $user_id,
  3238. $thread_id
  3239. );
  3240. // Update
  3241. $sql = "UPDATE $table_threads_qualify
  3242. SET
  3243. qualify = '".$thread_qualify."',
  3244. qualify_time = '".$qualify_time."'
  3245. WHERE
  3246. c_id = $course_id AND
  3247. user_id=".$user_id." AND
  3248. thread_id=".$thread_id." AND
  3249. qualify_user_id = $currentUserId
  3250. ";
  3251. Database::query($sql);
  3252. return 'update';
  3253. }
  3254. } else {
  3255. return null;
  3256. }
  3257. }
  3258. }
  3259. /**
  3260. * This function shows qualify.
  3261. *
  3262. * @param string $option contains the information of option to run
  3263. * @param int $user_id contains the information the current user id
  3264. * @param int $thread_id contains the information the current thread id
  3265. *
  3266. * @return int qualify
  3267. * <code> $option=1 obtained the qualification of the current thread</code>
  3268. *
  3269. * @author Isaac Flores <isaac.flores@dokeos.com>, U.N.A.S University
  3270. *
  3271. * @version October 2008, dokeos 1.8.6
  3272. */
  3273. function showQualify($option, $user_id, $thread_id)
  3274. {
  3275. $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
  3276. $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
  3277. $course_id = api_get_course_int_id();
  3278. $user_id = (int) $user_id;
  3279. $thread_id = (int) $thread_id;
  3280. if (empty($user_id) || empty($thread_id)) {
  3281. return false;
  3282. }
  3283. $sql = '';
  3284. switch ($option) {
  3285. case 1:
  3286. $sql = "SELECT qualify FROM $table_threads_qualify
  3287. WHERE
  3288. c_id = $course_id AND
  3289. user_id=".$user_id." AND
  3290. thread_id=".$thread_id;
  3291. break;
  3292. case 2:
  3293. $sql = "SELECT thread_qualify_max FROM $table_threads
  3294. WHERE c_id = $course_id AND thread_id=".$thread_id;
  3295. break;
  3296. }
  3297. if (!empty($sql)) {
  3298. $rs = Database::query($sql);
  3299. $row = Database::fetch_array($rs);
  3300. return $row[0];
  3301. }
  3302. return [];
  3303. }
  3304. /**
  3305. * This function gets qualify historical.
  3306. *
  3307. * @param int $user_id contains the information the current user id
  3308. * @param int $thread_id contains the information the current thread id
  3309. * @param bool $opt contains the information of option to run
  3310. *
  3311. * @return array
  3312. *
  3313. * @author Christian Fasanando <christian.fasanando@dokeos.com>,
  3314. * @author Isaac Flores <isaac.flores@dokeos.com>,
  3315. *
  3316. * @version October 2008, dokeos 1.8.6
  3317. */
  3318. function getThreadScoreHistory($user_id, $thread_id, $opt)
  3319. {
  3320. $user_id = (int) $user_id;
  3321. $thread_id = (int) $thread_id;
  3322. $table_threads_qualify_log = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG);
  3323. $course_id = api_get_course_int_id();
  3324. if ($opt == 'false') {
  3325. $sql = "SELECT * FROM $table_threads_qualify_log
  3326. WHERE
  3327. c_id = $course_id AND
  3328. thread_id='".$thread_id."' AND
  3329. user_id='".$user_id."'
  3330. ORDER BY qualify_time";
  3331. } else {
  3332. $sql = "SELECT * FROM $table_threads_qualify_log
  3333. WHERE
  3334. c_id = $course_id AND
  3335. thread_id='".$thread_id."' AND
  3336. user_id='".$user_id."'
  3337. ORDER BY qualify_time DESC";
  3338. }
  3339. $rs = Database::query($sql);
  3340. $log = [];
  3341. while ($row = Database::fetch_array($rs, 'ASSOC')) {
  3342. $log[] = $row;
  3343. }
  3344. return $log;
  3345. }
  3346. /**
  3347. * This function stores qualify historical.
  3348. *
  3349. * @param bool contains the information of option to run
  3350. * @param string contains the information the current course id
  3351. * @param int contains the information the current forum id
  3352. * @param int contains the information the current user id
  3353. * @param int contains the information the current thread id
  3354. * @param int contains the information the current qualify
  3355. * @param string $option
  3356. * @param int $course_id
  3357. * @param int $user_id
  3358. * @param int $thread_id
  3359. *
  3360. * @author Isaac Flores <isaac.flores@dokeos.com>, U.N.A.S University
  3361. *
  3362. * @version October 2008, dokeos 1.8.6
  3363. */
  3364. function saveThreadScoreHistory(
  3365. $option,
  3366. $course_id,
  3367. $user_id,
  3368. $thread_id
  3369. ) {
  3370. $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
  3371. $table_threads_qualify_log = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG);
  3372. $course_id = intval($course_id);
  3373. $qualify_user_id = api_get_user_id();
  3374. if ($user_id == strval(intval($user_id)) &&
  3375. $thread_id == strval(intval($thread_id)) && $option == 1
  3376. ) {
  3377. // Extract information of thread_qualify.
  3378. $sql = "SELECT qualify, qualify_time
  3379. FROM $table_threads_qualify
  3380. WHERE
  3381. c_id = $course_id AND
  3382. user_id = ".$user_id." AND
  3383. thread_id = ".$thread_id." AND
  3384. qualify_user_id = $qualify_user_id
  3385. ";
  3386. $rs = Database::query($sql);
  3387. $row = Database::fetch_array($rs);
  3388. // Insert thread_historical.
  3389. $sql = "INSERT INTO $table_threads_qualify_log (c_id, user_id, thread_id, qualify, qualify_user_id,qualify_time,session_id)
  3390. VALUES(".$course_id.", '".$user_id."','".$thread_id."',".(float) $row[0].", '".$qualify_user_id."','".$row[1]."','')";
  3391. Database::query($sql);
  3392. $insertId = Database::insert_id();
  3393. if ($insertId) {
  3394. $sql = "UPDATE $table_threads_qualify_log SET id = iid
  3395. WHERE iid = $insertId";
  3396. Database::query($sql);
  3397. }
  3398. }
  3399. }
  3400. /**
  3401. * This function shows current thread qualify .
  3402. *
  3403. * @param int $threadId
  3404. * @param int $sessionId
  3405. * @param int $userId
  3406. *
  3407. * @return array or null if is empty
  3408. *
  3409. * @author Isaac Flores <isaac.flores@dokeos.com>, U.N.A.S University
  3410. *
  3411. * @version December 2008, dokeos 1.8.6
  3412. */
  3413. function current_qualify_of_thread($threadId, $sessionId, $userId)
  3414. {
  3415. $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY);
  3416. $course_id = api_get_course_int_id();
  3417. $currentUserId = api_get_user_id();
  3418. $sessionId = intval($sessionId);
  3419. $threadId = intval($threadId);
  3420. $sql = "SELECT qualify FROM $table_threads_qualify
  3421. WHERE
  3422. c_id = $course_id AND
  3423. thread_id = $threadId AND
  3424. session_id = $sessionId AND
  3425. qualify_user_id = $currentUserId AND
  3426. user_id = $userId
  3427. ";
  3428. $res = Database::query($sql);
  3429. $row = Database::fetch_array($res, 'ASSOC');
  3430. return $row['qualify'];
  3431. }
  3432. /**
  3433. * This function stores a reply in the forum_post table.
  3434. * It also updates the forum_threads table (thread_replies +1 , thread_last_post, thread_date).
  3435. *
  3436. * @param array $current_forum
  3437. * @param array $values
  3438. * @param int $courseId Optional
  3439. * @param int $userId Optional
  3440. *
  3441. * @return int post id
  3442. *
  3443. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  3444. *
  3445. * @version february 2006, dokeos 1.8
  3446. */
  3447. function store_reply($current_forum, $values, $courseId = 0, $userId = 0)
  3448. {
  3449. $courseId = !empty($courseId) ? $courseId : api_get_course_int_id();
  3450. $_course = api_get_course_info_by_id($courseId);
  3451. $table_posts = Database::get_course_table(TABLE_FORUM_POST);
  3452. $post_date = api_get_utc_datetime();
  3453. $userId = $userId ?: api_get_user_id();
  3454. if ($current_forum['allow_anonymous'] == 1) {
  3455. if (api_is_anonymous() && empty($userId)) {
  3456. $userId = api_get_anonymous_id();
  3457. }
  3458. }
  3459. if (empty($userId)) {
  3460. return false;
  3461. }
  3462. $visible = 1;
  3463. if ($current_forum['approval_direct_post'] == '1' &&
  3464. !api_is_allowed_to_edit(null, true)
  3465. ) {
  3466. $visible = 0;
  3467. }
  3468. $upload_ok = 1;
  3469. $new_post_id = 0;
  3470. if ($upload_ok) {
  3471. // We first store an entry in the forum_post table.
  3472. $new_post_id = Database::insert(
  3473. $table_posts,
  3474. [
  3475. 'c_id' => $courseId,
  3476. 'post_title' => $values['post_title'],
  3477. 'post_text' => isset($values['post_text']) ? ($values['post_text']) : null,
  3478. 'thread_id' => $values['thread_id'],
  3479. 'forum_id' => $values['forum_id'],
  3480. 'poster_id' => $userId,
  3481. 'post_id' => 0,
  3482. 'post_date' => $post_date,
  3483. 'post_notification' => isset($values['post_notification']) ? $values['post_notification'] : null,
  3484. 'post_parent_id' => isset($values['post_parent_id']) ? $values['post_parent_id'] : null,
  3485. 'visible' => $visible,
  3486. ]
  3487. );
  3488. if ($new_post_id) {
  3489. $sql = "UPDATE $table_posts SET post_id = iid WHERE iid = $new_post_id";
  3490. Database::query($sql);
  3491. $values['new_post_id'] = $new_post_id;
  3492. $message = get_lang('The reply has been added');
  3493. if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
  3494. foreach ($_POST['file_ids'] as $key => $id) {
  3495. editAttachedFile(
  3496. [
  3497. 'comment' => $_POST['file_comments'][$key],
  3498. 'post_id' => $new_post_id,
  3499. ],
  3500. $id
  3501. );
  3502. }
  3503. }
  3504. // Update the thread.
  3505. updateThreadInfo($values['thread_id'], $new_post_id, $post_date);
  3506. // Update the forum.
  3507. api_item_property_update(
  3508. $_course,
  3509. TOOL_FORUM,
  3510. $values['forum_id'],
  3511. 'NewMessageInForum',
  3512. $userId
  3513. );
  3514. // Insert post
  3515. api_item_property_update(
  3516. $_course,
  3517. TOOL_FORUM_POST,
  3518. $new_post_id,
  3519. 'NewPost',
  3520. $userId
  3521. );
  3522. if ($current_forum['approval_direct_post'] == '1' &&
  3523. !api_is_allowed_to_edit(null, true)
  3524. ) {
  3525. $message .= '<br />'.get_lang('Your message has to be approved before people can view it.').'<br />';
  3526. }
  3527. if ($current_forum['moderated'] &&
  3528. !api_is_allowed_to_edit(null, true)
  3529. ) {
  3530. $message .= '<br />'.get_lang('Your message has to be approved before people can view it.').'<br />';
  3531. }
  3532. // Setting the notification correctly.
  3533. $my_post_notification = isset($values['post_notification']) ? $values['post_notification'] : null;
  3534. if ($my_post_notification == 1) {
  3535. set_notification('thread', $values['thread_id'], true);
  3536. }
  3537. send_notification_mails(
  3538. $values['forum_id'],
  3539. $values['thread_id'],
  3540. $values
  3541. );
  3542. add_forum_attachment_file('', $new_post_id);
  3543. $logInfo = [
  3544. 'tool' => TOOL_FORUM,
  3545. 'tool_id' => $values['forum_id'],
  3546. 'tool_id_detail' => $values['thread_id'],
  3547. 'action' => 'new-post',
  3548. 'action_details' => $values['action'],
  3549. 'info' => $values['post_title'],
  3550. ];
  3551. Event::registerLog($logInfo);
  3552. }
  3553. Session::erase('formelements');
  3554. Session::erase('origin');
  3555. Session::erase('breadcrumbs');
  3556. Session::erase('addedresource');
  3557. Session::erase('addedresourceid');
  3558. Display::addFlash(Display::return_message($message, 'confirmation', false));
  3559. } else {
  3560. Display::addFlash(
  3561. Display::return_message(
  3562. get_lang('No file was uploaded.').' '.get_lang('Please select a file before pressing the upload button.'),
  3563. 'error'
  3564. )
  3565. );
  3566. }
  3567. return $new_post_id;
  3568. }
  3569. /**
  3570. * This function displays the form that is used to edit a post. This can be a new thread or a reply.
  3571. *
  3572. * @param array contains all the information about the current post
  3573. * @param array contains all the information about the current thread
  3574. * @param array contains all info about the current forum (to check if attachments are allowed)
  3575. * @param array contains the default values to fill the form
  3576. *
  3577. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  3578. *
  3579. * @version february 2006, dokeos 1.8
  3580. */
  3581. function show_edit_post_form(
  3582. $current_post,
  3583. $current_thread,
  3584. $current_forum,
  3585. $form_values = '',
  3586. $id_attach = 0
  3587. ) {
  3588. // Initialize the object.
  3589. $form = new FormValidator(
  3590. 'edit_post',
  3591. 'post',
  3592. api_get_self().'?'.api_get_cidreq().'&forum='.intval($_GET['forum']).'&thread='.intval($_GET['thread']).'&post='.intval($_GET['post'])
  3593. );
  3594. $form->addElement('header', get_lang('Edit a post'));
  3595. // Setting the form elements.
  3596. $form->addElement('hidden', 'post_id', $current_post['post_id']);
  3597. $form->addElement('hidden', 'thread_id', $current_thread['thread_id']);
  3598. $form->addElement('hidden', 'id_attach', $id_attach);
  3599. if (empty($current_post['post_parent_id'])) {
  3600. $form->addElement('hidden', 'is_first_post_of_thread', '1');
  3601. }
  3602. $form->addElement('text', 'post_title', get_lang('Title'));
  3603. $form->applyFilter('post_title', 'html_filter');
  3604. $form->addElement(
  3605. 'html_editor',
  3606. 'post_text',
  3607. get_lang('Text'),
  3608. null,
  3609. api_is_allowed_to_edit(null, true) ? [
  3610. 'ToolbarSet' => 'Forum',
  3611. 'Width' => '100%',
  3612. 'Height' => '400',
  3613. ] : [
  3614. 'ToolbarSet' => 'ForumStudent',
  3615. 'Width' => '100%',
  3616. 'Height' => '400',
  3617. 'UserStatus' => 'student',
  3618. ]
  3619. );
  3620. $form->addRule('post_text', get_lang('Required field'), 'required');
  3621. $extraFields = new ExtraField('forum_post');
  3622. $extraFields->addElements($form, $current_post['post_id']);
  3623. $form->addButtonAdvancedSettings('advanced_params');
  3624. $form->addElement('html', '<div id="advanced_params_options" style="display:none">');
  3625. if ($current_forum['moderated'] && api_is_allowed_to_edit(null, true)) {
  3626. $group = [];
  3627. $group[] = $form->createElement(
  3628. 'radio',
  3629. 'status',
  3630. null,
  3631. get_lang('Validated'),
  3632. 1
  3633. );
  3634. $group[] = $form->createElement(
  3635. 'radio',
  3636. 'status',
  3637. null,
  3638. get_lang('Waiting for moderation'),
  3639. 2
  3640. );
  3641. $group[] = $form->createElement(
  3642. 'radio',
  3643. 'status',
  3644. null,
  3645. get_lang('Rejected'),
  3646. 3
  3647. );
  3648. $form->addGroup($group, 'status', get_lang('Status'));
  3649. }
  3650. $defaults['status']['status'] = isset($current_post['status']) && !empty($current_post['status']) ? $current_post['status'] : 2;
  3651. $form->addElement(
  3652. 'checkbox',
  3653. 'post_notification',
  3654. '',
  3655. get_lang('Notify me by e-mail when somebody replies').' ('.$current_post['email'].')'
  3656. );
  3657. if (api_is_allowed_to_edit(null, true) &&
  3658. empty($current_post['post_parent_id'])
  3659. ) {
  3660. // The sticky checkbox only appears when it is the first post of a thread.
  3661. $form->addElement('checkbox', 'thread_sticky', '', get_lang('This is a sticky message (appears always on top and has a special sticky icon)'));
  3662. if ($current_thread['thread_sticky'] == 1) {
  3663. $defaults['thread_sticky'] = true;
  3664. }
  3665. }
  3666. $form->addElement('html', '</div>');
  3667. $form->addFile('user_upload[]', get_lang('Attachment'));
  3668. $form->addButton(
  3669. 'add_attachment',
  3670. get_lang('Add attachment'),
  3671. 'paperclip',
  3672. 'default',
  3673. 'default',
  3674. null,
  3675. ['id' => 'reply-add-attachment']
  3676. );
  3677. $form->addButtonUpdate(get_lang('Edit'), 'SubmitPost');
  3678. // Setting the default values for the form elements.
  3679. $defaults['post_title'] = $current_post['post_title'];
  3680. $defaults['post_text'] = $current_post['post_text'];
  3681. if ($current_post['post_notification'] == 1) {
  3682. $defaults['post_notification'] = true;
  3683. }
  3684. if (!empty($form_values)) {
  3685. $defaults['post_notification'] = Security::remove_XSS($form_values['post_notification']);
  3686. $defaults['thread_sticky'] = Security::remove_XSS($form_values['thread_sticky']);
  3687. }
  3688. $form->setDefaults($defaults);
  3689. // The course admin can make a thread sticky (=appears with special icon and always on top).
  3690. $form->addRule('post_title', get_lang('Required field'), 'required');
  3691. // Validation or display
  3692. if ($form->validate()) {
  3693. $values = $form->exportValues();
  3694. $values['item_id'] = $current_post['post_id'];
  3695. $extraFieldValues = new ExtraFieldValue('forum_post');
  3696. $extraFieldValues->saveFieldValues($values);
  3697. store_edit_post($current_forum, $values);
  3698. } else {
  3699. // Delete from $_SESSION forum attachment from other posts
  3700. clearAttachedFiles($current_post['post_id']);
  3701. // Get forum attachment ajax table to add it to form
  3702. $fileData = getAttachmentsAjaxTable($current_post['post_id'], $current_forum['forum_id']);
  3703. $form->addElement('html', $fileData);
  3704. $form->display();
  3705. }
  3706. }
  3707. /**
  3708. * This function stores the edit of a post in the forum_post table.
  3709. *
  3710. * @param array
  3711. *
  3712. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  3713. *
  3714. * @version february 2006, dokeos 1.8
  3715. */
  3716. function store_edit_post($forumInfo, $values)
  3717. {
  3718. $logInfo = [
  3719. 'tool' => TOOL_FORUM,
  3720. 'tool_id' => $_GET['forum'],
  3721. 'tool_id_detail' => $values['thread_id'],
  3722. 'action' => 'edit-post',
  3723. 'action_details' => 'post',
  3724. 'info' => $values['post_title'],
  3725. ];
  3726. Event::registerLog($logInfo);
  3727. $threadTable = Database::get_course_table(TABLE_FORUM_THREAD);
  3728. $table_posts = Database::get_course_table(TABLE_FORUM_POST);
  3729. $course_id = api_get_course_int_id();
  3730. //check if this post is the first of the thread
  3731. // First we check if the change affects the thread and if so we commit
  3732. // the changes (sticky and post_title=thread_title are relevant).
  3733. $posts = getPosts($forumInfo, $values['thread_id']);
  3734. $first_post = null;
  3735. if (!empty($posts) && count($posts) > 0 && isset($posts[0])) {
  3736. $first_post = $posts[0];
  3737. }
  3738. if (!empty($first_post) && $first_post['post_id'] == $values['post_id']) {
  3739. // Simple edit
  3740. $params = [
  3741. 'thread_title' => $values['post_title'],
  3742. 'thread_sticky' => isset($values['thread_sticky']) ? $values['thread_sticky'] : 0,
  3743. ];
  3744. $where = ['c_id = ? AND thread_id = ?' => [$course_id, $values['thread_id']]];
  3745. Database::update($threadTable, $params, $where);
  3746. }
  3747. $status = '';
  3748. $updateStatus = false;
  3749. if ($forumInfo['moderated']) {
  3750. if (api_is_allowed_to_edit(null, true)) {
  3751. $status = $values['status']['status'];
  3752. $updateStatus = true;
  3753. } else {
  3754. $status = CForumPost::STATUS_WAITING_MODERATION;
  3755. $updateStatus = true;
  3756. }
  3757. }
  3758. // Update the post_title and the post_text.
  3759. $params = [
  3760. 'post_title' => $values['post_title'],
  3761. 'post_text' => $values['post_text'],
  3762. 'post_notification' => isset($values['post_notification']) ? $values['post_notification'] : '',
  3763. ];
  3764. if ($updateStatus) {
  3765. $params['status'] = $status;
  3766. }
  3767. $where = ['c_id = ? AND post_id = ?' => [$course_id, $values['post_id']]];
  3768. Database::update($table_posts, $params, $where);
  3769. // Update attached files
  3770. if (!empty($_POST['file_ids']) && is_array($_POST['file_ids'])) {
  3771. foreach ($_POST['file_ids'] as $key => $id) {
  3772. editAttachedFile(
  3773. [
  3774. 'comment' => $_POST['file_comments'][$key],
  3775. 'post_id' => $values['post_id'],
  3776. ],
  3777. $id
  3778. );
  3779. }
  3780. }
  3781. if (!empty($values['remove_attach'])) {
  3782. delete_attachment($values['post_id']);
  3783. }
  3784. if (empty($values['id_attach'])) {
  3785. add_forum_attachment_file(
  3786. isset($values['file_comment']) ? $values['file_comment'] : null,
  3787. $values['post_id']
  3788. );
  3789. } else {
  3790. edit_forum_attachment_file(
  3791. isset($values['file_comment']) ? $values['file_comment'] : null,
  3792. $values['post_id'],
  3793. $values['id_attach']
  3794. );
  3795. }
  3796. $message = get_lang('The post has been modified').'<br />';
  3797. $message .= get_lang('You can now return to the').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.intval($_GET['forum']).'&">'.get_lang('Forum').'</a><br />';
  3798. $message .= get_lang('You can now return to the').' <a href="viewthread.php?'.api_get_cidreq().'&forum='.intval($_GET['forum']).'&thread='.$values['thread_id'].'&post='.Security::remove_XSS($_GET['post']).'">'.get_lang('Message').'</a>';
  3799. Session::erase('formelements');
  3800. Session::erase('origin');
  3801. Session::erase('breadcrumbs');
  3802. Session::erase('addedresource');
  3803. Session::erase('addedresourceid');
  3804. echo Display::return_message($message, 'confirmation', false);
  3805. }
  3806. /**
  3807. * This function displays the firstname and lastname of the user as a link to the user tool.
  3808. *
  3809. * @param string names
  3810. * @ in_title : title tootip
  3811. *
  3812. * @return string HTML
  3813. *
  3814. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  3815. *
  3816. * @version february 2006, dokeos 1.8
  3817. */
  3818. function display_user_link($user_id, $name, $origin = '', $in_title = '')
  3819. {
  3820. if ($user_id != 0) {
  3821. $userInfo = api_get_user_info($user_id);
  3822. return '<a href="'.$userInfo['profile_url'].'">'.Security::remove_XSS($userInfo['complete_name']).'</a>';
  3823. } else {
  3824. return $name.' ('.get_lang('Anonymous').')';
  3825. }
  3826. }
  3827. /**
  3828. * This function displays the user image from the profile, with a link to the user's details.
  3829. *
  3830. * @param int User's database ID
  3831. * @param string User's name
  3832. * @param string the origin where the forum is called (example : learnpath)
  3833. *
  3834. * @return string An HTML with the anchor and the image of the user
  3835. *
  3836. * @author Julio Montoya <gugli100@gmail.com>
  3837. */
  3838. function display_user_image($user_id, $name, $origin = '')
  3839. {
  3840. $userInfo = api_get_user_info($user_id);
  3841. $link = '<a href="'.(!empty($origin) ? '#' : $userInfo['profile_url']).'" '.(!empty($origin) ? 'target="_self"' : '').'>';
  3842. if ($user_id != 0) {
  3843. return $link.'<img src="'.$userInfo['avatar'].'" alt="'.$name.'" title="'.$name.'" /></a>';
  3844. } else {
  3845. return $link.Display::return_icon('unknown.jpg', $name).'</a>';
  3846. }
  3847. }
  3848. /**
  3849. * The thread view counter gets increased every time someone looks at the thread.
  3850. *
  3851. * @param int
  3852. *
  3853. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  3854. *
  3855. * @version february 2006, dokeos 1.8
  3856. */
  3857. function increase_thread_view($thread_id)
  3858. {
  3859. $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
  3860. $course_id = api_get_course_int_id();
  3861. $sql = "UPDATE $table_threads
  3862. SET thread_views = thread_views + 1
  3863. WHERE
  3864. c_id = $course_id AND
  3865. thread_id = '".intval($thread_id)."'";
  3866. Database::query($sql);
  3867. }
  3868. /**
  3869. * The relies counter gets increased every time somebody replies to the thread.
  3870. *
  3871. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  3872. *
  3873. * @version february 2006, dokeos 1.8
  3874. *
  3875. * @param int $threadId
  3876. * @param string $lastPostId
  3877. * @param string $post_date
  3878. */
  3879. function updateThreadInfo($threadId, $lastPostId, $post_date)
  3880. {
  3881. $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
  3882. $course_id = api_get_course_int_id();
  3883. $sql = "UPDATE $table_threads SET
  3884. thread_replies = thread_replies+1,
  3885. thread_last_post = '".Database::escape_string($lastPostId)."',
  3886. thread_date = '".Database::escape_string($post_date)."'
  3887. WHERE
  3888. c_id = $course_id AND
  3889. thread_id='".Database::escape_string($threadId)."'"; // this needs to be cleaned first
  3890. Database::query($sql);
  3891. }
  3892. /**
  3893. * This function is used to find all the information about what's new in the forum tool.
  3894. *
  3895. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  3896. *
  3897. * @version february 2006, dokeos 1.8
  3898. */
  3899. function get_whats_new()
  3900. {
  3901. $userId = api_get_user_id();
  3902. $course_id = api_get_course_int_id();
  3903. if (empty($course_id) || empty($userId)) {
  3904. return false;
  3905. }
  3906. $table_posts = Database::get_course_table(TABLE_FORUM_POST);
  3907. $tracking_last_tool_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
  3908. $tool = TOOL_FORUM;
  3909. $lastForumAccess = Session::read('last_forum_access');
  3910. if (!$lastForumAccess) {
  3911. $sql = "SELECT * FROM $tracking_last_tool_access
  3912. WHERE
  3913. access_user_id = $userId AND
  3914. c_id = $course_id AND
  3915. access_tool = '".Database::escape_string($tool)."'";
  3916. $result = Database::query($sql);
  3917. $row = Database::fetch_array($result);
  3918. Session::write('last_forum_access', $row['access_date']);
  3919. $lastForumAccess = $row['access_date'];
  3920. }
  3921. $whatsNew = Session::read('whatsnew_post_info');
  3922. if (!$whatsNew) {
  3923. if ($lastForumAccess != '') {
  3924. $postInfo = [];
  3925. $sql = "SELECT * FROM $table_posts
  3926. WHERE
  3927. c_id = $course_id AND
  3928. visible = 1 AND
  3929. post_date > '".Database::escape_string($lastForumAccess)."'";
  3930. $result = Database::query($sql);
  3931. while ($row = Database::fetch_array($result)) {
  3932. $postInfo[$row['forum_id']][$row['thread_id']][$row['post_id']] = $row['post_date'];
  3933. }
  3934. Session::write('whatsnew_post_info', $postInfo);
  3935. }
  3936. }
  3937. }
  3938. /**
  3939. * This function approves a post = change.
  3940. *
  3941. * @param int $post_id the id of the post that will be deleted
  3942. * @param string $action make the post visible or invisible
  3943. *
  3944. * @return string language variable
  3945. *
  3946. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  3947. *
  3948. * @version february 2006, dokeos 1.8
  3949. */
  3950. function approve_post($post_id, $action)
  3951. {
  3952. $table_posts = Database::get_course_table(TABLE_FORUM_POST);
  3953. $course_id = api_get_course_int_id();
  3954. if ($action == 'invisible') {
  3955. $visibility_value = 0;
  3956. }
  3957. if ($action == 'visible') {
  3958. $visibility_value = 1;
  3959. handle_mail_cue('post', $post_id);
  3960. }
  3961. $sql = "UPDATE $table_posts SET
  3962. visible='".Database::escape_string($visibility_value)."'
  3963. WHERE c_id = $course_id AND post_id='".Database::escape_string($post_id)."'";
  3964. $return = Database::query($sql);
  3965. if ($return) {
  3966. return 'PostThe visibility has been changed.';
  3967. }
  3968. }
  3969. /**
  3970. * This function retrieves all the unapproved messages for a given forum
  3971. * This is needed to display the icon that there are unapproved messages in that thread (only the courseadmin can see this).
  3972. *
  3973. * @param $forum_id the forum where we want to know the unapproved messages of
  3974. *
  3975. * @return array returns
  3976. *
  3977. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  3978. *
  3979. * @version february 2006, dokeos 1.8
  3980. */
  3981. function get_unaproved_messages($forum_id)
  3982. {
  3983. $table_posts = Database::get_course_table(TABLE_FORUM_POST);
  3984. $course_id = api_get_course_int_id();
  3985. $return_array = [];
  3986. $sql = "SELECT DISTINCT thread_id FROM $table_posts
  3987. WHERE
  3988. c_id = $course_id AND
  3989. forum_id='".Database::escape_string($forum_id)."' AND
  3990. visible='0' ";
  3991. $result = Database::query($sql);
  3992. while ($row = Database::fetch_array($result)) {
  3993. $return_array[] = $row['thread_id'];
  3994. }
  3995. return $return_array;
  3996. }
  3997. /**
  3998. * This function sends the notification mails to everybody who stated that they wanted to be informed when a new post
  3999. * was added to a given thread.
  4000. *
  4001. * @param array reply information
  4002. *
  4003. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  4004. *
  4005. * @version february 2006, dokeos 1.8
  4006. */
  4007. function send_notification_mails($forumId, $thread_id, $reply_info)
  4008. {
  4009. $table = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
  4010. // First we need to check if
  4011. // 1. the forum category is visible
  4012. // 2. the forum is visible
  4013. // 3. the thread is visible
  4014. // 4. the reply is visible (=when there is)
  4015. $current_thread = get_thread_information($forumId, $thread_id);
  4016. $current_forum = get_forum_information($current_thread['forum_id'], $current_thread['c_id']);
  4017. $current_forum_category = null;
  4018. if (isset($current_forum['forum_category'])) {
  4019. $current_forum_category = get_forumcategory_information($current_forum['forum_category']);
  4020. }
  4021. $send_mails = false;
  4022. if ($current_thread['visibility'] == '1' &&
  4023. $current_forum['visibility'] == '1' &&
  4024. ($current_forum_category && $current_forum_category['visibility'] == '1') &&
  4025. $current_forum['approval_direct_post'] != '1'
  4026. ) {
  4027. $send_mails = true;
  4028. }
  4029. // The forum category, the forum, the thread and the reply are visible to the user
  4030. if ($send_mails && !empty($forumId)) {
  4031. $postId = isset($reply_info['new_post_id']) ? $reply_info['new_post_id'] : 0;
  4032. send_notifications($forumId, $thread_id, $postId);
  4033. } else {
  4034. $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
  4035. if (isset($current_forum['forum_id'])) {
  4036. $sql = "SELECT * FROM $table_notification
  4037. WHERE
  4038. c_id = ".api_get_course_int_id()." AND
  4039. (
  4040. forum_id = '".intval($current_forum['forum_id'])."' OR
  4041. thread_id = '".intval($thread_id)."'
  4042. ) ";
  4043. $result = Database::query($sql);
  4044. $user_id = api_get_user_id();
  4045. while ($row = Database::fetch_array($result)) {
  4046. $sql = "INSERT INTO $table (c_id, thread_id, post_id, user_id)
  4047. VALUES (".api_get_course_int_id().", '".intval($thread_id)."', '".intval($reply_info['new_post_id'])."', '$user_id' )";
  4048. Database::query($sql);
  4049. }
  4050. }
  4051. }
  4052. }
  4053. /**
  4054. * This function is called whenever something is made visible because there might
  4055. * be new posts and the user might have indicated that (s)he wanted to be
  4056. * informed about the new posts by mail.
  4057. *
  4058. * @param string $content Content type (post, thread, forum, forum_category)
  4059. * @param int $id Item DB ID of the corresponding content type
  4060. *
  4061. * @return string language variable
  4062. *
  4063. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  4064. *
  4065. * @version february 2006, dokeos 1.8
  4066. */
  4067. function handle_mail_cue($content, $id)
  4068. {
  4069. $table_mailcue = Database::get_course_table(TABLE_FORUM_MAIL_QUEUE);
  4070. $table_forums = Database::get_course_table(TABLE_FORUM);
  4071. $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
  4072. $table_posts = Database::get_course_table(TABLE_FORUM_POST);
  4073. $table_users = Database::get_main_table(TABLE_MAIN_USER);
  4074. $course_id = api_get_course_int_id();
  4075. $id = (int) $id;
  4076. /* If the post is made visible we only have to send mails to the people
  4077. who indicated that they wanted to be informed for that thread.*/
  4078. if ($content == 'post') {
  4079. // Getting the information about the post (need the thread_id).
  4080. $post_info = get_post_information($id);
  4081. $thread_id = (int) $post_info['thread_id'];
  4082. // Sending the mail to all the users that wanted to be informed for replies on this thread.
  4083. $sql = "SELECT users.firstname, users.lastname, users.user_id, users.email
  4084. FROM $table_mailcue mailcue, $table_posts posts, $table_users users
  4085. WHERE
  4086. posts.c_id = $course_id AND
  4087. mailcue.c_id = $course_id AND
  4088. posts.thread_id = $thread_id AND
  4089. posts.post_notification = '1' AND
  4090. mailcue.thread_id = $thread_id AND
  4091. users.user_id = posts.poster_id AND
  4092. users.active = 1
  4093. GROUP BY users.email";
  4094. $result = Database::query($sql);
  4095. while ($row = Database::fetch_array($result)) {
  4096. $forumInfo = get_forum_information($post_info['forum_id']);
  4097. send_mail($row, $forumInfo, get_thread_information($post_info['forum_id'], $post_info['thread_id']), $post_info);
  4098. }
  4099. } elseif ($content == 'thread') {
  4100. // Sending the mail to all the users that wanted to be informed for replies on this thread.
  4101. $sql = "SELECT users.firstname, users.lastname, users.user_id, users.email, posts.forum_id
  4102. FROM $table_mailcue mailcue, $table_posts posts, $table_users users
  4103. WHERE
  4104. posts.c_id = $course_id AND
  4105. mailcue.c_id = $course_id AND
  4106. posts.thread_id = $id AND
  4107. posts.post_notification = '1' AND
  4108. mailcue.thread_id = $id AND
  4109. users.user_id = posts.poster_id AND
  4110. users.active = 1
  4111. GROUP BY users.email";
  4112. $result = Database::query($sql);
  4113. while ($row = Database::fetch_array($result)) {
  4114. $forumInfo = get_forum_information($row['forum_id']);
  4115. send_mail($row, $forumInfo, get_thread_information($row['forum_id'], $id));
  4116. }
  4117. // Deleting the relevant entries from the mailcue.
  4118. $sql = "DELETE FROM $table_mailcue
  4119. WHERE c_id = $course_id AND thread_id = $id";
  4120. Database::query($sql);
  4121. } elseif ($content == 'forum') {
  4122. $sql = "SELECT thread_id FROM $table_threads
  4123. WHERE c_id = $course_id AND forum_id = $id";
  4124. $result = Database::query($sql);
  4125. while ($row = Database::fetch_array($result)) {
  4126. handle_mail_cue('thread', $row['thread_id']);
  4127. }
  4128. } elseif ($content == 'forum_category') {
  4129. $sql = "SELECT forum_id FROM $table_forums
  4130. WHERE c_id = $course_id AND forum_category = $id";
  4131. $result = Database::query($sql);
  4132. while ($row = Database::fetch_array($result)) {
  4133. handle_mail_cue('forum', $row['forum_id']);
  4134. }
  4135. } else {
  4136. return get_lang('Error');
  4137. }
  4138. }
  4139. /**
  4140. * This function sends the mails for the mail notification.
  4141. *
  4142. * @param array
  4143. * @param array
  4144. * @param array
  4145. * @param array
  4146. *
  4147. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  4148. *
  4149. * @version february 2006, dokeos 1.8
  4150. */
  4151. function send_mail($userInfo, $forumInfo, $thread_information, $postInfo = [])
  4152. {
  4153. if (empty($userInfo) || empty($forumInfo) || empty($thread_information)) {
  4154. return false;
  4155. }
  4156. $_course = api_get_course_info();
  4157. $user_id = api_get_user_id();
  4158. $thread_link = '';
  4159. if (isset($thread_information) && is_array($thread_information)) {
  4160. $thread_link = api_get_path(WEB_CODE_PATH).
  4161. 'forum/viewthread.php?'.api_get_cidreq().'&forum='.$thread_information['forum_id'].'&thread='.$thread_information['thread_id'];
  4162. }
  4163. $email_body = get_lang('Dear').' '.api_get_person_name($userInfo['firstname'], $userInfo['lastname'], null, PERSON_NAME_EMAIL_ADDRESS).", <br />\n\r";
  4164. $email_body .= get_lang('New Post in the forum').': '.$forumInfo['forum_title'].' - '.$thread_information['thread_title']." <br />\n";
  4165. $courseId = api_get_configuration_value('global_forums_course_id');
  4166. $subject = get_lang('New Post in the forum').' - '.$_course['official_code'].': '.$forumInfo['forum_title'].' - '.$thread_information['thread_title']." <br />\n";
  4167. $courseInfoTitle = get_lang('Course').': '.$_course['name'].' - ['.$_course['official_code']."] - <br />\n";
  4168. if (!empty($courseId) && $_course['real_id'] == $courseId) {
  4169. $subject = get_lang('New Post in the forum').': '.$forumInfo['forum_title'].' - '.$thread_information['thread_title']." <br />\n";
  4170. $courseInfoTitle = " <br />\n";
  4171. }
  4172. $email_body .= $courseInfoTitle;
  4173. if (!empty($postInfo) && isset($postInfo['post_text'])) {
  4174. $text = cut(strip_tags($postInfo['post_text']), 100);
  4175. if (!empty($text)) {
  4176. $email_body .= get_lang('Message').": <br />\n ";
  4177. $email_body .= $text;
  4178. $email_body .= "<br /><br />\n";
  4179. }
  4180. }
  4181. $email_body .= get_lang('You stated that you wanted to be informed by e-mail whenever somebody replies on the thread')."<br />\n";
  4182. if (!empty($thread_link)) {
  4183. $email_body .= get_lang('The thread can be found here')." : <br /><a href=\"".$thread_link."\">".$thread_link."</a>\n";
  4184. }
  4185. if ($userInfo['user_id'] != $user_id) {
  4186. MessageManager::send_message(
  4187. $userInfo['user_id'],
  4188. $subject,
  4189. $email_body,
  4190. [],
  4191. [],
  4192. null,
  4193. null,
  4194. null,
  4195. null,
  4196. $user_id
  4197. );
  4198. }
  4199. }
  4200. /**
  4201. * This function displays the form for moving a thread to a different (already existing) forum.
  4202. *
  4203. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  4204. *
  4205. * @version february 2006, dokeos 1.8
  4206. */
  4207. function move_thread_form()
  4208. {
  4209. $form = new FormValidator(
  4210. 'movepost',
  4211. 'post',
  4212. api_get_self().'?forum='.intval($_GET['forum']).'&thread='.intval($_GET['thread']).'&action='.Security::remove_XSS($_GET['action']).'&'.api_get_cidreq()
  4213. );
  4214. // The header for the form
  4215. $form->addElement('header', get_lang('Move Thread'));
  4216. // Invisible form: the thread_id
  4217. $form->addElement('hidden', 'thread_id', intval($_GET['thread']));
  4218. // the fora
  4219. $forum_categories = get_forum_categories();
  4220. $forums = get_forums();
  4221. $htmlcontent = '<div class="row">
  4222. <div class="label">
  4223. <span class="form_required">*</span>'.get_lang('Move to').'
  4224. </div>
  4225. <div class="formw">';
  4226. $htmlcontent .= '<select name="forum">';
  4227. foreach ($forum_categories as $key => $category) {
  4228. $htmlcontent .= '<optgroup label="'.$category['cat_title'].'">';
  4229. foreach ($forums as $key => $forum) {
  4230. if (isset($forum['forum_category'])) {
  4231. if ($forum['forum_category'] == $category['cat_id']) {
  4232. $htmlcontent .= '<option value="'.$forum['forum_id'].'">'.$forum['forum_title'].'</option>';
  4233. }
  4234. }
  4235. }
  4236. $htmlcontent .= '</optgroup>';
  4237. }
  4238. $htmlcontent .= "</select>";
  4239. $htmlcontent .= ' </div>
  4240. </div>';
  4241. $form->addElement('html', $htmlcontent);
  4242. // The OK button
  4243. $form->addButtonSave(get_lang('Move Thread'), 'SubmitForum');
  4244. // Validation or display
  4245. if ($form->validate()) {
  4246. $values = $form->exportValues();
  4247. if (isset($_POST['forum'])) {
  4248. store_move_thread($values);
  4249. }
  4250. } else {
  4251. $form->display();
  4252. }
  4253. }
  4254. /**
  4255. * This function displays the form for moving a post message to a different (already existing) or a new thread.
  4256. *
  4257. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  4258. *
  4259. * @version february 2006, dokeos 1.8
  4260. */
  4261. function move_post_form()
  4262. {
  4263. $form = new FormValidator(
  4264. 'movepost',
  4265. 'post',
  4266. api_get_self().'?'.api_get_cidreq().'&forum='.intval($_GET['forum']).'&thread='.intval($_GET['thread']).'&post='.Security::remove_XSS($_GET['post']).'&action='.Security::remove_XSS($_GET['action']).'&post='.Security::remove_XSS($_GET['post'])
  4267. );
  4268. // The header for the form
  4269. $form->addElement('header', '', get_lang('Move post'));
  4270. // Invisible form: the post_id
  4271. $form->addElement('hidden', 'post_id', intval($_GET['post']));
  4272. // Dropdown list: Threads of this forum
  4273. $threads = get_threads($_GET['forum']);
  4274. //my_print_r($threads);
  4275. $threads_list[0] = get_lang('A new thread');
  4276. foreach ($threads as $key => $value) {
  4277. $threads_list[$value['thread_id']] = $value['thread_title'];
  4278. }
  4279. $form->addElement('select', 'thread', get_lang('Move toThread'), $threads_list);
  4280. $form->applyFilter('thread', 'html_filter');
  4281. // The OK button
  4282. $form->addButtonSave(get_lang('Move post'), 'submit');
  4283. // Setting the rules
  4284. $form->addRule('thread', get_lang('Required field'), 'required');
  4285. // Validation or display
  4286. if ($form->validate()) {
  4287. $values = $form->exportValues();
  4288. store_move_post($values);
  4289. } else {
  4290. $form->display();
  4291. }
  4292. }
  4293. /**
  4294. * @param array
  4295. *
  4296. * @return string HTML language variable
  4297. *
  4298. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  4299. *
  4300. * @version february 2006, dokeos 1.8
  4301. */
  4302. function store_move_post($values)
  4303. {
  4304. $_course = api_get_course_info();
  4305. $course_id = api_get_course_int_id();
  4306. $table_forums = Database::get_course_table(TABLE_FORUM);
  4307. $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
  4308. $table_posts = Database::get_course_table(TABLE_FORUM_POST);
  4309. if ($values['thread'] == '0') {
  4310. $current_post = get_post_information($values['post_id']);
  4311. // Storing a new thread.
  4312. $params = [
  4313. 'c_id' => $course_id,
  4314. 'thread_title' => $current_post['post_title'],
  4315. 'forum_id' => $current_post['forum_id'],
  4316. 'thread_poster_id' => $current_post['poster_id'],
  4317. 'thread_poster_name' => $current_post['poster_name'],
  4318. 'thread_last_post' => $values['post_id'],
  4319. 'thread_date' => $current_post['post_date'],
  4320. ];
  4321. $new_thread_id = Database::insert($table_threads, $params);
  4322. api_item_property_update(
  4323. $_course,
  4324. TOOL_FORUM_THREAD,
  4325. $new_thread_id,
  4326. 'visible',
  4327. $current_post['poster_id']
  4328. );
  4329. // Moving the post to the newly created thread.
  4330. $sql = "UPDATE $table_posts SET thread_id='".intval($new_thread_id)."', post_parent_id = NULL
  4331. WHERE c_id = $course_id AND post_id='".intval($values['post_id'])."'";
  4332. Database::query($sql);
  4333. // Resetting the parent_id of the thread to 0 for all those who had this moved post as parent.
  4334. $sql = "UPDATE $table_posts SET post_parent_id = NULL
  4335. WHERE c_id = $course_id AND post_parent_id='".intval($values['post_id'])."'";
  4336. Database::query($sql);
  4337. // Updating updating the number of threads in the forum.
  4338. $sql = "UPDATE $table_forums SET forum_threads=forum_threads+1
  4339. WHERE c_id = $course_id AND forum_id='".intval($current_post['forum_id'])."'";
  4340. Database::query($sql);
  4341. // Resetting the last post of the old thread and decreasing the number of replies and the thread.
  4342. $sql = "SELECT * FROM $table_posts
  4343. WHERE c_id = $course_id AND thread_id='".intval($current_post['thread_id'])."'
  4344. ORDER BY post_id DESC";
  4345. $result = Database::query($sql);
  4346. $row = Database::fetch_array($result);
  4347. $sql = "UPDATE $table_threads SET
  4348. thread_last_post='".$row['post_id']."',
  4349. thread_replies=thread_replies-1
  4350. WHERE
  4351. c_id = $course_id AND
  4352. thread_id='".intval($current_post['thread_id'])."'";
  4353. Database::query($sql);
  4354. } else {
  4355. // Moving to the chosen thread.
  4356. $sql = "SELECT thread_id FROM ".$table_posts."
  4357. WHERE c_id = $course_id AND post_id = '".$values['post_id']."' ";
  4358. $result = Database::query($sql);
  4359. $row = Database::fetch_array($result);
  4360. $original_thread_id = $row['thread_id'];
  4361. $sql = "SELECT thread_last_post FROM ".$table_threads."
  4362. WHERE c_id = $course_id AND thread_id = '".$original_thread_id."' ";
  4363. $result = Database::query($sql);
  4364. $row = Database::fetch_array($result);
  4365. $thread_is_last_post = $row['thread_last_post'];
  4366. // If is this thread, update the thread_last_post with the last one.
  4367. if ($thread_is_last_post == $values['post_id']) {
  4368. $sql = "SELECT post_id FROM ".$table_posts."
  4369. WHERE c_id = $course_id AND thread_id = '".$original_thread_id."' AND post_id <> '".$values['post_id']."'
  4370. ORDER BY post_date DESC LIMIT 1";
  4371. $result = Database::query($sql);
  4372. $row = Database::fetch_array($result);
  4373. $thread_new_last_post = $row['post_id'];
  4374. $sql = "UPDATE ".$table_threads." SET thread_last_post = '".$thread_new_last_post."'
  4375. WHERE c_id = $course_id AND thread_id = '".$original_thread_id."' ";
  4376. Database::query($sql);
  4377. }
  4378. $sql = "UPDATE $table_threads SET thread_replies=thread_replies-1
  4379. WHERE c_id = $course_id AND thread_id='".$original_thread_id."'";
  4380. Database::query($sql);
  4381. // moving to the chosen thread
  4382. $sql = "UPDATE $table_posts SET thread_id='".intval($_POST['thread'])."', post_parent_id = NULL
  4383. WHERE c_id = $course_id AND post_id='".intval($values['post_id'])."'";
  4384. Database::query($sql);
  4385. // resetting the parent_id of the thread to 0 for all those who had this moved post as parent
  4386. $sql = "UPDATE $table_posts SET post_parent_id = NULL
  4387. WHERE c_id = $course_id AND post_parent_id='".intval($values['post_id'])."'";
  4388. Database::query($sql);
  4389. $sql = "UPDATE $table_threads SET thread_replies=thread_replies+1
  4390. WHERE c_id = $course_id AND thread_id='".intval($_POST['thread'])."'";
  4391. Database::query($sql);
  4392. }
  4393. return get_lang('Thread moved');
  4394. }
  4395. /**
  4396. * @param array
  4397. *
  4398. * @return string HTML language variable
  4399. *
  4400. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  4401. *
  4402. * @version february 2006, dokeos 1.8
  4403. */
  4404. function store_move_thread($values)
  4405. {
  4406. $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
  4407. $table_posts = Database::get_course_table(TABLE_FORUM_POST);
  4408. $courseId = api_get_course_int_id();
  4409. $sessionId = api_get_session_id();
  4410. $forumId = intval($_POST['forum']);
  4411. $threadId = intval($_POST['thread_id']);
  4412. $forumInfo = get_forums($forumId);
  4413. // Change the thread table: Setting the forum_id to the new forum.
  4414. $sql = "UPDATE $table_threads SET forum_id = $forumId
  4415. WHERE c_id = $courseId AND thread_id = $threadId";
  4416. Database::query($sql);
  4417. // Changing all the posts of the thread: setting the forum_id to the new forum.
  4418. $sql = "UPDATE $table_posts SET forum_id = $forumId
  4419. WHERE c_id = $courseId AND thread_id= $threadId";
  4420. Database::query($sql);
  4421. // Fix group id, if forum is moved to a different group
  4422. if (!empty($forumInfo['to_group_id'])) {
  4423. $groupId = $forumInfo['to_group_id'];
  4424. $item = api_get_item_property_info(
  4425. $courseId,
  4426. TABLE_FORUM_THREAD,
  4427. $threadId,
  4428. $sessionId,
  4429. $groupId
  4430. );
  4431. $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
  4432. $sessionCondition = api_get_session_condition($sessionId);
  4433. if (!empty($item)) {
  4434. if ($item['to_group_id'] != $groupId) {
  4435. $sql = "UPDATE $table
  4436. SET to_group_id = $groupId
  4437. WHERE
  4438. tool = '".TABLE_FORUM_THREAD."' AND
  4439. c_id = $courseId AND
  4440. ref = ".$item['ref']."
  4441. $sessionCondition
  4442. ";
  4443. Database::query($sql);
  4444. }
  4445. } else {
  4446. $sql = "UPDATE $table
  4447. SET to_group_id = $groupId
  4448. WHERE
  4449. tool = '".TABLE_FORUM_THREAD."' AND
  4450. c_id = $courseId AND
  4451. ref = ".$threadId."
  4452. $sessionCondition
  4453. ";
  4454. Database::query($sql);
  4455. }
  4456. }
  4457. return get_lang('Thread moved');
  4458. }
  4459. /**
  4460. * Prepares a string for displaying by highlighting the search results inside, if any.
  4461. *
  4462. * @param string $input the input string
  4463. *
  4464. * @return string the same string with highlighted hits inside
  4465. *
  4466. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, February 2006 - the initial version.
  4467. * @author Ivan Tcholakov, March 2011 - adaptation for Chamilo LMS.
  4468. */
  4469. function prepare4display($input)
  4470. {
  4471. static $highlightcolors = ['yellow', '#33CC33', '#3399CC', '#9999FF', '#33CC33'];
  4472. static $search;
  4473. if (!isset($search)) {
  4474. if (isset($_POST['search_term'])) {
  4475. $search = $_POST['search_term']; // No html at all.
  4476. } elseif (isset($_GET['search'])) {
  4477. $search = $_GET['search'];
  4478. } else {
  4479. $search = '';
  4480. }
  4481. }
  4482. if (!empty($search)) {
  4483. if (strstr($search, '+')) {
  4484. $search_terms = explode('+', $search);
  4485. } else {
  4486. $search_terms[] = trim($search);
  4487. }
  4488. $counter = 0;
  4489. foreach ($search_terms as $key => $search_term) {
  4490. $input = api_preg_replace(
  4491. '/'.preg_quote(trim($search_term), '/').'/i',
  4492. '<span style="background-color: '.$highlightcolors[$counter].'">$0</span>',
  4493. $input
  4494. );
  4495. $counter++;
  4496. }
  4497. }
  4498. // TODO: Security should be implemented outside this function.
  4499. // Change this to COURSEMANAGERLOWSECURITY or COURSEMANAGER to lower filtering and allow more styles
  4500. // (see comments of Security::remove_XSS() method to learn about other levels).
  4501. return Security::remove_XSS($input, STUDENT, true);
  4502. }
  4503. /**
  4504. * Display the search form for the forum and display the search results.
  4505. *
  4506. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  4507. *
  4508. * @version march 2008, dokeos 1.8.5
  4509. */
  4510. function forum_search()
  4511. {
  4512. $form = new FormValidator(
  4513. 'forumsearch',
  4514. 'post',
  4515. 'forumsearch.php?'.api_get_cidreq()
  4516. );
  4517. // Setting the form elements.
  4518. $form->addElement('header', '', get_lang('Search in the Forum'));
  4519. $form->addElement('text', 'search_term', get_lang('Search term'), ['autofocus']);
  4520. $form->applyFilter('search_term', 'html_filter');
  4521. $form->addElement('static', 'search_information', '', get_lang('Search in the ForumInformation'));
  4522. $form->addButtonSearch(get_lang('Search'));
  4523. // Setting the rules.
  4524. $form->addRule('search_term', get_lang('Required field'), 'required');
  4525. $form->addRule('search_term', get_lang('Too short'), 'minlength', 3);
  4526. // Validation or display.
  4527. if ($form->validate()) {
  4528. $values = $form->exportValues();
  4529. $form->setDefaults($values);
  4530. $form->display();
  4531. // Display the search results.
  4532. display_forum_search_results(stripslashes($values['search_term']));
  4533. } else {
  4534. $form->display();
  4535. }
  4536. }
  4537. /**
  4538. * Display the search results.
  4539. *
  4540. * @param string
  4541. * @param string $search_term
  4542. *
  4543. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  4544. *
  4545. * @version march 2008, dokeos 1.8.5
  4546. */
  4547. function display_forum_search_results($search_term)
  4548. {
  4549. $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
  4550. $table_posts = Database::get_course_table(TABLE_FORUM_POST);
  4551. $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
  4552. $session_id = api_get_session_id();
  4553. $course_id = api_get_course_int_id();
  4554. // Defining the search strings as an array.
  4555. if (strstr($search_term, '+')) {
  4556. $search_terms = explode('+', $search_term);
  4557. } else {
  4558. $search_terms[] = $search_term;
  4559. }
  4560. // Search restriction.
  4561. foreach ($search_terms as $value) {
  4562. $search_restriction[] = "
  4563. (
  4564. posts.post_title LIKE '%".Database::escape_string(trim($value))."%' OR
  4565. posts.post_text LIKE '%".Database::escape_string(trim($value))."%'
  4566. )";
  4567. }
  4568. $sessionCondition = api_get_session_condition(
  4569. $session_id,
  4570. true,
  4571. false,
  4572. 'item_property.session_id'
  4573. );
  4574. $sql = "SELECT posts.*
  4575. FROM $table_posts posts
  4576. INNER JOIN $table_threads threads
  4577. ON (posts.thread_id = threads.thread_id AND posts.c_id = threads.c_id)
  4578. INNER JOIN $table_item_property item_property
  4579. ON (item_property.ref = threads.thread_id AND item_property.c_id = threads.c_id)
  4580. WHERE
  4581. posts.c_id = $course_id AND
  4582. item_property.c_id = $course_id AND
  4583. item_property.visibility = 1
  4584. $sessionCondition AND
  4585. posts.visible = 1 AND
  4586. item_property.tool = '".TOOL_FORUM_THREAD."' AND
  4587. ".implode(' AND ', $search_restriction)."
  4588. GROUP BY posts.post_id";
  4589. // Getting all the information of the forum categories.
  4590. $forum_categories_list = get_forum_categories();
  4591. // Getting all the information of the forums.
  4592. $forum_list = get_forums();
  4593. $result = Database::query($sql);
  4594. $search_results = [];
  4595. while ($row = Database::fetch_array($result, 'ASSOC')) {
  4596. $forumId = $row['forum_id'];
  4597. $forumData = get_forums($forumId);
  4598. $category = isset($forum_categories_list[$forumData['forum_category']]) ? $forum_categories_list[$forumData['forum_category']] : null;
  4599. $display_result = false;
  4600. /*
  4601. We only show it when
  4602. 1. forum category is visible
  4603. 2. forum is visible
  4604. 3. thread is visible (to do)
  4605. 4. post is visible
  4606. */
  4607. if (!api_is_allowed_to_edit(null, true)) {
  4608. if (!empty($category)) {
  4609. if ($category['visibility'] == '1' && $forumData['visibility'] == '1') {
  4610. $display_result = true;
  4611. }
  4612. } else {
  4613. if ($forumData['visible'] == '1') {
  4614. $display_result = true;
  4615. }
  4616. }
  4617. } else {
  4618. $display_result = true;
  4619. }
  4620. if ($display_result) {
  4621. $categoryName = !empty($category) ? $category['cat_title'] : '';
  4622. $search_results_item = '<li><a href="viewforumcategory.php?'.api_get_cidreq().'&forumcategory='.$forumData['forum_category'].'&search='.urlencode($search_term).'">'.
  4623. prepare4display($categoryName).'</a> &gt; ';
  4624. $search_results_item .= '<a href="viewforum.php?'.api_get_cidreq().'&forum='.$forumId.'&search='.urlencode($search_term).'">'.
  4625. prepare4display($forum_list[$row['forum_id']]['forum_title']).'</a> &gt; ';
  4626. $search_results_item .= '<a href="viewthread.php?'.api_get_cidreq().'&forum='.$forumId.'&thread='.$row['thread_id'].'&search='.urlencode($search_term).'">'.
  4627. prepare4display($row['post_title']).'</a>';
  4628. $search_results_item .= '<br />';
  4629. if (api_strlen($row['post_title']) > 200) {
  4630. $search_results_item .= prepare4display(api_substr(strip_tags($row['post_title']), 0, 200)).'...';
  4631. } else {
  4632. $search_results_item .= prepare4display($row['post_title']);
  4633. }
  4634. $search_results_item .= '</li>';
  4635. $search_results[] = $search_results_item;
  4636. }
  4637. }
  4638. echo '<legend>'.count($search_results).' '.get_lang('Search in the ForumResults').'</legend>';
  4639. echo '<ol>';
  4640. if ($search_results) {
  4641. echo implode($search_results);
  4642. }
  4643. echo '</ol>';
  4644. }
  4645. /**
  4646. * Return the link to the forum search page.
  4647. *
  4648. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  4649. *
  4650. * @version April 2008, dokeos 1.8.5
  4651. */
  4652. function search_link()
  4653. {
  4654. $return = '';
  4655. $origin = api_get_origin();
  4656. if ($origin != 'learnpath') {
  4657. $return = '<a href="forumsearch.php?'.api_get_cidreq().'&action=search"> ';
  4658. $return .= Display::return_icon('search.png', get_lang('Search'), '', ICON_SIZE_MEDIUM).'</a>';
  4659. if (!empty($_GET['search'])) {
  4660. $return .= ': '.Security::remove_XSS($_GET['search']).' ';
  4661. $url = api_get_self().'?';
  4662. $url_parameter = [];
  4663. foreach ($_GET as $key => $value) {
  4664. if ($key != 'search') {
  4665. $url_parameter[] = Security::remove_XSS($key).'='.Security::remove_XSS($value);
  4666. }
  4667. }
  4668. $url = $url.implode('&', $url_parameter);
  4669. $return .= '<a href="'.$url.'">'.Display::return_icon('delete.gif', get_lang('Clean search results')).'</a>';
  4670. }
  4671. }
  4672. return $return;
  4673. }
  4674. /**
  4675. * This function adds an attachment file into a forum.
  4676. *
  4677. * @param string $file_comment a comment about file
  4678. * @param int $last_id from forum_post table
  4679. *
  4680. * @return false|null
  4681. */
  4682. function add_forum_attachment_file($file_comment, $last_id)
  4683. {
  4684. $_course = api_get_course_info();
  4685. $agenda_forum_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
  4686. if (empty($_FILES['user_upload'])) {
  4687. return false;
  4688. }
  4689. $filesData = [];
  4690. if (!is_array($_FILES['user_upload']['name'])) {
  4691. $filesData[] = $_FILES['user_upload'];
  4692. } else {
  4693. $fileCount = count($_FILES['user_upload']['name']);
  4694. $fileKeys = array_keys($_FILES['user_upload']);
  4695. for ($i = 0; $i < $fileCount; $i++) {
  4696. foreach ($fileKeys as $key) {
  4697. $filesData[$i][$key] = $_FILES['user_upload'][$key][$i];
  4698. }
  4699. }
  4700. }
  4701. foreach ($filesData as $attachment) {
  4702. if (empty($attachment['name'])) {
  4703. continue;
  4704. }
  4705. $upload_ok = process_uploaded_file($attachment);
  4706. if (!$upload_ok) {
  4707. continue;
  4708. }
  4709. $course_dir = $_course['path'].'/upload/forum';
  4710. $sys_course_path = api_get_path(SYS_COURSE_PATH);
  4711. $updir = $sys_course_path.$course_dir;
  4712. // Try to add an extension to the file if it hasn't one.
  4713. $new_file_name = add_ext_on_mime(
  4714. stripslashes($attachment['name']),
  4715. $attachment['type']
  4716. );
  4717. // User's file name
  4718. $file_name = $attachment['name'];
  4719. if (!filter_extension($new_file_name)) {
  4720. Display::addFlash(
  4721. Display::return_message(
  4722. get_lang('File upload failed: this file extension or file type is prohibited'),
  4723. 'error'
  4724. )
  4725. );
  4726. return;
  4727. }
  4728. $new_file_name = uniqid('');
  4729. $new_path = $updir.'/'.$new_file_name;
  4730. $result = @move_uploaded_file($attachment['tmp_name'], $new_path);
  4731. $safe_file_comment = Database::escape_string($file_comment);
  4732. $safe_file_name = Database::escape_string($file_name);
  4733. $safe_new_file_name = Database::escape_string($new_file_name);
  4734. $last_id = intval($last_id);
  4735. // Storing the attachments if any.
  4736. if (!$result) {
  4737. return;
  4738. }
  4739. $last_id_file = Database::insert(
  4740. $agenda_forum_attachment,
  4741. [
  4742. 'c_id' => api_get_course_int_id(),
  4743. 'filename' => $safe_file_name,
  4744. 'comment' => $safe_file_comment,
  4745. 'path' => $safe_new_file_name,
  4746. 'post_id' => $last_id,
  4747. 'size' => intval($attachment['size']),
  4748. ]
  4749. );
  4750. api_item_property_update(
  4751. $_course,
  4752. TOOL_FORUM_ATTACH,
  4753. $last_id_file,
  4754. 'ForumAttachmentAdded',
  4755. api_get_user_id()
  4756. );
  4757. }
  4758. }
  4759. /**
  4760. * This function edits an attachment file into a forum.
  4761. *
  4762. * @param string $file_comment a comment about file
  4763. * @param int $post_id
  4764. * @param int $id_attach attachment file Id
  4765. */
  4766. function edit_forum_attachment_file($file_comment, $post_id, $id_attach)
  4767. {
  4768. $_course = api_get_course_info();
  4769. $table_forum_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
  4770. $course_id = api_get_course_int_id();
  4771. $filesData = [];
  4772. if (!is_array($_FILES['user_upload']['name'])) {
  4773. $filesData[] = $_FILES['user_upload'];
  4774. } else {
  4775. $fileCount = count($_FILES['user_upload']['name']);
  4776. $fileKeys = array_keys($_FILES['user_upload']);
  4777. for ($i = 0; $i < $fileCount; $i++) {
  4778. foreach ($fileKeys as $key) {
  4779. $filesData[$i][$key] = $_FILES['user_upload'][$key][$i];
  4780. }
  4781. }
  4782. }
  4783. foreach ($filesData as $attachment) {
  4784. if (empty($attachment['name'])) {
  4785. continue;
  4786. }
  4787. $upload_ok = process_uploaded_file($attachment);
  4788. if (!$upload_ok) {
  4789. continue;
  4790. }
  4791. $course_dir = $_course['path'].'/upload/forum';
  4792. $sys_course_path = api_get_path(SYS_COURSE_PATH);
  4793. $updir = $sys_course_path.$course_dir;
  4794. // Try to add an extension to the file if it hasn't one.
  4795. $new_file_name = add_ext_on_mime(stripslashes($attachment['name']), $attachment['type']);
  4796. // User's file name
  4797. $file_name = $attachment['name'];
  4798. if (!filter_extension($new_file_name)) {
  4799. Display::addFlash(
  4800. Display::return_message(
  4801. get_lang('File upload failed: this file extension or file type is prohibited'),
  4802. 'error'
  4803. )
  4804. );
  4805. } else {
  4806. $new_file_name = uniqid('');
  4807. $new_path = $updir.'/'.$new_file_name;
  4808. $result = @move_uploaded_file($attachment['tmp_name'], $new_path);
  4809. $safe_file_comment = Database::escape_string($file_comment);
  4810. $safe_file_name = Database::escape_string($file_name);
  4811. $safe_new_file_name = Database::escape_string($new_file_name);
  4812. $safe_post_id = (int) $post_id;
  4813. $safe_id_attach = (int) $id_attach;
  4814. // Storing the attachments if any.
  4815. if ($result) {
  4816. $sql = "UPDATE $table_forum_attachment
  4817. SET
  4818. filename = '$safe_file_name',
  4819. comment = '$safe_file_comment',
  4820. path = '$safe_new_file_name',
  4821. post_id = '$safe_post_id',
  4822. size ='".$attachment['size']."'
  4823. WHERE c_id = $course_id AND id = '$safe_id_attach'";
  4824. Database::query($sql);
  4825. api_item_property_update(
  4826. $_course,
  4827. TOOL_FORUM_ATTACH,
  4828. $safe_id_attach,
  4829. 'ForumAttachmentUpdated',
  4830. api_get_user_id()
  4831. );
  4832. }
  4833. }
  4834. }
  4835. }
  4836. /**
  4837. * Show a list with all the attachments according to the post's id.
  4838. *
  4839. * @param int $postId
  4840. *
  4841. * @return array with the post info
  4842. *
  4843. * @author Julio Montoya
  4844. *
  4845. * @version avril 2008, dokeos 1.8.5
  4846. */
  4847. function get_attachment($postId)
  4848. {
  4849. $table = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
  4850. $course_id = api_get_course_int_id();
  4851. $row = [];
  4852. $postId = (int) $postId;
  4853. if (empty($postId)) {
  4854. return [];
  4855. }
  4856. $sql = "SELECT iid, path, filename, comment
  4857. FROM $table
  4858. WHERE c_id = $course_id AND post_id = $postId";
  4859. $result = Database::query($sql);
  4860. if (Database::num_rows($result) != 0) {
  4861. $row = Database::fetch_array($result);
  4862. }
  4863. return $row;
  4864. }
  4865. /**
  4866. * @param int $postId
  4867. *
  4868. * @return array
  4869. */
  4870. function getAllAttachment($postId)
  4871. {
  4872. $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
  4873. $courseId = api_get_course_int_id();
  4874. $postId = (int) $postId;
  4875. if (empty($postId)) {
  4876. return [];
  4877. }
  4878. $columns = ['iid', 'path', 'filename', 'comment'];
  4879. $conditions = [
  4880. 'where' => [
  4881. 'c_id = ? AND post_id = ?' => [$courseId, $postId],
  4882. ],
  4883. ];
  4884. $array = Database::select(
  4885. $columns,
  4886. $forumAttachmentTable,
  4887. $conditions,
  4888. 'all',
  4889. 'ASSOC'
  4890. );
  4891. return $array;
  4892. }
  4893. /**
  4894. * Delete the all the attachments from the DB and the file according to the post's id or attach id(optional).
  4895. *
  4896. * @param int $post_id
  4897. * @param int $id_attach
  4898. *
  4899. * @return int
  4900. *
  4901. * @author Julio Montoya
  4902. *
  4903. * @version october 2014, chamilo 1.9.8
  4904. */
  4905. function delete_attachment($post_id, $id_attach = 0)
  4906. {
  4907. $_course = api_get_course_info();
  4908. $forum_table_attachment = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
  4909. $course_id = api_get_course_int_id();
  4910. $cond = (!empty($id_attach)) ? " iid = ".(int) $id_attach."" : " post_id = ".(int) $post_id."";
  4911. $sql = "SELECT path FROM $forum_table_attachment WHERE c_id = $course_id AND $cond";
  4912. $res = Database::query($sql);
  4913. $row = Database::fetch_array($res);
  4914. $course_dir = $_course['path'].'/upload/forum';
  4915. $sys_course_path = api_get_path(SYS_COURSE_PATH);
  4916. $updir = $sys_course_path.$course_dir;
  4917. $my_path = isset($row['path']) ? $row['path'] : null;
  4918. $file = $updir.'/'.$my_path;
  4919. if (Security::check_abs_path($file, $updir)) {
  4920. @unlink($file);
  4921. }
  4922. // Delete from forum_attachment table.
  4923. $sql = "DELETE FROM $forum_table_attachment
  4924. WHERE c_id = $course_id AND $cond ";
  4925. $result = Database::query($sql);
  4926. if ($result !== false) {
  4927. $affectedRows = Database::affected_rows($result);
  4928. } else {
  4929. $affectedRows = 0;
  4930. }
  4931. // Update item_property.
  4932. api_item_property_update(
  4933. $_course,
  4934. TOOL_FORUM_ATTACH,
  4935. $id_attach,
  4936. 'ForumAttachmentDelete',
  4937. api_get_user_id()
  4938. );
  4939. if (!empty($result) && !empty($id_attach)) {
  4940. Display::addFlash(Display::return_message(get_lang('The attached file has been deleted'), 'confirmation'));
  4941. }
  4942. return $affectedRows;
  4943. }
  4944. /**
  4945. * This function gets all the forum information of the all the forum of the group.
  4946. *
  4947. * @param array $groupInfo the id of the group we need the fora of (see forum.forum_of_group)
  4948. *
  4949. * @return array
  4950. *
  4951. * @todo this is basically the same code as the get_forums function. Consider merging the two.
  4952. */
  4953. function get_forums_of_group($groupInfo)
  4954. {
  4955. $table_forums = Database::get_course_table(TABLE_FORUM);
  4956. $table_threads = Database::get_course_table(TABLE_FORUM_THREAD);
  4957. $table_posts = Database::get_course_table(TABLE_FORUM_POST);
  4958. $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
  4959. $course_id = api_get_course_int_id();
  4960. $groupId = (int) $groupInfo['id'];
  4961. // Student
  4962. // Select all the forum information of all forums (that are visible to students).
  4963. $sql = "SELECT * FROM $table_forums forum
  4964. INNER JOIN $table_item_property item_properties
  4965. ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
  4966. WHERE
  4967. forum.forum_of_group = $groupId AND
  4968. forum.c_id = $course_id AND
  4969. item_properties.c_id = $course_id AND
  4970. item_properties.visibility = 1 AND
  4971. item_properties.tool = '".TOOL_FORUM."'
  4972. ORDER BY forum.forum_order ASC";
  4973. // Select the number of threads of the forums (only the threads that are visible).
  4974. $sql2 = "SELECT
  4975. count(thread_id) AS number_of_threads,
  4976. threads.forum_id
  4977. FROM $table_threads threads
  4978. INNER JOIN $table_item_property item_properties
  4979. ON (threads.thread_id = item_properties.ref AND item_properties.c_id = threads.c_id)
  4980. WHERE
  4981. threads.c_id = $course_id AND
  4982. item_properties.c_id = $course_id AND
  4983. item_properties.visibility = 1 AND
  4984. item_properties.tool='".TOOL_FORUM_THREAD."'
  4985. GROUP BY threads.forum_id";
  4986. // Select the number of posts of the forum (post that are visible and that are in a thread that is visible).
  4987. $sql3 = "SELECT count(post_id) AS number_of_posts, posts.forum_id
  4988. FROM $table_posts posts
  4989. INNER JOIN $table_threads threads
  4990. ON (posts.thread_id = threads.thread_id AND posts.c_id = threads.c_id)
  4991. INNER JOIN $table_item_property item_properties
  4992. ON (threads.thread_id = item_properties.ref AND item_properties.c_id = threads.c_id)
  4993. WHERE
  4994. posts.visible=1 AND
  4995. posts.c_id = $course_id AND
  4996. item_properties.c_id = $course_id AND
  4997. threads.c_id = $course_id AND
  4998. item_properties.visibility = 1 AND
  4999. item_properties.tool='".TOOL_FORUM_THREAD."'
  5000. GROUP BY threads.forum_id";
  5001. // Course Admin
  5002. if (api_is_allowed_to_edit()) {
  5003. // Select all the forum information of all forums (that are not deleted).
  5004. $sql = "SELECT *
  5005. FROM $table_forums forum
  5006. INNER JOIN $table_item_property item_properties
  5007. ON (forum.forum_id = item_properties.ref AND item_properties.c_id = forum.c_id)
  5008. WHERE
  5009. forum.forum_of_group = $groupId AND
  5010. forum.c_id = $course_id AND
  5011. item_properties.c_id = $course_id AND
  5012. item_properties.visibility <> 2 AND
  5013. item_properties.tool = '".TOOL_FORUM."'
  5014. ORDER BY forum_order ASC";
  5015. // Select the number of threads of the forums (only the threads that are not deleted).
  5016. $sql2 = "SELECT count(thread_id) AS number_of_threads, threads.forum_id
  5017. FROM $table_threads threads
  5018. INNER JOIN $table_item_property item_properties
  5019. ON (threads.thread_id=item_properties.ref AND item_properties.c_id = threads.c_id)
  5020. WHERE
  5021. threads.c_id = $course_id AND
  5022. item_properties.c_id = $course_id AND
  5023. item_properties.visibility <> 2 AND
  5024. item_properties.tool='".TOOL_FORUM_THREAD."'
  5025. GROUP BY threads.forum_id";
  5026. // Select the number of posts of the forum.
  5027. $sql3 = "SELECT count(post_id) AS number_of_posts, forum_id
  5028. FROM $table_posts
  5029. WHERE c_id = $course_id
  5030. GROUP BY forum_id";
  5031. }
  5032. // Handling all the forum information.
  5033. $result = Database::query($sql);
  5034. $forum_list = [];
  5035. while ($row = Database::fetch_array($result, 'ASSOC')) {
  5036. $forum_list[$row['forum_id']] = $row;
  5037. }
  5038. // Handling the thread count information.
  5039. $result2 = Database::query($sql2);
  5040. while ($row2 = Database::fetch_array($result2, 'ASSOC')) {
  5041. if (is_array($forum_list)) {
  5042. if (array_key_exists($row2['forum_id'], $forum_list)) {
  5043. $forum_list[$row2['forum_id']]['number_of_threads'] = $row2['number_of_threads'];
  5044. }
  5045. }
  5046. }
  5047. // Handling the post count information.
  5048. $result3 = Database::query($sql3);
  5049. while ($row3 = Database::fetch_array($result3, 'ASSOC')) {
  5050. if (is_array($forum_list)) {
  5051. if (array_key_exists($row3['forum_id'], $forum_list)) {
  5052. // This is needed because sql3 takes also the deleted forums into account.
  5053. $forum_list[$row3['forum_id']]['number_of_posts'] = $row3['number_of_posts'];
  5054. }
  5055. }
  5056. }
  5057. // Finding the last post information
  5058. // (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname).
  5059. if (!empty($forum_list)) {
  5060. foreach ($forum_list as $key => $value) {
  5061. $lastPost = get_last_post_information($key, api_is_allowed_to_edit());
  5062. if ($lastPost) {
  5063. $forum_list[$key]['last_post_id'] = $lastPost['last_post_id'];
  5064. $forum_list[$key]['last_poster_id'] = $lastPost['last_poster_id'];
  5065. $forum_list[$key]['last_post_date'] = $lastPost['last_post_date'];
  5066. $forum_list[$key]['last_poster_name'] = $lastPost['last_poster_name'];
  5067. $forum_list[$key]['last_poster_lastname'] = $lastPost['last_poster_lastname'];
  5068. $forum_list[$key]['last_poster_firstname'] = $lastPost['last_poster_firstname'];
  5069. }
  5070. }
  5071. }
  5072. return $forum_list;
  5073. }
  5074. /**
  5075. * This function stores which users have to be notified of which forums or threads.
  5076. *
  5077. * @param string $content does the user want to be notified about a forum or about a thread
  5078. * @param int $id the id of the forum or thread
  5079. * @param bool $addOnly
  5080. * @param array $userInfo
  5081. * @param array $courseInfo
  5082. *
  5083. * @return string language variable
  5084. *
  5085. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  5086. * @author Julio Montoya
  5087. *
  5088. * @since May 2008 v1.8.5
  5089. */
  5090. function set_notification($content, $id, $addOnly = false, $userInfo = [], $courseInfo = [])
  5091. {
  5092. $userInfo = empty($userInfo) ? api_get_user_info() : $userInfo;
  5093. $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
  5094. $id = (int) $id;
  5095. if (empty($userInfo) || empty($courseInfo) || empty($id) || empty($content)) {
  5096. return false;
  5097. }
  5098. // Database table definition
  5099. $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
  5100. $course_id = $courseInfo['real_id'];
  5101. // Which database field do we have to store the id in?
  5102. $field = 'thread_id';
  5103. if ($content === 'forum') {
  5104. $field = 'forum_id';
  5105. }
  5106. $userId = $userInfo['user_id'];
  5107. // First we check if the notification is already set for this.
  5108. $sql = "SELECT * FROM $table_notification
  5109. WHERE
  5110. c_id = $course_id AND
  5111. $field = $id AND
  5112. user_id = $userId ";
  5113. $result = Database::query($sql);
  5114. $total = Database::num_rows($result);
  5115. // If the user did not indicate that (s)he wanted to be notified already
  5116. // then we store the notification request (to prevent double notification requests).
  5117. if ($total <= 0) {
  5118. $sql = "INSERT INTO $table_notification (c_id, $field, user_id)
  5119. VALUES ($course_id, '$id','$userId')";
  5120. Database::query($sql);
  5121. Session::erase('forum_notification');
  5122. getNotificationsPerUser(0, true);
  5123. return get_lang('You will be notified of new posts by e-mail.');
  5124. } else {
  5125. if (!$addOnly) {
  5126. $sql = "DELETE FROM $table_notification
  5127. WHERE
  5128. c_id = $course_id AND
  5129. $field = $id AND
  5130. user_id = $userId ";
  5131. Database::query($sql);
  5132. Session::erase('forum_notification');
  5133. getNotificationsPerUser(0, true);
  5134. return get_lang('You will no longer be notified of new posts by email');
  5135. }
  5136. }
  5137. }
  5138. /**
  5139. * This function retrieves all the email adresses of the users who wanted to be notified
  5140. * about a new post in a certain forum or thread.
  5141. *
  5142. * @param string $content does the user want to be notified about a forum or about a thread
  5143. * @param int $id the id of the forum or thread
  5144. *
  5145. * @return array returns
  5146. *
  5147. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  5148. * @author Julio Montoya
  5149. *
  5150. * @version May 2008, dokeos 1.8.5
  5151. *
  5152. * @since May 2008, dokeos 1.8.5
  5153. */
  5154. function get_notifications($content, $id)
  5155. {
  5156. // Database table definition
  5157. $table_users = Database::get_main_table(TABLE_MAIN_USER);
  5158. $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
  5159. $course_id = api_get_course_int_id();
  5160. // Which database field contains the notification?
  5161. $field = 'thread_id';
  5162. if ($content === 'forum') {
  5163. $field = 'forum_id';
  5164. }
  5165. $id = (int) $id;
  5166. $sql = "SELECT user.user_id, user.firstname, user.lastname, user.email, user.user_id user
  5167. FROM $table_users user, $table_notification notification
  5168. WHERE
  5169. notification.c_id = $course_id AND user.active = 1 AND
  5170. user.user_id = notification.user_id AND
  5171. notification.$field = $id ";
  5172. $result = Database::query($sql);
  5173. $return = [];
  5174. while ($row = Database::fetch_array($result)) {
  5175. $return['user'.$row['user_id']] = ['email' => $row['email'], 'user_id' => $row['user_id']];
  5176. }
  5177. return $return;
  5178. }
  5179. /**
  5180. * Get all the users who need to receive a notification of a new post (those subscribed to
  5181. * the forum or the thread).
  5182. *
  5183. * @param int $forum_id the id of the forum
  5184. * @param int $thread_id the id of the thread
  5185. * @param int $post_id the id of the post
  5186. *
  5187. * @return false|null
  5188. *
  5189. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  5190. *
  5191. * @version May 2008, dokeos 1.8.5
  5192. *
  5193. * @since May 2008, dokeos 1.8.5
  5194. */
  5195. function send_notifications($forum_id = 0, $thread_id = 0, $post_id = 0)
  5196. {
  5197. $forum_id = (int) $forum_id;
  5198. // Users who subscribed to the forum
  5199. if ($forum_id != 0) {
  5200. $users_to_be_notified_by_forum = get_notifications('forum', $forum_id);
  5201. } else {
  5202. return false;
  5203. }
  5204. $current_thread = get_thread_information($forum_id, $thread_id);
  5205. // User who subscribed to the thread
  5206. if ($thread_id != 0) {
  5207. $users_to_be_notified_by_thread = get_notifications('thread', $thread_id);
  5208. }
  5209. $postInfo = [];
  5210. if (!empty($post_id)) {
  5211. $postInfo = get_post_information($post_id);
  5212. }
  5213. // Merging the two
  5214. $users_to_be_notified = array_merge($users_to_be_notified_by_forum, $users_to_be_notified_by_thread);
  5215. $forumInfo = get_forum_information($forum_id);
  5216. if (is_array($users_to_be_notified)) {
  5217. foreach ($users_to_be_notified as $value) {
  5218. $userInfo = api_get_user_info($value['user_id']);
  5219. send_mail($userInfo, $forumInfo, $current_thread, $postInfo);
  5220. }
  5221. }
  5222. }
  5223. /**
  5224. * Get all the notification subscriptions of the user
  5225. * = which forums and which threads does the user wants to be informed of when a new
  5226. * post is added to this thread.
  5227. *
  5228. * @param int $user_id the user_id of a user (default = 0 => the current user)
  5229. * @param bool $force force get the notification subscriptions (even if the information is already in the session
  5230. *
  5231. * @return array
  5232. *
  5233. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  5234. *
  5235. * @version May 2008, dokeos 1.8.5
  5236. *
  5237. * @since May 2008, dokeos 1.8.5
  5238. */
  5239. function getNotificationsPerUser($user_id = 0, $force = false, $course_id = 0)
  5240. {
  5241. // Database table definition
  5242. $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
  5243. $course_id = empty($course_id) ? api_get_course_int_id() : (int) $course_id;
  5244. if (empty($course_id) || $course_id == -1) {
  5245. return null;
  5246. }
  5247. $user_id = empty($user_id) ? api_get_user_id() : (int) $user_id;
  5248. if (!isset($_SESSION['forum_notification']) ||
  5249. $_SESSION['forum_notification']['course'] != $course_id ||
  5250. $force == true
  5251. ) {
  5252. $_SESSION['forum_notification']['course'] = $course_id;
  5253. $sql = "SELECT * FROM $table_notification
  5254. WHERE c_id = $course_id AND user_id='".$user_id."'";
  5255. $result = Database::query($sql);
  5256. while ($row = Database::fetch_array($result)) {
  5257. if (!is_null($row['forum_id'])) {
  5258. $_SESSION['forum_notification']['forum'][] = $row['forum_id'];
  5259. }
  5260. if (!is_null($row['thread_id'])) {
  5261. $_SESSION['forum_notification']['thread'][] = $row['thread_id'];
  5262. }
  5263. }
  5264. }
  5265. }
  5266. /**
  5267. * This function counts the number of post inside a thread.
  5268. *
  5269. * @param int $thread_id
  5270. *
  5271. * @return int the number of post inside a thread
  5272. *
  5273. * @author Jhon Hinojosa <jhon.hinojosa@dokeos.com>,
  5274. *
  5275. * @version octubre 2008, dokeos 1.8
  5276. */
  5277. function count_number_of_post_in_thread($thread_id)
  5278. {
  5279. $table_posts = Database::get_course_table(TABLE_FORUM_POST);
  5280. $course_id = api_get_course_int_id();
  5281. if (empty($course_id)) {
  5282. return 0;
  5283. }
  5284. $sql = "SELECT count(*) count FROM $table_posts
  5285. WHERE
  5286. c_id = $course_id AND
  5287. thread_id='".intval($thread_id)."' ";
  5288. $result = Database::query($sql);
  5289. $count = 0;
  5290. if (Database::num_rows($result) > 0) {
  5291. $row = Database::fetch_array($result);
  5292. $count = $row['count'];
  5293. }
  5294. return $count;
  5295. }
  5296. /**
  5297. * This function counts the number of post inside a thread user.
  5298. *
  5299. * @param int $thread_id
  5300. * @param int $user_id
  5301. *
  5302. * @return int the number of post inside a thread user
  5303. */
  5304. function count_number_of_post_for_user_thread($thread_id, $user_id)
  5305. {
  5306. $table_posts = Database::get_course_table(TABLE_FORUM_POST);
  5307. $course_id = api_get_course_int_id();
  5308. $sql = "SELECT count(iid) as count
  5309. FROM $table_posts
  5310. WHERE c_id = $course_id AND
  5311. thread_id=".intval($thread_id)." AND
  5312. poster_id = ".intval($user_id)." AND visible = 1 ";
  5313. $result = Database::query($sql);
  5314. $count = 0;
  5315. if (Database::num_rows($result) > 0) {
  5316. $count = Database::fetch_array($result);
  5317. $count = $count['count'];
  5318. }
  5319. return $count;
  5320. }
  5321. /**
  5322. * This function retrieves information of statistical.
  5323. *
  5324. * @param int $thread_id
  5325. * @param int $user_id
  5326. * @param int $course_id
  5327. *
  5328. * @return array the information of statistical
  5329. *
  5330. * @author Jhon Hinojosa <jhon.hinojosa@dokeos.com>,
  5331. *
  5332. * @version oct 2008, dokeos 1.8
  5333. */
  5334. function get_statistical_information($thread_id, $user_id, $course_id)
  5335. {
  5336. $result = [];
  5337. $courseInfo = api_get_course_info_by_id($course_id);
  5338. $result['user_course'] = CourseManager::get_users_count_in_course($courseInfo['code']);
  5339. $result['post'] = count_number_of_post_in_thread($thread_id);
  5340. $result['user_post'] = count_number_of_post_for_user_thread($thread_id, $user_id);
  5341. return $result;
  5342. }
  5343. /**
  5344. * This function return the posts inside a thread from a given user.
  5345. *
  5346. * @param string $course_code
  5347. * @param int $thread_id
  5348. * @param int $user_id
  5349. *
  5350. * @return array posts inside a thread
  5351. *
  5352. * @author Jhon Hinojosa <jhon.hinojosa@dokeos.com>,
  5353. *
  5354. * @version oct 2008, dokeos 1.8
  5355. */
  5356. function get_thread_user_post($course_code, $thread_id, $user_id)
  5357. {
  5358. $table_posts = Database::get_course_table(TABLE_FORUM_POST);
  5359. $table_users = Database::get_main_table(TABLE_MAIN_USER);
  5360. $thread_id = intval($thread_id);
  5361. $user_id = intval($user_id);
  5362. $course_info = api_get_user_info($course_code);
  5363. $course_id = $course_info['real_id'];
  5364. if (empty($course_id)) {
  5365. $course_id = api_get_course_int_id();
  5366. }
  5367. $sql = "SELECT * FROM $table_posts posts
  5368. LEFT JOIN $table_users users
  5369. ON posts.poster_id=users.user_id
  5370. WHERE
  5371. posts.c_id = $course_id AND
  5372. posts.thread_id='$thread_id'
  5373. AND posts.poster_id='$user_id'
  5374. ORDER BY posts.post_id ASC";
  5375. $result = Database::query($sql);
  5376. $post_list = [];
  5377. while ($row = Database::fetch_array($result)) {
  5378. $row['status'] = '1';
  5379. $post_list[] = $row;
  5380. $sql = "SELECT * FROM $table_posts posts
  5381. LEFT JOIN $table_users users
  5382. ON (posts.poster_id=users.user_id)
  5383. WHERE
  5384. posts.c_id = $course_id AND
  5385. posts.thread_id='$thread_id'
  5386. AND posts.post_parent_id='".$row['post_id']."'
  5387. ORDER BY posts.post_id ASC";
  5388. $result2 = Database::query($sql);
  5389. while ($row2 = Database::fetch_array($result2)) {
  5390. $row2['status'] = '0';
  5391. $post_list[] = $row2;
  5392. }
  5393. }
  5394. return $post_list;
  5395. }
  5396. /**
  5397. * This function get the name of an thread by id.
  5398. *
  5399. * @param int thread_id
  5400. *
  5401. * @return string
  5402. *
  5403. * @author Christian Fasanando
  5404. * @author Julio Montoya <gugli100@gmail.com> Adding security
  5405. */
  5406. function get_name_thread_by_id($thread_id)
  5407. {
  5408. $t_forum_thread = Database::get_course_table(TABLE_FORUM_THREAD);
  5409. $course_id = api_get_course_int_id();
  5410. $sql = "SELECT thread_title
  5411. FROM $t_forum_thread
  5412. WHERE c_id = $course_id AND thread_id = '".intval($thread_id)."' ";
  5413. $result = Database::query($sql);
  5414. $row = Database::fetch_array($result);
  5415. return $row[0];
  5416. }
  5417. /**
  5418. * This function gets all the post written by an user.
  5419. *
  5420. * @param int $user_id
  5421. * @param string $course_code
  5422. *
  5423. * @return string
  5424. */
  5425. function get_all_post_from_user($user_id, $course_code)
  5426. {
  5427. $j = 0;
  5428. $forums = get_forums('', $course_code);
  5429. krsort($forums);
  5430. $forum_results = '';
  5431. foreach ($forums as $forum) {
  5432. if ($forum['visibility'] == 0) {
  5433. continue;
  5434. }
  5435. if ($j <= 4) {
  5436. $threads = get_threads($forum['forum_id']);
  5437. if (is_array($threads)) {
  5438. $i = 0;
  5439. $hand_forums = '';
  5440. $post_counter = 0;
  5441. foreach ($threads as $thread) {
  5442. if ($thread['visibility'] == 0) {
  5443. continue;
  5444. }
  5445. if ($i <= 4) {
  5446. $post_list = get_thread_user_post_limit(
  5447. $course_code,
  5448. $thread['thread_id'],
  5449. $user_id,
  5450. 1
  5451. );
  5452. $post_counter = count($post_list);
  5453. if (is_array($post_list) && count($post_list) > 0) {
  5454. $hand_forums .= '<div id="social-thread">';
  5455. $hand_forums .= Display::return_icon(
  5456. 'thread.png',
  5457. get_lang('Thread'),
  5458. '',
  5459. ICON_SIZE_MEDIUM
  5460. );
  5461. $hand_forums .= '&nbsp;'.Security::remove_XSS($thread['thread_title'], STUDENT);
  5462. $hand_forums .= '</div>';
  5463. foreach ($post_list as $posts) {
  5464. $hand_forums .= '<div id="social-post">';
  5465. $hand_forums .= '<strong>'.Security::remove_XSS($posts['post_title'], STUDENT).'</strong>';
  5466. $hand_forums .= '<br / >';
  5467. $hand_forums .= Security::remove_XSS($posts['post_text'], STUDENT);
  5468. $hand_forums .= '</div>';
  5469. $hand_forums .= '<br / >';
  5470. }
  5471. }
  5472. }
  5473. $i++;
  5474. }
  5475. $forum_results .= '<div id="social-forum">';
  5476. $forum_results .= '<div class="clear"></div><br />';
  5477. $forum_results .= '<div id="social-forum-title">'.
  5478. Display::return_icon('forum.gif', get_lang('Forum')).'&nbsp;'.Security::remove_XSS($forum['forum_title'], STUDENT).
  5479. '<div style="float:right;margin-top:-35px">
  5480. <a href="../forum/viewforum.php?'.api_get_cidreq_params($course_code).'&forum='.$forum['forum_id'].' " >'.
  5481. get_lang('See forum').'
  5482. </a>
  5483. </div></div>';
  5484. $forum_results .= '<br / >';
  5485. if ($post_counter > 0) {
  5486. $forum_results .= $hand_forums;
  5487. }
  5488. $forum_results .= '</div>';
  5489. }
  5490. $j++;
  5491. }
  5492. }
  5493. return $forum_results;
  5494. }
  5495. /**
  5496. * @param string $course_code
  5497. * @param int $thread_id
  5498. * @param int $user_id
  5499. * @param int $limit
  5500. *
  5501. * @return array
  5502. */
  5503. function get_thread_user_post_limit($course_code, $thread_id, $user_id, $limit = 10)
  5504. {
  5505. $table_posts = Database::get_course_table(TABLE_FORUM_POST);
  5506. $table_users = Database::get_main_table(TABLE_MAIN_USER);
  5507. $course_info = api_get_course_info($course_code);
  5508. $course_id = $course_info['real_id'];
  5509. $sql = "SELECT * FROM $table_posts posts
  5510. LEFT JOIN $table_users users
  5511. ON posts.poster_id=users.user_id
  5512. WHERE
  5513. posts.c_id = $course_id AND
  5514. posts.thread_id='".Database::escape_string($thread_id)."' AND
  5515. posts.poster_id='".Database::escape_string($user_id)."'
  5516. ORDER BY posts.post_id DESC LIMIT $limit ";
  5517. $result = Database::query($sql);
  5518. $post_list = [];
  5519. while ($row = Database::fetch_array($result)) {
  5520. $row['status'] = '1';
  5521. $post_list[] = $row;
  5522. }
  5523. return $post_list;
  5524. }
  5525. /**
  5526. * @param string $userId
  5527. * @param array $courseInfo
  5528. * @param int $sessionId
  5529. *
  5530. * @return array
  5531. */
  5532. function getForumCreatedByUser($userId, $courseInfo, $sessionId)
  5533. {
  5534. if (empty($userId) || empty($courseInfo)) {
  5535. return [];
  5536. }
  5537. $courseId = $courseInfo['real_id'];
  5538. $items = api_get_item_property_list_by_tool_by_user(
  5539. $userId,
  5540. 'forum',
  5541. $courseId,
  5542. $sessionId
  5543. );
  5544. $forumList = [];
  5545. if (!empty($items)) {
  5546. foreach ($items as $forum) {
  5547. $forumInfo = get_forums(
  5548. $forum['ref'],
  5549. $courseInfo['code'],
  5550. true,
  5551. $sessionId
  5552. );
  5553. if (!empty($forumInfo) && isset($forumInfo['forum_title'])) {
  5554. $forumList[] = [
  5555. $forumInfo['forum_title'],
  5556. api_get_local_time($forum['insert_date']),
  5557. api_get_local_time($forum['lastedit_date']),
  5558. ];
  5559. }
  5560. }
  5561. }
  5562. return $forumList;
  5563. }
  5564. /**
  5565. * This function builds an array of all the posts in a given thread
  5566. * where the key of the array is the post_id
  5567. * It also adds an element children to the array which itself is an array
  5568. * that contains all the id's of the first-level children.
  5569. *
  5570. * @return array $rows containing all the information on the posts of a thread
  5571. *
  5572. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  5573. */
  5574. function calculate_children($rows)
  5575. {
  5576. $sorted_rows = [0 => []];
  5577. if (!empty($rows)) {
  5578. foreach ($rows as $row) {
  5579. $rows_with_children[$row['post_id']] = $row;
  5580. $rows_with_children[$row['post_parent_id']]['children'][] = $row['post_id'];
  5581. }
  5582. $rows = $rows_with_children;
  5583. forumRecursiveSort($rows, $sorted_rows);
  5584. unset($sorted_rows[0]);
  5585. }
  5586. return $sorted_rows;
  5587. }
  5588. /**
  5589. * @param $rows
  5590. * @param $threads
  5591. * @param int $seed
  5592. * @param int $indent
  5593. */
  5594. function forumRecursiveSort($rows, &$threads, $seed = 0, $indent = 0)
  5595. {
  5596. if ($seed > 0) {
  5597. $threads[$rows[$seed]['post_id']] = $rows[$seed];
  5598. $threads[$rows[$seed]['post_id']]['indent_cnt'] = $indent;
  5599. $indent++;
  5600. }
  5601. if (isset($rows[$seed]['children'])) {
  5602. foreach ($rows[$seed]['children'] as $child) {
  5603. forumRecursiveSort($rows, $threads, $child, $indent);
  5604. }
  5605. }
  5606. }
  5607. /**
  5608. * Update forum attachment data, used to update comment and post ID.
  5609. *
  5610. * @param $array array (field => value) to update forum attachment row
  5611. * @param $id attach ID to find row to update
  5612. * @param null $courseId course ID to find row to update
  5613. *
  5614. * @return int number of affected rows
  5615. */
  5616. function editAttachedFile($array, $id, $courseId = null)
  5617. {
  5618. // Init variables
  5619. $setString = '';
  5620. $id = (int) $id;
  5621. $courseId = (int) $courseId;
  5622. if (empty($courseId)) {
  5623. // $courseId can be null, use api method
  5624. $courseId = api_get_course_int_id();
  5625. }
  5626. /*
  5627. * Check if Attachment ID and Course ID are greater than zero
  5628. * and array of field values is not empty
  5629. */
  5630. if ($id > 0 && $courseId > 0 && !empty($array) && is_array($array)) {
  5631. foreach ($array as $key => &$item) {
  5632. $item = Database::escape_string($item);
  5633. $setString .= $key.' = "'.$item.'", ';
  5634. }
  5635. // Delete last comma
  5636. $setString = substr($setString, 0, strlen($setString) - 2);
  5637. $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
  5638. $sql = "UPDATE $forumAttachmentTable
  5639. SET $setString WHERE c_id = $courseId AND id = $id";
  5640. $result = Database::query($sql);
  5641. if ($result !== false) {
  5642. $affectedRows = Database::affected_rows($result);
  5643. if ($affectedRows > 0) {
  5644. /*
  5645. * If exist in $_SESSION variable, then delete them from it
  5646. * because they would be deprecated
  5647. */
  5648. if (!empty($_SESSION['forum']['upload_file'][$courseId][$id])) {
  5649. unset($_SESSION['forum']['upload_file'][$courseId][$id]);
  5650. }
  5651. }
  5652. return $affectedRows;
  5653. }
  5654. }
  5655. return 0;
  5656. }
  5657. /**
  5658. * Return a table where the attachments will be set.
  5659. *
  5660. * @param int $postId Forum Post ID
  5661. *
  5662. * @return string The Forum Attachments Ajax Table
  5663. */
  5664. function getAttachmentsAjaxTable($postId = 0)
  5665. {
  5666. $postId = (int) $postId;
  5667. $courseId = api_get_course_int_id();
  5668. $attachIds = getAttachmentIdsByPostId($postId, $courseId);
  5669. $fileDataContent = '';
  5670. // Update comment to show if form did not pass validation
  5671. if (!empty($_REQUEST['file_ids']) && is_array($_REQUEST['file_ids'])) {
  5672. // 'file_ids is the name from forum attachment ajax form
  5673. foreach ($_REQUEST['file_ids'] as $key => $attachId) {
  5674. if (!empty($_SESSION['forum']['upload_file'][$courseId][$attachId]) &&
  5675. is_array($_SESSION['forum']['upload_file'][$courseId][$attachId])
  5676. ) {
  5677. // If exist forum attachment then update into $_SESSION data
  5678. $_SESSION['forum']['upload_file'][$courseId][$attachId]['comment'] = $_POST['file_comments'][$key];
  5679. }
  5680. }
  5681. }
  5682. // Get data to fill into attachment files table
  5683. if (!empty($_SESSION['forum']['upload_file'][$courseId]) &&
  5684. is_array($_SESSION['forum']['upload_file'][$courseId])
  5685. ) {
  5686. $uploadedFiles = $_SESSION['forum']['upload_file'][$courseId];
  5687. foreach ($uploadedFiles as $k => $uploadedFile) {
  5688. if (!empty($uploadedFile) && in_array($uploadedFile['id'], $attachIds)) {
  5689. // Buil html table including an input with attachmentID
  5690. $fileDataContent .= '<tr id="'.$uploadedFile['id'].'" ><td>'.$uploadedFile['name'].'</td><td>'.$uploadedFile['size'].'</td><td>&nbsp;'.$uploadedFile['result'].
  5691. ' </td><td> <input style="width:90%;" type="text" value="'.$uploadedFile['comment'].'" name="file_comments[]"> </td><td>'.
  5692. $uploadedFile['delete'].'</td>'.
  5693. '<input type="hidden" value="'.$uploadedFile['id'].'" name="file_ids[]">'.'</tr>';
  5694. } else {
  5695. /*
  5696. * If attachment data is empty, then delete it from $_SESSION
  5697. * because could generate and empty row into html table
  5698. */
  5699. unset($_SESSION['forum']['upload_file'][$courseId][$k]);
  5700. }
  5701. }
  5702. }
  5703. $style = empty($fileDataContent) ? 'display: none;' : '';
  5704. // Forum attachment Ajax table
  5705. $fileData = '
  5706. <div class="control-group " style="'.$style.'">
  5707. <label class="control-label">'.get_lang('Attachments list').'</label>
  5708. <div class="controls">
  5709. <table id="attachmentFileList" class="files data_table span10">
  5710. <tr>
  5711. <th>'.get_lang('Filename').'</th>
  5712. <th>'.get_lang('Size').'</th>
  5713. <th>'.get_lang('Status').'</th>
  5714. <th>'.get_lang('Comment').'</th>
  5715. <th>'.get_lang('Delete').'</th>
  5716. </tr>
  5717. '.$fileDataContent.'
  5718. </table>
  5719. </div>
  5720. </div>';
  5721. return $fileData;
  5722. }
  5723. /**
  5724. * Return an array of prepared attachment data to build forum attachment table
  5725. * Also, save this array into $_SESSION to do available the attachment data.
  5726. *
  5727. * @param int $forumId
  5728. * @param int $threadId
  5729. * @param int $postId
  5730. * @param int $attachId
  5731. * @param int $courseId
  5732. *
  5733. * @return array
  5734. */
  5735. function getAttachedFiles(
  5736. $forumId,
  5737. $threadId,
  5738. $postId = 0,
  5739. $attachId = 0,
  5740. $courseId = 0
  5741. ) {
  5742. $forumId = (int) $forumId;
  5743. $courseId = (int) $courseId;
  5744. $attachId = (int) $attachId;
  5745. $postId = (int) $postId;
  5746. $threadId = !empty($threadId) ? intval($threadId) : isset($_REQUEST['thread']) ? intval($_REQUEST['thread']) : '';
  5747. if (empty($courseId)) {
  5748. // $courseId can be null, use api method
  5749. $courseId = api_get_course_int_id();
  5750. }
  5751. if (empty($forumId)) {
  5752. if (!empty($_REQUEST['forum'])) {
  5753. $forumId = (int) $_REQUEST['forum'];
  5754. } else {
  5755. // if forum ID is empty, cannot generate delete url
  5756. return [];
  5757. }
  5758. }
  5759. // Check if exist at least one of them to filter forum attachment select query
  5760. if (empty($postId) && empty($attachId)) {
  5761. return [];
  5762. } elseif (empty($postId)) {
  5763. $filter = "AND iid = $attachId";
  5764. } elseif (empty($attachId)) {
  5765. $filter = "AND post_id = $postId";
  5766. } else {
  5767. $filter = "AND post_id = $postId AND iid = $attachId";
  5768. }
  5769. $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
  5770. $sql = "SELECT iid, comment, filename, path, size
  5771. FROM $forumAttachmentTable
  5772. WHERE c_id = $courseId $filter";
  5773. $result = Database::query($sql);
  5774. $json = [];
  5775. if ($result !== false && Database::num_rows($result) > 0) {
  5776. while ($row = Database::fetch_array($result, 'ASSOC')) {
  5777. // name contains an URL to download attachment file and its filename
  5778. $json['name'] = Display::url(
  5779. api_htmlentities($row['filename']),
  5780. api_get_path(WEB_CODE_PATH).'forum/download.php?file='.$row['path'].'&'.api_get_cidreq(),
  5781. ['target' => '_blank', 'class' => 'attachFilename']
  5782. );
  5783. $json['id'] = $row['iid'];
  5784. $json['comment'] = $row['comment'];
  5785. // Format file size
  5786. $json['size'] = format_file_size($row['size']);
  5787. // Check if $row is consistent
  5788. if (!empty($row) && is_array($row)) {
  5789. // Set result as success and bring delete URL
  5790. $json['result'] = Display::return_icon('accept.png', get_lang('Uploaded.'));
  5791. $url = api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.api_get_cidreq().'&action=delete_attach&forum='.$forumId.'&thread='.$threadId.'&id_attach='.$row['iid'];
  5792. $json['delete'] = Display::url(
  5793. Display::return_icon('delete.png', get_lang('Delete'), [], ICON_SIZE_SMALL),
  5794. $url,
  5795. ['class' => 'deleteLink']
  5796. );
  5797. } else {
  5798. // If not, set an exclamation result
  5799. $json['result'] = Display::return_icon('exclamation.png', get_lang('Error'));
  5800. }
  5801. // Store array data into $_SESSION
  5802. $_SESSION['forum']['upload_file'][$courseId][$json['id']] = $json;
  5803. }
  5804. }
  5805. return $json;
  5806. }
  5807. /**
  5808. * Clear forum attachment data stored in $_SESSION,
  5809. * If is not defined post, it will clear all forum attachment data from course.
  5810. *
  5811. * @param int $postId -1 : Clear all attachments from course stored in $_SESSION
  5812. * 0 : Clear attachments from course, except from temporal post "0"
  5813. * but without delete them from file system and database
  5814. * Other values : Clear attachments from course except specified post
  5815. * and delete them from file system and database
  5816. * @param int $courseId : Course ID, if it is null, will use api_get_course_int_id()
  5817. *
  5818. * @return array
  5819. */
  5820. function clearAttachedFiles($postId = 0, $courseId = 0)
  5821. {
  5822. // Init variables
  5823. $courseId = (int) $courseId;
  5824. $postId = (int) $postId;
  5825. $array = [];
  5826. if (empty($courseId)) {
  5827. // $courseId can be null, use api method
  5828. $courseId = api_get_course_int_id();
  5829. }
  5830. if ($postId === -1) {
  5831. // If post ID is -1 then delete course's attachment data from $_SESSION
  5832. if (!empty($_SESSION['forum']['upload_file'][$courseId])) {
  5833. $array = array_keys($_SESSION['forum']['upload_file'][$courseId]);
  5834. unset($_SESSION['forum']['upload_file'][$courseId]);
  5835. }
  5836. } else {
  5837. $attachIds = getAttachmentIdsByPostId($postId, $courseId);
  5838. if (!empty($_SESSION['forum']['upload_file'][$courseId]) &&
  5839. is_array($_SESSION['forum']['upload_file'][$courseId])) {
  5840. foreach ($_SESSION['forum']['upload_file'][$courseId] as $attachId => $attach) {
  5841. if (!in_array($attachId, $attachIds)) {
  5842. // If attach ID is not into specified post, delete attachment
  5843. // Save deleted attachment ID
  5844. $array[] = $attachId;
  5845. if ($postId !== 0) {
  5846. // Post 0 is temporal, delete them from file system and DB
  5847. delete_attachment(0, $attachId);
  5848. }
  5849. // Delete attachment data from $_SESSION
  5850. unset($_SESSION['forum']['upload_file'][$courseId][$attachId]);
  5851. }
  5852. }
  5853. }
  5854. }
  5855. return $array;
  5856. }
  5857. /**
  5858. * Returns an array of forum attachment ids into a course and forum post.
  5859. *
  5860. * @param int $postId
  5861. * @param int $courseId
  5862. *
  5863. * @return array
  5864. */
  5865. function getAttachmentIdsByPostId($postId, $courseId = 0)
  5866. {
  5867. $array = [];
  5868. $courseId = (int) $courseId;
  5869. $postId = (int) $postId;
  5870. if (empty($courseId)) {
  5871. // $courseId can be null, use api method
  5872. $courseId = api_get_course_int_id();
  5873. }
  5874. if ($courseId > 0) {
  5875. $forumAttachmentTable = Database::get_course_table(TABLE_FORUM_ATTACHMENT);
  5876. $sql = "SELECT id FROM $forumAttachmentTable
  5877. WHERE c_id = $courseId AND post_id = $postId";
  5878. $result = Database::query($sql);
  5879. if ($result !== false && Database::num_rows($result) > 0) {
  5880. while ($row = Database::fetch_array($result, 'ASSOC')) {
  5881. $array[] = $row['id'];
  5882. }
  5883. }
  5884. }
  5885. return $array;
  5886. }
  5887. /**
  5888. * Check if the forum category exists looking for its title.
  5889. *
  5890. * @param string $title The forum category title
  5891. * @param int $courseId The course ID
  5892. * @param int $sessionId Optional. The session ID
  5893. *
  5894. * @return bool
  5895. */
  5896. function getForumCategoryByTitle($title, $courseId, $sessionId = 0)
  5897. {
  5898. $sessionId = (int) $sessionId;
  5899. $courseId = (int) $courseId;
  5900. $forumCategoryTable = Database::get_course_table(TABLE_FORUM_CATEGORY);
  5901. $itemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
  5902. $fakeFrom = "$forumCategoryTable fc
  5903. INNER JOIN $itemProperty ip ";
  5904. if ($sessionId === 0) {
  5905. $fakeFrom .= "
  5906. ON (
  5907. fc.cat_id = ip.ref AND fc.c_id = ip.c_id AND (fc.session_id = ip.session_id OR ip.session_id IS NULL)
  5908. )
  5909. ";
  5910. } else {
  5911. $fakeFrom .= "
  5912. ON (
  5913. fc.cat_id = ip.ref AND fc.c_id = ip.c_id AND fc.session_id = ip.session_id
  5914. )
  5915. ";
  5916. }
  5917. $resultData = Database::select(
  5918. 'fc.*',
  5919. $fakeFrom,
  5920. [
  5921. 'where' => [
  5922. 'ip.visibility != ? AND ' => 2,
  5923. 'ip.tool = ? AND ' => TOOL_FORUM_CATEGORY,
  5924. 'fc.session_id = ? AND ' => $sessionId,
  5925. 'fc.cat_title = ? AND ' => $title,
  5926. 'fc.c_id = ?' => $courseId,
  5927. ],
  5928. ],
  5929. 'first'
  5930. );
  5931. if (empty($resultData)) {
  5932. return false;
  5933. }
  5934. return $resultData;
  5935. }
  5936. /**
  5937. * @param array $current_forum
  5938. * @param array $row
  5939. * @param bool $addWrapper
  5940. *
  5941. * @return string
  5942. */
  5943. function getPostStatus($current_forum, $row, $addWrapper = true)
  5944. {
  5945. $statusIcon = '';
  5946. if ($current_forum['moderated']) {
  5947. if ($addWrapper) {
  5948. $statusIcon = '<br /><br /><span id="status_post_'.$row['iid'].'">';
  5949. }
  5950. $row['status'] = empty($row['status']) ? 2 : $row['status'];
  5951. $addUrl = false;
  5952. $showStatus = false;
  5953. if (api_is_allowed_to_edit(false, true)) {
  5954. $addUrl = true;
  5955. } else {
  5956. if ($row['user_id'] == api_get_user_id()) {
  5957. $showStatus = true;
  5958. }
  5959. }
  5960. $label = '';
  5961. $icon = '';
  5962. $buttonType = '';
  5963. switch ($row['status']) {
  5964. case CForumPost::STATUS_VALIDATED:
  5965. $label = get_lang('Validated');
  5966. $icon = 'check-circle';
  5967. $buttonType = 'success';
  5968. break;
  5969. case CForumPost::STATUS_WAITING_MODERATION:
  5970. $label = get_lang('Waiting for moderation');
  5971. $icon = 'warning';
  5972. $buttonType = 'warning';
  5973. break;
  5974. case CForumPost::STATUS_REJECTED:
  5975. $label = get_lang('Rejected');
  5976. $icon = 'minus-circle';
  5977. $buttonType = 'danger';
  5978. break;
  5979. }
  5980. if ($addUrl) {
  5981. $statusIcon .= Display::toolbarButton(
  5982. $label.'&nbsp;',
  5983. 'javascript:void(0)',
  5984. $icon,
  5985. $buttonType,
  5986. ['class' => 'change_post_status']
  5987. );
  5988. } else {
  5989. if ($showStatus) {
  5990. $statusIcon .= Display::label(
  5991. Display::returnFontAwesomeIcon($icon).$label,
  5992. $buttonType
  5993. );
  5994. }
  5995. }
  5996. if ($addWrapper) {
  5997. $statusIcon .= '</span>';
  5998. }
  5999. }
  6000. return $statusIcon;
  6001. }
  6002. /**
  6003. * @param array $forumInfo
  6004. * @param int $threadId
  6005. * @param int $status
  6006. *
  6007. * @return mixed
  6008. */
  6009. function getCountPostsWithStatus($status, $forumInfo, $threadId = null)
  6010. {
  6011. $em = Database::getManager();
  6012. $criteria = Criteria::create();
  6013. $criteria
  6014. ->where(Criteria::expr()->eq('status', $status))
  6015. ->andWhere(Criteria::expr()->eq('cId', $forumInfo['c_id']))
  6016. ->andWhere(Criteria::expr()->eq('visible', 1))
  6017. ;
  6018. if (!empty($threadId)) {
  6019. $criteria->andWhere(Criteria::expr()->eq('threadId', $threadId));
  6020. }
  6021. $qb = $em->getRepository('ChamiloCourseBundle:CForumPost')->createQueryBuilder('p');
  6022. $qb->select('count(p.iid)')
  6023. ->addCriteria($criteria);
  6024. return $qb->getQuery()->getSingleScalarResult();
  6025. }
  6026. /**
  6027. * @param array $forum
  6028. * @param array $post
  6029. *
  6030. * @return bool
  6031. */
  6032. function postIsEditableByStudent($forum, $post)
  6033. {
  6034. if (api_is_platform_admin() || api_is_allowed_to_edit()) {
  6035. return true;
  6036. }
  6037. if ($forum['moderated'] == 1) {
  6038. if (is_null($post['status'])) {
  6039. return true;
  6040. } else {
  6041. return in_array(
  6042. $post['status'],
  6043. [
  6044. CForumPost::STATUS_WAITING_MODERATION,
  6045. CForumPost::STATUS_REJECTED,
  6046. ]
  6047. );
  6048. }
  6049. } else {
  6050. return true;
  6051. }
  6052. }
  6053. /**
  6054. * @param int $postId
  6055. *
  6056. * @return bool
  6057. */
  6058. function savePostRevision($postId)
  6059. {
  6060. $postData = get_post_information($postId);
  6061. if (empty($postData)) {
  6062. return false;
  6063. }
  6064. $userId = api_get_user_id();
  6065. if ($postData['poster_id'] != $userId) {
  6066. return false;
  6067. }
  6068. $status = (int) !postNeedsRevision($postId);
  6069. $extraFieldValue = new ExtraFieldValue('forum_post');
  6070. $params = [
  6071. 'item_id' => $postId,
  6072. 'extra_ask_for_revision' => ['extra_ask_for_revision' => $status],
  6073. ];
  6074. if (empty($status)) {
  6075. unset($params['extra_ask_for_revision']);
  6076. }
  6077. $extraFieldValue->saveFieldValues(
  6078. $params,
  6079. true,
  6080. false,
  6081. ['ask_for_revision']
  6082. );
  6083. }
  6084. /**
  6085. * @param int $postId
  6086. *
  6087. * @return string
  6088. */
  6089. function getPostRevision($postId)
  6090. {
  6091. $extraFieldValue = new ExtraFieldValue('forum_post');
  6092. $value = $extraFieldValue->get_values_by_handler_and_field_variable(
  6093. $postId,
  6094. 'revision_language'
  6095. );
  6096. $revision = '';
  6097. if ($value && isset($value['value'])) {
  6098. $revision = $value['value'];
  6099. }
  6100. return $revision;
  6101. }
  6102. /**
  6103. * @param int $postId
  6104. *
  6105. * @return bool
  6106. */
  6107. function postNeedsRevision($postId)
  6108. {
  6109. $extraFieldValue = new ExtraFieldValue('forum_post');
  6110. $value = $extraFieldValue->get_values_by_handler_and_field_variable(
  6111. $postId,
  6112. 'ask_for_revision'
  6113. );
  6114. $hasRevision = false;
  6115. if ($value && isset($value['value'])) {
  6116. return $value['value'] == 1;
  6117. }
  6118. return $hasRevision;
  6119. }
  6120. /**
  6121. * @param int $postId
  6122. * @param array $threadInfo
  6123. *
  6124. * @return string
  6125. */
  6126. function getAskRevisionButton($postId, $threadInfo)
  6127. {
  6128. if (api_get_configuration_value('allow_forum_post_revisions') === false) {
  6129. return '';
  6130. }
  6131. $postId = (int) $postId;
  6132. $status = 'btn-default';
  6133. if (postNeedsRevision($postId)) {
  6134. $status = 'btn-success';
  6135. }
  6136. return Display::url(
  6137. get_lang('Ask for a revision'),
  6138. api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.
  6139. api_get_cidreq().'&action=ask_revision&post_id='.$postId.'&forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'],
  6140. ['class' => "btn $status", 'title' => get_lang('Ask for a revision')]
  6141. );
  6142. }
  6143. /**
  6144. * @param int $postId
  6145. * @param array $threadInfo
  6146. *
  6147. * @return string
  6148. */
  6149. function giveRevisionButton($postId, $threadInfo)
  6150. {
  6151. $postId = (int) $postId;
  6152. return Display::toolbarButton(
  6153. get_lang('Give revision'),
  6154. api_get_path(WEB_CODE_PATH).'forum/reply.php?'.api_get_cidreq().'&'.http_build_query(
  6155. [
  6156. 'forum' => $threadInfo['forum_id'],
  6157. 'thread' => $threadInfo['thread_id'],
  6158. 'post' => $postId = (int) $postId,
  6159. 'action' => 'replymessage',
  6160. 'give_revision' => 1,
  6161. ]
  6162. ),
  6163. 'reply',
  6164. 'primary',
  6165. ['id' => "reply-to-post-{$postId}"]
  6166. );
  6167. }
  6168. /**
  6169. * @param int $postId
  6170. * @param array $threadInfo
  6171. *
  6172. * @return string
  6173. */
  6174. function getReportButton($postId, $threadInfo)
  6175. {
  6176. $postId = (int) $postId;
  6177. return Display::url(
  6178. Display::returnFontAwesomeIcon('flag'),
  6179. api_get_path(WEB_CODE_PATH).'forum/viewthread.php?'.
  6180. api_get_cidreq().'&action=report&post_id='.$postId.'&forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'],
  6181. ['class' => 'btn btn-danger', 'title' => get_lang('Report')]
  6182. );
  6183. }
  6184. /**
  6185. * @return bool
  6186. */
  6187. function reportAvailable()
  6188. {
  6189. $extraFieldValue = new ExtraFieldValue('course');
  6190. $value = $extraFieldValue->get_values_by_handler_and_field_variable(
  6191. api_get_course_int_id(),
  6192. 'allow_forum_report_button'
  6193. );
  6194. $allowReport = false;
  6195. if ($value && isset($value['value']) && $value['value'] == 1) {
  6196. $allowReport = true;
  6197. }
  6198. return $allowReport;
  6199. }
  6200. /**
  6201. * @return array
  6202. */
  6203. function getReportRecipients()
  6204. {
  6205. $extraFieldValue = new ExtraFieldValue('course');
  6206. $value = $extraFieldValue->get_values_by_handler_and_field_variable(
  6207. api_get_course_int_id(),
  6208. 'forum_report_recipients'
  6209. );
  6210. $users = [];
  6211. if ($value && isset($value['value'])) {
  6212. $usersType = explode(';', $value['value']);
  6213. foreach ($usersType as $type) {
  6214. switch ($type) {
  6215. case 'teachers':
  6216. $teachers = CourseManager::get_teacher_list_from_course_code(api_get_course_id());
  6217. if (!empty($teachers)) {
  6218. $users = array_merge($users, array_column($teachers, 'user_id'));
  6219. }
  6220. break;
  6221. case 'admins':
  6222. $admins = UserManager::get_all_administrators();
  6223. if (!empty($admins)) {
  6224. $users = array_merge($users, array_column($admins, 'user_id'));
  6225. }
  6226. break;
  6227. case 'community_managers':
  6228. $managers = api_get_configuration_value('community_managers_user_list');
  6229. if (!empty($managers) && isset($managers['users'])) {
  6230. $users = array_merge($users, $managers['users']);
  6231. }
  6232. break;
  6233. }
  6234. }
  6235. $users = array_unique(array_filter($users));
  6236. }
  6237. return $users;
  6238. }
  6239. /**
  6240. * @param int $postId
  6241. * @param array $forumInfo
  6242. * @param array $threadInfo
  6243. *
  6244. * @return bool
  6245. */
  6246. function reportPost($postId, $forumInfo, $threadInfo)
  6247. {
  6248. if (!reportAvailable()) {
  6249. return false;
  6250. }
  6251. if (empty($forumInfo) || empty($threadInfo)) {
  6252. return false;
  6253. }
  6254. $postId = (int) $postId;
  6255. $postData = get_post_information($postId);
  6256. $currentUser = api_get_user_info();
  6257. if (!empty($postData)) {
  6258. $users = getReportRecipients();
  6259. if (!empty($users)) {
  6260. $url = api_get_path(WEB_CODE_PATH).
  6261. 'forum/viewthread.php?forum='.$threadInfo['forum_id'].'&thread='.$threadInfo['thread_id'].'&'.api_get_cidreq().'&post_id='.$postId.'#post_id_'.$postId;
  6262. $postLink = Display::url(
  6263. $postData['post_title'],
  6264. $url
  6265. );
  6266. $subject = get_lang('Post reported');
  6267. $content = sprintf(
  6268. get_lang('User %s has reported the message %s in the forum %s'),
  6269. $currentUser['complete_name'],
  6270. $postLink,
  6271. $forumInfo['forum_title']
  6272. );
  6273. foreach ($users as $userId) {
  6274. MessageManager::send_message_simple($userId, $subject, $content);
  6275. }
  6276. }
  6277. }
  6278. }