forumfunction.inc.php 245 KB

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