summaryrefslogtreecommitdiff
path: root/src/application
diff options
context:
space:
mode:
Diffstat (limited to 'src/application')
-rw-r--r--src/application/assets/mimetypes771
-rw-r--r--src/application/assets/user-fallback.jpgbin0 -> 812 bytes
-rw-r--r--src/application/fetch-mime-types.php22
-rw-r--r--src/application/mystic/forum/orm/User.php3
-rw-r--r--src/application/mystic/forum/utils/FileUtils.php33
-rw-r--r--src/application/mystic/forum/utils/RequestUtils.php7
-rw-r--r--src/application/mystic/forum/utils/StringUtils.php4
-rw-r--r--src/application/views/form_addpost.php2
-rw-r--r--src/application/views/form_delete_post_confirm.php17
-rw-r--r--src/application/views/form_login.php2
-rw-r--r--src/application/views/template_end.php8
-rw-r--r--src/application/views/template_start.php4
-rw-r--r--src/application/views/view_post.php53
-rw-r--r--src/application/views/view_topic_start.php28
-rw-r--r--src/application/views/view_user.php154
15 files changed, 1069 insertions, 39 deletions
diff --git a/src/application/assets/mimetypes b/src/application/assets/mimetypes
new file mode 100644
index 0000000..5440824
--- /dev/null
+++ b/src/application/assets/mimetypes
@@ -0,0 +1,771 @@
+application/andrew-inset ez
+application/applixware aw
+application/atom+xml atom
+application/atomcat+xml atomcat
+application/atomsvc+xml atomsvc
+application/ccxml+xml ccxml
+application/cdmi-capability cdmia
+application/cdmi-container cdmic
+application/cdmi-domain cdmid
+application/cdmi-object cdmio
+application/cdmi-queue cdmiq
+application/cu-seeme cu
+application/davmount+xml davmount
+application/docbook+xml dbk
+application/dssc+der dssc
+application/dssc+xml xdssc
+application/ecmascript ecma
+application/emma+xml emma
+application/epub+zip epub
+application/exi exi
+application/font-tdpfr pfr
+application/gml+xml gml
+application/gpx+xml gpx
+application/gxf gxf
+application/hyperstudio stk
+application/inkml+xml ink inkml
+application/ipfix ipfix
+application/java-archive jar
+application/java-serialized-object ser
+application/java-vm class
+application/json json
+application/jsonml+json jsonml
+application/lost+xml lostxml
+application/mac-binhex40 hqx
+application/mac-compactpro cpt
+application/mads+xml mads
+application/marc mrc
+application/marcxml+xml mrcx
+application/mathematica ma nb mb
+application/mathml+xml mathml
+application/mbox mbox
+application/mediaservercontrol+xml mscml
+application/metalink+xml metalink
+application/metalink4+xml meta4
+application/mets+xml mets
+application/mods+xml mods
+application/mp21 m21 mp21
+application/mp4 mp4s
+application/msword doc dot
+application/mxf mxf
+application/octet-stream bin dms lrf mar so dist distz pkg bpk dump elc deploy
+application/oda oda
+application/oebps-package+xml opf
+application/ogg ogx
+application/omdoc+xml omdoc
+application/onenote onetoc onetoc2 onetmp onepkg
+application/oxps oxps
+application/patch-ops-error+xml xer
+application/pdf pdf
+application/pgp-encrypted pgp
+application/pgp-signature asc sig
+application/pics-rules prf
+application/pkcs10 p10
+application/pkcs7-mime p7m p7c
+application/pkcs7-signature p7s
+application/pkcs8 p8
+application/pkix-attr-cert ac
+application/pkix-cert cer
+application/pkix-crl crl
+application/pkix-pkipath pkipath
+application/pkixcmp pki
+application/pls+xml pls
+application/postscript ai eps ps
+application/prs.cww cww
+application/pskc+xml pskcxml
+application/rdf+xml rdf
+application/reginfo+xml rif
+application/relax-ng-compact-syntax rnc
+application/resource-lists+xml rl
+application/resource-lists-diff+xml rld
+application/rls-services+xml rs
+application/rpki-ghostbusters gbr
+application/rpki-manifest mft
+application/rpki-roa roa
+application/rsd+xml rsd
+application/rss+xml rss
+application/rtf rtf
+application/sbml+xml sbml
+application/scvp-cv-request scq
+application/scvp-cv-response scs
+application/scvp-vp-request spq
+application/scvp-vp-response spp
+application/sdp sdp
+application/set-payment-initiation setpay
+application/set-registration-initiation setreg
+application/shf+xml shf
+application/smil+xml smi smil
+application/sparql-query rq
+application/sparql-results+xml srx
+application/srgs gram
+application/srgs+xml grxml
+application/sru+xml sru
+application/ssdl+xml ssdl
+application/ssml+xml ssml
+application/tei+xml tei teicorpus
+application/thraud+xml tfi
+application/timestamped-data tsd
+application/vnd.3gpp.pic-bw-large plb
+application/vnd.3gpp.pic-bw-small psb
+application/vnd.3gpp.pic-bw-var pvb
+application/vnd.3gpp2.tcap tcap
+application/vnd.3m.post-it-notes pwn
+application/vnd.accpac.simply.aso aso
+application/vnd.accpac.simply.imp imp
+application/vnd.acucobol acu
+application/vnd.acucorp atc acutc
+application/vnd.adobe.air-application-installer-package+zip air
+application/vnd.adobe.formscentral.fcdt fcdt
+application/vnd.adobe.fxp fxp fxpl
+application/vnd.adobe.xdp+xml xdp
+application/vnd.adobe.xfdf xfdf
+application/vnd.ahead.space ahead
+application/vnd.airzip.filesecure.azf azf
+application/vnd.airzip.filesecure.azs azs
+application/vnd.amazon.ebook azw
+application/vnd.americandynamics.acc acc
+application/vnd.amiga.ami ami
+application/vnd.android.package-archive apk
+application/vnd.anser-web-certificate-issue-initiation cii
+application/vnd.anser-web-funds-transfer-initiation fti
+application/vnd.antix.game-component atx
+application/vnd.apple.installer+xml mpkg
+application/vnd.apple.mpegurl m3u8
+application/vnd.aristanetworks.swi swi
+application/vnd.astraea-software.iota iota
+application/vnd.audiograph aep
+application/vnd.blueice.multipass mpm
+application/vnd.bmi bmi
+application/vnd.businessobjects rep
+application/vnd.chemdraw+xml cdxml
+application/vnd.chipnuts.karaoke-mmd mmd
+application/vnd.cinderella cdy
+application/vnd.claymore cla
+application/vnd.cloanto.rp9 rp9
+application/vnd.clonk.c4group c4g c4d c4f c4p c4u
+application/vnd.cluetrust.cartomobile-config c11amc
+application/vnd.cluetrust.cartomobile-config-pkg c11amz
+application/vnd.commonspace csp
+application/vnd.contact.cmsg cdbcmsg
+application/vnd.cosmocaller cmc
+application/vnd.crick.clicker clkx
+application/vnd.crick.clicker.keyboard clkk
+application/vnd.crick.clicker.palette clkp
+application/vnd.crick.clicker.template clkt
+application/vnd.crick.clicker.wordbank clkw
+application/vnd.criticaltools.wbs+xml wbs
+application/vnd.ctc-posml pml
+application/vnd.cups-ppd ppd
+application/vnd.curl.car car
+application/vnd.curl.pcurl pcurl
+application/vnd.dart dart
+application/vnd.data-vision.rdz rdz
+application/vnd.dece.data uvf uvvf uvd uvvd
+application/vnd.dece.ttml+xml uvt uvvt
+application/vnd.dece.unspecified uvx uvvx
+application/vnd.dece.zip uvz uvvz
+application/vnd.denovo.fcselayout-link fe_launch
+application/vnd.dna dna
+application/vnd.dolby.mlp mlp
+application/vnd.dpgraph dpg
+application/vnd.dreamfactory dfac
+application/vnd.ds-keypoint kpxx
+application/vnd.dvb.ait ait
+application/vnd.dvb.service svc
+application/vnd.dynageo geo
+application/vnd.ecowin.chart mag
+application/vnd.enliven nml
+application/vnd.epson.esf esf
+application/vnd.epson.msf msf
+application/vnd.epson.quickanime qam
+application/vnd.epson.salt slt
+application/vnd.epson.ssf ssf
+application/vnd.eszigno3+xml es3 et3
+application/vnd.ezpix-album ez2
+application/vnd.ezpix-package ez3
+application/vnd.fdf fdf
+application/vnd.fdsn.mseed mseed
+application/vnd.fdsn.seed seed dataless
+application/vnd.flographit gph
+application/vnd.fluxtime.clip ftc
+application/vnd.framemaker fm frame maker book
+application/vnd.frogans.fnc fnc
+application/vnd.frogans.ltf ltf
+application/vnd.fsc.weblaunch fsc
+application/vnd.fujitsu.oasys oas
+application/vnd.fujitsu.oasys2 oa2
+application/vnd.fujitsu.oasys3 oa3
+application/vnd.fujitsu.oasysgp fg5
+application/vnd.fujitsu.oasysprs bh2
+application/vnd.fujixerox.ddd ddd
+application/vnd.fujixerox.docuworks xdw
+application/vnd.fujixerox.docuworks.binder xbd
+application/vnd.fuzzysheet fzs
+application/vnd.genomatix.tuxedo txd
+application/vnd.geogebra.file ggb
+application/vnd.geogebra.slides ggs
+application/vnd.geogebra.tool ggt
+application/vnd.geometry-explorer gex gre
+application/vnd.geonext gxt
+application/vnd.geoplan g2w
+application/vnd.geospace g3w
+application/vnd.gmx gmx
+application/vnd.google-earth.kml+xml kml
+application/vnd.google-earth.kmz kmz
+application/vnd.grafeq gqf gqs
+application/vnd.groove-account gac
+application/vnd.groove-help ghf
+application/vnd.groove-identity-message gim
+application/vnd.groove-injector grv
+application/vnd.groove-tool-message gtm
+application/vnd.groove-tool-template tpl
+application/vnd.groove-vcard vcg
+application/vnd.hal+xml hal
+application/vnd.handheld-entertainment+xml zmm
+application/vnd.hbci hbci
+application/vnd.hhe.lesson-player les
+application/vnd.hp-hpgl hpgl
+application/vnd.hp-hpid hpid
+application/vnd.hp-hps hps
+application/vnd.hp-jlyt jlt
+application/vnd.hp-pcl pcl
+application/vnd.hp-pclxl pclxl
+application/vnd.hydrostatix.sof-data sfd-hdstx
+application/vnd.ibm.minipay mpy
+application/vnd.ibm.modcap afp listafp list3820
+application/vnd.ibm.rights-management irm
+application/vnd.ibm.secure-container sc
+application/vnd.iccprofile icc icm
+application/vnd.igloader igl
+application/vnd.immervision-ivp ivp
+application/vnd.immervision-ivu ivu
+application/vnd.insors.igm igm
+application/vnd.intercon.formnet xpw xpx
+application/vnd.intergeo i2g
+application/vnd.intu.qbo qbo
+application/vnd.intu.qfx qfx
+application/vnd.ipunplugged.rcprofile rcprofile
+application/vnd.irepository.package+xml irp
+application/vnd.is-xpr xpr
+application/vnd.isac.fcs fcs
+application/vnd.jam jam
+application/vnd.jcp.javame.midlet-rms rms
+application/vnd.jisp jisp
+application/vnd.joost.joda-archive joda
+application/vnd.kahootz ktz ktr
+application/vnd.kde.karbon karbon
+application/vnd.kde.kchart chrt
+application/vnd.kde.kformula kfo
+application/vnd.kde.kivio flw
+application/vnd.kde.kontour kon
+application/vnd.kde.kpresenter kpr kpt
+application/vnd.kde.kspread ksp
+application/vnd.kde.kword kwd kwt
+application/vnd.kenameaapp htke
+application/vnd.kidspiration kia
+application/vnd.kinar kne knp
+application/vnd.koan skp skd skt skm
+application/vnd.kodak-descriptor sse
+application/vnd.las.las+xml lasxml
+application/vnd.llamagraphics.life-balance.desktop lbd
+application/vnd.llamagraphics.life-balance.exchange+xml lbe
+application/vnd.lotus-1-2-3 123
+application/vnd.lotus-approach apr
+application/vnd.lotus-freelance pre
+application/vnd.lotus-notes nsf
+application/vnd.lotus-organizer org
+application/vnd.lotus-screencam scm
+application/vnd.lotus-wordpro lwp
+application/vnd.macports.portpkg portpkg
+application/vnd.mcd mcd
+application/vnd.medcalcdata mc1
+application/vnd.mediastation.cdkey cdkey
+application/vnd.mfer mwf
+application/vnd.mfmp mfm
+application/vnd.micrografx.flo flo
+application/vnd.micrografx.igx igx
+application/vnd.mif mif
+application/vnd.mobius.daf daf
+application/vnd.mobius.dis dis
+application/vnd.mobius.mbk mbk
+application/vnd.mobius.mqy mqy
+application/vnd.mobius.msl msl
+application/vnd.mobius.plc plc
+application/vnd.mobius.txf txf
+application/vnd.mophun.application mpn
+application/vnd.mophun.certificate mpc
+application/vnd.mozilla.xul+xml xul
+application/vnd.ms-artgalry cil
+application/vnd.ms-cab-compressed cab
+application/vnd.ms-excel xls xlm xla xlc xlt xlw
+application/vnd.ms-excel.addin.macroenabled.12 xlam
+application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsb
+application/vnd.ms-excel.sheet.macroenabled.12 xlsm
+application/vnd.ms-excel.template.macroenabled.12 xltm
+application/vnd.ms-fontobject eot
+application/vnd.ms-htmlhelp chm
+application/vnd.ms-ims ims
+application/vnd.ms-lrm lrm
+application/vnd.ms-officetheme thmx
+application/vnd.ms-pki.seccat cat
+application/vnd.ms-pki.stl stl
+application/vnd.ms-powerpoint ppt pps pot
+application/vnd.ms-powerpoint.addin.macroenabled.12 ppam
+application/vnd.ms-powerpoint.presentation.macroenabled.12 pptm
+application/vnd.ms-powerpoint.slide.macroenabled.12 sldm
+application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsm
+application/vnd.ms-powerpoint.template.macroenabled.12 potm
+application/vnd.ms-project mpp mpt
+application/vnd.ms-word.document.macroenabled.12 docm
+application/vnd.ms-word.template.macroenabled.12 dotm
+application/vnd.ms-works wps wks wcm wdb
+application/vnd.ms-wpl wpl
+application/vnd.ms-xpsdocument xps
+application/vnd.mseq mseq
+application/vnd.musician mus
+application/vnd.muvee.style msty
+application/vnd.mynfc taglet
+application/vnd.neurolanguage.nlu nlu
+application/vnd.nitf ntf nitf
+application/vnd.noblenet-directory nnd
+application/vnd.noblenet-sealer nns
+application/vnd.noblenet-web nnw
+application/vnd.nokia.n-gage.data ngdat
+application/vnd.nokia.n-gage.symbian.install n-gage
+application/vnd.nokia.radio-preset rpst
+application/vnd.nokia.radio-presets rpss
+application/vnd.novadigm.edm edm
+application/vnd.novadigm.edx edx
+application/vnd.novadigm.ext ext
+application/vnd.oasis.opendocument.chart odc
+application/vnd.oasis.opendocument.chart-template otc
+application/vnd.oasis.opendocument.database odb
+application/vnd.oasis.opendocument.formula odf
+application/vnd.oasis.opendocument.formula-template odft
+application/vnd.oasis.opendocument.graphics odg
+application/vnd.oasis.opendocument.graphics-template otg
+application/vnd.oasis.opendocument.image odi
+application/vnd.oasis.opendocument.image-template oti
+application/vnd.oasis.opendocument.presentation odp
+application/vnd.oasis.opendocument.presentation-template otp
+application/vnd.oasis.opendocument.spreadsheet ods
+application/vnd.oasis.opendocument.spreadsheet-template ots
+application/vnd.oasis.opendocument.text odt
+application/vnd.oasis.opendocument.text-master odm
+application/vnd.oasis.opendocument.text-template ott
+application/vnd.oasis.opendocument.text-web oth
+application/vnd.olpc-sugar xo
+application/vnd.oma.dd2+xml dd2
+application/vnd.openofficeorg.extension oxt
+application/vnd.openxmlformats-officedocument.presentationml.presentation pptx
+application/vnd.openxmlformats-officedocument.presentationml.slide sldx
+application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx
+application/vnd.openxmlformats-officedocument.presentationml.template potx
+application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx
+application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx
+application/vnd.openxmlformats-officedocument.wordprocessingml.document docx
+application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx
+application/vnd.osgeo.mapguide.package mgp
+application/vnd.osgi.dp dp
+application/vnd.osgi.subsystem esa
+application/vnd.palm pdb pqa oprc
+application/vnd.pawaafile paw
+application/vnd.pg.format str
+application/vnd.pg.osasli ei6
+application/vnd.picsel efif
+application/vnd.pmi.widget wg
+application/vnd.pocketlearn plf
+application/vnd.powerbuilder6 pbd
+application/vnd.previewsystems.box box
+application/vnd.proteus.magazine mgz
+application/vnd.publishare-delta-tree qps
+application/vnd.pvi.ptid1 ptid
+application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb
+application/vnd.realvnc.bed bed
+application/vnd.recordare.musicxml mxl
+application/vnd.recordare.musicxml+xml musicxml
+application/vnd.rig.cryptonote cryptonote
+application/vnd.rim.cod cod
+application/vnd.rn-realmedia rm
+application/vnd.rn-realmedia-vbr rmvb
+application/vnd.route66.link66+xml link66
+application/vnd.sailingtracker.track st
+application/vnd.seemail see
+application/vnd.sema sema
+application/vnd.semd semd
+application/vnd.semf semf
+application/vnd.shana.informed.formdata ifm
+application/vnd.shana.informed.formtemplate itp
+application/vnd.shana.informed.interchange iif
+application/vnd.shana.informed.package ipk
+application/vnd.simtech-mindmapper twd twds
+application/vnd.smaf mmf
+application/vnd.smart.teacher teacher
+application/vnd.solent.sdkm+xml sdkm sdkd
+application/vnd.spotfire.dxp dxp
+application/vnd.spotfire.sfs sfs
+application/vnd.stardivision.calc sdc
+application/vnd.stardivision.draw sda
+application/vnd.stardivision.impress sdd
+application/vnd.stardivision.math smf
+application/vnd.stardivision.writer sdw vor
+application/vnd.stardivision.writer-global sgl
+application/vnd.stepmania.package smzip
+application/vnd.stepmania.stepchart sm
+application/vnd.sun.xml.calc sxc
+application/vnd.sun.xml.calc.template stc
+application/vnd.sun.xml.draw sxd
+application/vnd.sun.xml.draw.template std
+application/vnd.sun.xml.impress sxi
+application/vnd.sun.xml.impress.template sti
+application/vnd.sun.xml.math sxm
+application/vnd.sun.xml.writer sxw
+application/vnd.sun.xml.writer.global sxg
+application/vnd.sun.xml.writer.template stw
+application/vnd.sus-calendar sus susp
+application/vnd.svd svd
+application/vnd.symbian.install sis sisx
+application/vnd.syncml+xml xsm
+application/vnd.syncml.dm+wbxml bdm
+application/vnd.syncml.dm+xml xdm
+application/vnd.tao.intent-module-archive tao
+application/vnd.tcpdump.pcap pcap cap dmp
+application/vnd.tmobile-livetv tmo
+application/vnd.trid.tpt tpt
+application/vnd.triscape.mxs mxs
+application/vnd.trueapp tra
+application/vnd.ufdl ufd ufdl
+application/vnd.uiq.theme utz
+application/vnd.umajin umj
+application/vnd.unity unityweb
+application/vnd.uoml+xml uoml
+application/vnd.vcx vcx
+application/vnd.visio vsd vst vss vsw
+application/vnd.visionary vis
+application/vnd.vsf vsf
+application/vnd.wap.wbxml wbxml
+application/vnd.wap.wmlc wmlc
+application/vnd.wap.wmlscriptc wmlsc
+application/vnd.webturbo wtb
+application/vnd.wolfram.player nbp
+application/vnd.wordperfect wpd
+application/vnd.wqd wqd
+application/vnd.wt.stf stf
+application/vnd.xara xar
+application/vnd.xfdl xfdl
+application/vnd.yamaha.hv-dic hvd
+application/vnd.yamaha.hv-script hvs
+application/vnd.yamaha.hv-voice hvp
+application/vnd.yamaha.openscoreformat osf
+application/vnd.yamaha.openscoreformat.osfpvg+xml osfpvg
+application/vnd.yamaha.smaf-audio saf
+application/vnd.yamaha.smaf-phrase spf
+application/vnd.yellowriver-custom-menu cmp
+application/vnd.zul zir zirz
+application/vnd.zzazz.deck+xml zaz
+application/voicexml+xml vxml
+application/wasm wasm
+application/widget wgt
+application/winhlp hlp
+application/wsdl+xml wsdl
+application/wspolicy+xml wspolicy
+application/x-7z-compressed 7z
+application/x-abiword abw
+application/x-ace-compressed ace
+application/x-apple-diskimage dmg
+application/x-authorware-bin aab x32 u32 vox
+application/x-authorware-map aam
+application/x-authorware-seg aas
+application/x-bcpio bcpio
+application/x-bittorrent torrent
+application/x-blorb blb blorb
+application/x-bzip bz
+application/x-bzip2 bz2 boz
+application/x-cbr cbr cba cbt cbz cb7
+application/x-cdlink vcd
+application/x-cfs-compressed cfs
+application/x-chat chat
+application/x-chess-pgn pgn
+application/x-conference nsc
+application/x-cpio cpio
+application/x-csh csh
+application/x-debian-package deb udeb
+application/x-dgc-compressed dgc
+application/x-director dir dcr dxr cst cct cxt w3d fgd swa
+application/x-doom wad
+application/x-dtbncx+xml ncx
+application/x-dtbook+xml dtb
+application/x-dtbresource+xml res
+application/x-dvi dvi
+application/x-envoy evy
+application/x-eva eva
+application/x-font-bdf bdf
+application/x-font-ghostscript gsf
+application/x-font-linux-psf psf
+application/x-font-pcf pcf
+application/x-font-snf snf
+application/x-font-type1 pfa pfb pfm afm
+application/x-freearc arc
+application/x-futuresplash spl
+application/x-gca-compressed gca
+application/x-glulx ulx
+application/x-gnumeric gnumeric
+application/x-gramps-xml gramps
+application/x-gtar gtar
+application/x-hdf hdf
+application/x-install-instructions install
+application/x-iso9660-image iso
+application/x-java-jnlp-file jnlp
+application/x-latex latex
+application/x-lzh-compressed lzh lha
+application/x-mie mie
+application/x-mobipocket-ebook prc mobi
+application/x-ms-application application
+application/x-ms-shortcut lnk
+application/x-ms-wmd wmd
+application/x-ms-wmz wmz
+application/x-ms-xbap xbap
+application/x-msaccess mdb
+application/x-msbinder obd
+application/x-mscardfile crd
+application/x-msclip clp
+application/x-msdownload exe dll com bat msi
+application/x-msmediaview mvb m13 m14
+application/x-msmetafile wmf wmz emf emz
+application/x-msmoney mny
+application/x-mspublisher pub
+application/x-msschedule scd
+application/x-msterminal trm
+application/x-mswrite wri
+application/x-netcdf nc cdf
+application/x-nzb nzb
+application/x-pkcs12 p12 pfx
+application/x-pkcs7-certificates p7b spc
+application/x-pkcs7-certreqresp p7r
+application/x-rar-compressed rar
+application/x-research-info-systems ris
+application/x-sh sh
+application/x-shar shar
+application/x-shockwave-flash swf
+application/x-silverlight-app xap
+application/x-sql sql
+application/x-stuffit sit
+application/x-stuffitx sitx
+application/x-subrip srt
+application/x-sv4cpio sv4cpio
+application/x-sv4crc sv4crc
+application/x-t3vm-image t3
+application/x-tads gam
+application/x-tar tar
+application/x-tcl tcl
+application/x-tex tex
+application/x-tex-tfm tfm
+application/x-texinfo texinfo texi
+application/x-tgif obj
+application/x-ustar ustar
+application/x-wais-source src
+application/x-x509-ca-cert der crt
+application/x-xfig fig
+application/x-xliff+xml xlf
+application/x-xpinstall xpi
+application/x-xz xz
+application/x-zmachine z1 z2 z3 z4 z5 z6 z7 z8
+application/xaml+xml xaml
+application/xcap-diff+xml xdf
+application/xenc+xml xenc
+application/xhtml+xml xhtml xht
+application/xml xml xsl
+application/xml-dtd dtd
+application/xop+xml xop
+application/xproc+xml xpl
+application/xslt+xml xslt
+application/xspf+xml xspf
+application/xv+xml mxml xhvml xvml xvm
+application/yang yang
+application/yin+xml yin
+application/zip zip
+audio/adpcm adp
+audio/basic au snd
+audio/midi mid midi kar rmi
+audio/mp4 m4a mp4a
+audio/mpeg mpga mp2 mp2a mp3 m2a m3a
+audio/ogg oga ogg spx opus
+audio/s3m s3m
+audio/silk sil
+audio/vnd.dece.audio uva uvva
+audio/vnd.digital-winds eol
+audio/vnd.dra dra
+audio/vnd.dts dts
+audio/vnd.dts.hd dtshd
+audio/vnd.lucent.voice lvp
+audio/vnd.ms-playready.media.pya pya
+audio/vnd.nuera.ecelp4800 ecelp4800
+audio/vnd.nuera.ecelp7470 ecelp7470
+audio/vnd.nuera.ecelp9600 ecelp9600
+audio/vnd.rip rip
+audio/webm weba
+audio/x-aac aac
+audio/x-aiff aif aiff aifc
+audio/x-caf caf
+audio/x-flac flac
+audio/x-matroska mka
+audio/x-mpegurl m3u
+audio/x-ms-wax wax
+audio/x-ms-wma wma
+audio/x-pn-realaudio ram ra
+audio/x-pn-realaudio-plugin rmp
+audio/x-wav wav
+audio/xm xm
+chemical/x-cdx cdx
+chemical/x-cif cif
+chemical/x-cmdf cmdf
+chemical/x-cml cml
+chemical/x-csml csml
+chemical/x-xyz xyz
+font/collection ttc
+font/otf otf
+font/ttf ttf
+font/woff woff
+font/woff2 woff2
+image/avif avif
+image/bmp bmp
+image/cgm cgm
+image/g3fax g3
+image/gif gif
+image/ief ief
+image/jpeg jpeg jpg jpe
+image/jxl jxl
+image/ktx ktx
+image/png png
+image/prs.btif btif
+image/sgi sgi
+image/svg+xml svg svgz
+image/tiff tiff tif
+image/vnd.adobe.photoshop psd
+image/vnd.dece.graphic uvi uvvi uvg uvvg
+image/vnd.djvu djvu djv
+image/vnd.dvb.subtitle sub
+image/vnd.dwg dwg
+image/vnd.dxf dxf
+image/vnd.fastbidsheet fbs
+image/vnd.fpx fpx
+image/vnd.fst fst
+image/vnd.fujixerox.edmics-mmr mmr
+image/vnd.fujixerox.edmics-rlc rlc
+image/vnd.ms-modi mdi
+image/vnd.ms-photo wdp
+image/vnd.net-fpx npx
+image/vnd.wap.wbmp wbmp
+image/vnd.xiff xif
+image/webp webp
+image/x-3ds 3ds
+image/x-cmu-raster ras
+image/x-cmx cmx
+image/x-freehand fh fhc fh4 fh5 fh7
+image/x-icon ico
+image/x-mrsid-image sid
+image/x-pcx pcx
+image/x-pict pic pct
+image/x-portable-anymap pnm
+image/x-portable-bitmap pbm
+image/x-portable-graymap pgm
+image/x-portable-pixmap ppm
+image/x-rgb rgb
+image/x-tga tga
+image/x-xbitmap xbm
+image/x-xpixmap xpm
+image/x-xwindowdump xwd
+message/rfc822 eml mime
+model/iges igs iges
+model/mesh msh mesh silo
+model/vnd.collada+xml dae
+model/vnd.dwf dwf
+model/vnd.gdl gdl
+model/vnd.gtw gtw
+model/vnd.vtu vtu
+model/vrml wrl vrml
+model/x3d+binary x3db x3dbz
+model/x3d+vrml x3dv x3dvz
+model/x3d+xml x3d x3dz
+text/cache-manifest appcache
+text/calendar ics ifb
+text/css css
+text/csv csv
+text/html html htm
+text/javascript js mjs
+text/n3 n3
+text/plain txt text conf def list log in
+text/prs.lines.tag dsc
+text/richtext rtx
+text/sgml sgml sgm
+text/tab-separated-values tsv
+text/troff t tr roff man me ms
+text/turtle ttl
+text/uri-list uri uris urls
+text/vcard vcard
+text/vnd.curl curl
+text/vnd.curl.dcurl dcurl
+text/vnd.curl.mcurl mcurl
+text/vnd.curl.scurl scurl
+text/vnd.dvb.subtitle sub
+text/vnd.fly fly
+text/vnd.fmi.flexstor flx
+text/vnd.graphviz gv
+text/vnd.in3d.3dml 3dml
+text/vnd.in3d.spot spot
+text/vnd.sun.j2me.app-descriptor jad
+text/vnd.wap.wml wml
+text/vnd.wap.wmlscript wmls
+text/x-asm s asm
+text/x-c c cc cxx cpp h hh dic
+text/x-fortran f for f77 f90
+text/x-java-source java
+text/x-nfo nfo
+text/x-opml opml
+text/x-pascal p pas
+text/x-setext etx
+text/x-sfv sfv
+text/x-uuencode uu
+text/x-vcalendar vcs
+text/x-vcard vcf
+video/3gpp 3gp
+video/3gpp2 3g2
+video/h261 h261
+video/h263 h263
+video/h264 h264
+video/jpeg jpgv
+video/jpm jpm jpgm
+video/mj2 mj2 mjp2
+video/mp2t ts m2t m2ts mts
+video/mp4 mp4 mp4v mpg4
+video/mpeg mpeg mpg mpe m1v m2v
+video/ogg ogv
+video/quicktime qt mov
+video/vnd.dece.hd uvh uvvh
+video/vnd.dece.mobile uvm uvvm
+video/vnd.dece.pd uvp uvvp
+video/vnd.dece.sd uvs uvvs
+video/vnd.dece.video uvv uvvv
+video/vnd.dvb.file dvb
+video/vnd.fvt fvt
+video/vnd.mpegurl mxu m4u
+video/vnd.ms-playready.media.pyv pyv
+video/vnd.uvvu.mp4 uvu uvvu
+video/vnd.vivo viv
+video/webm webm
+video/x-f4v f4v
+video/x-fli fli
+video/x-flv flv
+video/x-m4v m4v
+video/x-matroska mkv mk3d mks
+video/x-mng mng
+video/x-ms-asf asf asx
+video/x-ms-vob vob
+video/x-ms-wm wm
+video/x-ms-wmv wmv
+video/x-ms-wmx wmx
+video/x-ms-wvx wvx
+video/x-msvideo avi
+video/x-sgi-movie movie
+video/x-smv smv
+x-conference/x-cooltalk ice
diff --git a/src/application/assets/user-fallback.jpg b/src/application/assets/user-fallback.jpg
new file mode 100644
index 0000000..e657866
--- /dev/null
+++ b/src/application/assets/user-fallback.jpg
Binary files differ
diff --git a/src/application/fetch-mime-types.php b/src/application/fetch-mime-types.php
new file mode 100644
index 0000000..2e49726
--- /dev/null
+++ b/src/application/fetch-mime-types.php
@@ -0,0 +1,22 @@
+<?php
+
+if (PHP_SAPI !== "cli") {
+ http_response_code(400);
+ echo "This script must be run from the command line";
+ exit;
+}
+
+$input = "https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types";
+$output = __DIR__ . "/assets/mimetypes";
+
+$hInput = fopen($input, "r") or die("Failed to open input file");
+$hOutput = fopen($output, "w") or die("Failed to open output file");
+
+while (($ln = fgets($hInput)) !== false) {
+ if (strpos($ln, "#") === 0)
+ continue;
+ fputs($hOutput, $ln);
+}
+
+fclose($hInput);
+fclose($hOutput);
diff --git a/src/application/mystic/forum/orm/User.php b/src/application/mystic/forum/orm/User.php
index 1db1d04..97acbaf 100644
--- a/src/application/mystic/forum/orm/User.php
+++ b/src/application/mystic/forum/orm/User.php
@@ -3,6 +3,7 @@ declare(strict_types=1);
namespace mystic\forum\orm;
+use mystic\forum\attributes\Column;
use mystic\forum\attributes\PrimaryKey;
use mystic\forum\attributes\Table;
use mystic\forum\attributes\Unique;
@@ -22,6 +23,8 @@ class User extends Entity {
public bool $passwordResetRequired;
public string $activationToken;
public bool $activated;
+ #[Column(columnType: "bytea")] public ?string $profilePicture;
+ public ?\DateTimeImmutable $nameLastChanged;
public function hasPermission(int $perm): bool {
if ($this->id === self::SUPERUSER_ID)
diff --git a/src/application/mystic/forum/utils/FileUtils.php b/src/application/mystic/forum/utils/FileUtils.php
new file mode 100644
index 0000000..1910f0c
--- /dev/null
+++ b/src/application/mystic/forum/utils/FileUtils.php
@@ -0,0 +1,33 @@
+<?php
+declare(strict_types=1);
+
+namespace mystic\forum\utils;
+
+final class FileUtils {
+ use StaticClass;
+
+ private const MIME_FILE = __DIR__ . "/../../../assets/mimetypes";
+ public const DEFAULT_MIME_TYPE = "application/octet-stream";
+
+ private static ?array $extToMime = null;
+
+ private static function ensureMimeMapping(): void {
+ if (self::$extToMime !== null)
+ return;
+
+ self::$extToMime = [];
+
+ $hFile = fopen(self::MIME_FILE, "r");
+ while (($ln = fgets($hFile)) !== false) {
+ [$mime, $extensions] = preg_split('/\t+/', $ln, 2);
+ $extensions = explode(" ", strtolower($extensions));
+ foreach ($extensions as $ext)
+ self::$extToMime[$ext] = $mime;
+ }
+ }
+
+ public static function getMimeTypeForExtension(string $extension, string $defaultMimeType = self::DEFAULT_MIME_TYPE): string {
+ self::ensureMimeMapping();
+ return self::$extToMime[strtolower($extension)] ?? $defaultMimeType;
+ }
+}
diff --git a/src/application/mystic/forum/utils/RequestUtils.php b/src/application/mystic/forum/utils/RequestUtils.php
index f6ce3a3..6599052 100644
--- a/src/application/mystic/forum/utils/RequestUtils.php
+++ b/src/application/mystic/forum/utils/RequestUtils.php
@@ -30,9 +30,10 @@ final class RequestUtils {
public static function getRequiredField(string $field): string {
$fieldValue = $_POST[$field] ?? null;
if ($fieldValue === null) {
- http_response_code(400);
- Messaging::error("Missing required field $field");
- exit;
+ //http_response_code(400);
+ //Messaging::error("Missing required field $field");
+ RequestUtils::triggerFormError("Missing required field '$field'");
+ //exit;
}
return $fieldValue;
}
diff --git a/src/application/mystic/forum/utils/StringUtils.php b/src/application/mystic/forum/utils/StringUtils.php
index 7d4bf9d..fd38915 100644
--- a/src/application/mystic/forum/utils/StringUtils.php
+++ b/src/application/mystic/forum/utils/StringUtils.php
@@ -21,4 +21,8 @@ final class StringUtils {
return ltrim($result, '_');
}
+
+ public static function truncate(string $str, int $maxLength, string $ellipsis = "…"): string {
+ return mb_strimwidth($str, 0, $maxLength, $ellipsis);
+ }
}
diff --git a/src/application/views/form_addpost.php b/src/application/views/form_addpost.php
index b3cd6ca..88eda27 100644
--- a/src/application/views/form_addpost.php
+++ b/src/application/views/form_addpost.php
@@ -20,7 +20,7 @@ if (($_formError = RequestUtils::getAndClearFormError()) !== null) {
<textarea class="form-control" id="i_message" name="message" required rows="12" cols="60" style="resize:vertical;max-height:499px"></textarea>
</div>
<div class="form-group">
- <label for="i_files">Attachments:</label>
+ <label for="i_files">Attachments: <small>(max. 4 files, max. 2 MiB each)</small></label>
<input type="file" name="files[]" id="i_files" multiple accept="*/*">
</div>
<button type="submit" class="btn btn-success">Post reply</button>
diff --git a/src/application/views/form_delete_post_confirm.php b/src/application/views/form_delete_post_confirm.php
index 9d04095..2dc417d 100644
--- a/src/application/views/form_delete_post_confirm.php
+++ b/src/application/views/form_delete_post_confirm.php
@@ -1,16 +1,21 @@
<div class="panel panel-danger">
<div class="panel-heading">
- <h3 class="panel-title">Do you want to delete your post?</h3>
+ <?php if ($postAuthor->id === $GLOBALS["currentUser"]->id): ?>
+ <h3 class="panel-title">Do you want to delete your post?</h3>
+ <?php else: ?>
+ <h3 class="panel-title">Do you want to delete <?= htmlentities($postAuthor->displayName) ?>'s post?</h3>
+ <?php endif; ?>
</div>
<div class="panel-body">
- Are you sure you want to delete the following post:
- <div class="well">
- <?= renderPost($post->content); ?>
- </div>
+ Are you sure you want to delete the following post:<br>
+ <?php _view("view_post", [
+ ...$___PARAMS,
+ "hide_actions" => true
+ ]) ?>
</div>
<div class="panel-footer">
<div class="text-right">
- <form action="." method="get" class="seamless-inline">
+ <form action=".#post-<?= htmlentities(urlencode($post->id)) ?>" method="get" class="seamless-inline">
<input type="hidden" name="_action" value="viewtopic">
<input type="hidden" name="topic" value="<?= htmlentities($post->topicId) ?>">
<button class="btn btn-default">Keep my post</button>
diff --git a/src/application/views/form_login.php b/src/application/views/form_login.php
index 0e98a24..8ddb22e 100644
--- a/src/application/views/form_login.php
+++ b/src/application/views/form_login.php
@@ -20,7 +20,7 @@ if (($_formError = RequestUtils::getAndClearFormError()) !== null) {
<form action="<?= htmlentities($_SERVER["REQUEST_URI"]) ?>" method="post">
<div class="form-group">
<label for="i_username">Username:</label>
- <input class="form-control" type="text" id="i_username" name="username" value="<?= htmlentities($lastForm["username"] ?? "") ?>" required>
+ <input class="form-control" type="text" id="i_username" name="username" value="<?= htmlentities($lastForm["username"] ?? "") ?>" required autofocus>
</div>
<div class="form-group">
diff --git a/src/application/views/template_end.php b/src/application/views/template_end.php
index f7f70a9..27fc3ba 100644
--- a/src/application/views/template_end.php
+++ b/src/application/views/template_end.php
@@ -15,6 +15,14 @@ $(function() {
var date = new Date($(e).text());
$(e).text(date.toLocaleString());
});
+ $("._date").each(function(i, e) {
+ var date = new Date($(e).text());
+ $(e).text(date.toLocaleDateString());
+ });
+ $("._time-only").each(function(i, e) {
+ var date = new Date($(e).text());
+ $(e).text(date.toLocaleTimeString());
+ });
});
</script>
diff --git a/src/application/views/template_start.php b/src/application/views/template_start.php
index e011f74..4cfdb74 100644
--- a/src/application/views/template_start.php
+++ b/src/application/views/template_start.php
@@ -8,9 +8,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title><?= htmlentities($_title ?? "") ?></title>
- <link rel="stylesheet" href="/ui/dist/css/bootstrap.min.css">
- <link rel="stylesheet" href="/ui/dist/css/bootstrap-theme.min.css">
- <link rel="stylesheet" href="/ui/site.css">
+ <link rel="stylesheet" href="/ui/theme-default.css">
<script src="/ui/jquery-1.12.4.min.js"></script>
<script src="/ui/dist/js/bootstrap.min.js"></script>
<script src="/ui/modernizr-2.6.2.min.js"></script>
diff --git a/src/application/views/view_post.php b/src/application/views/view_post.php
index 0776fb5..5022d4a 100644
--- a/src/application/views/view_post.php
+++ b/src/application/views/view_post.php
@@ -11,36 +11,49 @@ $canReply = $GLOBALS["currentUser"]?->hasPermission(UserPermissions::CREATE_OWN_
$canDelete = ($GLOBALS["currentUser"]?->id === $postAuthor?->id && $postAuthor?->hasPermission(UserPermissions::DELETE_OWN_POST))
|| ($GLOBALS["currentUser"]?->hasPermission(UserPermissions::DELETE_OTHER_POST));
+$hide_actions ??= false;
+$hide_pfp ??= false;
+$your_are_the_author = $GLOBALS["currentUser"]?->id === $postAuthor?->id;
+
?>
<?php if ($post->deleted): ?>
-<div class="media">
+<div class="media" id="post-<?= htmlentities($post->id) ?>">
<div class="media-left hidden-sm hidden-xs">
<div class="media-object" style="width:64px"></div>
</div>
<div class="media-body">
- <div class="well">
+ <div class="well icon-well text-warning">
+ <span class="glyphicon glyphicon-exclamation-sign color-warning" aria-hidden="true"></span>
<em>This post has been deleted</em>
</div>
</div>
</div>
<?php else: ?>
-<div class="media">
+<div class="media" id="post-<?= htmlentities($post->id) ?>">
+<?php if (!$hide_pfp): ?>
<div class="media-left hidden-sm hidden-xs">
<?php if ($postAuthor): ?>
- <a href="?_action=viewuser&amp;user=<?= htmlentities(urlencode($postAuthor->id)) ?>">
- <img class="media-object" src="/ui/placeholder.svg" alt="" width="64" height="64">
- </a>
+ <?php if ($hide_actions): ?>
+ <img class="media-object" alt="Profile picture" src="?_action=profilepicture&amp;user=<?= htmlentities(urlencode($postAuthor->id)) ?>" alt="" width="64" height="64">
+ <?php else: ?>
+ <a href="?_action=viewuser&amp;user=<?= htmlentities(urlencode($postAuthor->id)) ?>">
+ <img class="media-object" alt="Profile picture" src="?_action=profilepicture&amp;user=<?= htmlentities(urlencode($postAuthor->id)) ?>" alt="" width="64" height="64">
+ </a>
+ <?php endif; ?>
<?php else: ?>
<div class="media-object" style="width:64px;height:64px"></div>
<?php endif; ?>
</div>
+<?php endif; ?>
<div class="media-body">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
+ <?php if (!$hide_actions): ?>
<div class="pull-right">
<?php if ($canReply): ?>
+ <a href="#post-<?= htmlentities(urlencode($post->id)) ?>" class="btn btn-default"><span class="glyphicon glyphicon-link" aria-hidden="true"></span><span class="sr-only">Permalink</span></a>
<button data-text="<?= htmlentities($post->content) ?>" class="btn btn-default js-only _reply-post"><span class="glyphicon glyphicon-share-alt" aria-hidden="true"></span><span class="sr-only">Reply to post</span></button>
<?php endif; ?>
<?php if ($canDelete): ?>
@@ -50,8 +63,16 @@ $canDelete = ($GLOBALS["currentUser"]?->id === $postAuthor?->id && $postAuthor?-
</form>
<?php endif; ?>
</div>
+ <?php endif; ?>
<?php if ($postAuthor): ?>
- <a href="?_action=viewuser&amp;user=<?= htmlentities(urlencode($postAuthor->id)) ?>"><?= htmlentities($postAuthor->displayName) ?></a>
+ <?php if ($hide_actions): ?>
+ <?= htmlentities($postAuthor->displayName) ?>
+ <?php else: ?>
+ <a href="?_action=viewuser&amp;user=<?= htmlentities(urlencode($postAuthor->id)) ?>"><?= htmlentities($postAuthor->displayName) ?></a>
+ <?php endif; ?>
+ <?php if ($your_are_the_author): ?>
+ <span class="text-normal label label-primary">You</span>
+ <?php endif; ?>
<?php else: ?>
<em class="text-muted">(deleted)</em>
<?php endif; ?>
@@ -63,9 +84,15 @@ $canDelete = ($GLOBALS["currentUser"]?->id === $postAuthor?->id && $postAuthor?-
<?php if (count($imageAttachments) > 0): ?>
<div class="post-images clearfix">
<?php /** @var Attachment $attachment */ foreach ($imageAttachments as $attachment): ?>
- <a class="image-attachment" href="?_action=attachment&amp;attachment=<?= htmlentities(urlencode($attachment->id)) ?>" title="<?= htmlentities($attachment->name) ?>">
- <img class="image-attachment-image" src="?_action=thumb&amp;attachment=<?= htmlentities(urlencode($attachment->id)) ?>" alt="" width="110">
- </a>
+ <?php if ($hide_actions): ?>
+ <span class="image-attachment" title="<?= htmlentities($attachment->name) ?>">
+ <img class="image-attachment-image" src="?_action=thumb&amp;attachment=<?= htmlentities(urlencode($attachment->id)) ?>" alt="" width="110">
+ </span>
+ <?php else: ?>
+ <a class="image-attachment" href="?_action=attachment&amp;attachment=<?= htmlentities(urlencode($attachment->id)) ?>" title="<?= htmlentities($attachment->name) ?>">
+ <img class="image-attachment-image" src="?_action=thumb&amp;attachment=<?= htmlentities(urlencode($attachment->id)) ?>" alt="" width="110">
+ </a>
+ <?php endif; ?>
<?php endforeach; ?>
</div>
<?php endif; ?>
@@ -74,7 +101,11 @@ $canDelete = ($GLOBALS["currentUser"]?->id === $postAuthor?->id && $postAuthor?-
<div class="panel-footer">
<div class="btn-group">
<?php /** @var Attachment $attachment */ foreach ($fileAttachments as $attachment): ?>
- <a class="btn btn-default" href="?_action=attachment&amp;attachment=<?= htmlentities(urlencode($attachment->id)) ?>"><?= htmlentities($attachment->name) ?></a>
+ <?php if ($hide_actions): ?>
+ <button class="btn btn-default"><?= htmlentities($attachment->name) ?></button>
+ <?php else: ?>
+ <a class="btn btn-default" href="?_action=attachment&amp;attachment=<?= htmlentities(urlencode($attachment->id)) ?>"><?= htmlentities($attachment->name) ?></a>
+ <?php endif; ?>
<?php endforeach; ?>
</div>
</div>
diff --git a/src/application/views/view_topic_start.php b/src/application/views/view_topic_start.php
index 5818483..84a29de 100644
--- a/src/application/views/view_topic_start.php
+++ b/src/application/views/view_topic_start.php
@@ -6,19 +6,21 @@ $canReply = $GLOBALS["currentUser"]?->hasPermission(UserPermissions::CREATE_OWN_
$canDelete = ($GLOBALS["currentUser"]?->id === $topicAuthor->id && $topicAuthor->hasPermission(UserPermissions::DELETE_OWN_TOPIC))
|| ($GLOBALS["currentUser"]?->hasPermission(UserPermissions::DELETE_OTHER_TOPIC));
?>
-<div role="heading" class="h1">
-<?= htmlentities($topic->title) ?>
-<div class="pull-right">
-<?php if ($canReply): ?>
-<button id="btn-reply" class="btn btn-default js-only"><span class="glyphicon glyphicon-share-alt" aria-hidden="true"></span> Reply</button>
-<?php endif; ?>
-<?php if ($canDelete): ?>
-<form action="?_action=deletetopic" method="post" class="seamless-inline">
-<input type="hidden" name="topic" value="<?= htmlentities($topic->id) ?>">
-<button type="submit" class="btn btn-danger"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete topic</button>
-</form>
-<?php endif; ?>
-</div>
+<div class="page-header margin-top-0">
+ <div role="heading" class="h1 margin-top-0">
+ <?= htmlentities($topic->title) ?>
+ <div class="pull-right">
+ <?php if ($canReply): ?>
+ <button id="btn-reply" class="btn btn-default js-only"><span class="glyphicon glyphicon-share-alt" aria-hidden="true"></span> Reply</button>
+ <?php endif; ?>
+ <?php if ($canDelete): ?>
+ <form action="?_action=deletetopic" method="post" class="seamless-inline">
+ <input type="hidden" name="topic" value="<?= htmlentities($topic->id) ?>">
+ <button type="submit" class="btn btn-danger"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete topic</button>
+ </form>
+ <?php endif; ?>
+ </div>
+ </div>
</div>
<p>
Started by
diff --git a/src/application/views/view_user.php b/src/application/views/view_user.php
index 334928b..23d2b71 100644
--- a/src/application/views/view_user.php
+++ b/src/application/views/view_user.php
@@ -1 +1,153 @@
-<h1><?= htmlentities($user->displayName) ?></h1>
+<?php
+
+use mystic\forum\orm\UserPermissions;
+use mystic\forum\utils\RequestUtils;
+use mystic\forum\utils\StringUtils;
+
+/** @var mystic\forum\orm\User $user */
+/** @var bool $lastNameChangeTooRecent */
+
+$canEdit = ($user->id === $GLOBALS["currentUser"]?->id && $user->hasPermission(UserPermissions::EDIT_OWN_USER))
+ || $GLOBALS["currentUser"]?->hasPermission(UserPermissions::EDIT_OTHER_USER);
+
+$isOwnProfile = $user->id === $GLOBALS["currentUser"]?->id;
+
+$sIsOwn_your = "";
+if ($isOwnProfile)
+ $sIsOwn_your = " your";
+
+$sUserPossessive = "";
+if ($isOwnProfile)
+ $sUserPossessive = "Your";
+else
+ $sUserPossessive = $user->displayName . "'s";
+
+$dateJoined = DateTime::createFromImmutable($user->created);
+$dateJoined->setTime(0, 0, 0, 0);
+?>
+
+<div class="clearfix">
+ <img class="pull-left margin-right" src="?_action=profilepicture&amp;user=<?= htmlentities(urlencode($user->id)) ?>">
+ <span class="h1"><?= htmlentities($user->displayName) ?></span>
+ <?php if ($isOwnProfile): ?>
+ <span class="label label-primary">You</span>
+ <?php endif; ?><br>
+ @<?= htmlentities($user->name) ?> &bull; <span class="text-muted">Member since <span class="_date"><?= htmlentities($dateJoined->format("c")); ?></span>
+</div>
+
+<?php if ($canEdit): ?>
+<div class="row">
+<div class="col-md-9">
+<?php endif; ?>
+
+<h3><?= $sUserPossessive ?> posts</h3>
+
+<?php if (count($posts) > 0): ?>
+ <div class="post-container">
+ <div class="post-container-posts">
+ <div class="list-group margin-top">
+ <?php foreach ($posts as $post): if ($post->deleted) continue; ?>
+ <a href="?_action=viewtopic&amp;topic=<?= htmlentities(urlencode($post->topicId)) ?>#post-<?= htmlentities(urlencode($post->id)) ?>" class="list-group-item">
+ <?= htmlentities(StringUtils::truncate(strip_tags(renderPost($post->content)), 100)) ?><br>
+ <span class="text-muted">posted on <span class="_time"><?= htmlentities($post->postDate->format("c")) ?></span> in <em><?= htmlentities($topics[$post->topicId]?->title ?? "unknown") ?></em></span>
+ </a>
+ <?php endforeach; ?>
+ </div>
+ </div>
+ <div class="post-container-controls">
+ <button class="btn btn-default">Show all posts</button>
+ </div>
+ </div>
+<?php else: ?>
+ <div class="well icon-well text-info margin-top margin-bottom">
+ <span class="glyphicon glyphicon-info-sign color-info" aria-hidden="true"></span>
+ <em>This user has not posted anything yet</em>
+ </div>
+<?php endif; ?>
+
+<?php if ($canEdit): ?>
+</div>
+
+<div class="col-md-3">
+<h3>Edit<?= $sIsOwn_your ?> profile</h3>
+<?php
+if (($_formError = RequestUtils::getAndClearFormError()) !== null) {
+ _view("alert_error", ["message" => $_formError]);
+}
+?>
+<form action="<?= htmlentities($_SERVER["REQUEST_URI"]) ?>" method="post" enctype="multipart/form-data">
+ <div class="form-group">
+ <label for="i_display_name">Display name:</label>
+ <input required class="form-control" type="text" name="display_name" id="i_display_name" value="<?= htmlentities($user->displayName) ?>">
+ </div>
+ <div class="form-group">
+ <label for="i_name">Login name:</label>
+ <?php if ($lastNameChangeTooRecent): ?>
+ <input required class="form-control" type="text" id="i_name" value="<?= htmlentities($user->name) ?>" disabled>
+ <small class="text-danger"><strong>You can only change your username every 30 days!</strong></small>
+ <?php else: ?>
+ <input required class="form-control" type="text" name="name" id="i_name" value="<?= htmlentities($user->name) ?>">
+ <?php endif; ?>
+ </div>
+ <div class="form-group">
+ <label for="i_email">Email address:</label>
+ <input required class="form-control" type="email" id="i_email" value="<?= htmlentities($user->email) ?>" disabled>
+ </div>
+ <div class="form-group">
+ <label>Profile picture:</label>
+<?php
+$_checkbox_disabled = empty($user->profilePicture);
+$_checkbox_disabled_class = $_checkbox_disabled ? " disabled" : "";
+?>
+ <div class="radio margin-top-0 <?= $_checkbox_disabled_class ?>">
+ <label>
+ <input type="radio" name="pfp_action" id="pfp_action_1" value="keep"<?= !empty($user->profilePicture) ? ' checked' : ' disabled' ?>>
+ Existing profile picture
+ </label>
+ </div>
+ <div class="radio">
+ <label>
+ <input type="radio" name="pfp_action" id="pfp_action_2" value="remove"<?= empty($user->profilePicture) ? ' checked' : '' ?>>
+ No profile picture
+ </label>
+ </div>
+ <div class="radio">
+ <label>
+ <input type="radio" name="pfp_action" value="replace" id="pfp_action_3">
+ Upload new profile picture
+ </label>
+ </div>
+ <input type="file" name="pfp" id="i_pfp" accept="image/png,image/jpeg" class="margin-left-3x">
+ </div>
+ <div class="form-group">
+ <button type="submit" class="btn btn-success">Save changes</button>
+ </div>
+</form>
+</div>
+
+</div>
+<?php endif; ?>
+
+<script>
+$(function() {
+ $(".post-container").each(function(i, e) {
+ if ($(e).height() > 900) { // more than 800 so it doesn't collapse just a few pixels
+ $(e).addClass("collapsed");
+ }
+ $(e).find(".post-container-controls button").click(function() {
+ $(e).removeClass("collapsed");
+ });
+ });
+});
+<?php if ($canEdit): ?>
+$(function() {
+ $("#i_pfp").hide().prop("disabled", true).prop("required", false);
+ $("[name='pfp_action']").on("change input check click", function() {
+ if ($("#pfp_action_3").is(":checked"))
+ $("#i_pfp").show().prop("disabled", false).prop("required", true);
+ else
+ $("#i_pfp").hide().prop("disabled", true).prop("required", false);
+ })
+});
+<?php endif; ?>
+</script>