forumfunction.inc.php 244 KB

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