Compare commits
No commits in common. "master" and "v3.1.0-beta.1" have entirely different histories.
master
...
v3.1.0-bet
16
.babelrc
@ -1,16 +0,0 @@
|
||||
{ "presets": [ [ "@babel/env"
|
||||
, { "targets": { "browsers": [ "last 2 chrome versions"
|
||||
, "last 2 chromeandroid versions"
|
||||
, "firefox esr"
|
||||
, "last 2 firefox versions"
|
||||
, "last 2 edge versions"
|
||||
, "safari >= 15"
|
||||
, "ios >= 15"
|
||||
]
|
||||
}
|
||||
, "debug": true
|
||||
, "include": [ ]
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
@ -1 +0,0 @@
|
||||
3a88e73ee106ef675affb76a6399625bccf446e1
|
3
.gitattributes
vendored
@ -1,3 +0,0 @@
|
||||
*.php diff=php
|
||||
*.css diff=css
|
||||
*.scss diff=css
|
70
.gitignore
vendored
@ -1,13 +1,63 @@
|
||||
node_modules
|
||||
# Linux
|
||||
# backup files
|
||||
*~
|
||||
|
||||
be.bastelstu.chat.tar.gz
|
||||
be.bastelstu.chat.tar
|
||||
files.tar
|
||||
files_wcf.tar
|
||||
acptemplates.tar
|
||||
templates.tar
|
||||
# Windows
|
||||
# thumbnails
|
||||
Thumbs.db
|
||||
|
||||
Bastelstu.be.Chat.js
|
||||
Bastelstu.be.Chat.babel.js
|
||||
# Mac OS X
|
||||
# metadata
|
||||
.DS_Store
|
||||
# thumbnails
|
||||
._*
|
||||
|
||||
files_wcf/js/Bastelstu.be.Chat.min.js
|
||||
# Visual Studio PHP
|
||||
*.sln
|
||||
*.phpproj
|
||||
*.puo
|
||||
*.suo
|
||||
*.cache
|
||||
|
||||
# Netbeans
|
||||
nbproject/
|
||||
catalog.xml
|
||||
nbactions.xml
|
||||
|
||||
# Eclipse
|
||||
.settings/
|
||||
.buildpath
|
||||
.classpath
|
||||
.project
|
||||
|
||||
# SVN
|
||||
# svn folders
|
||||
.svn/
|
||||
|
||||
# PHPStorm
|
||||
.idea/
|
||||
.nameencodings
|
||||
.xmlmisc
|
||||
.xmlmodules
|
||||
.xmlprojectCodeStyle
|
||||
.xmlvcs.xml
|
||||
*.imlworkspace
|
||||
.xml
|
||||
|
||||
# Sublime Text 2
|
||||
*.sublime-*
|
||||
|
||||
# Textmate
|
||||
*.tmproj
|
||||
|
||||
# Community Framework
|
||||
# Ignore packages build directly in the workspace. They can however be added manually via git add, if wanted.
|
||||
*.tar
|
||||
*.tar.gz
|
||||
|
||||
# Javascript - CoffeeScript is used instead ;)
|
||||
*.js
|
||||
.sass-cache
|
||||
*.css
|
||||
|
||||
*.bak
|
||||
|
@ -1 +0,0 @@
|
||||
require.build.js
|
@ -1,3 +0,0 @@
|
||||
semi: false
|
||||
singleQuote: true
|
||||
useTabs: true
|
16
.travis.yml
Normal file
@ -0,0 +1,16 @@
|
||||
language: php
|
||||
php:
|
||||
- 5.6
|
||||
- 5.3
|
||||
before_install:
|
||||
- pyrus install pear/PHP_CodeSniffer
|
||||
- phpenv rehash
|
||||
before_script:
|
||||
- git clone --branch=master --depth=1 --quiet git://github.com/WoltLab/WCF.git WCF
|
||||
- rm WCF/CodeSniff/WCF/Sniffs/Namespaces/ClassMustBeImportedSniff.php
|
||||
- rm WCF/CodeSniff/WCF/Sniffs/Namespaces/UseDeclarationSniff.php
|
||||
- sed -i 's/<rule ref="WCF.Namespaces.ClassMustBeImported" \/>//' WCF/CodeSniff/WCF/ruleset.xml
|
||||
- sed -i 's/<rule ref="WCF.Namespaces.UseDeclaration" \/>//' WCF/CodeSniff/WCF/ruleset.xml
|
||||
script:
|
||||
- find file -type f -name '*.php' |xargs -I file php -l file
|
||||
- phpcs -p --extensions=php --standard="`pwd`/WCF/CodeSniff/WCF" file
|
8
.vscode/settings.json
vendored
@ -1,8 +0,0 @@
|
||||
{
|
||||
"editor.rulers": [
|
||||
{
|
||||
"column": 120,
|
||||
"color": "#ff00ff40"
|
||||
}
|
||||
]
|
||||
}
|
433
LICENSE
@ -1,104 +1,383 @@
|
||||
License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
|
||||
“Business Source License” is a trademark of MariaDB Corporation Ab.
|
||||
The following license applies to Tim’s Chat in whole:
|
||||
|
||||
Parameters
|
||||
The name "Tim’s Chat" may not be used in any derivated work, except for the
|
||||
purpose of giving proper attribution to the original authors (e.g. “Based on
|
||||
Tim’s Chat, developed in Tim’s Bastelstube”). Tim’s Chat in a whole is licensed
|
||||
under the terms of
|
||||
Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported
|
||||
with exceptions made for some files, as specified below.
|
||||
|
||||
Licensor: Tim Düsterhus
|
||||
Licensed Work: Tim’s Chat 4.3
|
||||
The Licensed Work is (c) 2010-2024 Tim Düsterhus
|
||||
Additional Use Grant: You may use the Licensed Work when your application
|
||||
uses the Licensed Work for a purpose that does neither
|
||||
directly or indirectly generate revenue.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Change Date: 2028-06-15
|
||||
The following license applies to all artwork, logos, images and any other
|
||||
digital asset, unless specified otherwise in the file itself:
|
||||
|
||||
Change License: Version 2 or later of the GNU General Public License as
|
||||
published by the Free Software Foundation.
|
||||
The files may ONLY be used in the context of and distributed together with an
|
||||
UNMODIFIED copy of Tim’s Chat. Any further RESTRICTION that applies to Tim’s Chat
|
||||
in a whole (i.e. attribution, prohibition of commercial usage, etc.; see below)
|
||||
applies to the artwork, logos, images and any other digital asset as well, any
|
||||
further PERMISSION that applies to Tim’s Chat in a whole DOES NOT apply to the
|
||||
artwork, logos, images and any other digital asset. Any use not explicitly
|
||||
allowed by this license is PROHIBITED.
|
||||
|
||||
For information about alternative licensing arrangements for the Software,
|
||||
please email: tim <at the domain> bastelstu.be
|
||||
If any provision of this License is invalid or unenforceable under
|
||||
applicable law, it shall not affect the validity or enforceability of
|
||||
the remainder of the terms of this License, and without further action
|
||||
by the parties to this agreement, such provision shall be reformed to
|
||||
the minimum extent necessary to make such provision valid and
|
||||
enforceable.
|
||||
|
||||
Notice
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
The Business Source License (this document, or the “License”) is not an Open
|
||||
Source license. However, the Licensed Work will eventually be made available
|
||||
under an Open Source License, as stated in this License.
|
||||
Creative Commons Legal Code
|
||||
|
||||
For more information on the use of the Business Source License for MariaDB
|
||||
products, please visit the MariaDB Business Source License FAQ at
|
||||
https://mariadb.com/bsl-faq-mariadb.
|
||||
Attribution-NonCommercial-ShareAlike 3.0 Unported
|
||||
|
||||
For more information on the use of the Business Source License generally,
|
||||
please visit the Adopting and Developing Business Source License FAQ at
|
||||
https://mariadb.com/bsl-faq-adopting.
|
||||
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE
|
||||
COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY
|
||||
COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
|
||||
AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE
|
||||
TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY
|
||||
BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS
|
||||
CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND
|
||||
CONDITIONS.
|
||||
|
||||
Business Source License 1.1
|
||||
1. Definitions
|
||||
|
||||
Terms
|
||||
a. "Adaptation" means a work based upon the Work, or upon the Work and
|
||||
other pre-existing works, such as a translation, adaptation,
|
||||
derivative work, arrangement of music or other alterations of a
|
||||
literary or artistic work, or phonogram or performance and includes
|
||||
cinematographic adaptations or any other form in which the Work may be
|
||||
recast, transformed, or adapted including in any form recognizably
|
||||
derived from the original, except that a work that constitutes a
|
||||
Collection will not be considered an Adaptation for the purpose of
|
||||
this License. For the avoidance of doubt, where the Work is a musical
|
||||
work, performance or phonogram, the synchronization of the Work in
|
||||
timed-relation with a moving image ("synching") will be considered an
|
||||
Adaptation for the purpose of this License.
|
||||
b. "Collection" means a collection of literary or artistic works, such as
|
||||
encyclopedias and anthologies, or performances, phonograms or
|
||||
broadcasts, or other works or subject matter other than works listed
|
||||
in Section 1(g) below, which, by reason of the selection and
|
||||
arrangement of their contents, constitute intellectual creations, in
|
||||
which the Work is included in its entirety in unmodified form along
|
||||
with one or more other contributions, each constituting separate and
|
||||
independent works in themselves, which together are assembled into a
|
||||
collective whole. A work that constitutes a Collection will not be
|
||||
considered an Adaptation (as defined above) for the purposes of this
|
||||
License.
|
||||
c. "Distribute" means to make available to the public the original and
|
||||
copies of the Work or Adaptation, as appropriate, through sale or
|
||||
other transfer of ownership.
|
||||
d. "License Elements" means the following high-level license attributes
|
||||
as selected by Licensor and indicated in the title of this License:
|
||||
Attribution, Noncommercial, ShareAlike.
|
||||
e. "Licensor" means the individual, individuals, entity or entities that
|
||||
offer(s) the Work under the terms of this License.
|
||||
f. "Original Author" means, in the case of a literary or artistic work,
|
||||
the individual, individuals, entity or entities who created the Work
|
||||
or if no individual or entity can be identified, the publisher; and in
|
||||
addition (i) in the case of a performance the actors, singers,
|
||||
musicians, dancers, and other persons who act, sing, deliver, declaim,
|
||||
play in, interpret or otherwise perform literary or artistic works or
|
||||
expressions of folklore; (ii) in the case of a phonogram the producer
|
||||
being the person or legal entity who first fixes the sounds of a
|
||||
performance or other sounds; and, (iii) in the case of broadcasts, the
|
||||
organization that transmits the broadcast.
|
||||
g. "Work" means the literary and/or artistic work offered under the terms
|
||||
of this License including without limitation any production in the
|
||||
literary, scientific and artistic domain, whatever may be the mode or
|
||||
form of its expression including digital form, such as a book,
|
||||
pamphlet and other writing; a lecture, address, sermon or other work
|
||||
of the same nature; a dramatic or dramatico-musical work; a
|
||||
choreographic work or entertainment in dumb show; a musical
|
||||
composition with or without words; a cinematographic work to which are
|
||||
assimilated works expressed by a process analogous to cinematography;
|
||||
a work of drawing, painting, architecture, sculpture, engraving or
|
||||
lithography; a photographic work to which are assimilated works
|
||||
expressed by a process analogous to photography; a work of applied
|
||||
art; an illustration, map, plan, sketch or three-dimensional work
|
||||
relative to geography, topography, architecture or science; a
|
||||
performance; a broadcast; a phonogram; a compilation of data to the
|
||||
extent it is protected as a copyrightable work; or a work performed by
|
||||
a variety or circus performer to the extent it is not otherwise
|
||||
considered a literary or artistic work.
|
||||
h. "You" means an individual or entity exercising rights under this
|
||||
License who has not previously violated the terms of this License with
|
||||
respect to the Work, or who has received express permission from the
|
||||
Licensor to exercise rights under this License despite a previous
|
||||
violation.
|
||||
i. "Publicly Perform" means to perform public recitations of the Work and
|
||||
to communicate to the public those public recitations, by any means or
|
||||
process, including by wire or wireless means or public digital
|
||||
performances; to make available to the public Works in such a way that
|
||||
members of the public may access these Works from a place and at a
|
||||
place individually chosen by them; to perform the Work to the public
|
||||
by any means or process and the communication to the public of the
|
||||
performances of the Work, including by public digital performance; to
|
||||
broadcast and rebroadcast the Work by any means including signs,
|
||||
sounds or images.
|
||||
j. "Reproduce" means to make copies of the Work by any means including
|
||||
without limitation by sound or visual recordings and the right of
|
||||
fixation and reproducing fixations of the Work, including storage of a
|
||||
protected performance or phonogram in digital form or other electronic
|
||||
medium.
|
||||
|
||||
The Licensor hereby grants you the right to copy, modify, create derivative
|
||||
works, redistribute, and make non-production use of the Licensed Work. The
|
||||
Licensor may make an Additional Use Grant, above, permitting limited
|
||||
production use.
|
||||
2. Fair Dealing Rights. Nothing in this License is intended to reduce,
|
||||
limit, or restrict any uses free from copyright or rights arising from
|
||||
limitations or exceptions that are provided for in connection with the
|
||||
copyright protection under copyright law or other applicable laws.
|
||||
|
||||
Effective on the Change Date, or the fourth anniversary of the first publicly
|
||||
available distribution of a specific version of the Licensed Work under this
|
||||
License, whichever comes first, the Licensor hereby grants you rights under
|
||||
the terms of the Change License, and the rights granted in the paragraph
|
||||
above terminate.
|
||||
3. License Grant. Subject to the terms and conditions of this License,
|
||||
Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
|
||||
perpetual (for the duration of the applicable copyright) license to
|
||||
exercise the rights in the Work as stated below:
|
||||
|
||||
If your use of the Licensed Work does not comply with the requirements
|
||||
currently in effect as described in this License, you must purchase a
|
||||
commercial license from the Licensor, its affiliated entities, or authorized
|
||||
resellers, or you must refrain from using the Licensed Work.
|
||||
a. to Reproduce the Work, to incorporate the Work into one or more
|
||||
Collections, and to Reproduce the Work as incorporated in the
|
||||
Collections;
|
||||
b. to create and Reproduce Adaptations provided that any such Adaptation,
|
||||
including any translation in any medium, takes reasonable steps to
|
||||
clearly label, demarcate or otherwise identify that changes were made
|
||||
to the original Work. For example, a translation could be marked "The
|
||||
original work was translated from English to Spanish," or a
|
||||
modification could indicate "The original work has been modified.";
|
||||
c. to Distribute and Publicly Perform the Work including as incorporated
|
||||
in Collections; and,
|
||||
d. to Distribute and Publicly Perform Adaptations.
|
||||
|
||||
All copies of the original and modified Licensed Work, and derivative works
|
||||
of the Licensed Work, are subject to this License. This License applies
|
||||
separately for each version of the Licensed Work and the Change Date may vary
|
||||
for each version of the Licensed Work released by Licensor.
|
||||
The above rights may be exercised in all media and formats whether now
|
||||
known or hereafter devised. The above rights include the right to make
|
||||
such modifications as are technically necessary to exercise the rights in
|
||||
other media and formats. Subject to Section 8(f), all rights not expressly
|
||||
granted by Licensor are hereby reserved, including but not limited to the
|
||||
rights described in Section 4(e).
|
||||
|
||||
You must conspicuously display this License on each original or modified copy
|
||||
of the Licensed Work. If you receive the Licensed Work in original or
|
||||
modified form from a third party, the terms and conditions set forth in this
|
||||
License apply to your use of that work.
|
||||
4. Restrictions. The license granted in Section 3 above is expressly made
|
||||
subject to and limited by the following restrictions:
|
||||
|
||||
Any use of the Licensed Work in violation of this License will automatically
|
||||
terminate your rights under this License for the current and all other
|
||||
versions of the Licensed Work.
|
||||
a. You may Distribute or Publicly Perform the Work only under the terms
|
||||
of this License. You must include a copy of, or the Uniform Resource
|
||||
Identifier (URI) for, this License with every copy of the Work You
|
||||
Distribute or Publicly Perform. You may not offer or impose any terms
|
||||
on the Work that restrict the terms of this License or the ability of
|
||||
the recipient of the Work to exercise the rights granted to that
|
||||
recipient under the terms of the License. You may not sublicense the
|
||||
Work. You must keep intact all notices that refer to this License and
|
||||
to the disclaimer of warranties with every copy of the Work You
|
||||
Distribute or Publicly Perform. When You Distribute or Publicly
|
||||
Perform the Work, You may not impose any effective technological
|
||||
measures on the Work that restrict the ability of a recipient of the
|
||||
Work from You to exercise the rights granted to that recipient under
|
||||
the terms of the License. This Section 4(a) applies to the Work as
|
||||
incorporated in a Collection, but this does not require the Collection
|
||||
apart from the Work itself to be made subject to the terms of this
|
||||
License. If You create a Collection, upon notice from any Licensor You
|
||||
must, to the extent practicable, remove from the Collection any credit
|
||||
as required by Section 4(d), as requested. If You create an
|
||||
Adaptation, upon notice from any Licensor You must, to the extent
|
||||
practicable, remove from the Adaptation any credit as required by
|
||||
Section 4(d), as requested.
|
||||
b. You may Distribute or Publicly Perform an Adaptation only under: (i)
|
||||
the terms of this License; (ii) a later version of this License with
|
||||
the same License Elements as this License; (iii) a Creative Commons
|
||||
jurisdiction license (either this or a later license version) that
|
||||
contains the same License Elements as this License (e.g.,
|
||||
Attribution-NonCommercial-ShareAlike 3.0 US) ("Applicable License").
|
||||
You must include a copy of, or the URI, for Applicable License with
|
||||
every copy of each Adaptation You Distribute or Publicly Perform. You
|
||||
may not offer or impose any terms on the Adaptation that restrict the
|
||||
terms of the Applicable License or the ability of the recipient of the
|
||||
Adaptation to exercise the rights granted to that recipient under the
|
||||
terms of the Applicable License. You must keep intact all notices that
|
||||
refer to the Applicable License and to the disclaimer of warranties
|
||||
with every copy of the Work as included in the Adaptation You
|
||||
Distribute or Publicly Perform. When You Distribute or Publicly
|
||||
Perform the Adaptation, You may not impose any effective technological
|
||||
measures on the Adaptation that restrict the ability of a recipient of
|
||||
the Adaptation from You to exercise the rights granted to that
|
||||
recipient under the terms of the Applicable License. This Section 4(b)
|
||||
applies to the Adaptation as incorporated in a Collection, but this
|
||||
does not require the Collection apart from the Adaptation itself to be
|
||||
made subject to the terms of the Applicable License.
|
||||
c. You may not exercise any of the rights granted to You in Section 3
|
||||
above in any manner that is primarily intended for or directed toward
|
||||
commercial advantage or private monetary compensation. The exchange of
|
||||
the Work for other copyrighted works by means of digital file-sharing
|
||||
or otherwise shall not be considered to be intended for or directed
|
||||
toward commercial advantage or private monetary compensation, provided
|
||||
there is no payment of any monetary compensation in con-nection with
|
||||
the exchange of copyrighted works.
|
||||
d. If You Distribute, or Publicly Perform the Work or any Adaptations or
|
||||
Collections, You must, unless a request has been made pursuant to
|
||||
Section 4(a), keep intact all copyright notices for the Work and
|
||||
provide, reasonable to the medium or means You are utilizing: (i) the
|
||||
name of the Original Author (or pseudonym, if applicable) if supplied,
|
||||
and/or if the Original Author and/or Licensor designate another party
|
||||
or parties (e.g., a sponsor institute, publishing entity, journal) for
|
||||
attribution ("Attribution Parties") in Licensor's copyright notice,
|
||||
terms of service or by other reasonable means, the name of such party
|
||||
or parties; (ii) the title of the Work if supplied; (iii) to the
|
||||
extent reasonably practicable, the URI, if any, that Licensor
|
||||
specifies to be associated with the Work, unless such URI does not
|
||||
refer to the copyright notice or licensing information for the Work;
|
||||
and, (iv) consistent with Section 3(b), in the case of an Adaptation,
|
||||
a credit identifying the use of the Work in the Adaptation (e.g.,
|
||||
"French translation of the Work by Original Author," or "Screenplay
|
||||
based on original Work by Original Author"). The credit required by
|
||||
this Section 4(d) may be implemented in any reasonable manner;
|
||||
provided, however, that in the case of a Adaptation or Collection, at
|
||||
a minimum such credit will appear, if a credit for all contributing
|
||||
authors of the Adaptation or Collection appears, then as part of these
|
||||
credits and in a manner at least as prominent as the credits for the
|
||||
other contributing authors. For the avoidance of doubt, You may only
|
||||
use the credit required by this Section for the purpose of attribution
|
||||
in the manner set out above and, by exercising Your rights under this
|
||||
License, You may not implicitly or explicitly assert or imply any
|
||||
connection with, sponsorship or endorsement by the Original Author,
|
||||
Licensor and/or Attribution Parties, as appropriate, of You or Your
|
||||
use of the Work, without the separate, express prior written
|
||||
permission of the Original Author, Licensor and/or Attribution
|
||||
Parties.
|
||||
e. For the avoidance of doubt:
|
||||
|
||||
This License does not grant you any right in any trademark or logo of
|
||||
Licensor or its affiliates (provided that you may use a trademark or logo of
|
||||
Licensor as expressly required by this License).
|
||||
i. Non-waivable Compulsory License Schemes. In those jurisdictions in
|
||||
which the right to collect royalties through any statutory or
|
||||
compulsory licensing scheme cannot be waived, the Licensor
|
||||
reserves the exclusive right to collect such royalties for any
|
||||
exercise by You of the rights granted under this License;
|
||||
ii. Waivable Compulsory License Schemes. In those jurisdictions in
|
||||
which the right to collect royalties through any statutory or
|
||||
compulsory licensing scheme can be waived, the Licensor reserves
|
||||
the exclusive right to collect such royalties for any exercise by
|
||||
You of the rights granted under this License if Your exercise of
|
||||
such rights is for a purpose or use which is otherwise than
|
||||
noncommercial as permitted under Section 4(c) and otherwise waives
|
||||
the right to collect royalties through any statutory or compulsory
|
||||
licensing scheme; and,
|
||||
iii. Voluntary License Schemes. The Licensor reserves the right to
|
||||
collect royalties, whether individually or, in the event that the
|
||||
Licensor is a member of a collecting society that administers
|
||||
voluntary licensing schemes, via that society, from any exercise
|
||||
by You of the rights granted under this License that is for a
|
||||
purpose or use which is otherwise than noncommercial as permitted
|
||||
under Section 4(c).
|
||||
f. Except as otherwise agreed in writing by the Licensor or as may be
|
||||
otherwise permitted by applicable law, if You Reproduce, Distribute or
|
||||
Publicly Perform the Work either by itself or as part of any
|
||||
Adaptations or Collections, You must not distort, mutilate, modify or
|
||||
take other derogatory action in relation to the Work which would be
|
||||
prejudicial to the Original Author's honor or reputation. Licensor
|
||||
agrees that in those jurisdictions (e.g. Japan), in which any exercise
|
||||
of the right granted in Section 3(b) of this License (the right to
|
||||
make Adaptations) would be deemed to be a distortion, mutilation,
|
||||
modification or other derogatory action prejudicial to the Original
|
||||
Author's honor and reputation, the Licensor will waive or not assert,
|
||||
as appropriate, this Section, to the fullest extent permitted by the
|
||||
applicable national law, to enable You to reasonably exercise Your
|
||||
right under Section 3(b) of this License (right to make Adaptations)
|
||||
but not otherwise.
|
||||
|
||||
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
|
||||
AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
|
||||
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
|
||||
TITLE.
|
||||
5. Representations, Warranties and Disclaimer
|
||||
|
||||
MariaDB hereby grants you permission to use this License’s text to license
|
||||
your works, and to refer to it using the trademark “Business Source License”,
|
||||
as long as you comply with the Covenants of Licensor below.
|
||||
UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING AND TO THE
|
||||
FULLEST EXTENT PERMITTED BY APPLICABLE LAW, LICENSOR OFFERS THE WORK AS-IS
|
||||
AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE
|
||||
WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT
|
||||
LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||
ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT
|
||||
DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED
|
||||
WARRANTIES, SO THIS EXCLUSION MAY NOT APPLY TO YOU.
|
||||
|
||||
Covenants of Licensor
|
||||
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE
|
||||
LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR
|
||||
ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES
|
||||
ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS
|
||||
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
In consideration of the right to use this License’s text and the “Business
|
||||
Source License” name and trademark, Licensor covenants to MariaDB, and to all
|
||||
other recipients of the licensed work to be provided by Licensor:
|
||||
7. Termination
|
||||
|
||||
1. To specify as the Change License the GPL Version 2.0 or any later version,
|
||||
or a license that is compatible with GPL Version 2.0 or a later version,
|
||||
where “compatible” means that software provided under the Change License can
|
||||
be included in a program with software provided under GPL Version 2.0 or a
|
||||
later version. Licensor may specify additional Change Licenses without
|
||||
limitation.
|
||||
a. This License and the rights granted hereunder will terminate
|
||||
automatically upon any breach by You of the terms of this License.
|
||||
Individuals or entities who have received Adaptations or Collections
|
||||
from You under this License, however, will not have their licenses
|
||||
terminated provided such individuals or entities remain in full
|
||||
compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will
|
||||
survive any termination of this License.
|
||||
b. Subject to the above terms and conditions, the license granted here is
|
||||
perpetual (for the duration of the applicable copyright in the Work).
|
||||
Notwithstanding the above, Licensor reserves the right to release the
|
||||
Work under different license terms or to stop distributing the Work at
|
||||
any time; provided, however that any such election will not serve to
|
||||
withdraw this License (or any other license that has been, or is
|
||||
required to be, granted under the terms of this License), and this
|
||||
License will continue in full force and effect unless terminated as
|
||||
stated above.
|
||||
|
||||
2. To either: (a) specify an additional grant of rights to use that does not
|
||||
impose any additional restriction on the right granted in this License, as
|
||||
the Additional Use Grant; or (b) insert the text “None”.
|
||||
8. Miscellaneous
|
||||
|
||||
3. To specify a Change Date.
|
||||
a. Each time You Distribute or Publicly Perform the Work or a Collection,
|
||||
the Licensor offers to the recipient a license to the Work on the same
|
||||
terms and conditions as the license granted to You under this License.
|
||||
b. Each time You Distribute or Publicly Perform an Adaptation, Licensor
|
||||
offers to the recipient a license to the original Work on the same
|
||||
terms and conditions as the license granted to You under this License.
|
||||
c. If any provision of this License is invalid or unenforceable under
|
||||
applicable law, it shall not affect the validity or enforceability of
|
||||
the remainder of the terms of this License, and without further action
|
||||
by the parties to this agreement, such provision shall be reformed to
|
||||
the minimum extent necessary to make such provision valid and
|
||||
enforceable.
|
||||
d. No term or provision of this License shall be deemed waived and no
|
||||
breach consented to unless such waiver or consent shall be in writing
|
||||
and signed by the party to be charged with such waiver or consent.
|
||||
e. This License constitutes the entire agreement between the parties with
|
||||
respect to the Work licensed here. There are no understandings,
|
||||
agreements or representations with respect to the Work not specified
|
||||
here. Licensor shall not be bound by any additional provisions that
|
||||
may appear in any communication from You. This License may not be
|
||||
modified without the mutual written agreement of the Licensor and You.
|
||||
f. The rights granted under, and the subject matter referenced, in this
|
||||
License were drafted utilizing the terminology of the Berne Convention
|
||||
for the Protection of Literary and Artistic Works (as amended on
|
||||
September 28, 1979), the Rome Convention of 1961, the WIPO Copyright
|
||||
Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996
|
||||
and the Universal Copyright Convention (as revised on July 24, 1971).
|
||||
These rights and subject matter take effect in the relevant
|
||||
jurisdiction in which the License terms are sought to be enforced
|
||||
according to the corresponding provisions of the implementation of
|
||||
those treaty provisions in the applicable national law. If the
|
||||
standard suite of rights granted under applicable copyright law
|
||||
includes additional rights not granted under this License, such
|
||||
additional rights are deemed to be included in the License; this
|
||||
License is not intended to restrict the license of any rights under
|
||||
applicable law.
|
||||
|
||||
4. Not to modify this License in any other way.
|
||||
|
||||
Creative Commons Notice
|
||||
|
||||
Creative Commons is not a party to this License, and makes no warranty
|
||||
whatsoever in connection with the Work. Creative Commons will not be
|
||||
liable to You or any party on any legal theory for any damages
|
||||
whatsoever, including without limitation any general, special,
|
||||
incidental or consequential damages arising in connection to this
|
||||
license. Notwithstanding the foregoing two (2) sentences, if Creative
|
||||
Commons has expressly identified itself as the Licensor hereunder, it
|
||||
shall have all rights and obligations of Licensor.
|
||||
|
||||
Except for the limited purpose of indicating to the public that the
|
||||
Work is licensed under the CCPL, Creative Commons does not authorize
|
||||
the use by either party of the trademark "Creative Commons" or any
|
||||
related trademark or logo of Creative Commons without the prior
|
||||
written consent of Creative Commons. Any permitted use will be in
|
||||
compliance with Creative Commons' then-current trademark usage
|
||||
guidelines, as may be published on its website or otherwise made
|
||||
available upon request from time to time. For the avoidance of doubt,
|
||||
this trademark restriction does not form part of this License.
|
||||
|
||||
Creative Commons may be contacted at http://creativecommons.org/.
|
||||
|
||||
|
46
Makefile
@ -1,46 +0,0 @@
|
||||
FILES = $(shell find files -type f)
|
||||
WCF_FILES = $(shell find files_wcf -type f)
|
||||
JS_MODULE_FILES = $(shell find files_wcf/js/Bastelstu.be -type f)
|
||||
|
||||
all: be.bastelstu.chat.tar be.bastelstu.chat.tar.gz
|
||||
|
||||
be.bastelstu.chat.tar.gz: be.bastelstu.chat.tar
|
||||
gzip -9 < $< > $@
|
||||
|
||||
be.bastelstu.chat.tar: files.tar files_wcf.tar acptemplates.tar templates.tar *.xml LICENSE sql/*.sql language/*.xml
|
||||
tar cvf $@ --mtime="@$(shell git log -1 --format=%ct)" --owner=0 --group=0 --numeric-owner --exclude-vcs -- $^
|
||||
|
||||
files.tar: $(FILES)
|
||||
files_wcf.tar: $(WCF_FILES) files_wcf/js/Bastelstu.be.Chat.min.js
|
||||
acptemplates.tar: acptemplates/*.tpl
|
||||
templates.tar: templates/*.tpl
|
||||
|
||||
%.tar:
|
||||
tar cvf $@ --mtime="@$(shell git log -1 --format=%ct)" --owner=0 --group=0 --numeric-owner --exclude-vcs -C $* -- $(^:$*/%=%)
|
||||
|
||||
files_wcf/js/Bastelstu.be.Chat.min.js: Bastelstu.be.Chat.babel.js
|
||||
yarn run terser --comments '/Copyright|stackoverflow/' -m -c pure_funcs=[console.debug] --verbose --timings -o $@ $^
|
||||
|
||||
Bastelstu.be.Chat.babel.js: Bastelstu.be.Chat.js .babelrc
|
||||
yarn run babel $< --out-file $@
|
||||
|
||||
Bastelstu.be.Chat.js: $(JS_MODULE_FILES)
|
||||
yarn run r_js -o require.build.js
|
||||
|
||||
clean:
|
||||
-rm -f files.tar
|
||||
-rm -f files_wcf.tar
|
||||
-rm -f templates.tar
|
||||
-rm -f acptemplates.tar
|
||||
-rm -f Bastelstu.be.Chat.js
|
||||
-rm -f Bastelstu.be.Chat.babel.js
|
||||
-rm -f files_wcf/js/Bastelstu.be.Chat.min.js
|
||||
|
||||
distclean: clean
|
||||
-rm -f be.bastelstu.chat.tar
|
||||
-rm -f be.bastelstu.chat.tar.gz
|
||||
|
||||
constants.php: option.xml
|
||||
(echo "<?php" ; xq -r '.data.import.options.option[] | "define(\"" + (.["@name"] | ascii_upcase) + "\", " + .defaultvalue + ");"' < option.xml) > constants.php
|
||||
|
||||
.PHONY: distclean clean
|
10
README.md
Normal file
@ -0,0 +1,10 @@
|
||||
Tim’s Chat 3.0
|
||||
==============
|
||||
|
||||
Tim’s Chat is a chat-plugin for WoltLab Community Framework.
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
For licensing information refer to the LICENSE file in this folder.
|
@ -9,13 +9,9 @@
|
||||
<objecttype>be.bastelstu.chat.room</objecttype>
|
||||
</category>
|
||||
</categories>
|
||||
|
||||
|
||||
<options>
|
||||
<option name="user.canSee">
|
||||
<objecttype>be.bastelstu.chat.room</objecttype>
|
||||
<categoryname>user</categoryname>
|
||||
</option>
|
||||
<option name="user.canSeeLog">
|
||||
<option name="user.canEnter">
|
||||
<objecttype>be.bastelstu.chat.room</objecttype>
|
||||
<categoryname>user</categoryname>
|
||||
</option>
|
||||
@ -23,7 +19,13 @@
|
||||
<objecttype>be.bastelstu.chat.room</objecttype>
|
||||
<categoryname>user</categoryname>
|
||||
</option>
|
||||
<option name="mod.canIgnoreUserLimit">
|
||||
|
||||
|
||||
<option name="mod.canAlwaysEnter">
|
||||
<objecttype>be.bastelstu.chat.room</objecttype>
|
||||
<categoryname>mod</categoryname>
|
||||
</option>
|
||||
<option name="mod.canAlwaysWrite">
|
||||
<objecttype>be.bastelstu.chat.room</objecttype>
|
||||
<categoryname>mod</categoryname>
|
||||
</option>
|
||||
@ -31,18 +33,10 @@
|
||||
<objecttype>be.bastelstu.chat.room</objecttype>
|
||||
<categoryname>mod</categoryname>
|
||||
</option>
|
||||
<option name="mod.canIgnoreMute">
|
||||
<objecttype>be.bastelstu.chat.room</objecttype>
|
||||
<categoryname>mod</categoryname>
|
||||
</option>
|
||||
<option name="mod.canBan">
|
||||
<objecttype>be.bastelstu.chat.room</objecttype>
|
||||
<categoryname>mod</categoryname>
|
||||
</option>
|
||||
<option name="mod.canIgnoreBan">
|
||||
<objecttype>be.bastelstu.chat.room</objecttype>
|
||||
<categoryname>mod</categoryname>
|
||||
</option>
|
||||
</options>
|
||||
</import>
|
||||
</data>
|
||||
</data>
|
46
acpMenu.xml
@ -2,41 +2,39 @@
|
||||
<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/maelstrom/acpMenu.xsd">
|
||||
<import>
|
||||
<acpmenuitem name="chat.acp.menu.link.chat">
|
||||
<parent>wcf.acp.menu.link.application</parent>
|
||||
<parent>wcf.acp.menu.link.community</parent>
|
||||
</acpmenuitem>
|
||||
|
||||
|
||||
<acpmenuitem name="chat.acp.menu.link.room.list">
|
||||
<controller>chat\acp\page\RoomListPage</controller>
|
||||
<controller><![CDATA[chat\acp\page\RoomListPage]]></controller>
|
||||
<parent>chat.acp.menu.link.chat</parent>
|
||||
<permissions>admin.chat.canManageRoom</permissions>
|
||||
<permissions>admin.chat.canEditRoom,admin.chat.canDeleteRoom</permissions>
|
||||
<showorder>1</showorder>
|
||||
</acpmenuitem>
|
||||
|
||||
|
||||
<acpmenuitem name="chat.acp.menu.link.room.add">
|
||||
<controller>chat\acp\form\RoomAddForm</controller>
|
||||
<parent>chat.acp.menu.link.room.list</parent>
|
||||
<permissions>admin.chat.canManageRoom</permissions>
|
||||
<icon>plus</icon>
|
||||
</acpmenuitem>
|
||||
|
||||
<acpmenuitem name="chat.acp.menu.link.command.trigger.list">
|
||||
<controller>chat\acp\page\CommandTriggerListPage</controller>
|
||||
<controller><![CDATA[chat\acp\form\RoomAddForm]]></controller>
|
||||
<parent>chat.acp.menu.link.chat</parent>
|
||||
<permissions>admin.chat.canManageTriggers</permissions>
|
||||
<permissions>admin.chat.canAddRoom</permissions>
|
||||
<showorder>2</showorder>
|
||||
</acpmenuitem>
|
||||
|
||||
<acpmenuitem name="chat.acp.menu.link.command.trigger.add">
|
||||
<controller>chat\acp\form\CommandTriggerAddForm</controller>
|
||||
<parent>chat.acp.menu.link.command.trigger.list</parent>
|
||||
<permissions>admin.chat.canManageTriggers</permissions>
|
||||
<icon>plus</icon>
|
||||
</acpmenuitem>
|
||||
|
||||
|
||||
<acpmenuitem name="chat.acp.menu.link.suspension.list">
|
||||
<controller>chat\acp\page\SuspensionListPage</controller>
|
||||
<controller><![CDATA[chat\acp\page\ChatSuspensionListPage]]></controller>
|
||||
<parent>chat.acp.menu.link.chat</parent>
|
||||
<permissions>admin.chat.canManageSuspensions</permissions>
|
||||
<showorder>3</showorder>
|
||||
</acpmenuitem>
|
||||
|
||||
<acpmenuitem name="chat.acp.menu.link.log">
|
||||
<controller><![CDATA[chat\acp\page\MessageLogPage]]></controller>
|
||||
<parent>chat.acp.menu.link.chat</parent>
|
||||
<permissions>admin.chat.canReadLog</permissions>
|
||||
<showorder>4</showorder>
|
||||
</acpmenuitem>
|
||||
</import>
|
||||
|
||||
<delete>
|
||||
<acpmenuitem name="chat.acp.menu.link" />
|
||||
</delete>
|
||||
</data>
|
||||
|
||||
|
1
acptemplate/__headerLogo.tpl
Normal file
@ -0,0 +1 @@
|
||||
{if $__chat->isActiveApplication()}<img src="{$__wcf->getPath('chat')}images/chatLogo.png" style="width: 246px; height: 90px;" alt="" />{/if}
|
26
acptemplate/__messageLogTable.tpl
Normal file
@ -0,0 +1,26 @@
|
||||
{if $messages|count > 0}
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{lang}wcf.global.objectID{/lang}</th>
|
||||
<th>{lang}chat.global.time{/lang}</th>
|
||||
<th colspan="2">{lang}wcf.user.username{/lang}</th>
|
||||
<th>{lang}chat.acp.log.message{/lang}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{foreach from=$messages item="message"}
|
||||
<tr>
|
||||
<td class="columnID">{$message->messageID}</td>
|
||||
<td style="width: 1px !important;">{$message->time|date:"chat.global.timeFormat"}</td>
|
||||
<td class="columnIcon"><p class="framed">{@$message->getUserProfile()->getAvatar()->getImageTag(24)}</p></td>
|
||||
<td class="columnTitle columnUsername right" style="width: 1px !important;">{$message->username}</td>
|
||||
<td>{@$message->getFormattedMessage("text/simplified-html")}</td>
|
||||
</tr>
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
{else}
|
||||
<p class="info">{lang}wcf.global.noItems{/lang}</p>
|
||||
{/if}
|
4
acptemplate/__softwareVersions.tpl
Normal file
@ -0,0 +1,4 @@
|
||||
<dl>
|
||||
<dt>{lang}wcf.acp.index.system.software.chatVersion{/lang}</dt>
|
||||
<dd>{$__chat->getPackage()->packageVersion}</dd>
|
||||
</dl>
|
166
acptemplate/chatSuspensionList.tpl
Normal file
@ -0,0 +1,166 @@
|
||||
{include file='header' pageTitle='chat.acp.suspension.list'}
|
||||
|
||||
<script data-relocate="true">
|
||||
//<![CDATA[
|
||||
$(function() {
|
||||
new WCF.Search.User('#username', null, false, [ ], false);
|
||||
new WCF.Search.User('#issuerUsername', null, false, [ ], false);
|
||||
|
||||
var proxy = new WCF.Action.Proxy({
|
||||
success: function (data, textStatus, jqXHR) {
|
||||
$('.jsSuspensionRow').each(function(index, row) {
|
||||
var row = $(row);
|
||||
if (WCF.inArray(row.data('objectID'), data.objectIDs)) {
|
||||
row.find('.jsRevokeButton').addClass('disabled').removeClass('pointer').off('click');
|
||||
|
||||
(new WCF.System.Notification('{"chat.acp.suspension.revoke.success"|language|encodeJS}')).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
$('.jsRevokeButton:not(.disabled)').click(function () {
|
||||
var objectID = $(this).parents('.jsSuspensionRow').data('objectID');
|
||||
|
||||
WCF.System.Confirmation.show($(this).data('confirmMessage'), $.proxy(function (action) {
|
||||
if (action === 'confirm') {
|
||||
proxy.setOption('data', {
|
||||
actionName: 'revoke',
|
||||
className: '\\chat\\data\\suspension\\SuspensionAction',
|
||||
objectIDs: [ objectID ]
|
||||
});
|
||||
proxy.sendRequest();
|
||||
}
|
||||
}, this));
|
||||
});
|
||||
});
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
<header class="boxHeadline">
|
||||
<h1>{lang}chat.acp.suspension.list{/lang}</h1>
|
||||
</header>
|
||||
|
||||
<form method="post" action="{link controller='ChatSuspensionList' application='chat'}{/link}">
|
||||
<div class="container containerPadding marginTop">
|
||||
<fieldset>
|
||||
<legend>{lang}wcf.global.filter{/lang}</legend>
|
||||
|
||||
<dl>
|
||||
<dd>
|
||||
<label><input type="checkbox" id="displayRevoked" name="displayRevoked" value="1"{if $displayRevoked} checked="checked"{/if} /> {lang}chat.acp.suspension.displayRevoked{/lang}</label>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl>
|
||||
<dt><label for="username">{lang}wcf.user.username{/lang}</label></dt>
|
||||
<dd>
|
||||
<input type="text" id="username" name="username" class="medium" value="{$username}" />
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl>
|
||||
<dt><label for="issuerUsername">{lang}chat.acp.suspension.issuer{/lang}</label></dt>
|
||||
<dd>
|
||||
<input type="text" id="issuerUsername" name="issuerUsername" class="medium" value="{$issuerUsername}" />
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl>
|
||||
<dt><label for="roomID">{lang}chat.global.room{/lang}</label></dt>
|
||||
<dd>
|
||||
<select id="roomID" name="roomID">
|
||||
<option value="-1"{if $roomID == -1} selected="selected"{/if}></option>
|
||||
<option value="0"{if $roomID == 0} selected="selected"{/if}>{lang}chat.room.global{/lang}</option>
|
||||
<option value="" disabled="disabled">-------------</option>
|
||||
{foreach from=$availableRooms key=id item=room}
|
||||
<option value="{$id}" {if $roomID == $id}selected="selected"{/if}>{$room}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl>
|
||||
<dt><label for="suspensionType">{lang}chat.acp.suspension.type{/lang}</label></dt>
|
||||
<dd>
|
||||
<select id="suspensionType" name="suspensionType">
|
||||
<option value=""{if $suspensionType === null} selected="selected"{/if}></option>
|
||||
<option value="{'\chat\data\suspension\Suspension::TYPE_MUTE'|constant}"{if $suspensionType == '\chat\data\suspension\Suspension::TYPE_MUTE'|constant} selected="selected"{/if}>{lang}chat.suspension.{'\chat\data\suspension\Suspension::TYPE_MUTE'|constant}{/lang}</option>
|
||||
<option value="{'\chat\data\suspension\Suspension::TYPE_BAN'|constant}"{if $suspensionType == '\chat\data\suspension\Suspension::TYPE_BAN'|constant} selected="selected"{/if}>{lang}chat.suspension.{'\chat\data\suspension\Suspension::TYPE_BAN'|constant}{/lang}</option>
|
||||
</select>
|
||||
</dd>
|
||||
</dl>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div class="formSubmit">
|
||||
<input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s" />
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{if $objects|count}
|
||||
{capture assign=additionalParameters}{*
|
||||
*}{if $userID}&userID={$userID}{/if}{*
|
||||
*}{if $issuerUserID}&issuerUserID={$issuerUserID}{/if}{*
|
||||
*}{if $roomID}&roomID={$roomID}{/if}{*
|
||||
*}{if $suspensionType}&suspensionType={$suspensionType}{/if}{*
|
||||
*}{if $displayRevoked}&displayRevoked={$displayRevoked}{/if}{*
|
||||
*}{/capture}
|
||||
|
||||
<div class="contentNavigation">
|
||||
{pages print=true assign=pagesLinks application="chat" controller="ChatSuspensionList" link="pageNo=%d$additionalParameters"}
|
||||
</div>
|
||||
|
||||
<div class="tabularBox tabularBoxTitle marginTop">
|
||||
<header>
|
||||
<h2>{lang}chat.acp.suspension.list{/lang} <span class="badge badgeInverse">{#$items}</span></h2>
|
||||
</header>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="columnID{if $sortField == 'suspensionID'} active {@$sortOrder}{/if}" colspan="2"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=suspensionID&sortOrder={if $sortField == 'suspensionID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}wcf.global.objectID{/lang}</a></th>
|
||||
<th class="columnUsername{if $sortField == 'username'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=username&sortOrder={if $sortField == 'username' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}wcf.user.username{/lang}</a></th>
|
||||
<th class="columnRoomID{if $sortField == 'roomID'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=roomID&sortOrder={if $sortField == 'roomID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.global.room{/lang}</a></th>
|
||||
<th class="columnSuspensionType{if $sortField == 'type'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=type&sortOrder={if $sortField == 'type' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.acp.suspension.type{/lang}</a></th>
|
||||
<th class="columnTime{if $sortField == 'time'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=time&sortOrder={if $sortField == 'time' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.global.time{/lang}</a></th>
|
||||
<th class="columnExpires{if $sortField == 'expires'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=expires&sortOrder={if $sortField == 'expires' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.global.expires{/lang}</a></th>
|
||||
<th class="columnIssuer{if $sortField == 'issuer'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=issuer&sortOrder={if $sortField == 'issuer' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.acp.suspension.issuer{/lang}</a></th>
|
||||
<th class="columnMessage{if $sortField == 'reason'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=reason&sortOrder={if $sortField == 'reason' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.acp.suspension.reason{/lang}</a></th>
|
||||
|
||||
{event name='columnHeads'}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{foreach from=$objects item=$suspension}
|
||||
<tr class="jsSuspensionRow" data-object-id="{$suspension->suspensionID}">
|
||||
<td class="columnIcon">
|
||||
<span class="icon icon16 icon-undo{if $suspension->expires <= TIME_NOW} disabled{else} pointer{/if} jsRevokeButton" title="{lang}chat.acp.suspension.revoke{/lang}" data-confirm-message="{lang}chat.acp.suspension.revoke.sure{/lang}"></span>
|
||||
{event name='rowButtons'}
|
||||
</td>
|
||||
<td id="columnID">{#$suspension->suspensionID}</td>
|
||||
<td id="columnUsername"><a href="{link application='chat' controller='ChatSuspensionList'}userID={$suspension->userID}{/link}">{$suspension->username}</a></td>
|
||||
<td id="columnRoomID"><a href="{link application='chat' controller='ChatSuspensionList'}roomID={if $suspension->roomID}{$suspension->roomID}{else}0{/if}{/link}">{if $suspension->roomID}{$suspension->roomTitle|language}{else}{lang}chat.room.global{/lang}{/if}</a></td>
|
||||
<td id="columnSuspensionType"><a href="{link application='chat' controller='ChatSuspensionList'}suspensionType={$suspension->type}{/link}">{lang}chat.suspension.{@$suspension->type}{/lang}</a></td>
|
||||
<td id="columnTime">{$suspension->time|plainTime}</td>
|
||||
<td id="columnExpires">
|
||||
<p>{$suspension->expires|plainTime}{if $suspension->expires > TIME_NOW} ({$suspension->expires|dateDiff}){/if}</p>
|
||||
{if $suspension->revoker && $suspension->expires <= TIME_NOW}<p><small>{lang}chat.acp.suspension.revokedBy{/lang}</small></p>{/if}
|
||||
</td>
|
||||
<td id="columnIssuer"><a href="{link application='chat' controller='ChatSuspensionList'}issuerUserID={$suspension->issuer}{/link}">{$suspension->issuerUsername}</a></td>
|
||||
<td id="columnMessage"{if $suspension->reason != $suspension->reason|truncate:30} class="jsTooltip" title="{$suspension->reason}"{/if}>{$suspension->reason|truncate:30}</a></td>
|
||||
{event name='columns'}
|
||||
</tr>
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="contentNavigation">
|
||||
{@$pagesLinks}
|
||||
</div>
|
||||
{else}
|
||||
<p class="info">{lang}wcf.global.noItems{/lang}</p>
|
||||
{/if}
|
||||
|
||||
{include file='footer'}
|
109
acptemplate/messageLog.tpl
Normal file
@ -0,0 +1,109 @@
|
||||
{include file='header' pageTitle='chat.acp.log.title'}
|
||||
|
||||
{if CHAT_LOG_ARCHIVETIME !== 0}
|
||||
<script data-relocate="true" src="{$__wcf->getPath('chat')}acp/js/be.bastelstu.Chat.ACP.Log.js?version={PACKAGE_VERSION|rawurlencode}"></script>
|
||||
|
||||
{if $errorField === ''}
|
||||
<script data-relocate="true">
|
||||
//<![CDATA[
|
||||
$(function() {
|
||||
be.bastelstu.Chat.ACP.Log.TabMenu.init();
|
||||
WCF.TabMenu.init();
|
||||
});
|
||||
//]]>
|
||||
</script>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<header class="boxHeadline">
|
||||
<h1>{lang}{@$pageTitle}{/lang}</h1>
|
||||
</header>
|
||||
|
||||
{if CHAT_LOG_ARCHIVETIME !== 0}
|
||||
<form method="post" action="{link controller='MessageLog' application='chat'}{/link}">
|
||||
<div class="container containerPadding marginTop">
|
||||
<fieldset>
|
||||
<legend>{lang}wcf.global.filter{/lang}</legend>
|
||||
|
||||
<dl>
|
||||
<dt><label for="id">{lang}chat.global.room{/lang}</label></dt>
|
||||
<dd>
|
||||
<select id="id" name="id">
|
||||
{foreach from=$rooms item='roomBit'}
|
||||
<option value="{$roomBit->roomID}"{if $roomBit->roomID == $room->roomID} selected="selected"{/if}>{$roomBit}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl{if $errorField == 'date'} class="formError"{/if}>
|
||||
<dt><label for="date">{lang}chat.global.time{/lang}</label></dt>
|
||||
<dd>
|
||||
<input id="date" type="date" name="date"{if CHAT_LOG_ARCHIVETIME != -1} min="{TIME_NOW-CHAT_LOG_ARCHIVETIME*60|date:'Y-m-d'}"{/if} max="{TIME_NOW|date:'Y-m-d'}" value="{$date|date:'Y-m-d'}" />
|
||||
{if $errorField == 'date'}
|
||||
<small class="innerError">
|
||||
{lang}chat.acp.log.date.error.{$errorType}{/lang}
|
||||
</small>
|
||||
{/if}
|
||||
</dd>
|
||||
</dl>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div class="formSubmit">
|
||||
<input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s" />
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="contentNavigation">
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<a class="button" href="{link controller='MessageLogDownload' application='chat' object=$room date=$date|date:'Y-m-d'}{/link}">
|
||||
<span class="icon icon16 icon-download-alt"></span>
|
||||
<span>{lang}chat.acp.log.download{/lang}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
{if $errorField === ''}
|
||||
<div id="messageLogContent" class="tabMenuContainer marginTop" data-active="timeTab-0" data-store="activeTabMenuItem" data-base-time="{$date}" data-room-id="{$room->roomID}">
|
||||
<nav class="tabMenu">
|
||||
<ul>
|
||||
{section name=tabLoop loop=24 step=3}
|
||||
<li>
|
||||
{assign var=anchor value='timeTab-'|concat:$tabLoop}
|
||||
<a href="{@$__wcf->getAnchor($anchor)}">{if $tabLoop < 10}0{/if}{$tabLoop}:00 - {if $tabLoop + 2 < 10}0{/if}{$tabLoop + 2}:59</a>
|
||||
</li>
|
||||
{/section}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
{section name=contentLoop loop=24 step=3}
|
||||
<div id="timeTab-{$contentLoop}" class="container containerPadding tabMenuContainer tabMenuContent" data-menu-item="timeTab-{$contentLoop}">
|
||||
<nav class="menu">
|
||||
<ul>
|
||||
{section name=subTabLoop loop=6}
|
||||
{assign var=subAnchor value='timeTab-'|concat:$contentLoop|concat:'-subTab-'|concat:$subTabLoop}
|
||||
<li data-hour="{$contentLoop + $subTabLoop / 2|floor}" data-minutes="{($subTabLoop % 2) * 30}">
|
||||
<a href="{@$__wcf->getAnchor($subAnchor)}">{if $contentLoop + $subTabLoop / 2 < 10}0{/if}{$contentLoop + $subTabLoop / 2|floor}:{if $subTabLoop % 2 == 0}0{/if}{($subTabLoop % 2) * 30} - {if $contentLoop + $subTabLoop / 2 < 10}0{/if}{$contentLoop + $subTabLoop / 2|floor}:{($subTabLoop % 2) * 30 + 29}</a>
|
||||
</li>
|
||||
{/section}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
{section name=subTabLoop loop=6}
|
||||
{assign var=subAnchor value='timeTab-'|concat:$contentLoop|concat:'-subTab-'|concat:$subTabLoop}
|
||||
<div id="{$subAnchor}" class="hidden subTabMenuContent empty"></div>
|
||||
{/section}
|
||||
</div>
|
||||
{/section}
|
||||
</div>
|
||||
{/if}
|
||||
{else}
|
||||
<p class="error">{lang}chat.acp.log.error.disabled{/lang}</p>
|
||||
{/if}
|
||||
|
||||
{include file='footer'}
|
5
acptemplate/messageLogDownload.tpl
Normal file
@ -0,0 +1,5 @@
|
||||
{foreach from=$messages item=$rawMessage}{*
|
||||
*}{assign var=message value=$rawMessage->jsonify(true)}{*
|
||||
*}({$message['time']|date:'chat.global.timeFormat'}) {$message[username]|str_pad:15:' ':STR_PAD_LEFT}{$message[separator]} {$message[message]}
|
||||
|
||||
{/foreach}
|
103
acptemplate/roomAdd.tpl
Normal file
@ -0,0 +1,103 @@
|
||||
{include file='header' pageTitle='chat.acp.room.'|concat:$action}
|
||||
|
||||
{include file='aclPermissions'}
|
||||
{if !$roomID|isset}
|
||||
{include file='aclPermissionJavaScript' containerID='groupPermissions'}
|
||||
{else}
|
||||
{include file='aclPermissionJavaScript' containerID='groupPermissions' objectID=$roomID}
|
||||
{/if}
|
||||
|
||||
<header class="boxHeadline">
|
||||
<h1>{lang}chat.acp.room.{$action}{/lang}</h1>
|
||||
</header>
|
||||
|
||||
{include file='formError'}
|
||||
|
||||
{if $success|isset}
|
||||
<p class="success">{lang}wcf.global.success.{$action}{/lang}</p>
|
||||
{/if}
|
||||
|
||||
<div class="contentNavigation">
|
||||
{hascontent}
|
||||
<nav>
|
||||
<ul>
|
||||
{content}
|
||||
<li><a href="{link application='chat' controller='RoomList'}{/link}" class="button"><span class="icon icon16 icon-list"></span> <span>{lang}chat.acp.menu.link.room.list{/lang}</span></a></li>
|
||||
{event name='contentNavigationButtonsTop'}
|
||||
{/content}
|
||||
</ul>
|
||||
</nav>
|
||||
{/hascontent}
|
||||
</div>
|
||||
|
||||
<form method="post" action="{if $action == 'add'}{link application='chat' controller='RoomAdd'}{/link}{else}{link application='chat' controller='RoomEdit' id=$roomID}{/link}{/if}">
|
||||
<div class="container containerPadding marginTop">
|
||||
<fieldset>
|
||||
<legend>{lang}wcf.global.form.data{/lang}</legend>
|
||||
|
||||
<dl{if $errorField == 'title'} class="formError"{/if}>
|
||||
<dt><label for="title">{lang}chat.acp.room.title{/lang}</label></dt>
|
||||
<dd>
|
||||
<input type="text" id="title" name="title" value="{$title}" autofocus="autofocus" class="long" />
|
||||
{if $errorField == 'title'}
|
||||
<small class="innerError">
|
||||
{if $errorType == 'empty'}
|
||||
{lang}wcf.global.form.error.empty{/lang}
|
||||
{else}
|
||||
{lang}chat.acp.room.title.error.{@$errorType}{/lang}
|
||||
{/if}
|
||||
</small>
|
||||
{/if}
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
{include file='multipleLanguageInputJavascript' elementIdentifier='title' forceSelection=false}
|
||||
|
||||
<dl{if $errorField == 'topic'} class="formError"{/if}>
|
||||
<dt><label for="topic">{lang}chat.acp.room.topic{/lang}</label></dt>
|
||||
<dd>
|
||||
<input type="text" id="topic" name="topic" value="{$topic}" class="long" />
|
||||
{if $errorField == 'topic'}
|
||||
<small class="innerError">
|
||||
{if $errorType == 'empty'}
|
||||
{lang}wcf.global.form.error.empty{/lang}
|
||||
{else}
|
||||
{lang}chat.acp.room.topic.error.{@$errorType}{/lang}
|
||||
{/if}
|
||||
</small>
|
||||
{/if}
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
{include file='multipleLanguageInputJavascript' elementIdentifier='topic' forceSelection=false}
|
||||
|
||||
<dl{if $errorField == 'maxUsers'} class="formError"{/if}>
|
||||
<dt><label for="maxUsers">{lang}chat.acp.room.maxUsers{/lang}</label></dt>
|
||||
<dd>
|
||||
<input id="maxUsers" class="tiny" type="number" min="0" value="{$maxUsers}" name="maxUsers" />
|
||||
{if $errorField == 'maxUsers'}
|
||||
<small class="innerError">
|
||||
{if $errorType == 'empty'}
|
||||
{lang}wcf.global.form.error.empty{/lang}
|
||||
{else}
|
||||
{lang}chat.acp.room.topic.error.{@$errorType}{/lang}
|
||||
{/if}
|
||||
</small>
|
||||
{/if}
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="groupPermissions">
|
||||
<dt>{lang}wcf.acl.permissions{/lang}</dt>
|
||||
<dd></dd>
|
||||
</dl>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div class="formSubmit">
|
||||
<input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s" />
|
||||
{@SECURITY_TOKEN_INPUT_TAG}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{include file='footer'}
|
66
acptemplate/roomList.tpl
Normal file
@ -0,0 +1,66 @@
|
||||
{include file='header' pageTitle='chat.acp.room.list'}
|
||||
|
||||
<script data-relocate="true">
|
||||
//<![CDATA[
|
||||
$(function() {
|
||||
new WCF.Action.Delete('\\chat\\data\\room\\RoomAction', $('.chatRoomRow'));
|
||||
new WCF.Sortable.List('roomList', '\\chat\\data\\room\\RoomAction');
|
||||
});
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
<header class="boxHeadline">
|
||||
<h1>{lang}chat.acp.room.list{/lang}</h1>
|
||||
</header>
|
||||
|
||||
<div class="contentNavigation">
|
||||
{hascontent}
|
||||
<nav>
|
||||
<ul>
|
||||
{content}
|
||||
{if $__wcf->session->getPermission('admin.chat.canAddRoom')}
|
||||
<li><a href="{link application='chat' controller='RoomAdd'}{/link}" class="button"><span class="icon icon16 icon-plus"></span> <span>{lang}chat.acp.room.add{/lang}</span></a></li>
|
||||
{/if}
|
||||
{event name='contentNavigationButtonsTop'}
|
||||
{/content}
|
||||
</ul>
|
||||
</nav>
|
||||
{/hascontent}
|
||||
</div>
|
||||
|
||||
{if $objects|count}
|
||||
<section id="roomList" class="container containerPadding sortableListContainer marginTop">
|
||||
<ol class="sortableList" data-object-id="0">
|
||||
{foreach from=$objects item=chatRoom}
|
||||
<li class="sortableNode sortableNoNesting chatRoomRow" data-object-id="{@$chatRoom->roomID}">
|
||||
<span class="sortableNodeLabel">
|
||||
{if $__wcf->session->getPermission('admin.chat.canEditRoom')}
|
||||
<a href="{link application='chat' controller='RoomEdit' id=$chatRoom->roomID}{/link}">{$chatRoom->title|language}</a>
|
||||
{else}
|
||||
{$chatRoom->title|language}
|
||||
{/if}
|
||||
|
||||
<span class="statusDisplay sortableButtonContainer">
|
||||
{if $__wcf->session->getPermission('admin.chat.canEditRoom')}
|
||||
<a href="{link application='chat' controller='RoomEdit' id=$chatRoom->roomID}{/link}"><span title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip icon icon16 icon-pencil" /></a>
|
||||
{/if}
|
||||
{if $__wcf->session->getPermission('admin.chat.canDeleteRoom')}
|
||||
<span title="{lang}wcf.global.button.delete{/lang}" class="jsDeleteButton jsTooltip icon icon16 icon-remove" data-object-id="{@$chatRoom->roomID}" data-confirm-message="{lang}chat.acp.room.delete.sure{/lang}" />
|
||||
{/if}
|
||||
|
||||
{event name='itemButtons'}
|
||||
</span>
|
||||
</span>
|
||||
<ol class="sortableList" data-object-id="{@$chatRoom->roomID}"></ol></li>
|
||||
</li>
|
||||
{/foreach}
|
||||
</ol>
|
||||
<div class="formSubmit">
|
||||
<button class="button buttonPrimary" data-type="submit">{lang}wcf.global.button.saveSorting{/lang}</button>
|
||||
</div>
|
||||
</section>
|
||||
{else}
|
||||
<p class="warning">{lang}wcf.global.noItems{/lang}</p>
|
||||
{/if}
|
||||
|
||||
{include file='footer'}
|
@ -1,68 +0,0 @@
|
||||
{include file='header' pageTitle='chat.acp.command.trigger.'|concat:$action}
|
||||
|
||||
<header class="contentHeader">
|
||||
<div class="contentHeaderTitle">
|
||||
<h1 class="contentTitle">{lang}chat.acp.command.trigger.{$action}{/lang}</h1>
|
||||
</div>
|
||||
|
||||
<nav class="contentHeaderNavigation">
|
||||
<ul>
|
||||
<li><a href="{link application='chat' controller='CommandTriggerList'}{/link}" class="button">{icon name='list'} <span>{lang}chat.acp.command.trigger.list{/lang}</span></a></li>
|
||||
|
||||
{event name='contentHeaderNavigation'}
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
{include file='formNotice'}
|
||||
|
||||
<form method="post" action="{if $action == 'add'}{link application='chat' controller='CommandTriggerAdd'}{/link}{else}{link application='chat' controller='CommandTriggerEdit' id=$triggerID}{/link}{/if}">
|
||||
<div class="section">
|
||||
<div class="section">
|
||||
<dl{if $errorField == 'commandTrigger'} class="formError"{/if}>
|
||||
<dt><label for="commandTrigger">{lang}chat.acp.command.trigger{/lang}</label></dt>
|
||||
<dd>
|
||||
<input type="text" id="commandTrigger" name="commandTrigger" value="{$commandTrigger}" autofocus class="medium">
|
||||
{if $errorField == 'commandTrigger'}
|
||||
<small class="innerError">
|
||||
{if $errorType == 'empty'}
|
||||
{lang}wcf.global.form.error.empty{/lang}
|
||||
{else}
|
||||
{lang}chat.acp.command.trigger.commandTrigger.error.{@$errorType}{/lang}
|
||||
{/if}
|
||||
</small>
|
||||
{/if}
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl{if $errorField == 'className'} class="formError"{/if}>
|
||||
<dt><label for="className">{lang}chat.acp.command.className{/lang}</label></dt>
|
||||
<dd>
|
||||
<select id="className" name="className">
|
||||
{foreach from=$availableCommands item=$command}
|
||||
<option value="{$command->className}"{if $command->className === $className} selected{/if}>{$command->className}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
|
||||
{if $errorField == 'className'}
|
||||
<small class="innerError">
|
||||
{if $errorType == 'empty'}
|
||||
{lang}wcf.global.form.error.empty{/lang}
|
||||
{else}
|
||||
{lang}chat.acp.command.trigger.className.error.{@$errorType}{/lang}
|
||||
{/if}
|
||||
</small>
|
||||
{/if}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="formSubmit">
|
||||
<input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s">
|
||||
{csrfToken}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{include file='footer'}
|
||||
|
@ -1,86 +0,0 @@
|
||||
{include file='header' pageTitle='chat.acp.command.trigger.list'}
|
||||
|
||||
<script data-relocate="true">
|
||||
$(function() {
|
||||
new WCF.Action.Delete('chat\\data\\command\\CommandTriggerAction', '.jsTriggerRow');
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<header class="contentHeader">
|
||||
<div class="contentHeaderTitle">
|
||||
<h1 class="contentTitle">{lang}chat.acp.command.trigger.list{/lang}</h1>
|
||||
</div>
|
||||
|
||||
<nav class="contentHeaderNavigation">
|
||||
<ul>
|
||||
<li><a href="{link controller='CommandTriggerAdd' application='chat'}{/link}" class="button">{icon name='plus'} <span>{lang}chat.acp.command.trigger.add{/lang}</span></a></li>
|
||||
|
||||
{event name='contentHeaderNavigation'}
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
{hascontent}
|
||||
<div class="paginationTop">
|
||||
{content}{pages print=true assign=pagesLinks controller="CommandTriggerList" application="chat" link="pageNo=%d&sortField=$sortField&sortOrder=$sortOrder"}{/content}
|
||||
</div>
|
||||
{/hascontent}
|
||||
|
||||
{hascontent}
|
||||
<div class="section tabularBox">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="columnID columnTriggerID{if $sortField == 'triggerID'} active {@$sortOrder}{/if}" colspan="2"><a href="{link controller='CommandTriggerList' application='chat'}pageNo={@$pageNo}&sortField=triggerID&sortOrder={if $sortField == 'triggerID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.global.objectID{/lang}</a></th>
|
||||
<th class="columnTitle columnTrigger{if $sortField == 'commandTrigger'} active {@$sortOrder}{/if}"><a href="{link controller='CommandTriggerList' application='chat'}pageNo={@$pageNo}&sortField=commandTrigger&sortOrder={if $sortField == 'commandTrigger' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}chat.acp.command.trigger{/lang}</a></th>
|
||||
<th class="columnText columnClassName{if $sortField == 'className'} active {@$sortOrder}{/if}"><a href="{link controller='CommandTriggerList' application='chat'}pageNo={@$pageNo}&sortField=className&sortOrder={if $sortField == 'className' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}chat.acp.command.className{/lang}</a></th>
|
||||
|
||||
{event name='columnHeads'}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{content}
|
||||
{foreach from=$objects item=trigger}
|
||||
<tr class="jsTriggerRow">
|
||||
<td class="columnIcon">
|
||||
<a href="{link controller='CommandTriggerEdit' object=$trigger application='chat'}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip">{icon name='pencil'}</a>
|
||||
<span class="jsDeleteButton jsTooltip pointer" title="{lang}wcf.global.button.delete{/lang}" data-object-id="{$trigger->triggerID}" data-confirm-message-html="{lang __encode=true}chat.acp.command.trigger.delete.sure{/lang}">{icon name='xmark'}</span>
|
||||
|
||||
{event name='rowButtons'}
|
||||
</td>
|
||||
|
||||
<td class="columnID">{@$trigger->triggerID}</td>
|
||||
<td class="columnTitle columnTrigger"><a href="{link controller='CommandTriggerEdit' object=$trigger application='chat'}{/link}">/{$trigger->commandTrigger}</a></td>
|
||||
<td class="columnText columnClassName">{$trigger->className}</td>
|
||||
|
||||
{event name='columns'}
|
||||
</tr>
|
||||
{/foreach}
|
||||
{/content}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{hascontentelse}
|
||||
<p class="info">{lang}wcf.global.noItems{/lang}</p>
|
||||
{/hascontent}
|
||||
|
||||
<footer class="contentFooter">
|
||||
{hascontent}
|
||||
<div class="paginationBottom">
|
||||
{content}{@$pagesLinks}{/content}
|
||||
</div>
|
||||
{/hascontent}
|
||||
|
||||
<nav class="contentFooterNavigation">
|
||||
<ul>
|
||||
<li><a href="{link controller='CommandTriggerAdd' application='chat'}{/link}" class="button">{icon name='plus'} <span>{lang}chat.acp.command.trigger.add{/lang}</span></a></li>
|
||||
|
||||
{event name='contentFooterNavigation'}
|
||||
</ul>
|
||||
</nav>
|
||||
</footer>
|
||||
|
||||
{include file='footer'}
|
||||
|
@ -1,109 +0,0 @@
|
||||
{include file='header' pageTitle='chat.acp.room.'|concat:$action}
|
||||
|
||||
{include file='aclPermissions'}
|
||||
|
||||
{include file='multipleLanguageInputJavascript' elementIdentifier='title' forceSelection=false}
|
||||
{include file='multipleLanguageInputJavascript' elementIdentifier='topic' forceSelection=false}
|
||||
|
||||
{if $roomID|isset}
|
||||
{include file='aclPermissionJavaScript' containerID='aclContainer' objectTypeID=$aclObjectTypeID objectID=$roomID}
|
||||
{else}
|
||||
{include file='aclPermissionJavaScript' containerID='aclContainer' objectTypeID=$aclObjectTypeID}
|
||||
{/if}
|
||||
|
||||
<header class="contentHeader">
|
||||
<div class="contentHeaderTitle">
|
||||
<h1 class="contentTitle">{lang}chat.acp.room.{$action}{/lang}</h1>
|
||||
{if $action == 'edit'}<p class="contentHeaderDescription">{$room->getTitle()}</p>{/if}
|
||||
</div>
|
||||
|
||||
<nav class="contentHeaderNavigation">
|
||||
<ul>
|
||||
<li><a href="{link application='chat' controller='RoomList'}{/link}" class="button">{icon name='list'} <span>{lang}chat.acp.room.list{/lang}</span></a></li>
|
||||
|
||||
{event name='contentHeaderNavigation'}
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
{include file='formNotice'}
|
||||
|
||||
<form method="post" action="{if $action == 'add'}{link application='chat' controller='RoomAdd'}{/link}{else}{link application='chat' controller='RoomEdit' id=$roomID}{/link}{/if}">
|
||||
<div class="section">
|
||||
<div class="section">
|
||||
<dl{if $errorField == 'title'} class="formError"{/if}>
|
||||
<dt><label for="title">{lang}wcf.global.title{/lang}</label></dt>
|
||||
<dd>
|
||||
<input type="text" id="title" name="title" value="{$i18nPlainValues['title']}" autofocus class="medium">
|
||||
{if $errorField == 'title'}
|
||||
<small class="innerError">
|
||||
{if $errorType == 'empty'}
|
||||
{lang}wcf.global.form.error.empty{/lang}
|
||||
{elseif $errorType == 'multilingual'}
|
||||
{lang}wcf.global.form.error.multilingual{/lang}
|
||||
{else}
|
||||
{lang}chat.acp.room.title.error.{@$errorType}{/lang}
|
||||
{/if}
|
||||
</small>
|
||||
{/if}
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl{if $errorField == 'topic'} class="formError"{/if}>
|
||||
<dt><label for="topic">{lang}chat.acp.room.topic{/lang}</label></dt>
|
||||
<dd>
|
||||
<input type="text" id="topic" name="topic" value="{$i18nPlainValues['topic']}" class="long">
|
||||
|
||||
{if $errorField == 'topic'}
|
||||
<small class="innerError">
|
||||
{if $errorType == 'empty'}
|
||||
{lang}wcf.global.form.error.empty{/lang}
|
||||
{else}
|
||||
{lang}chat.acp.room.topic.error.{@$errorType}{/lang}
|
||||
{/if}
|
||||
</small>
|
||||
{/if}
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl{if $errorField == 'topicUseHtml'} class="formError"{/if}>
|
||||
<dt></dt>
|
||||
<dd>
|
||||
<label><input type="checkbox" name="topicUseHtml" value="1"{if $topicUseHtml} checked{/if}> {lang}chat.acp.room.topicUseHtml{/lang}</label>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl{if $errorField == 'userLimit'} class="formError"{/if}>
|
||||
<dt><label for="userLimit">{lang}chat.acp.room.userLimit{/lang}</label></dt>
|
||||
<dd>
|
||||
<input type="number" id="userLimit" name="userLimit" value="{$userLimit}" min="0" class="medium">
|
||||
|
||||
{if $errorField == 'userLimit'}
|
||||
<small class="innerError">
|
||||
{if $errorType == 'empty'}
|
||||
{lang}wcf.global.form.error.empty{/lang}
|
||||
{else}
|
||||
{lang}chat.acp.room.userLimit.error.{@$errorType}{/lang}
|
||||
{/if}
|
||||
</small>
|
||||
{/if}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<dl id="aclContainer">
|
||||
<dt>{lang}wcf.acl.permissions{/lang}</dt>
|
||||
<dd></dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="formSubmit">
|
||||
<input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s">
|
||||
{csrfToken}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{include file='footer'}
|
||||
|
@ -1,81 +0,0 @@
|
||||
{include file='header' pageTitle='chat.acp.room.list'}
|
||||
|
||||
<script data-relocate="true">
|
||||
$(function() {
|
||||
require([ 'WoltLabSuite/Core/Ui/Sortable/List' ], function (UiSortableList) {
|
||||
new UiSortableList({ containerId: 'roomNodeList'
|
||||
, className: 'chat\\data\\room\\RoomAction'
|
||||
})
|
||||
})
|
||||
|
||||
new WCF.Action.Delete('chat\\data\\room\\RoomAction', '#roomNodeList')
|
||||
})
|
||||
</script>
|
||||
|
||||
<header class="contentHeader">
|
||||
<div class="contentHeaderTitle">
|
||||
<h1 class="contentTitle">{lang}chat.acp.room.list{/lang}</h1>
|
||||
</div>
|
||||
|
||||
<nav class="contentHeaderNavigation">
|
||||
<ul>
|
||||
<li><a href="{link controller='RoomAdd' application='chat'}{/link}" class="button">{icon name='plus'} <span>{lang}chat.acp.room.add{/lang}</span></a></li>
|
||||
|
||||
{event name='contentHeaderNavigation'}
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
{hascontent}
|
||||
<div class="paginationTop">
|
||||
{content}{pages print=true assign=pagesLinks controller="RoomList" application="chat" link="pageNo=%d&sortField=$sortField&sortOrder=$sortOrder"}{/content}
|
||||
</div>
|
||||
{/hascontent}
|
||||
|
||||
{hascontent}
|
||||
<div id="roomNodeList" class="section sortableListContainer">
|
||||
<ol id="roomContainer0" class="sortableList" data-object-id="0">
|
||||
{content}
|
||||
{foreach from=$objects item=room}
|
||||
<li class="sortableNode sortableNoNesting" data-object-id="{$room->roomID}">
|
||||
<span class="sortableNodeLabel">
|
||||
<a href="{link controller='RoomEdit' application='chat' object=$room}{/link}">{$room}</a>
|
||||
|
||||
<span class="statusDisplay sortableButtonContainer">
|
||||
<span class="sortableNodeHandle">{icon name='up-down-left-right'}</span>
|
||||
<a href="{link controller='RoomEdit' application='chat' object=$room}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip">{icon name='pencil'}</a>
|
||||
<span class="jsDeleteButton jsTooltip pointer" title="{lang}wcf.global.button.delete{/lang}" data-object-id="{$room->roomID}" data-confirm-message-html="{lang __encode=true}chat.acp.room.delete.sure{/lang}">{icon name='xmark'}</span>
|
||||
{event name='itemButtons'}
|
||||
</span>
|
||||
</span>
|
||||
</li>
|
||||
{/foreach}
|
||||
{/content}
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="formSubmit">
|
||||
<button class="button buttonPrimary" data-type="submit">{lang}wcf.global.button.saveSorting{/lang}</button>
|
||||
</div>
|
||||
{hascontentelse}
|
||||
<p class="info">{lang}wcf.global.noItems{/lang}</p>
|
||||
{/hascontent}
|
||||
|
||||
<footer class="contentFooter">
|
||||
{hascontent}
|
||||
<div class="paginationBottom">
|
||||
{content}{@$pagesLinks}{/content}
|
||||
</div>
|
||||
{/hascontent}
|
||||
|
||||
<nav class="contentFooterNavigation">
|
||||
<ul>
|
||||
<li><a href="{link controller='RoomAdd' application='chat'}{/link}" class="button">{icon name='plus'} <span>{lang}chat.acp.room.add{/lang}</span></a></li>
|
||||
|
||||
{event name='contentFooterNavigation'}
|
||||
</ul>
|
||||
</nav>
|
||||
</footer>
|
||||
|
||||
{include file='footer'}
|
||||
|
@ -1,192 +0,0 @@
|
||||
{include file='header' pageTitle='chat.acp.suspension.list'}
|
||||
|
||||
<script>
|
||||
require([ 'Bastelstu.be/PromiseWrap/Ajax', 'Bastelstu.be/PromiseWrap/Ui/Confirmation', 'WoltLabSuite/Core/Dom/Traverse' ], function (Ajax, Confirmation, Traverse) {
|
||||
elBySelAll('.jsRevokeButton:not(.disabled)', document, function (button) {
|
||||
const row = Traverse.parentByClass(button, 'jsSuspensionRow')
|
||||
if (row == null) {
|
||||
throw new Error('Unreachable')
|
||||
}
|
||||
const objectID = row.dataset.objectId
|
||||
const listener = function (event) {
|
||||
Confirmation.show({
|
||||
message: button.dataset.confirmMessageHtml,
|
||||
messageIsHtml: true
|
||||
}).then(function () {
|
||||
const payload = { data: { className: 'chat\\data\\suspension\\SuspensionAction'
|
||||
, actionName: 'revoke'
|
||||
, objectIDs: [ objectID ]
|
||||
}
|
||||
}
|
||||
return Ajax.apiOnce(payload)
|
||||
}).then(function () {
|
||||
button.classList.remove('pointer')
|
||||
button.classList.add('disabled')
|
||||
button.removeEventListener('click', listener)
|
||||
})
|
||||
}
|
||||
button.addEventListener('click', listener)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<header class="contentHeader">
|
||||
<div class="contentHeaderTitle">
|
||||
<h1 class="contentTitle">{lang}chat.acp.suspension.list{/lang}</h1>
|
||||
</div>
|
||||
|
||||
{hascontent}
|
||||
<nav class="contentHeaderNavigation">
|
||||
<ul>
|
||||
{content}{event name='contentHeaderNavigation'}{/content}
|
||||
</ul>
|
||||
</nav>
|
||||
{/hascontent}
|
||||
</header>
|
||||
|
||||
<form method="post" action="{link controller='SuspensionList' application='chat'}{/link}">
|
||||
<section class="section">
|
||||
<h2 class="sectionTitle">{lang}wcf.global.filter{/lang}</h2>
|
||||
|
||||
<div class="row rowColGap formGrid">
|
||||
<dl class="col-xs-12 col-md-4">
|
||||
<dt></dt>
|
||||
<dd>
|
||||
<select name="roomID" id="roomID">
|
||||
<option value=""{if $roomID === null} selected{/if}>{lang}chat.acp.suspension.room.all{/lang}</option>
|
||||
<option value="0"{if $roomID === 0} selected{/if}>{lang}chat.acp.suspension.room.global{/lang}</option>
|
||||
{htmlOptions options=$availableRooms selected=$roomID}
|
||||
</select>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl class="col-xs-12 col-md-4">
|
||||
<dt></dt>
|
||||
<dd>
|
||||
<select name="objectTypeID" id="objectTypeID">
|
||||
<option value="">{lang}chat.acp.suspension.objectType.allTypes{/lang}</option>
|
||||
{foreach from=$availableObjectTypes item=availableObjectType}
|
||||
<option value="{$availableObjectType->objectTypeID}"{if $availableObjectType->objectTypeID == $objectTypeID} selected{/if}>{lang}chat.acp.suspension.type.{$availableObjectType->objectType}{/lang}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl class="col-xs-12 col-md-4">
|
||||
<dt></dt>
|
||||
<dd>
|
||||
<input type="text" id="searchUsername" name="searchUsername" value="{$searchUsername}" placeholder="{lang}chat.acp.suspension.username{/lang}" class="long">
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
<dl class="col-xs-12 col-md-4">
|
||||
<dt></dt>
|
||||
<dd>
|
||||
<input type="text" id="searchJudge" name="searchJudge" value="{$searchJudge}" placeholder="{lang}chat.acp.suspension.judge{/lang}" class="long">
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl class="col-xs-12 col-md-4">
|
||||
<dt></dt>
|
||||
<dd>
|
||||
<label><input name="showExpired" value="1" type="checkbox"{if $showExpired !== false} checked{/if}>{lang}chat.acp.suspension.showExpired{/lang}</label>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
{event name='filterFields'}
|
||||
</div>
|
||||
|
||||
<div class="formSubmit">
|
||||
<input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s">
|
||||
{csrfToken}
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
|
||||
|
||||
{capture assign=additionalParameters}{*
|
||||
*}{if $userID !== null}&userID={$userID}{/if}{*
|
||||
*}{if $judgeID !== null}&judgeID={$judgeID}{/if}{*
|
||||
*}{if $roomID !== null}&roomID={$roomID}{/if}{*
|
||||
*}{if $objectTypeID !== null}&objectTypeID={$objectTypeID}{/if}{*
|
||||
*}{if $showExpired !== null}&showExpired={$showExpired}{/if}{*
|
||||
*}{/capture}
|
||||
|
||||
{hascontent}
|
||||
<div class="paginationTop">
|
||||
{content}{pages print=true assign=pagesLinks controller="SuspensionList" application="chat" link="pageNo=%d&sortField=$sortField&sortOrder=$sortOrder$additionalParameters"}{/content}
|
||||
</div>
|
||||
{/hascontent}
|
||||
|
||||
{hascontent}
|
||||
<div class="section tabularBox">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="columnID columnSuspensionID{if $sortField == 'suspensionID'} active {@$sortOrder}{/if}" colspan="2"><a href="{link controller='SuspensionList' application='chat'}pageNo={@$pageNo}&sortField=suspensionID&sortOrder={if $sortField == 'suspensionID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}wcf.global.objectID{/lang}</a></th>
|
||||
<th class="columnTitle columnObjectType">{lang}chat.acp.suspension.type{/lang}</th>
|
||||
<th class="columnText columnUsername">{lang}chat.acp.suspension.username{/lang}</th>
|
||||
<th class="columnText columnJudge">{lang}chat.acp.suspension.judge{/lang}</th>
|
||||
<th class="columnText columnRoom">{lang}chat.acp.suspension.room{/lang}</th>
|
||||
<th class="columnText columnTime{if $sortField == 'time'} active {@$sortOrder}{/if}"><a href="{link controller='SuspensionList' application='chat'}pageNo={@$pageNo}&sortField=time&sortOrder={if $sortField == 'time' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.acp.suspension.time{/lang}</a></th>
|
||||
<th class="columnText columnExpires{if $sortField == 'expiresSort'} active {@$sortOrder}{/if}"><a href="{link controller='SuspensionList' application='chat'}pageNo={@$pageNo}&sortField=expiresSort&sortOrder={if $sortField == 'expiresSort' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.acp.suspension.expires{/lang}</a></th>
|
||||
|
||||
{event name='columnHeads'}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{content}
|
||||
{foreach from=$objects item=suspension}
|
||||
<tr class="jsSuspensionRow" data-object-id="{$suspension->suspensionID}">
|
||||
<td class="columnIcon">
|
||||
<span class="jsRevokeButton{if !$suspension->isActive()} disabled{else} pointer{/if}" title="{lang}chat.acp.suspension.revoke{/lang}" data-confirm-message-html="{lang}chat.acp.suspension.revoke.sure{/lang}">{icon name='arrow-rotate-left'}</span>
|
||||
{event name='rowButtons'}
|
||||
</td>
|
||||
|
||||
<td class="columnID">{@$suspension->suspensionID}</td>
|
||||
<td class="columnTitle columnObjectType"><a href="{link controller="SuspensionList" application="chat"}objectTypeID={$suspension->objectTypeID}{/link}">{lang}chat.acp.suspension.type.{$suspension->getSuspensionType()->objectType}{/lang}</a></td>
|
||||
<td class="columnText columnUsername"><a href="{link controller="SuspensionList" application="chat"}userID={$suspension->userID}{/link}">{$suspension->getUser()->username}</a></td>
|
||||
<td class="columnText columnJudge"><a href="{link controller="SuspensionList" application="chat"}judgeID={$suspension->judgeID}{/link}">{$suspension->judge}</a></td>
|
||||
<td class="columnText columnRoom"><a href="{link controller="SuspensionList" application="chat"}roomID={$suspension->roomID}{/link}">{if $suspension->getRoom() !== null}{$suspension->getRoom()}{else}-{/if}</a></td>
|
||||
<td class="columnText columnTime">{@$suspension->time|time}</td>
|
||||
<td class="columnText columnExpires">
|
||||
{assign var='isActive' value=$suspension->isActive()}
|
||||
{if $isActive}<strong>{/if}
|
||||
{if $suspension->expires !== null}{@$suspension->expires|time}{else}{lang}chat.acp.suspension.expires.forever{/lang}{/if}
|
||||
{if $isActive}</strong>{/if}
|
||||
{if $suspension->revoked !== null}
|
||||
<br>{lang}chat.acp.suspension.revoked{/lang}
|
||||
{/if}
|
||||
</td>
|
||||
|
||||
{event name='columns'}
|
||||
</tr>
|
||||
{/foreach}
|
||||
{/content}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{hascontentelse}
|
||||
<p class="info">{lang}wcf.global.noItems{/lang}</p>
|
||||
{/hascontent}
|
||||
|
||||
<footer class="contentFooter">
|
||||
{hascontent}
|
||||
<div class="paginationBottom">
|
||||
{content}{@$pagesLinks}{/content}
|
||||
</div>
|
||||
{/hascontent}
|
||||
|
||||
{hascontent}
|
||||
<nav class="contentFooterNavigation">
|
||||
<ul>
|
||||
{content}{event name='contentFooterNavigation'}{/content}
|
||||
</ul>
|
||||
</nav>
|
||||
{/hascontent}
|
||||
</footer>
|
||||
|
||||
{include file='footer'}
|
||||
|
42
box.xml
@ -1,42 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/vortex/box.xsd">
|
||||
<import>
|
||||
<box identifier="be.bastelstu.chat.roomListDashboard">
|
||||
<name language="de">Chaträume (Inhaltsbereich)</name>
|
||||
<name language="en">Chat Rooms (Content)</name>
|
||||
<boxType>system</boxType>
|
||||
<objectType>be.bastelstu.chat.roomList</objectType>
|
||||
<position>contentTop</position>
|
||||
<showHeader>1</showHeader>
|
||||
<visibleEverywhere>0</visibleEverywhere>
|
||||
<visibilityExceptions>
|
||||
<page>com.woltlab.wcf.Dashboard</page>
|
||||
</visibilityExceptions>
|
||||
<content language="de">
|
||||
<title>Chaträume</title>
|
||||
</content>
|
||||
<content language="en">
|
||||
<title>Chat Rooms</title>
|
||||
</content>
|
||||
</box>
|
||||
|
||||
<box identifier="be.bastelstu.chat.roomListSidebar">
|
||||
<name language="de">Chaträume (Seitenleiste)</name>
|
||||
<name language="en">Chat Rooms (Sidebar)</name>
|
||||
<boxType>system</boxType>
|
||||
<objectType>be.bastelstu.chat.roomList</objectType>
|
||||
<position>sidebarRight</position>
|
||||
<showHeader>1</showHeader>
|
||||
<visibleEverywhere>0</visibleEverywhere>
|
||||
<visibilityExceptions>
|
||||
<page>be.bastelstu.chat.Room</page>
|
||||
</visibilityExceptions>
|
||||
<content language="de">
|
||||
<title>Chaträume</title>
|
||||
</content>
|
||||
<content language="en">
|
||||
<title>Chat Rooms</title>
|
||||
</content>
|
||||
</box>
|
||||
</import>
|
||||
</data>
|
103
chatCommand.xml
@ -1,103 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<import>
|
||||
<command name="away">
|
||||
<classname>chat\system\command\AwayCommand</classname>
|
||||
<triggers>
|
||||
<trigger>away</trigger>
|
||||
</triggers>
|
||||
</command>
|
||||
|
||||
<command name="back">
|
||||
<classname>chat\system\command\BackCommand</classname>
|
||||
</command>
|
||||
|
||||
<command name="ban">
|
||||
<classname>chat\system\command\BanCommand</classname>
|
||||
<triggers>
|
||||
<trigger>ban</trigger>
|
||||
</triggers>
|
||||
</command>
|
||||
|
||||
<command name="broadcast">
|
||||
<classname>chat\system\command\BroadcastCommand</classname>
|
||||
<triggers>
|
||||
<trigger>broadcast</trigger>
|
||||
</triggers>
|
||||
</command>
|
||||
|
||||
<command name="color">
|
||||
<classname>chat\system\command\ColorCommand</classname>
|
||||
<triggers>
|
||||
<trigger>color</trigger>
|
||||
</triggers>
|
||||
</command>
|
||||
|
||||
<command name="info">
|
||||
<classname>chat\system\command\InfoCommand</classname>
|
||||
<triggers>
|
||||
<trigger>info</trigger>
|
||||
</triggers>
|
||||
</command>
|
||||
|
||||
<command name="me">
|
||||
<classname>chat\system\command\MeCommand</classname>
|
||||
<triggers>
|
||||
<trigger>me</trigger>
|
||||
</triggers>
|
||||
</command>
|
||||
|
||||
<command name="mute">
|
||||
<classname>chat\system\command\MuteCommand</classname>
|
||||
<triggers>
|
||||
<trigger>mute</trigger>
|
||||
</triggers>
|
||||
</command>
|
||||
|
||||
<command name="plain">
|
||||
<classname>chat\system\command\PlainCommand</classname>
|
||||
</command>
|
||||
|
||||
<command name="team">
|
||||
<classname>chat\system\command\TeamCommand</classname>
|
||||
<triggers>
|
||||
<trigger>team</trigger>
|
||||
</triggers>
|
||||
</command>
|
||||
|
||||
<command name="temproom">
|
||||
<classname>chat\system\command\TemproomCommand</classname>
|
||||
<triggers>
|
||||
<trigger>temproom</trigger>
|
||||
</triggers>
|
||||
</command>
|
||||
|
||||
<command name="unban">
|
||||
<classname>chat\system\command\UnbanCommand</classname>
|
||||
<triggers>
|
||||
<trigger>unban</trigger>
|
||||
</triggers>
|
||||
</command>
|
||||
|
||||
<command name="unmute">
|
||||
<classname>chat\system\command\UnmuteCommand</classname>
|
||||
<triggers>
|
||||
<trigger>unmute</trigger>
|
||||
</triggers>
|
||||
</command>
|
||||
|
||||
<command name="where">
|
||||
<classname>chat\system\command\WhereCommand</classname>
|
||||
<triggers>
|
||||
<trigger>where</trigger>
|
||||
</triggers>
|
||||
</command>
|
||||
|
||||
<command name="whisper">
|
||||
<classname>chat\system\command\WhisperCommand</classname>
|
||||
<triggers>
|
||||
<trigger>whisper</trigger>
|
||||
</triggers>
|
||||
</command>
|
||||
</import>
|
||||
</data>
|
@ -1,6 +0,0 @@
|
||||
<?php
|
||||
define("CHAT_RELOADTIME", 3);
|
||||
define("CHAT_AUTOAWAYTIME", 0);
|
||||
define("CHAT_MAX_LENGTH", 500);
|
||||
define("CHAT_ARCHIVE_AFTER", 90);
|
||||
define("CHAT_LOG_ARCHIVETIME", 7);
|
136
contrib/build.php
Executable file
@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
namespace be\bastelstu\chat;
|
||||
|
||||
/**
|
||||
* Builds the Chat
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
*/
|
||||
$packageXML = file_get_contents('package.xml');
|
||||
preg_match('/<version>(.*?)<\/version>/', $packageXML, $matches);
|
||||
echo "Building Tims Chat $matches[1]\n";
|
||||
echo str_repeat("=", strlen("Building Tims Chat $matches[1]"))."\n";
|
||||
|
||||
echo <<<EOT
|
||||
Cleaning up
|
||||
-----------
|
||||
|
||||
EOT;
|
||||
if (file_exists('package.xml.old')) {
|
||||
file_put_contents('package.xml', file_get_contents('package.xml.old'));
|
||||
unlink('package.xml.old');
|
||||
}
|
||||
if (file_exists('file.tar')) unlink('file.tar');
|
||||
if (file_exists('template.tar')) unlink('template.tar');
|
||||
if (file_exists('acptemplate.tar')) unlink('acptemplate.tar');
|
||||
foreach (glob('file/js/*.js') as $jsFile) unlink($jsFile);
|
||||
foreach (glob('file/acp/js/*.js') as $jsFile) unlink($jsFile);
|
||||
if (file_exists('be.bastelstu.chat.tar')) unlink('be.bastelstu.chat.tar');
|
||||
echo <<<EOT
|
||||
|
||||
Building JavaScript
|
||||
-------------------
|
||||
|
||||
EOT;
|
||||
foreach (glob('file/js/*.{litcoffee,coffee}', GLOB_BRACE) as $coffeeFile) {
|
||||
echo $coffeeFile."\n";
|
||||
passthru('coffee -c '.escapeshellarg($coffeeFile), $code);
|
||||
if ($code != 0) exit($code);
|
||||
}
|
||||
echo <<<EOT
|
||||
|
||||
Building ACP-JavaScript
|
||||
-----------------------
|
||||
|
||||
EOT;
|
||||
foreach (glob('file/acp/js/*.{litcoffee,coffee}', GLOB_BRACE) as $coffeeFile) {
|
||||
echo $coffeeFile."\n";
|
||||
passthru('coffee -c '.escapeshellarg($coffeeFile), $code);
|
||||
if ($code != 0) exit($code);
|
||||
}
|
||||
echo <<<EOT
|
||||
|
||||
Compressing JavaScript
|
||||
----------------------
|
||||
|
||||
EOT;
|
||||
foreach (glob('file/js/*.js', GLOB_BRACE) as $jsFile) {
|
||||
echo $jsFile."\n";
|
||||
passthru('uglifyjs '.escapeshellarg($jsFile).' --screw-ie8 -m -c --verbose --comments -d production=true -o '.escapeshellarg(substr($jsFile, 0, -3).'.min.js'), $code);
|
||||
if ($code != 0) exit($code);
|
||||
}
|
||||
echo <<<EOT
|
||||
|
||||
Checking PHP for Syntax Errors
|
||||
------------------------------
|
||||
|
||||
EOT;
|
||||
chdir('file');
|
||||
$check = null;
|
||||
$check = function ($folder) use (&$check) {
|
||||
if (is_file($folder)) {
|
||||
if (substr($folder, -4) === '.php') {
|
||||
passthru('php -l '.escapeshellarg($folder), $code);
|
||||
if ($code != 0) exit($code);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
$files = glob($folder.'/*');
|
||||
foreach ($files as $file) {
|
||||
$check($file);
|
||||
}
|
||||
};
|
||||
$check('.');
|
||||
echo <<<EOT
|
||||
|
||||
Building file.tar
|
||||
-----------------
|
||||
|
||||
EOT;
|
||||
passthru('tar cvf ../file.tar --exclude=*coffee --exclude-vcs -- *', $code);
|
||||
if ($code != 0) exit($code);
|
||||
echo <<<EOT
|
||||
|
||||
Building template.tar
|
||||
---------------------
|
||||
|
||||
EOT;
|
||||
chdir('../template');
|
||||
passthru('tar cvf ../template.tar *', $code);
|
||||
if ($code != 0) exit($code);
|
||||
echo <<<EOT
|
||||
|
||||
Building acptemplate.tar
|
||||
------------------------
|
||||
|
||||
EOT;
|
||||
chdir('../acptemplate');
|
||||
passthru('tar cvf ../acptemplate.tar *', $code);
|
||||
if ($code != 0) exit($code);
|
||||
echo <<<EOT
|
||||
|
||||
Building be.bastelstu.chat.tar
|
||||
------------------------------
|
||||
|
||||
EOT;
|
||||
chdir('..');
|
||||
file_put_contents('package.xml.old', file_get_contents('package.xml'));
|
||||
file_put_contents('package.xml', preg_replace('~<date>\d{4}-\d{2}-\d{2}</date>~', '<date>'.date('Y-m-d').'</date>', file_get_contents('package.xml')));
|
||||
file_put_contents('package.xml', str_replace('</version>', '</version><!-- git id '.trim(shell_exec('git describe --always')).' -->', file_get_contents('package.xml')));
|
||||
passthru('tar cvf be.bastelstu.chat.tar --exclude=*.old --exclude=file --exclude-vcs --exclude=template --exclude=acptemplate --exclude=contrib -- *', $code);
|
||||
if (file_exists('package.xml.old')) {
|
||||
file_put_contents('package.xml', file_get_contents('package.xml.old'));
|
||||
unlink('package.xml.old');
|
||||
}
|
||||
if ($code != 0) exit($code);
|
||||
|
||||
if (file_exists('file.tar')) unlink('file.tar');
|
||||
if (file_exists('template.tar')) unlink('template.tar');
|
||||
if (file_exists('acptemplate.tar')) unlink('acptemplate.tar');
|
||||
foreach (glob('file/js/*.js') as $jsFile) unlink($jsFile);
|
||||
foreach (glob('file/acp/js/*.js') as $jsFile) unlink($jsFile);
|
59
contrib/icon/chat.svg
Normal file
@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!--
|
||||
@author Maximilian Mader
|
||||
@copyright 2011-2014 Tim Düsterhus
|
||||
@license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
@package be.bastelstu.chat
|
||||
-->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="16px" height="16px" viewBox="0 0 16 16" xml:space="preserve">
|
||||
<title>Chat</title>
|
||||
<desc>Chat Icon (outlined)</desc>
|
||||
|
||||
<defs>
|
||||
<style type="text/css">
|
||||
<![CDATA[
|
||||
.Lower .bubble {
|
||||
fill:none;
|
||||
stroke:#ffffff;
|
||||
stroke-opacity:1;
|
||||
}
|
||||
.Lower .leaderLine {
|
||||
fill:#ffffff;
|
||||
fill-opacity:1;
|
||||
stroke:none;
|
||||
}
|
||||
.Upper .bubble {
|
||||
fill:none;
|
||||
stroke:#666666;
|
||||
stroke-opacity:1;
|
||||
}
|
||||
.Upper .leaderLine {
|
||||
fill:#666666;
|
||||
fill-opacity:1;
|
||||
stroke:none;
|
||||
}
|
||||
]]>
|
||||
</style>
|
||||
</defs>
|
||||
|
||||
<g id="IconChat">
|
||||
<g class="Lower" style="display:inline">
|
||||
<path class="bubble"
|
||||
d="M 15,8 A 6,5 0 1 1 3,8 6,5 0 1 1 15,8 z"
|
||||
transform="matrix(1.0345788,0,0,0.95089627,-1.510083,0.10801843)" />
|
||||
<path class="leaderLine"
|
||||
d="m 3.9001344,11.947742 c 0.075049,1.120603 -0.7948094,1.693805 -1.4915533,2.143417 1.0104403,
|
||||
0.104041 3.4597063,-0.953975 3.9167086,-1.276108 0.00808,-0.0057 -2.4251553,-0.867309 -2.4251553,-0.867309 z" />
|
||||
</g>
|
||||
|
||||
<g class="Upper" style="display:inline">
|
||||
<path class="bubble"
|
||||
d="M 15,8 A 6,5 0 1 1 3,8 6,5 0 1 1 15,8 z"
|
||||
transform="matrix(1.0345788,0,0,0.95089627,-1.5100816,-0.50773368)" />
|
||||
<path class="leaderLine"
|
||||
d="m 3.9001358,11.331991 c 0.075049,1.120603 -0.7948094,1.693805 -1.4915533,2.143417 1.0104403,
|
||||
0.104041 3.4597063,-0.953975 3.9167086,-1.276108 0.00808,-0.0057 -2.4251553,-0.867309 -2.4251553,-0.867309 z" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
BIN
contrib/icon/chat16.png
Normal file
After Width: | Height: | Size: 657 B |
BIN
contrib/icon/chat32.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
contrib/icon/chat48.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
contrib/icon/chatL.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
contrib/icon/chatM.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
contrib/icon/chatS.png
Normal file
After Width: | Height: | Size: 795 B |
9
dashboardBox.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/dashboardBox.xsd">
|
||||
<import>
|
||||
<dashboardbox name="be.bastelstu.chat.onlineList">
|
||||
<classname><![CDATA[chat\system\dashboard\box\OnlineListDashboardBox]]></classname>
|
||||
<boxtype>content</boxtype>
|
||||
</dashboardbox>
|
||||
</import>
|
||||
</data>
|
@ -1,166 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/maelstrom/eventListener.xsd">
|
||||
<import>
|
||||
<!-- Hourly Cleanup -->
|
||||
<eventlistener name="hourlyCleanUpUser">
|
||||
<eventlistener>
|
||||
<eventclassname>wcf\system\cronjob\HourlyCleanUpCronjob</eventclassname>
|
||||
<eventname>execute</eventname>
|
||||
<listenerclassname>chat\system\event\listener\HourlyCleanUpCronjobExecuteChatCleanUpListener</listenerclassname>
|
||||
<environment>user</environment>
|
||||
</eventlistener>
|
||||
<eventlistener name="hourlyCleanUpAdmin">
|
||||
<eventlistener>
|
||||
<eventclassname>wcf\system\cronjob\HourlyCleanUpCronjob</eventclassname>
|
||||
<eventname>execute</eventname>
|
||||
<listenerclassname>chat\system\event\listener\HourlyCleanUpCronjobExecuteChatCleanUpListener</listenerclassname>
|
||||
<environment>admin</environment>
|
||||
</eventlistener>
|
||||
|
||||
<!-- Temprooms -->
|
||||
<eventlistener name="temproomHourlyCleanUpUser">
|
||||
<eventclassname>wcf\system\cronjob\HourlyCleanUpCronjob</eventclassname>
|
||||
<eventname>execute</eventname>
|
||||
<listenerclassname>chat\system\event\listener\HourlyCleanUpCronjobExecuteTemproomListener</listenerclassname>
|
||||
<environment>user</environment>
|
||||
</eventlistener>
|
||||
<eventlistener name="temproomHourlyCleanUpAdmin">
|
||||
<eventclassname>wcf\system\cronjob\HourlyCleanUpCronjob</eventclassname>
|
||||
<eventname>execute</eventname>
|
||||
<listenerclassname>chat\system\event\listener\HourlyCleanUpCronjobExecuteTemproomListener</listenerclassname>
|
||||
<environment>admin</environment>
|
||||
</eventlistener>
|
||||
<eventlistener name="temproomCanSee">
|
||||
<eventclassname>chat\data\room\Room</eventclassname>
|
||||
<eventname>canSee</eventname>
|
||||
<listenerclassname>chat\system\event\listener\RoomCanSeeTemproomListener</listenerclassname>
|
||||
<environment>user</environment>
|
||||
</eventlistener>
|
||||
<eventlistener name="temproomRoomList">
|
||||
<eventclassname>chat\acp\page\RoomListPage</eventclassname>
|
||||
<eventname>calculateNumberOfPages</eventname>
|
||||
<listenerclassname>chat\system\event\listener\RoomListPageTemproomListener</listenerclassname>
|
||||
<environment>admin</environment>
|
||||
</eventlistener>
|
||||
<eventlistener name="temproomRoomEdit">
|
||||
<eventclassname>chat\acp\form\RoomEditForm</eventclassname>
|
||||
<eventname>readParameters</eventname>
|
||||
<listenerclassname>chat\system\event\listener\RoomEditFormTemproomListener</listenerclassname>
|
||||
<environment>admin</environment>
|
||||
</eventlistener>
|
||||
<eventlistener name="temproomSuspensionList">
|
||||
<eventclassname>chat\acp\page\SuspensionListPage</eventclassname>
|
||||
<eventname>readData</eventname>
|
||||
<listenerclassname>chat\system\event\listener\SuspensionListPageTemproomListener</listenerclassname>
|
||||
<environment>admin</environment>
|
||||
</eventlistener>
|
||||
|
||||
<!-- User Limit -->
|
||||
<eventlistener name="userLimitCanJoin">
|
||||
<eventclassname>chat\data\room\Room</eventclassname>
|
||||
<eventname>canJoin</eventname>
|
||||
<listenerclassname>chat\system\event\listener\RoomCanJoinUserLimitListener</listenerclassname>
|
||||
<environment>user</environment>
|
||||
</eventlistener>
|
||||
|
||||
<!-- Suspensions -->
|
||||
<eventlistener name="suspensionCanJoin">
|
||||
<eventclassname>chat\data\room\Room</eventclassname>
|
||||
<eventname>canJoin</eventname>
|
||||
<listenerclassname>chat\system\event\listener\RoomCanJoinBanListener</listenerclassname>
|
||||
<environment>user</environment>
|
||||
</eventlistener>
|
||||
<eventlistener name="suspensionCanWritePublicly">
|
||||
<eventclassname>chat\data\room\Room</eventclassname>
|
||||
<eventname>canWritePublicly</eventname>
|
||||
<listenerclassname>chat\system\event\listener\RoomCanWritePubliclyMuteListener</listenerclassname>
|
||||
<environment>user</environment>
|
||||
</eventlistener>
|
||||
<eventlistener name="suspensionInfoCommand">
|
||||
<eventclassname>chat\system\command\InfoCommand</eventclassname>
|
||||
<eventname>execute</eventname>
|
||||
<listenerclassname>chat\system\event\listener\InfoCommandSuspensionsListener</listenerclassname>
|
||||
<environment>user</environment>
|
||||
</eventlistener>
|
||||
<eventlistener name="moderatorPermissions">
|
||||
<eventclassname>chat\data\room\RoomAction</eventclassname>
|
||||
<eventname>getUsers</eventname>
|
||||
<listenerclassname>chat\system\event\listener\RoomActionGetUsersModeratorListener</listenerclassname>
|
||||
<environment>user</environment>
|
||||
</eventlistener>
|
||||
</import>
|
||||
|
||||
<delete>
|
||||
<!-- Hourly Cleanup -->
|
||||
<eventlistener>
|
||||
<eventclassname>wcf\system\cronjob\HourlyCleanUpCronjob</eventclassname>
|
||||
<eventname>execute</eventname>
|
||||
<listenerclassname>chat\system\event\listener\HourlyCleanUpCronjobExecuteChatCleanUpListener</listenerclassname>
|
||||
<environment>user</environment>
|
||||
</eventlistener>
|
||||
<eventlistener>
|
||||
<eventclassname>wcf\system\cronjob\HourlyCleanUpCronjob</eventclassname>
|
||||
<eventname>execute</eventname>
|
||||
<listenerclassname>chat\system\event\listener\HourlyCleanUpCronjobExecuteChatCleanUpListener</listenerclassname>
|
||||
<environment>admin</environment>
|
||||
</eventlistener>
|
||||
|
||||
<!-- Temprooms -->
|
||||
<eventlistener>
|
||||
<eventclassname>wcf\system\cronjob\HourlyCleanUpCronjob</eventclassname>
|
||||
<eventname>execute</eventname>
|
||||
<listenerclassname>chat\system\event\listener\HourlyCleanUpCronjobExecuteTemproomListener</listenerclassname>
|
||||
<environment>user</environment>
|
||||
</eventlistener>
|
||||
<eventlistener>
|
||||
<eventclassname>wcf\system\cronjob\HourlyCleanUpCronjob</eventclassname>
|
||||
<eventname>execute</eventname>
|
||||
<listenerclassname>chat\system\event\listener\HourlyCleanUpCronjobExecuteTemproomListener</listenerclassname>
|
||||
<environment>admin</environment>
|
||||
</eventlistener>
|
||||
<eventlistener>
|
||||
<eventclassname>chat\data\room\Room</eventclassname>
|
||||
<eventname>canSee</eventname>
|
||||
<listenerclassname>chat\system\event\listener\RoomCanSeeTemproomListener</listenerclassname>
|
||||
<environment>user</environment>
|
||||
</eventlistener>
|
||||
<eventlistener>
|
||||
<eventclassname>chat\acp\page\RoomListPage</eventclassname>
|
||||
<eventname>calculateNumberOfPages</eventname>
|
||||
<listenerclassname>chat\system\event\listener\RoomListPageTemproomListener</listenerclassname>
|
||||
<environment>admin</environment>
|
||||
</eventlistener>
|
||||
<eventlistener>
|
||||
<eventclassname>chat\acp\form\RoomEditForm</eventclassname>
|
||||
<eventname>readParameters</eventname>
|
||||
<listenerclassname>chat\system\event\listener\RoomEditFormTemproomListener</listenerclassname>
|
||||
<environment>admin</environment>
|
||||
</eventlistener>
|
||||
|
||||
<!-- User Limit -->
|
||||
<eventlistener>
|
||||
<eventclassname>chat\data\room\Room</eventclassname>
|
||||
<eventname>canJoin</eventname>
|
||||
<listenerclassname>chat\system\event\listener\RoomCanJoinUserLimitListener</listenerclassname>
|
||||
<environment>user</environment>
|
||||
</eventlistener>
|
||||
|
||||
<!-- Suspensions -->
|
||||
<eventlistener>
|
||||
<eventclassname>chat\data\room\Room</eventclassname>
|
||||
<eventname>canJoin</eventname>
|
||||
<listenerclassname>chat\system\event\listener\RoomCanJoinBanListener</listenerclassname>
|
||||
<environment>user</environment>
|
||||
</eventlistener>
|
||||
<eventlistener>
|
||||
<eventclassname>chat\data\room\Room</eventclassname>
|
||||
<eventname>canWritePublicly</eventname>
|
||||
<listenerclassname>chat\system\event\listener\RoomCanWritePubliclyMuteListener</listenerclassname>
|
||||
<environment>user</environment>
|
||||
</eventlistener>
|
||||
<eventlistener>
|
||||
<eventclassname>chat\system\command\InfoCommand</eventclassname>
|
||||
<eventname>execute</eventname>
|
||||
<listenerclassname>chat\system\event\listener\InfoCommandSuspensionsListener</listenerclassname>
|
||||
<environment>user</environment>
|
||||
</eventlistener>
|
||||
</delete>
|
||||
</data>
|
||||
</data>
|
61
file/acp/be.bastelstu.chat.install.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
namespace be\bastelstu\chat;
|
||||
|
||||
/**
|
||||
* Handles installation of Tims Chat.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
*/
|
||||
// @codingStandardsIgnoreFile
|
||||
final class Install {
|
||||
/**
|
||||
* Contains all the styles the current installation has.
|
||||
*
|
||||
* @var array<\wcf\data\style\Style>
|
||||
*/
|
||||
private $styles = null;
|
||||
|
||||
/**
|
||||
* Do we need to update the page title?
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
private $updateTitle = false;
|
||||
|
||||
public function __construct() {
|
||||
$this->styles = \wcf\system\style\StyleHandler::getInstance()->getAvailableStyles();
|
||||
if (!defined('PAGE_TITLE') || !PAGE_TITLE) $this->updateTitle = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets styles.
|
||||
*/
|
||||
public function execute() {
|
||||
foreach ($this->styles as $style) {
|
||||
\wcf\system\style\StyleHandler::getInstance()->resetStylesheet($style);
|
||||
}
|
||||
|
||||
if ($this->updateTitle) {
|
||||
$sql = "UPDATE
|
||||
wcf".WCF_N."_option
|
||||
SET
|
||||
optionValue = ?
|
||||
WHERE
|
||||
optionName = ?";
|
||||
$stmt = \wcf\system\WCF::getDB()->prepareStatement($sql);
|
||||
$stmt->execute(array('Tims Chat 3', 'page_title'));
|
||||
\wcf\data\option\OptionEditor::resetCache();
|
||||
}
|
||||
|
||||
\wcf\system\dashboard\DashboardHandler::setDefaultValues('com.woltlab.wcf.user.DashboardPage', array(
|
||||
// content
|
||||
'be.bastelstu.chat.onlineList' => 1
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
$install = new Install();
|
||||
$install->execute();
|
57
file/acp/be.bastelstu.chat.update.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
namespace be\bastelstu\chat;
|
||||
|
||||
/**
|
||||
* Handles updates of Tims Chat.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
*/
|
||||
// @codingStandardsIgnoreFile
|
||||
final class Update {
|
||||
/**
|
||||
* Contains all the rooms the current installation has.
|
||||
*
|
||||
* @var array<\wcf\data\chat\room\ChatRoom>
|
||||
*/
|
||||
private $rooms = null;
|
||||
|
||||
/**
|
||||
* Contains all the styles the current installation has.
|
||||
*
|
||||
* @var array<\wcf\data\style\Style>
|
||||
*/
|
||||
private $styles = null;
|
||||
|
||||
public function __construct() {
|
||||
$this->rooms = \chat\data\room\RoomCache::getInstance()->getRooms();
|
||||
$this->styles = \wcf\system\style\StyleHandler::getInstance()->getAvailableStyles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies users to refresh the chat as the JS may no longer be fully compatible with the PHP code.
|
||||
* Resets styles.
|
||||
*/
|
||||
public function execute() {
|
||||
foreach ($this->rooms as $room) {
|
||||
$messageAction = new \chat\data\message\MessageAction(array(), 'create', array(
|
||||
'data' => array(
|
||||
'roomID' => $room->roomID,
|
||||
'time' => TIME_NOW,
|
||||
'type' => \chat\data\message\Message::TYPE_INFORMATION,
|
||||
'message' => \wcf\system\WCF::getLanguage()->get('chat.global.information.chatUpdate')
|
||||
)
|
||||
));
|
||||
$messageAction->executeAction();
|
||||
}
|
||||
|
||||
foreach ($this->styles as $style) {
|
||||
\wcf\system\style\StyleHandler::getInstance()->resetStylesheet($style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$update = new Update();
|
||||
$update->execute();
|
15
file/acp/global.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
*/
|
||||
// define paths
|
||||
define('RELATIVE_CHAT_DIR', '../');
|
||||
|
||||
// include config
|
||||
require_once(dirname(dirname(__FILE__)).'/config.inc.php');
|
||||
|
||||
// include WCF
|
||||
require_once(RELATIVE_WCF_DIR.'acp/global.php');
|
9
file/acp/index.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
*/
|
||||
require_once(__DIR__.'/global.php');
|
||||
wcf\system\request\RequestHandler::getInstance()->handle('chat', true);
|
92
file/acp/js/be.bastelstu.Chat.ACP.Log.litcoffee
Normal file
@ -0,0 +1,92 @@
|
||||
Tims Chat 3
|
||||
===========
|
||||
|
||||
This is the javascript file providing functions related to the message log for [##Tims Chat##](https://github.com/wbbaddons/Tims-Chat).
|
||||
|
||||
### Copyright Information
|
||||
# @author Maximilian Mader
|
||||
# @copyright 2010-2014 Tim Düsterhus
|
||||
# @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
# @package be.bastelstu.chat
|
||||
###
|
||||
|
||||
## Code
|
||||
|
||||
(($, window) ->
|
||||
"use strict";
|
||||
|
||||
_messageLogContent = null
|
||||
_hasContent = {}
|
||||
_proxy = null
|
||||
|
||||
init = ->
|
||||
_messageLogContent = $ '#messageLogContent'
|
||||
|
||||
activeMenuItem = _messageLogContent.data 'active'
|
||||
enableProxy = false
|
||||
|
||||
_messageLogContent.find('div.tabMenuContent > .subTabMenuContent').each (index, container) ->
|
||||
containerID = $(container).wcfIdentify()
|
||||
|
||||
unless $("##{containerID}").hasClass 'empty'
|
||||
_hasContent[containerID] = true
|
||||
else
|
||||
_hasContent[containerID] = false
|
||||
enableProxy = true
|
||||
|
||||
if enableProxy
|
||||
_proxy = new WCF.Action.Proxy
|
||||
success: _success
|
||||
|
||||
_messageLogContent.bind 'wcftabsbeforeactivate',
|
||||
_loadContent
|
||||
|
||||
if not _hasContent[activeMenuItem]
|
||||
_loadContent {},
|
||||
newPanel: $("##{activeMenuItem}")
|
||||
newTab: $("##{activeMenuItem}").parent().find(".menu > ul > li").first()
|
||||
|
||||
_loadContent = (event, ui) ->
|
||||
containerID = $(ui.newPanel).attr 'id'
|
||||
|
||||
if $("##{$(ui.newPanel).attr('id')}").hasClass 'tabMenuContainer'
|
||||
containerID = $("##{containerID} > .subTabMenuContent").first().attr 'id'
|
||||
tab = $("##{containerID}").parent().find(".menu > ul > li").first()
|
||||
else
|
||||
tab = $ ui.newTab
|
||||
|
||||
unless _hasContent[containerID]
|
||||
start = _messageLogContent.data('baseTime') + (tab.data('hour') * 3600) + (tab.data('minutes') * 60)
|
||||
|
||||
_proxy.setOption 'data',
|
||||
actionName: 'getMessages'
|
||||
className: 'chat\\data\\message\\MessageAction'
|
||||
parameters:
|
||||
containerID: containerID
|
||||
start: start
|
||||
end: start + 1799
|
||||
roomID: _messageLogContent.data 'roomID'
|
||||
do _proxy.sendRequest
|
||||
|
||||
_success = (data, textStatus, jqWHR) ->
|
||||
containerID = data.returnValues.containerID
|
||||
_hasContent[containerID] = true
|
||||
|
||||
content = _messageLogContent.find "##{containerID}"
|
||||
unless data.returnValues.template is ''
|
||||
$("<div>#{data.returnValues.template}</div>").hide().appendTo content
|
||||
unless data.returnValues.noMessages
|
||||
content.addClass 'tabularBox'
|
||||
|
||||
do content.children().first().show
|
||||
Log =
|
||||
TabMenu:
|
||||
init: init
|
||||
|
||||
window.be ?= {}
|
||||
be.bastelstu ?= {}
|
||||
be.bastelstu.Chat ?= {}
|
||||
be.bastelstu.Chat.ACP ?= {}
|
||||
be.bastelstu.Chat.ACP.Log ?= {}
|
||||
window.be.bastelstu.Chat.ACP.Log = Log
|
||||
)(jQuery, @)
|
13
file/global.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
*/
|
||||
|
||||
// include config
|
||||
require_once(__DIR__.'/config.inc.php');
|
||||
|
||||
// include wcf
|
||||
require_once(RELATIVE_WCF_DIR.'global.php');
|
BIN
file/images/chatLogo.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
10
file/index.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
*/
|
||||
|
||||
require_once(__DIR__.'/global.php');
|
||||
\wcf\system\request\RequestHandler::getInstance()->handle('chat');
|
1509
file/js/be.bastelstu.Chat.litcoffee
Normal file
160
file/lib/acp/form/RoomAddForm.class.php
Normal file
@ -0,0 +1,160 @@
|
||||
<?php
|
||||
namespace chat\acp\form;
|
||||
use \wcf\system\exception\UserInputException;
|
||||
use \wcf\system\language\I18nHandler;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Shows the chatroom add form.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage acp.form
|
||||
*/
|
||||
class RoomAddForm extends \wcf\form\AbstractForm {
|
||||
/**
|
||||
* @see \wcf\acp\page\AbstractPage::$activeMenuItem
|
||||
*/
|
||||
public $activeMenuItem = 'chat.acp.menu.link.room.add';
|
||||
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::$neededPermissions
|
||||
*/
|
||||
public $neededPermissions = array('admin.chat.canAddRoom');
|
||||
|
||||
/**
|
||||
* Title of the room
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $title = '';
|
||||
|
||||
/**
|
||||
* Topic of the room
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $topic = '';
|
||||
|
||||
/**
|
||||
* Maximum number of users
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $maxUsers = 0;
|
||||
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::__construct()
|
||||
*/
|
||||
public function __run() {
|
||||
$this->objectTypeID = \wcf\system\acl\ACLHandler::getInstance()->getObjectTypeID('be.bastelstu.chat.room');
|
||||
|
||||
parent::__run();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \wcf\page\IPage::readParameters()
|
||||
*/
|
||||
public function readParameters() {
|
||||
parent::readParameters();
|
||||
|
||||
I18nHandler::getInstance()->register('title');
|
||||
I18nHandler::getInstance()->register('topic');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \wcf\form\IForm::readFormParameters()
|
||||
*/
|
||||
public function readFormParameters() {
|
||||
parent::readFormParameters();
|
||||
|
||||
I18nHandler::getInstance()->readValues();
|
||||
|
||||
if (I18nHandler::getInstance()->isPlainValue('title')) $this->title = I18nHandler::getInstance()->getValue('title');
|
||||
if (I18nHandler::getInstance()->isPlainValue('topic')) $this->topic = I18nHandler::getInstance()->getValue('topic');
|
||||
if (isset($_POST['maxUsers'])) $this->maxUsers = intval($_POST['maxUsers']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \wcf\form\IForm::validate()
|
||||
*/
|
||||
public function validate() {
|
||||
parent::validate();
|
||||
|
||||
// validate title
|
||||
if (!I18nHandler::getInstance()->validateValue('title')) {
|
||||
throw new UserInputException('title');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \wcf\form\IForm::save()
|
||||
*/
|
||||
public function save() {
|
||||
parent::save();
|
||||
|
||||
// save room
|
||||
$this->objectAction = new \chat\data\room\RoomAction(array(), 'create', array('data' => array_merge($this->additionalFields, array(
|
||||
'title' => $this->title,
|
||||
'topic' => $this->topic,
|
||||
'maxUsers' => $this->maxUsers
|
||||
))));
|
||||
$this->objectAction->executeAction();
|
||||
$returnValues = $this->objectAction->getReturnValues();
|
||||
$roomEditor = new \chat\data\room\RoomEditor($returnValues['returnValues']);
|
||||
$roomID = $returnValues['returnValues']->roomID;
|
||||
|
||||
if (!I18nHandler::getInstance()->isPlainValue('title')) {
|
||||
I18nHandler::getInstance()->save('title', 'chat.room.title'.$roomID, 'chat.room', \chat\util\ChatUtil::getPackageID());
|
||||
|
||||
// update title
|
||||
$roomEditor->update(array(
|
||||
'title' => 'chat.room.title'.$roomID
|
||||
));
|
||||
}
|
||||
|
||||
if (!I18nHandler::getInstance()->isPlainValue('topic')) {
|
||||
I18nHandler::getInstance()->save('topic', 'chat.room.topic'.$roomID, 'chat.room', \chat\util\ChatUtil::getPackageID());
|
||||
|
||||
// update topic
|
||||
$roomEditor->update(array(
|
||||
'topic' => 'chat.room.topic'.$roomID
|
||||
));
|
||||
}
|
||||
|
||||
\wcf\system\acl\ACLHandler::getInstance()->save($roomID, $this->objectTypeID);
|
||||
\wcf\system\acl\ACLHandler::getInstance()->disableAssignVariables();
|
||||
\chat\system\permission\PermissionHandler::clearCache();
|
||||
|
||||
$this->saved();
|
||||
|
||||
// reset values
|
||||
$this->topic = $this->title = '';
|
||||
I18nHandler::getInstance()->reset();
|
||||
|
||||
// show success
|
||||
WCF::getTPL()->assign(array(
|
||||
'success' => true
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \wcf\page\IPage::assignVariables()
|
||||
*/
|
||||
public function assignVariables() {
|
||||
parent::assignVariables();
|
||||
|
||||
I18nHandler::getInstance()->assignVariables();
|
||||
\wcf\system\acl\ACLHandler::getInstance()->assignVariables($this->objectTypeID);
|
||||
|
||||
WCF::getTPL()->assign(array(
|
||||
'action' => 'add',
|
||||
'title' => $this->title,
|
||||
'topic' => $this->topic,
|
||||
'maxUsers' => $this->maxUsers,
|
||||
'objectTypeID' => $this->objectTypeID
|
||||
));
|
||||
}
|
||||
}
|
134
file/lib/acp/form/RoomEditForm.class.php
Normal file
@ -0,0 +1,134 @@
|
||||
<?php
|
||||
namespace chat\acp\form;
|
||||
use \wcf\system\language\I18nHandler;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Shows the chatroom edit form.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage acp.form
|
||||
*/
|
||||
class RoomEditForm extends RoomAddForm {
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::$templateName
|
||||
*/
|
||||
public $templateName = 'roomAdd';
|
||||
|
||||
/**
|
||||
* @see \wcf\acp\form\ACPForm::$activeMenuItem
|
||||
*/
|
||||
public $activeMenuItem = 'chat.acp.menu.link.chat';
|
||||
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::$neededPermissions
|
||||
*/
|
||||
public $neededPermissions = array('admin.chat.canEditRoom');
|
||||
|
||||
/**
|
||||
* room id
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $roomID = 0;
|
||||
|
||||
/**
|
||||
* room object
|
||||
*
|
||||
* @var \chat\data\room\Room
|
||||
*/
|
||||
public $roomObj = null;
|
||||
|
||||
/**
|
||||
* @see \wcf\page\IPage::readParameters()
|
||||
*/
|
||||
public function readParameters() {
|
||||
parent::readParameters();
|
||||
|
||||
if (isset($_REQUEST['id'])) $this->roomID = intval($_REQUEST['id']);
|
||||
$this->roomObj = new \chat\data\room\Room($this->roomID);
|
||||
if (!$this->roomObj->roomID) {
|
||||
throw new \wcf\system\exception\IllegalLinkException();
|
||||
}
|
||||
if (!$this->roomObj->permanent) {
|
||||
throw new \wcf\system\exception\PermissionDeniedException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \wcf\form\IForm::save()
|
||||
*/
|
||||
public function save() {
|
||||
\wcf\form\AbstractForm::save();
|
||||
|
||||
$this->title = 'chat.room.title'.$this->roomObj->roomID;
|
||||
if (I18nHandler::getInstance()->isPlainValue('title')) {
|
||||
I18nHandler::getInstance()->remove($this->title);
|
||||
$this->title = I18nHandler::getInstance()->getValue('title');
|
||||
}
|
||||
else {
|
||||
I18nHandler::getInstance()->save('title', $this->title, 'chat.room', \chat\util\ChatUtil::getPackageID());
|
||||
}
|
||||
|
||||
$this->topic = 'chat.room.topic'.$this->roomObj->roomID;
|
||||
if (I18nHandler::getInstance()->isPlainValue('topic')) {
|
||||
I18nHandler::getInstance()->remove($this->topic);
|
||||
$this->topic = I18nHandler::getInstance()->getValue('topic');
|
||||
}
|
||||
else {
|
||||
I18nHandler::getInstance()->save('topic', $this->topic, 'chat.room', \chat\util\ChatUtil::getPackageID());
|
||||
}
|
||||
|
||||
\wcf\system\acl\ACLHandler::getInstance()->save($this->roomID, $this->objectTypeID);
|
||||
\wcf\system\acl\ACLHandler::getInstance()->disableAssignVariables();
|
||||
\chat\system\permission\PermissionHandler::clearCache();
|
||||
|
||||
// update room
|
||||
$this->objectAction = new \chat\data\room\RoomAction(array($this->roomID), 'update', array('data' => array_merge($this->additionalFields, array(
|
||||
'title' => $this->title,
|
||||
'topic' => $this->topic,
|
||||
'maxUsers' => $this->maxUsers
|
||||
))));
|
||||
$this->objectAction->executeAction();
|
||||
|
||||
$this->saved();
|
||||
|
||||
// show success
|
||||
WCF::getTPL()->assign(array(
|
||||
'success' => true
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \wcf\page\IPage::readData()
|
||||
*/
|
||||
public function readData() {
|
||||
parent::readData();
|
||||
|
||||
if (!count($_POST)) {
|
||||
I18nHandler::getInstance()->setOptions('title', \chat\util\ChatUtil::getPackageID(), $this->roomObj->title, 'chat.room.title\d+');
|
||||
I18nHandler::getInstance()->setOptions('topic', \chat\util\ChatUtil::getPackageID(), $this->roomObj->topic, 'chat.room.topic\d+');
|
||||
|
||||
$this->title = $this->roomObj->title;
|
||||
$this->topic = $this->roomObj->topic;
|
||||
$this->maxUsers = $this->roomObj->maxUsers;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \wcf\page\IPage::assignVariables()
|
||||
*/
|
||||
public function assignVariables() {
|
||||
parent::assignVariables();
|
||||
|
||||
I18nHandler::getInstance()->assignVariables((bool) count($_POST));
|
||||
|
||||
WCF::getTPL()->assign(array(
|
||||
'roomID' => $this->roomID,
|
||||
'action' => 'edit'
|
||||
));
|
||||
}
|
||||
}
|
183
file/lib/acp/page/ChatSuspensionListPage.class.php
Normal file
@ -0,0 +1,183 @@
|
||||
<?php
|
||||
namespace chat\acp\page;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Lists chat suspensions.
|
||||
*
|
||||
* @author Maximilian Mader
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage acp.page
|
||||
*/
|
||||
class ChatSuspensionListPage extends \wcf\page\SortablePage {
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::$activeMenuItem
|
||||
*/
|
||||
public $activeMenuItem = 'chat.acp.menu.link.suspension.list';
|
||||
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::$neededPermissions
|
||||
*/
|
||||
public $neededPermissions = array('admin.chat.canManageSuspensions');
|
||||
|
||||
/**
|
||||
* @see \wcf\page\SortablePage::$defaultSortField
|
||||
*/
|
||||
public $defaultSortField = 'expires';
|
||||
|
||||
/**
|
||||
* @see \wcf\page\SortablePage::$validSortFields
|
||||
*/
|
||||
public $validSortFields = array('suspensionID', 'userID', 'username', 'roomID', 'type', 'expires', 'issuer', 'time', 'reason');
|
||||
|
||||
/**
|
||||
* @see \wcf\page\MultipleLinkPage::$objectListClassName
|
||||
*/
|
||||
public $objectListClassName = 'chat\data\suspension\SuspensionList';
|
||||
|
||||
/**
|
||||
* type filter
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $filterSuspensionType = null;
|
||||
|
||||
/**
|
||||
* user filter
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $filterUserID = null;
|
||||
|
||||
/*
|
||||
* username
|
||||
*
|
||||
* @var String
|
||||
*/
|
||||
public $filterUsername = null;
|
||||
|
||||
/**
|
||||
* issuer filter
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $filterIssuerUserID = null;
|
||||
|
||||
/*
|
||||
* issuer username
|
||||
*
|
||||
* @var String
|
||||
*/
|
||||
public $filterIssuerUsername = null;
|
||||
|
||||
/**
|
||||
* room filter
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $filterRoomID = null;
|
||||
|
||||
/**
|
||||
* display revoked suspensions
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $displayRevoked = 0;
|
||||
|
||||
/**
|
||||
* @see \wcf\page\IPage::readParameters()
|
||||
*/
|
||||
public function readParameters() {
|
||||
parent::readParameters();
|
||||
|
||||
// get usernames
|
||||
if (isset($_REQUEST['username']) && !empty($_REQUEST['username'])) $this->filterUsername = \wcf\util\StringUtil::trim($_REQUEST['username']);
|
||||
if (isset($_REQUEST['issuerUsername']) && !empty($_REQUEST['issuerUsername'])) $this->filterIssuerUsername = \wcf\util\StringUtil::trim($_REQUEST['issuerUsername']);
|
||||
|
||||
// get user IDs by username
|
||||
if ($this->filterUsername != null) $this->filterUserID = \wcf\data\user\UserProfile::getUserProfileByUsername($this->filterUsername)->userID;
|
||||
if ($this->filterIssuerUsername != null) $this->filterIssuerUserID = \wcf\data\user\UserProfile::getUserProfileByUsername($this->filterIssuerUsername)->userID;
|
||||
|
||||
// get user IDs by request if no username was sent
|
||||
if ($this->filterUserID === null && isset($_REQUEST['userID']) && !empty($_REQUEST['userID'])) $this->filterUserID = intval($_REQUEST['userID']);
|
||||
if ($this->filterIssuerUserID === null && isset($_REQUEST['issuerUserID']) && !empty($_REQUEST['issuerUserID'])) $this->filterIssuerUserID = intval($_REQUEST['issuerUserID']);
|
||||
|
||||
// get usernames by ID if no usernames were sent
|
||||
if ($this->filterUsername === null) $this->filterUsername = \wcf\data\user\UserProfile::getUserProfile($this->filterUserID);
|
||||
if ($this->filterIssuerUsername === null) $this->filterIssuerUsername = \wcf\data\user\UserProfile::getUserProfile($this->filterIssuerUserID);
|
||||
|
||||
// get room IDs by request
|
||||
if (isset($_REQUEST['roomID']) && $_REQUEST['roomID'] != -1) {
|
||||
$this->filterRoomID = intval($_REQUEST['roomID']);
|
||||
$room = \chat\data\room\RoomCache::getInstance()->getRoom($this->filterRoomID);
|
||||
if (!$room) throw new \wcf\system\exception\IllegalLinkException();
|
||||
if (!$room->permanent) throw new \wcf\system\exception\PermissionDeniedException();
|
||||
}
|
||||
|
||||
if (isset($_REQUEST['suspensionType']) && !empty($_REQUEST['suspensionType'])) $this->filterSuspensionType = \wcf\util\StringUtil::trim($_REQUEST['suspensionType']);
|
||||
|
||||
// display revoked
|
||||
if (isset($_REQUEST['displayRevoked'])) $this->displayRevoked = intval($_REQUEST['displayRevoked']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see wcf\page\IPage::assignVariables()
|
||||
*/
|
||||
public function assignVariables() {
|
||||
parent::assignVariables();
|
||||
|
||||
$rooms = \chat\data\room\RoomCache::getInstance()->getRooms();
|
||||
foreach ($rooms as $id => $room) {
|
||||
if (!$room->permanent) unset($rooms[$id]);
|
||||
}
|
||||
|
||||
WCF::getTPL()->assign(array(
|
||||
'availableRooms' => $rooms,
|
||||
'roomID' => ($this->filterRoomID !== null) ? $this->filterRoomID : -1,
|
||||
'username' => $this->filterUsername,
|
||||
'issuerUsername' => $this->filterIssuerUsername,
|
||||
'suspensionType' => $this->filterSuspensionType,
|
||||
'userID' => $this->filterUserID,
|
||||
'issuerUserID' => $this->filterIssuerUserID,
|
||||
'displayRevoked' => $this->displayRevoked
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \wcf\page\MultipleLinkPage::readObjects()
|
||||
*/
|
||||
protected function initObjectList() {
|
||||
parent::initObjectList();
|
||||
|
||||
$this->objectList->sqlSelects .= "user_table_muted.username, user_table_issuer.username AS issuerUsername, user_table_revoker.username AS revokerUsername, room_table.title AS roomTitle";
|
||||
$this->objectList->sqlJoins .= "
|
||||
LEFT JOIN wcf".WCF_N."_user user_table_muted
|
||||
ON suspension.userID = user_table_muted.userID
|
||||
LEFT JOIN wcf".WCF_N."_user user_table_issuer
|
||||
ON suspension.issuer = user_table_issuer.userID
|
||||
LEFT JOIN wcf".WCF_N."_user user_table_revoker
|
||||
ON suspension.revoker = user_table_revoker.userID";
|
||||
$conditionJoins = " LEFT JOIN chat".WCF_N."_room room_table
|
||||
ON suspension.roomID = room_table.roomID";
|
||||
$this->objectList->sqlConditionJoins .= $conditionJoins;
|
||||
$this->objectList->sqlJoins .= $conditionJoins;
|
||||
|
||||
if (!$this->displayRevoked) {
|
||||
$this->objectList->getConditionBuilder()->add('expires > ?', array(TIME_NOW));
|
||||
}
|
||||
$this->objectList->getConditionBuilder()->add('(room_table.permanent = ? OR suspension.roomID IS NULL)', array(1));
|
||||
if ($this->filterSuspensionType !== null) $this->objectList->getConditionBuilder()->add('suspension.type = ?', array($this->filterSuspensionType));
|
||||
if ($this->filterUserID !== null) $this->objectList->getConditionBuilder()->add('suspension.userID = ?', array($this->filterUserID));
|
||||
if ($this->filterIssuerUserID !== null) $this->objectList->getConditionBuilder()->add('suspension.issuer = ?', array($this->filterIssuerUserID));
|
||||
if ($this->filterRoomID !== null) {
|
||||
if ($this->filterRoomID === 0) {
|
||||
$this->objectList->getConditionBuilder()->add('suspension.roomID IS NULL', array());
|
||||
}
|
||||
else {
|
||||
$this->objectList->getConditionBuilder()->add('suspension.roomID = ?', array($this->filterRoomID));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
141
file/lib/acp/page/MessageLogDownloadPage.class.php
Normal file
@ -0,0 +1,141 @@
|
||||
<?php
|
||||
namespace chat\acp\page;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Handles text/plain download of chat log.
|
||||
*
|
||||
* @author Maximilian Mader
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage acp.page
|
||||
*/
|
||||
class MessageLogDownloadPage extends \wcf\page\AbstractPage {
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::$activeMenuItem
|
||||
*/
|
||||
public $activeMenuItem = 'chat.acp.menu.link.log';
|
||||
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::$neededPermissions
|
||||
*/
|
||||
public $neededPermissions = array(
|
||||
'admin.chat.canReadLog'
|
||||
);
|
||||
|
||||
public $useTemplate = false;
|
||||
|
||||
/**
|
||||
* messages for the given day
|
||||
*
|
||||
* @var array<\chat\data\message\Message>
|
||||
*/
|
||||
public $messages = array();
|
||||
|
||||
/**
|
||||
* given roomID
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $roomID = 0;
|
||||
|
||||
/**
|
||||
* given date
|
||||
*
|
||||
* @var \DateTime
|
||||
*/
|
||||
public $date = null;
|
||||
|
||||
/**
|
||||
* active room
|
||||
*
|
||||
* @var \chat\data\room\Room
|
||||
*/
|
||||
public $room = null;
|
||||
|
||||
/**
|
||||
* available rooms
|
||||
*
|
||||
* @var array<\chat\data\room\Room>
|
||||
*/
|
||||
public $rooms = array();
|
||||
|
||||
public $tmpFile = '';
|
||||
|
||||
/**
|
||||
* @see \wcf\page\IPage::readData()
|
||||
*/
|
||||
public function readData() {
|
||||
parent::readData();
|
||||
|
||||
$now = new \DateTime('now', WCF::getUser()->getTimeZone());
|
||||
if ($this->date->getTimestamp() > $now->getTimestamp()) {
|
||||
throw new \wcf\system\exception\IllegalLinkException();
|
||||
}
|
||||
|
||||
$oldest = new \DateTime('today -'.ceil(CHAT_LOG_ARCHIVETIME / 1440).'day', WCF::getUser()->getTimeZone());
|
||||
if (CHAT_LOG_ARCHIVETIME !== -1 && $this->date->getTimestamp() < $oldest->getTimestamp()) {
|
||||
throw new \wcf\system\exception\IllegalLinkException();
|
||||
}
|
||||
|
||||
$this->tmpFile = \wcf\util\FileUtil::getTemporaryFilename();
|
||||
touch($this->tmpFile);
|
||||
\wcf\util\FileUtil::makeWritable($this->tmpFile);
|
||||
|
||||
if (is_writable($this->tmpFile)) {
|
||||
$file = new \wcf\system\io\File($this->tmpFile);
|
||||
$file->write(WCF::getLanguage()->get('chat.acp.log.title') . ': ' . (string) $this->room . "\n");
|
||||
|
||||
for ($start = $this->date->getTimestamp(), $end = $this->date->add(\DateInterval::createFromDateString('1day'))->sub(\DateInterval::createFromDateString('1second'))->getTimestamp(); $start < $end; $start += 1800) {
|
||||
$file->write(WCF::getTpl()->fetch('messageLogDownload', 'chat', array('messages' => \chat\data\message\MessageList::getMessagesBetween($this->room, $start, $start + 1799))));
|
||||
}
|
||||
|
||||
$file->close();
|
||||
}
|
||||
else {
|
||||
throw new \wcf\system\exception\IllegalLinkException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \wcf\page\IPage::readParameters()
|
||||
*/
|
||||
public function readParameters() {
|
||||
parent::readParameters();
|
||||
|
||||
if (isset($_REQUEST['id'])) {
|
||||
$this->roomID = intval($_REQUEST['id']);
|
||||
}
|
||||
else {
|
||||
throw new \wcf\system\exception\IllegalLinkException();
|
||||
}
|
||||
|
||||
$this->room = \chat\data\room\RoomCache::getInstance()->getRoom($this->roomID);
|
||||
if (!$this->room) throw new \wcf\system\exception\IllegalLinkException();
|
||||
if (!$this->room->permanent) throw new \wcf\system\exception\PermissionDeniedException();
|
||||
|
||||
if (isset($_REQUEST['date'])) $date = $_REQUEST['date'].' 00:00:00';
|
||||
else $date = 'today 00:00:00';
|
||||
|
||||
try {
|
||||
$this->date = new \DateTime($date, WCF::getUser()->getTimeZone());
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
throw new \wcf\system\exception\IllegalLinkException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see wcf\page\IPage::show()
|
||||
*/
|
||||
public function show() {
|
||||
parent::show();
|
||||
|
||||
$fileReader = new \wcf\util\FileReader($this->tmpFile, array('mimeType' => 'text/plain', 'filename' => str_replace(' ', '-', WCF::getLanguage()->get('chat.acp.log.title') . ' ' . $this->room.'-'.\wcf\util\DateUtil::format($this->date, 'Y-m-d').'.txt')));
|
||||
$fileReader->send();
|
||||
|
||||
exit;
|
||||
}
|
||||
}
|
130
file/lib/acp/page/MessageLogPage.class.php
Normal file
@ -0,0 +1,130 @@
|
||||
<?php
|
||||
namespace chat\acp\page;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Lists chat log.
|
||||
*
|
||||
* @author Maximilian Mader
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage acp.page
|
||||
*/
|
||||
class MessageLogPage extends \wcf\page\AbstractPage {
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::$activeMenuItem
|
||||
*/
|
||||
public $activeMenuItem = 'chat.acp.menu.link.log';
|
||||
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::$neededPermissions
|
||||
*/
|
||||
public $neededPermissions = array(
|
||||
'admin.chat.canReadLog'
|
||||
);
|
||||
|
||||
/**
|
||||
* name of error field
|
||||
* @var string
|
||||
*/
|
||||
public $errorField = '';
|
||||
|
||||
/**
|
||||
* error type
|
||||
* @var string
|
||||
*/
|
||||
public $errorType = '';
|
||||
|
||||
/**
|
||||
* given roomID
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $roomID = 0;
|
||||
|
||||
/**
|
||||
* given date
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $date = 0;
|
||||
|
||||
/**
|
||||
* active room
|
||||
*
|
||||
* @var \chat\data\room\Room
|
||||
*/
|
||||
public $room = null;
|
||||
|
||||
/**
|
||||
* available rooms
|
||||
*
|
||||
* @var array<\chat\data\room\Room>
|
||||
*/
|
||||
public $rooms = array();
|
||||
|
||||
/**
|
||||
* @see \wcf\page\IPage::readData()
|
||||
*/
|
||||
public function readData() {
|
||||
parent::readData();
|
||||
|
||||
try {
|
||||
if ($this->date > TIME_NOW) {
|
||||
throw new \wcf\system\exception\UserInputException('date', 'inFuture');
|
||||
}
|
||||
|
||||
if (CHAT_LOG_ARCHIVETIME !== -1 && $this->date < strtotime('today 00:00:00 -'.ceil(CHAT_LOG_ARCHIVETIME / 1440).'day')) {
|
||||
throw new \wcf\system\exception\UserInputException('date', 'tooLongAgo');
|
||||
}
|
||||
}
|
||||
catch (\wcf\system\exception\UserInputException $e) {
|
||||
$this->errorField = $e->getField();
|
||||
$this->errorType = $e->getType();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \wcf\page\IPage::readParameters()
|
||||
*/
|
||||
public function readParameters() {
|
||||
parent::readParameters();
|
||||
|
||||
$this->rooms = \chat\data\room\RoomCache::getInstance()->getRooms();
|
||||
|
||||
foreach ($this->rooms as $id => $room) {
|
||||
if (!$room->permanent) unset($this->rooms[$id]);
|
||||
}
|
||||
|
||||
if (isset($_REQUEST['id'])) $this->roomID = intval($_REQUEST['id']);
|
||||
else $this->roomID = reset($this->rooms)->roomID;
|
||||
|
||||
$this->room = \chat\data\room\RoomCache::getInstance()->getRoom($this->roomID);
|
||||
|
||||
if (!$this->room) throw new \wcf\system\exception\IllegalLinkException();
|
||||
if (!$this->room->permanent) throw new \wcf\system\exception\PermissionDeniedException();
|
||||
|
||||
if (isset($_REQUEST['date'])) $date = $_REQUEST['date'].' 00:00:00';
|
||||
else $date = 'today 00:00:00';
|
||||
$this->date = @strtotime($date);
|
||||
if ($this->date === false) throw new \wcf\system\exception\IllegalLinkException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see wcf\page\IPage::assignVariables()
|
||||
*/
|
||||
public function assignVariables() {
|
||||
parent::assignVariables();
|
||||
|
||||
WCF::getTPL()->assign(array(
|
||||
'rooms' => $this->rooms,
|
||||
'room' => $this->room,
|
||||
'date' => $this->date,
|
||||
'errorField' => $this->errorField,
|
||||
'errorType' => $this->errorType
|
||||
));
|
||||
}
|
||||
}
|
56
file/lib/acp/page/RoomListPage.class.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
namespace chat\acp\page;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Lists available chatrooms.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage acp.page
|
||||
*/
|
||||
class RoomListPage extends \wcf\page\AbstractPage {
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::$activeMenuItem
|
||||
*/
|
||||
public $activeMenuItem = 'chat.acp.menu.link.room.list';
|
||||
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::$neededPermissions
|
||||
*/
|
||||
public $neededPermissions = array(
|
||||
'admin.chat.canEditRoom',
|
||||
'admin.chat.canDeleteRoom'
|
||||
);
|
||||
|
||||
/**
|
||||
* room list
|
||||
* @var \chat\data\room\RoomListPage
|
||||
*/
|
||||
public $objects = null;
|
||||
|
||||
/**
|
||||
* @see \wcf\page\IPage::readData()
|
||||
*/
|
||||
public function readData() {
|
||||
parent::readData();
|
||||
|
||||
$this->objects = new \chat\data\room\RoomList();
|
||||
$this->objects->sqlOrderBy = 'showOrder ASC';
|
||||
$this->objects->getConditionBuilder()->add('permanent = ?', array(1));
|
||||
$this->objects->readObjects();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see wcf\page\IPage::assignVariables()
|
||||
*/
|
||||
public function assignVariables() {
|
||||
parent::assignVariables();
|
||||
|
||||
WCF::getTPL()->assign(array(
|
||||
'objects' => $this->objects
|
||||
));
|
||||
}
|
||||
}
|
20
file/lib/data/CHATDatabaseObject.class.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
namespace chat\data;
|
||||
|
||||
/**
|
||||
* Basic implementation that sets proper table name.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage data
|
||||
*/
|
||||
abstract class CHATDatabaseObject extends \wcf\data\DatabaseObject {
|
||||
/**
|
||||
* @see \wcf\data\DatabaseObject::getDatabaseTableName()
|
||||
*/
|
||||
public static function getDatabaseTableName() {
|
||||
return 'chat'.WCF_N.'_'.static::$databaseTableName;
|
||||
}
|
||||
}
|
177
file/lib/data/message/Message.class.php
Normal file
@ -0,0 +1,177 @@
|
||||
<?php
|
||||
namespace chat\data\message;
|
||||
use \chat\util\ChatUtil;
|
||||
use \wcf\system\bbcode\AttachmentBBCode;
|
||||
use \wcf\system\Regex;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Represents a chat message.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage data.message
|
||||
*/
|
||||
class Message extends \chat\data\CHATDatabaseObject {
|
||||
/**
|
||||
* @see \wcf\data\DatabaseObject::$databaseTableName
|
||||
*/
|
||||
protected static $databaseTableName = 'message';
|
||||
|
||||
/**
|
||||
* @see \wcf\data\DatabaseObject::$databaseTableIndexName
|
||||
*/
|
||||
protected static $databaseTableIndexName = 'messageID';
|
||||
|
||||
const TYPE_NORMAL = 0;
|
||||
const TYPE_JOIN = 1;
|
||||
const TYPE_LEAVE = 2;
|
||||
const TYPE_AWAY = 3;
|
||||
const TYPE_BACK = 4;
|
||||
const TYPE_MODERATE = 5;
|
||||
const TYPE_ME = 6;
|
||||
const TYPE_WHISPER = 7;
|
||||
const TYPE_INFORMATION = 8;
|
||||
const TYPE_CLEAR = 9;
|
||||
const TYPE_TEAM = 10;
|
||||
const TYPE_GLOBALMESSAGE = 11;
|
||||
const TYPE_ATTACHMENT = 12;
|
||||
|
||||
/**
|
||||
* cache for users
|
||||
* @var array<\wcf\data\user\User>
|
||||
*/
|
||||
protected static $users = array();
|
||||
|
||||
/**
|
||||
* @see \wcf\data\DatabaseObject::handleData()
|
||||
*/
|
||||
protected function handleData($data) {
|
||||
parent::handleData($data);
|
||||
|
||||
if ($this->data['additionalData'] !== null) {
|
||||
$this->data['additionalData'] = unserialize($this->data['additionalData']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\data\message\Message::getFormattedMessage()
|
||||
*/
|
||||
public function __toString() {
|
||||
return $this->getFormattedMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatted message.
|
||||
*
|
||||
* @param string $outputType outputtype for messageparser
|
||||
* @return string
|
||||
*/
|
||||
public function getFormattedMessage($type = 'text/html') {
|
||||
$message = $this->message;
|
||||
$messageParser = \wcf\system\bbcode\MessageParser::getInstance();
|
||||
$messageParser->setOutputType($type);
|
||||
|
||||
switch ($this->type) {
|
||||
case self::TYPE_JOIN:
|
||||
case self::TYPE_LEAVE:
|
||||
case self::TYPE_BACK:
|
||||
$message = WCF::getLanguage()->getDynamicVariable('chat.message.'.$this->type, $this->data['additionalData'] ?: array());
|
||||
break;
|
||||
case self::TYPE_AWAY:
|
||||
$message = WCF::getLanguage()->getDynamicVariable('chat.message.'.$this->type, array('message' => $message));
|
||||
break;
|
||||
case self::TYPE_MODERATE:
|
||||
$message = unserialize($message);
|
||||
$message = WCF::getLanguage()->getDynamicVariable('chat.message.'.$this->type.'.'.$message['type'], $message ?: array());
|
||||
|
||||
if ($type === 'text/plain') return $message;
|
||||
$message = $messageParser->parse($message, false, false, true, false);
|
||||
break;
|
||||
case self::TYPE_ATTACHMENT:
|
||||
$attachmentList = new \wcf\data\attachment\GroupedAttachmentList('be.bastelstu.chat.message');
|
||||
$attachmentList->getConditionBuilder()->add('attachment.objectID IN (?)', array($this->messageID));
|
||||
$attachmentList->readObjects();
|
||||
|
||||
AttachmentBBCode::setAttachmentList($attachmentList);
|
||||
AttachmentBBCode::setObjectID($this->messageID);
|
||||
|
||||
$message = $messageParser->parse($message, false, false, true, false);
|
||||
break;
|
||||
case self::TYPE_WHISPER:
|
||||
case self::TYPE_NORMAL:
|
||||
case self::TYPE_ME:
|
||||
default:
|
||||
if ($type === 'text/plain') return $message;
|
||||
|
||||
$message = $messageParser->parse($message, $this->enableSmilies, $this->enableHTML, true, false);
|
||||
break;
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the username.
|
||||
*
|
||||
* @param boolean $colored
|
||||
* @return string
|
||||
*/
|
||||
public function getUsername($colored = false) {
|
||||
$username = $this->username;
|
||||
if ($this->type == self::TYPE_INFORMATION) return WCF::getLanguage()->get('chat.global.information');
|
||||
|
||||
if ($colored) {
|
||||
if ($this->color1 !== null || $this->color2 !== null) {
|
||||
$username = \chat\util\ChatUtil::gradient($username, $this->color1, $this->color2);
|
||||
}
|
||||
else {
|
||||
$username = '<span class="defaultColor">'.\wcf\util\StringUtil::encodeHTML($username).'</span>';
|
||||
}
|
||||
}
|
||||
|
||||
return $username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this message into json-form.
|
||||
*
|
||||
* @param boolean $raw
|
||||
* @return string
|
||||
*/
|
||||
public function jsonify($raw = false) {
|
||||
switch ($this->type) {
|
||||
case self::TYPE_WHISPER:
|
||||
case self::TYPE_NORMAL:
|
||||
case self::TYPE_INFORMATION:
|
||||
$separator = ':';
|
||||
break;
|
||||
default:
|
||||
$separator = '';
|
||||
break;
|
||||
}
|
||||
|
||||
$time = \wcf\util\DateUtil::getDateTimeByTimestamp($this->time);
|
||||
$startOfDay = new \DateTime('today', WCF::getUser()->getTimezone());
|
||||
$array = array(
|
||||
'formattedUsername' => $this->getUsername(true),
|
||||
'formattedMessage' => $this->getFormattedMessage('text/html'),
|
||||
'formattedTime' => ($time->getTimestamp() < $startOfDay->getTimestamp() ? \wcf\util\DateUtil::format($time, 'chat.global.dateFormat').' ' : '').\wcf\util\DateUtil::format($time, 'chat.global.timeFormat'),
|
||||
'separator' => $separator,
|
||||
'message' => $this->getFormattedMessage('text/plain'),
|
||||
'sender' => (int) $this->sender,
|
||||
'username' => $this->getUsername(),
|
||||
'time' => (int) $this->time,
|
||||
'receiver' => (int) $this->receiver,
|
||||
'type' => (int) $this->type,
|
||||
'roomID' => (int) $this->roomID,
|
||||
'messageID' => (int) $this->messageID,
|
||||
'additionalData' => $this->additionalData
|
||||
);
|
||||
|
||||
if ($raw) return $array;
|
||||
return \wcf\util\JSON::encode($array);
|
||||
}
|
||||
}
|
272
file/lib/data/message/MessageAction.class.php
Normal file
@ -0,0 +1,272 @@
|
||||
<?php
|
||||
namespace chat\data\message;
|
||||
use chat\data\room;
|
||||
use wcf\system\exception\UserInputException;
|
||||
use wcf\system\WCF;
|
||||
use wcf\util\MessageUtil;
|
||||
|
||||
/**
|
||||
* Executes message related actions.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage chat.message
|
||||
*/
|
||||
class MessageAction extends \wcf\data\AbstractDatabaseObjectAction {
|
||||
/**
|
||||
* @see \wcf\data\AbstractDatabaseObjectAction::$className
|
||||
*/
|
||||
protected $className = '\chat\data\message\MessageEditor';
|
||||
|
||||
/**
|
||||
* Removes old messages.
|
||||
*
|
||||
* @return integer Number of deleted messages.
|
||||
*/
|
||||
public function prune() {
|
||||
if (CHAT_LOG_ARCHIVETIME == -1) return 0;
|
||||
|
||||
$sql = "SELECT
|
||||
".call_user_func(array($this->className, 'getDatabaseTableIndexName'))."
|
||||
FROM
|
||||
".call_user_func(array($this->className, 'getDatabaseTableName'))."
|
||||
WHERE
|
||||
time < ?";
|
||||
$stmt = \wcf\system\WCF::getDB()->prepareStatement($sql);
|
||||
$stmt->execute(array(TIME_NOW - CHAT_LOG_ARCHIVETIME * 60));
|
||||
|
||||
$objectIDs = array();
|
||||
while ($objectID = $stmt->fetchColumn()) $objectIDs[] = $objectID;
|
||||
|
||||
return call_user_func(array($this->className, 'deleteAll'), $objectIDs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates message sending.
|
||||
*/
|
||||
public function validateSend() {
|
||||
// read user data
|
||||
$this->parameters['userData']['color1'] = WCF::getUser()->chatColor1;
|
||||
$this->parameters['userData']['color2'] = WCF::getUser()->chatColor2;
|
||||
$this->parameters['userData']['roomID'] = WCF::getUser()->chatRoomID;
|
||||
$this->parameters['userData']['away'] = WCF::getUser()->chatAway;
|
||||
|
||||
// read and validate room
|
||||
$this->readInteger('roomID', true);
|
||||
if (\wcf\system\WCF::getSession()->getPermission('admin.chat.isInAllRooms') && $this->parameters['roomID'] !== 0) {
|
||||
$this->parameters['userData']['roomID'] = $this->parameters['roomID'];
|
||||
}
|
||||
|
||||
$this->parameters['room'] = room\RoomCache::getInstance()->getRoom($this->parameters['userData']['roomID']);
|
||||
if ($this->parameters['room'] === null) throw new \wcf\system\exception\IllegalLinkException();
|
||||
if (!$this->parameters['room']->canEnter()) throw new \wcf\system\exception\PermissionDeniedException();
|
||||
if (!$this->parameters['room']->canWrite()) throw new \wcf\system\exception\PermissionDeniedException();
|
||||
|
||||
// read parameters
|
||||
$this->readString('text');
|
||||
$this->readBoolean('enableSmilies', true);
|
||||
$this->parameters['text'] = MessageUtil::stripCrap($this->parameters['text']);
|
||||
$this->parameters['enableHTML'] = false;
|
||||
|
||||
// validate text
|
||||
if (mb_strlen($this->parameters['text']) > CHAT_MAX_LENGTH) throw new UserInputException('text', 'tooLong');
|
||||
|
||||
// search for disallowed bbcodes
|
||||
$disallowedBBCodes = \wcf\system\bbcode\BBCodeParser::getInstance()->validateBBCodes($this->parameters['text'], explode(',', WCF::getSession()->getPermission('user.chat.allowedBBCodes')));
|
||||
if (!empty($disallowedBBCodes)) {
|
||||
throw new UserInputException('text', WCF::getLanguage()->getDynamicVariable('wcf.message.error.disallowedBBCodes', array('disallowedBBCodes' => $disallowedBBCodes)));
|
||||
}
|
||||
|
||||
// search for censored words
|
||||
if (ENABLE_CENSORSHIP) {
|
||||
$result = \wcf\system\message\censorship\Censorship::getInstance()->test($this->parameters['text']);
|
||||
if ($result) {
|
||||
throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.message.error.censoredWordsFound', array('censoredWords' => $result)));
|
||||
}
|
||||
}
|
||||
|
||||
$editor = new \wcf\data\user\UserEditor(WCF::getUser());
|
||||
$editor->update(array(
|
||||
'chatAway' => null,
|
||||
'chatLastActivity' => TIME_NOW
|
||||
));
|
||||
|
||||
// mark user as back
|
||||
if ($this->parameters['userData']['away'] !== null) {
|
||||
$messageAction = new MessageAction(array(), 'create', array(
|
||||
'data' => array(
|
||||
'roomID' => $this->parameters['room']->roomID,
|
||||
'sender' => WCF::getUser()->userID,
|
||||
'username' => WCF::getUser()->username,
|
||||
'time' => TIME_NOW,
|
||||
'type' => Message::TYPE_BACK,
|
||||
'message' => '',
|
||||
'color1' => $this->parameters['userData']['color1'],
|
||||
'color2' => $this->parameters['userData']['color2']
|
||||
)
|
||||
));
|
||||
$messageAction->executeAction();
|
||||
}
|
||||
|
||||
// handle commands
|
||||
$commandHandler = new \chat\system\command\CommandHandler($this->parameters['text'], $this->parameters['room']);
|
||||
if ($commandHandler->isCommand()) {
|
||||
try {
|
||||
$command = $commandHandler->loadCommand();
|
||||
|
||||
if ($command->enableSmilies != \chat\system\command\ICommand::SETTING_USER) $this->parameters['enableSmilies'] = $command->enableSmilies;
|
||||
$this->parameters['enableHTML'] = $command->enableHTML;
|
||||
|
||||
$this->parameters['type'] = $command->getType();
|
||||
$this->parameters['text'] = $command->getMessage();
|
||||
$this->parameters['receiver'] = $command->getReceiver();
|
||||
$this->parameters['additionalData'] = $command->getAdditionalData();
|
||||
}
|
||||
catch (\chat\system\command\NotFoundException $e) {
|
||||
throw new UserInputException('text', WCF::getLanguage()->getDynamicVariable('chat.error.notFound', array('exception' => $e)));
|
||||
}
|
||||
catch (\chat\system\command\UserNotFoundException $e) {
|
||||
throw new UserInputException('text', WCF::getLanguage()->getDynamicVariable('chat.error.userNotFound', array('exception' => $e)));
|
||||
}
|
||||
catch (\InvalidArgumentException $e) {
|
||||
throw new UserInputException('text', WCF::getLanguage()->getDynamicVariable('chat.error.invalidArgument', array('exception' => $e)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->parameters['type'] = Message::TYPE_NORMAL;
|
||||
$this->parameters['receiver'] = null;
|
||||
$this->parameters['additionalData'] = null;
|
||||
|
||||
$this->parameters['text'] = \wcf\system\bbcode\PreParser::getInstance()->parse($this->parameters['text'], explode(',', WCF::getSession()->getPermission('user.chat.allowedBBCodes')));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates sent message.
|
||||
*/
|
||||
public function send() {
|
||||
$this->objectAction = new MessageAction(array(), 'create', array(
|
||||
'data' => array(
|
||||
'roomID' => $this->parameters['room']->roomID,
|
||||
'sender' => WCF::getUser()->userID,
|
||||
'username' => WCF::getUser()->username,
|
||||
'receiver' => $this->parameters['receiver'],
|
||||
'time' => TIME_NOW,
|
||||
'type' => $this->parameters['type'],
|
||||
'message' => $this->parameters['text'],
|
||||
'enableSmilies' => $this->parameters['enableSmilies'] ? 1 : 0,
|
||||
'enableHTML' => $this->parameters['enableHTML'] ? 1 : 0,
|
||||
'color1' => $this->parameters['userData']['color1'],
|
||||
'color2' => $this->parameters['userData']['color2'],
|
||||
'additionalData' => serialize($this->parameters['additionalData'])
|
||||
)
|
||||
));
|
||||
$this->objectAction->executeAction();
|
||||
$returnValues = $this->objectAction->getReturnValues();
|
||||
|
||||
// add activity points
|
||||
\wcf\system\user\activity\point\UserActivityPointHandler::getInstance()->fireEvent('be.bastelstu.chat.activityPointEvent.message', $returnValues['returnValues']->messageID, WCF::getUser()->userID);
|
||||
|
||||
return $returnValues['returnValues'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates getting messages.
|
||||
*/
|
||||
public function validateGetMessages() {
|
||||
// check permissions
|
||||
WCF::getSession()->checkPermissions(array('admin.chat.canReadLog'));
|
||||
|
||||
// read parameters
|
||||
$this->readInteger('roomID');
|
||||
$this->readInteger('start');
|
||||
$this->readInteger('end');
|
||||
|
||||
// read and validate room
|
||||
$this->parameters['room'] = room\RoomCache::getInstance()->getRoom($this->parameters['roomID']);
|
||||
if ($this->parameters['room'] === null) throw new \wcf\system\exception\IllegalLinkException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches messages in between the specified timestamps.
|
||||
*
|
||||
* @return array Array containing message table, containerID and information about an empty message table.
|
||||
*/
|
||||
public function getMessages() {
|
||||
// read messages
|
||||
$messages = ViewableMessageList::getMessagesBetween($this->parameters['room'], $this->parameters['start'], $this->parameters['end']);
|
||||
|
||||
return array(
|
||||
'noMessages' => (count($messages) == 0) ? true : null,
|
||||
'containerID' => $this->parameters['containerID'],
|
||||
'template' => WCF::getTPL()->fetch('__messageLogTable', 'chat', array('messages' => $messages), true)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates setting an attachment.
|
||||
*/
|
||||
public function validateSendAttachment() {
|
||||
// read user data
|
||||
$this->parameters['userData']['color1'] = WCF::getUser()->chatColor1;
|
||||
$this->parameters['userData']['color2'] = WCF::getUser()->chatColor2;
|
||||
$this->parameters['userData']['roomID'] = WCF::getUser()->chatRoomID;
|
||||
$this->parameters['userData']['away'] = WCF::getUser()->chatAway;
|
||||
|
||||
// read and validate room
|
||||
$this->parameters['room'] = room\RoomCache::getInstance()->getRoom($this->parameters['userData']['roomID']);
|
||||
if ($this->parameters['room'] === null) throw new \wcf\system\exception\IllegalLinkException();
|
||||
if (!$this->parameters['room']->canEnter()) throw new \wcf\system\exception\PermissionDeniedException();
|
||||
if (!$this->parameters['room']->canWrite()) throw new \wcf\system\exception\PermissionDeniedException();
|
||||
|
||||
$this->readInteger('objectID');
|
||||
if (!$this->parameters['objectID']) throw new \wcf\system\exception\IllegalLinkException();
|
||||
|
||||
$this->readInteger('parentObjectID');
|
||||
if (!$this->parameters['parentObjectID']) throw new \wcf\system\exception\IllegalLinkException();
|
||||
|
||||
$editor = new \wcf\data\user\UserEditor(WCF::getUser());
|
||||
$editor->update(array(
|
||||
'chatAway' => null,
|
||||
'chatLastActivity' => TIME_NOW
|
||||
));
|
||||
|
||||
// mark user as back
|
||||
if ($this->parameters['userData']['away'] !== null) {
|
||||
$messageAction = new MessageAction(array(), 'create', array(
|
||||
'data' => array(
|
||||
'roomID' => $this->parameters['room']->roomID,
|
||||
'sender' => WCF::getUser()->userID,
|
||||
'username' => WCF::getUser()->username,
|
||||
'time' => TIME_NOW,
|
||||
'type' => Message::TYPE_BACK,
|
||||
'message' => '',
|
||||
'color1' => $this->parameters['userData']['color1'],
|
||||
'color2' => $this->parameters['userData']['color2']
|
||||
)
|
||||
));
|
||||
$messageAction->executeAction();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a message linked to an attachment
|
||||
*/
|
||||
public function sendAttachment() {
|
||||
$this->parameters['type'] = Message::TYPE_ATTACHMENT;
|
||||
$this->parameters['text'] = '[attach]'. $this->parameters['objectID'] .'[/attach]';
|
||||
$this->parameters['additionalData'] = null;
|
||||
$this->parameters['receiver'] = null;
|
||||
$this->parameters['enableSmilies'] = false;
|
||||
$this->parameters['enableHTML'] = false;
|
||||
|
||||
$messageAction = new MessageAction(array(), 'send', $this->parameters);
|
||||
$messageAction->executeAction();
|
||||
$returnValues = $messageAction->getReturnValues();
|
||||
|
||||
$attachmentHandler = new \wcf\system\attachment\AttachmentHandler('be.bastelstu.chat.message', $this->parameters['objectID'], $this->parameters['tmpHash'], 0);
|
||||
$attachmentHandler->updateObjectID($returnValues['returnValues']->messageID);
|
||||
}
|
||||
}
|
41
file/lib/data/message/MessageEditor.class.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
namespace chat\data\message;
|
||||
|
||||
/**
|
||||
* Provides functions to edit chat messages.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage chat.message
|
||||
*/
|
||||
class MessageEditor extends \wcf\data\DatabaseObjectEditor {
|
||||
/**
|
||||
* @see \wcf\data\DatabaseObjectDecorator::$baseClass
|
||||
*/
|
||||
protected static $baseClass = '\chat\data\message\Message';
|
||||
|
||||
/**
|
||||
* @see wcf\data\DatabaseObjectEditor::deleteAll()
|
||||
*/
|
||||
public static function deleteAll(array $objectIDs = array()) {
|
||||
$count = parent::deleteAll($objectIDs);
|
||||
|
||||
if ($count) {
|
||||
// delete attached files
|
||||
\wcf\system\attachment\AttachmentHandler::removeAttachments('be.bastelstu.chat.message', $objectIDs);
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the Push-Server.
|
||||
*/
|
||||
public static function create(array $parameters = array()) {
|
||||
\wcf\system\push\PushHandler::getInstance()->sendMessage('be.bastelstu.chat.newMessage');
|
||||
|
||||
return parent::create($parameters);
|
||||
}
|
||||
}
|
100
file/lib/data/message/MessageList.class.php
Normal file
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
namespace chat\data\message;
|
||||
|
||||
/**
|
||||
* Represents a list of chat messages.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage chat.room
|
||||
*/
|
||||
class MessageList extends \wcf\data\DatabaseObjectList {
|
||||
/**
|
||||
* @see \wcf\data\DatabaseObjectList::$className
|
||||
*/
|
||||
public $className = 'chat\data\message\Message';
|
||||
|
||||
/**
|
||||
* Reads the newest messages for the given room.
|
||||
*
|
||||
* @param \chat\data\room\Room $room
|
||||
* @param integer $number
|
||||
* @return array<\chat\data\message\Message>
|
||||
*/
|
||||
public static function getNewestMessages(\chat\data\room\Room $room, $number = CHAT_LASTMESSAGES) {
|
||||
if ($number === 0) return array();
|
||||
|
||||
$messageList = new static();
|
||||
$messageList->sqlOrderBy = "message.messageID DESC";
|
||||
$messageList->sqlLimit = $number;
|
||||
$messageList->getConditionBuilder()->add('message.receiver IS NULL', array());
|
||||
|
||||
if ($room->roomID !== \chat\data\room\Room::GLOBAL_ROOM) {
|
||||
$messageList->getConditionBuilder()->add('message.roomID = ?', array($room->roomID));
|
||||
}
|
||||
|
||||
$messageList->readObjects();
|
||||
return array_reverse($messageList->getObjects());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the messages since the given message-id for the given room.
|
||||
*
|
||||
* @param \chat\data\room\Room $room
|
||||
* @param integer $since
|
||||
* @return array<\chat\data\message\Message>
|
||||
*/
|
||||
public static function getMessagesSince(\chat\data\room\Room $room, $since) {
|
||||
$messageList = new static();
|
||||
$messageList->sqlOrderBy = "message.messageID ASC";
|
||||
$messageList->getConditionBuilder()->add('message.messageID > ?', array($since));
|
||||
|
||||
if ($room->roomID !== \chat\data\room\Room::GLOBAL_ROOM) {
|
||||
$messageList->getConditionBuilder()->add('
|
||||
((
|
||||
message.receiver IS NULL
|
||||
AND message.roomID = ?
|
||||
)
|
||||
OR message.receiver = ?
|
||||
OR message.sender = ?)',
|
||||
array($room->roomID, \wcf\system\WCF::getUser()->userID, \wcf\system\WCF::getUser()->userID)
|
||||
);
|
||||
}
|
||||
else {
|
||||
$messageList->getConditionBuilder()->add('
|
||||
(message.receiver IS NULL
|
||||
OR message.receiver = ?
|
||||
OR message.sender = ?)',
|
||||
array(\wcf\system\WCF::getUser()->userID, \wcf\system\WCF::getUser()->userID)
|
||||
);
|
||||
}
|
||||
|
||||
$messageList->readObjects();
|
||||
return $messageList->getObjects();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the message between the given timestamps for the given room.
|
||||
*
|
||||
* @param \chat\data\room\Room $room
|
||||
* @param integer $start
|
||||
* @param integer $end
|
||||
* @return array<\chat\data\message\Message>
|
||||
*/
|
||||
public static function getMessagesBetween(\chat\data\room\Room $room, $start, $end) {
|
||||
$messageList = new static();
|
||||
$messageList->sqlOrderBy = "message.messageID ASC";
|
||||
$messageList->getConditionBuilder()->add('message.receiver IS NULL', array());
|
||||
|
||||
if ($room->roomID !== \chat\data\room\Room::GLOBAL_ROOM) {
|
||||
$messageList->getConditionBuilder()->add('message.roomID = ?', array($room->roomID));
|
||||
}
|
||||
|
||||
$messageList->getConditionBuilder()->add('message.time BETWEEN ? AND ?', array($start, $end));
|
||||
|
||||
$messageList->readObjects();
|
||||
return $messageList->getObjects();
|
||||
}
|
||||
}
|
54
file/lib/data/message/ViewableMessage.class.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
namespace chat\data\message;
|
||||
|
||||
/**
|
||||
* Represents a viewable chat message.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage data.message
|
||||
*/
|
||||
class ViewableMessage extends \wcf\data\DatabaseObjectDecorator {
|
||||
/**
|
||||
* @see \wcf\data\DatabaseObjectDecorator::$baseClass
|
||||
*/
|
||||
protected static $baseClass = 'chat\data\message\Message';
|
||||
|
||||
/**
|
||||
* user profile object
|
||||
* @var \wcf\data\user\UserProfile
|
||||
*/
|
||||
protected $userProfile = null;
|
||||
|
||||
/**
|
||||
* Returns the profile object of the user who created the post.
|
||||
*
|
||||
* @return wcf\data\user\UserProfile
|
||||
*/
|
||||
public function getUserProfile() {
|
||||
if ($this->userProfile === null) {
|
||||
$this->userProfile = new \wcf\data\user\UserProfile(new \wcf\data\user\User(null, $this->getDecoratedObject()->data));
|
||||
}
|
||||
|
||||
return $this->userProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\data\message\Message::jsonify()
|
||||
*/
|
||||
public function jsonify($raw = false) {
|
||||
$array = parent::jsonify(true);
|
||||
|
||||
$array['avatar'] = array(
|
||||
16 => $this->getUserProfile()->getAvatar()->getImageTag(16),
|
||||
24 => $this->getUserProfile()->getAvatar()->getImageTag(24),
|
||||
32 => $this->getUserProfile()->getAvatar()->getImageTag(32),
|
||||
48 => $this->getUserProfile()->getAvatar()->getImageTag(48)
|
||||
);
|
||||
|
||||
if ($raw) return $array;
|
||||
return \wcf\util\JSON::encode($array);
|
||||
}
|
||||
}
|
35
file/lib/data/message/ViewableMessageList.class.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
namespace chat\data\message;
|
||||
|
||||
/**
|
||||
* Represents a list of viewable chat messages.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage chat.room
|
||||
*/
|
||||
class ViewableMessageList extends MessageList {
|
||||
/**
|
||||
* @see \wcf\data\DatabaseObjectList::$decoratorClassName
|
||||
*/
|
||||
public $decoratorClassName = 'chat\data\message\ViewableMessage';
|
||||
|
||||
/**
|
||||
* @see \wcf\data\DatabaseObjectList::__construct()
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->sqlSelects .= "user_avatar.*, user_option_value.*, user_table.*";
|
||||
$this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user user_table ON (user_table.userID = message.sender)";
|
||||
$this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user_avatar user_avatar ON (user_avatar.avatarID = user_table.avatarID)";
|
||||
$this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user_option_value user_option_value ON (user_option_value.userID = user_table.userID)";
|
||||
|
||||
if (MODULE_USER_RANK) {
|
||||
$this->sqlSelects .= ",user_rank.*";
|
||||
$this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user_rank user_rank ON (user_rank.rankID = user_table.rankID)";
|
||||
}
|
||||
}
|
||||
}
|
251
file/lib/data/room/Room.class.php
Normal file
@ -0,0 +1,251 @@
|
||||
<?php
|
||||
namespace chat\data\room;
|
||||
use \chat\data\suspension\Suspension;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Represents a chat room.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage data.room
|
||||
*/
|
||||
class Room extends \chat\data\CHATDatabaseObject implements \wcf\system\request\IRouteController {
|
||||
/**
|
||||
* @see \wcf\data\DatabaseObject::$databaseTableName
|
||||
*/
|
||||
protected static $databaseTableName = 'room';
|
||||
|
||||
/**
|
||||
* @see \wcf\data\DatabaseObject::$databaseTableIndexName
|
||||
*/
|
||||
protected static $databaseTableIndexName = 'roomID';
|
||||
|
||||
/**
|
||||
* cached users
|
||||
*
|
||||
* @var array<\wcf\data\user\UserProfile>
|
||||
*/
|
||||
protected static $users = null;
|
||||
|
||||
/**
|
||||
* room id of the “global” pseudo chat room
|
||||
*/
|
||||
const GLOBAL_ROOM = -1;
|
||||
|
||||
/**
|
||||
* @see \wcf\data\chat\room\ChatRoom::getTitle();
|
||||
*/
|
||||
public function __toString() {
|
||||
return $this->getTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whther the user is allowed to always enter the room.
|
||||
*
|
||||
* @param \wcf\data\user\User $user
|
||||
* @return boolean
|
||||
*/
|
||||
public function canAlwaysEnter(\wcf\data\user\User $user = null) {
|
||||
if ($user === null) $user = WCF::getUser();
|
||||
if (!$user->userID) return false;
|
||||
$user = new \wcf\data\user\UserProfile($user);
|
||||
|
||||
if ($this->isPermanent && $user->getPermission('admin.chat.canManageSuspensions')) return true;
|
||||
if ($this->isPermanent && $user->getPermission('mod.chat.canGban')) return true;
|
||||
|
||||
$ph = new \chat\system\permission\PermissionHandler($user->getDecoratedObject());
|
||||
if ($ph->getPermission($this, 'mod.canAlwaysEnter')) return true;
|
||||
if ($ph->getPermission($this, 'mod.canBan')) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the user is allowed to enter the room.
|
||||
*
|
||||
* @param \wcf\data\user\User $user
|
||||
* @return boolean
|
||||
*/
|
||||
public function canEnter(\wcf\data\user\User $user = null) {
|
||||
if ($user === null) $user = WCF::getUser();
|
||||
if (!$user->userID) return false;
|
||||
if ($this->canAlwaysEnter($user)) return true;
|
||||
$user = new \wcf\data\user\UserProfile($user);
|
||||
|
||||
$ph = new \chat\system\permission\PermissionHandler($user->getDecoratedObject());
|
||||
if (!$ph->getPermission($this, 'user.canEnter')) return false;
|
||||
|
||||
$suspensions = Suspension::getSuspensionsForUser($user->getDecoratedObject());
|
||||
// room suspension
|
||||
if (isset($suspensions[$this->roomID][Suspension::TYPE_BAN])) {
|
||||
if ($suspensions[$this->roomID][Suspension::TYPE_BAN]->isValid()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// global suspension
|
||||
if (isset($suspensions[null][Suspension::TYPE_BAN])) {
|
||||
if ($suspensions[null][Suspension::TYPE_BAN]->isValid()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the user is allowed to write messages in this room.
|
||||
*
|
||||
* @param \wcf\data\user\User $user
|
||||
* @return boolean
|
||||
*/
|
||||
public function canWrite(\wcf\data\user\User $user = null) {
|
||||
if ($user === null) $user = WCF::getUser();
|
||||
if (!$user->userID) return false;
|
||||
$user = new \wcf\data\user\UserProfile($user);
|
||||
|
||||
if ($user->getPermission('admin.chat.canManageSuspensions')) return true;
|
||||
if ($user->getPermission('mod.chat.canGmute')) return true;
|
||||
|
||||
$ph = new \chat\system\permission\PermissionHandler($user->getDecoratedObject());
|
||||
if ($ph->getPermission($this, 'mod.canAlwaysWrite')) return true;
|
||||
if ($ph->getPermission($this, 'mod.canMute')) return true;
|
||||
|
||||
if (!$ph->getPermission($this, 'user.canWrite')) return false;
|
||||
|
||||
$suspensions = Suspension::getSuspensionsForUser($user->getDecoratedObject());
|
||||
// room suspension
|
||||
if (isset($suspensions[$this->roomID][Suspension::TYPE_MUTE])) {
|
||||
if ($suspensions[$this->roomID][Suspension::TYPE_MUTE]->isValid()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// global suspension
|
||||
if (isset($suspensions[null][Suspension::TYPE_MUTE])) {
|
||||
if ($suspensions[null][Suspension::TYPE_MUTE]->isValid()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the user is allowed to mute other users in this room.
|
||||
*
|
||||
* @param \wcf\data\user\User $user
|
||||
* @return boolean
|
||||
*/
|
||||
public function canMute(\wcf\data\user\User $user = null) {
|
||||
if ($user === null) $user = WCF::getUser();
|
||||
if (!$user->userID) return false;
|
||||
$user = new \wcf\data\user\UserProfile($user);
|
||||
|
||||
if ($user->getPermission('admin.chat.canManageSuspensions')) return true;
|
||||
if ($user->getPermission('mod.chat.canGmute')) return true;
|
||||
|
||||
$ph = new \chat\system\permission\PermissionHandler($user->getDecoratedObject());
|
||||
return $ph->getPermission($this, 'mod.canMute');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the user is allowed to ban other users in this room.
|
||||
*
|
||||
* @param \wcf\data\user\User $user
|
||||
* @return boolean
|
||||
*/
|
||||
public function canBan(\wcf\data\user\User $user = null) {
|
||||
if ($user === null) $user = WCF::getUser();
|
||||
if (!$user->userID) return false;
|
||||
$user = new \wcf\data\user\UserProfile($user);
|
||||
|
||||
if ($user->getPermission('admin.chat.canManageSuspensions')) return true;
|
||||
if ($user->getPermission('mod.chat.canGban')) return true;
|
||||
|
||||
$ph = new \chat\system\permission\PermissionHandler($user->getDecoratedObject());
|
||||
return $ph->getPermission($this, 'mod.canBan');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID of this chatroom.
|
||||
*
|
||||
* @see \wcf\system\request\IRouteController
|
||||
*/
|
||||
public function getID() {
|
||||
return $this->roomID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this chatroom.
|
||||
*
|
||||
* @see \wcf\system\request\IRouteController
|
||||
*/
|
||||
public function getTitle() {
|
||||
return \wcf\system\WCF::getLanguage()->get($this->title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the topic of this chat room
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTopic() {
|
||||
return \wcf\system\WCF::getLanguage()->get($this->topic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the users that are currently active in this room.
|
||||
*
|
||||
* @return array<\wcf\data\user\UserProfile>
|
||||
*/
|
||||
public function getUsers() {
|
||||
if (self::$users === null) {
|
||||
$userList = new \wcf\data\user\UserProfileList();
|
||||
$userList->getConditionBuilder()->add('user_table.chatRoomID IS NOT NULL', array());
|
||||
|
||||
$userList->readObjects();
|
||||
$users = $userList->getObjects();
|
||||
|
||||
foreach ($users as $userID => $user) {
|
||||
if (!isset(self::$users[$user->chatRoomID])) self::$users[$user->chatRoomID] = array();
|
||||
self::$users[$user->chatRoomID][$userID] = $user;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->roomID === self::GLOBAL_ROOM) {
|
||||
return array_reduce(self::$users, function($a, $b) {
|
||||
return $a + $b;
|
||||
}, array());
|
||||
}
|
||||
|
||||
if (!isset(self::$users[$this->roomID])) self::$users[$this->roomID] = array();
|
||||
|
||||
return self::$users[$this->roomID];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the users that "timed out".
|
||||
*
|
||||
* @return \wcf\data\user\UserList
|
||||
*/
|
||||
public static function getDeadUsers() {
|
||||
if (\wcf\system\push\PushHandler::getInstance()->isEnabled()) {
|
||||
$time = TIME_NOW - 180;
|
||||
}
|
||||
else {
|
||||
$time = TIME_NOW;
|
||||
}
|
||||
|
||||
$userList = new \wcf\data\user\UserList();
|
||||
$userList->getConditionBuilder()->add('user_table.chatRoomID IS NOT NULL', array());
|
||||
$userList->getConditionBuilder()->add('user_table.chatLastActivity < ?', array($time - 30));
|
||||
|
||||
$userList->readObjects();
|
||||
|
||||
return $userList;
|
||||
}
|
||||
}
|
369
file/lib/data/room/RoomAction.class.php
Normal file
@ -0,0 +1,369 @@
|
||||
<?php
|
||||
namespace chat\data\room;
|
||||
use \chat\data\message;
|
||||
use \chat\util\ChatUtil;
|
||||
use \wcf\system\exception;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Executes chatroom-related actions.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage data.room
|
||||
*/
|
||||
class RoomAction extends \wcf\data\AbstractDatabaseObjectAction implements \wcf\data\ISortableAction {
|
||||
/**
|
||||
* @see \wcf\data\AbstractDatabaseObjectAction::$className
|
||||
*/
|
||||
protected $className = '\chat\data\room\RoomEditor';
|
||||
|
||||
/**
|
||||
* @see \wcf\data\AbstractDatabaseObjectAction::$permissionsDelete
|
||||
*/
|
||||
protected $permissionsDelete = array('admin.chat.canDeleteRoom');
|
||||
|
||||
/**
|
||||
* @see \wcf\data\AbstractDatabaseObjectAction::$permissionsUpdate
|
||||
*/
|
||||
protected $permissionsUpdate = array('admin.chat.canEditRoom');
|
||||
|
||||
/**
|
||||
* Resets cache if any of the listed actions is invoked
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $resetCache = array('create', 'delete', 'toggle', 'update', 'updatePosition', 'prune');
|
||||
|
||||
/**
|
||||
* Fixes create to append new rooms.
|
||||
*/
|
||||
public function create() {
|
||||
$room = parent::create();
|
||||
|
||||
WCF::getDB()->beginTransaction();
|
||||
$sql = "SELECT MAX(showOrder)
|
||||
FROM ".call_user_func(array($this->className, 'getDatabaseTableName'))."
|
||||
FOR UPDATE";
|
||||
$stmt = WCF::getDB()->prepareStatement($sql);
|
||||
$stmt->execute();
|
||||
|
||||
$editor = new RoomEditor($room);
|
||||
$editor->update(array('showOrder' => ($stmt->fetchColumn() + 1)));
|
||||
WCF::getDB()->commitTransaction();
|
||||
|
||||
return $room;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes temporary rooms that are unused.
|
||||
*
|
||||
* @return integer Number of deleted rooms
|
||||
*/
|
||||
public function prune() {
|
||||
$sql = "SELECT
|
||||
".call_user_func(array($this->className, 'getDatabaseTableIndexName'))."
|
||||
FROM
|
||||
".call_user_func(array($this->className, 'getDatabaseTableName'))."
|
||||
WHERE
|
||||
permanent = ?
|
||||
AND roomID NOT IN (
|
||||
SELECT chatRoomID
|
||||
FROM wcf".WCF_N."_user
|
||||
WHERE chatRoomID IS NOT NULL
|
||||
)";
|
||||
$stmt = \wcf\system\WCF::getDB()->prepareStatement($sql);
|
||||
$stmt->execute(array(0));
|
||||
$objectIDs = array();
|
||||
|
||||
while ($objectID = $stmt->fetchColumn()) $objectIDs[] = $objectID;
|
||||
|
||||
return call_user_func(array($this->className, 'deleteAll'), $objectIDs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see wcf\data\ISortableAction::validateUpdatePosition()
|
||||
*/
|
||||
public function validateUpdatePosition() {
|
||||
// validate permissions
|
||||
if (is_array($this->permissionsUpdate) && count($this->permissionsUpdate)) {
|
||||
WCF::getSession()->checkPermissions($this->permissionsUpdate);
|
||||
}
|
||||
else {
|
||||
throw new exception\PermissionDeniedException();
|
||||
}
|
||||
|
||||
if (!isset($this->parameters['data']['structure'])) {
|
||||
throw new exception\UserInputException('structure');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see wcf\data\ISortableAction::updatePosition()
|
||||
*/
|
||||
public function updatePosition() {
|
||||
$roomList = new RoomList();
|
||||
$roomList->readObjects();
|
||||
|
||||
$i = 0;
|
||||
WCF::getDB()->beginTransaction();
|
||||
foreach ($this->parameters['data']['structure'][0] as $roomID) {
|
||||
$room = $roomList->search($roomID);
|
||||
if ($room === null) continue;
|
||||
|
||||
$editor = new RoomEditor($room);
|
||||
$editor->update(array('showOrder' => $i++));
|
||||
}
|
||||
WCF::getDB()->commitTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates parameters and permissions.
|
||||
*/
|
||||
public function validateGetRoomList() {
|
||||
if (!MODULE_CHAT) throw new exception\IllegalLinkException();
|
||||
|
||||
$this->parameters['room'] = RoomCache::getInstance()->getRoom(WCF::getUser()->chatRoomID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the available rooms.
|
||||
*/
|
||||
public function getRoomList() {
|
||||
$rooms = RoomCache::getInstance()->getRooms();
|
||||
|
||||
$result = array();
|
||||
foreach ($rooms as $room) {
|
||||
if (!$room->canEnter()) continue;
|
||||
|
||||
$result[] = array(
|
||||
'title' => (string) $room,
|
||||
'topic' => $room->getTopic(),
|
||||
'link' => \wcf\system\request\LinkHandler::getInstance()->getLink('Chat', array(
|
||||
'application' => 'chat',
|
||||
'object' => $room
|
||||
)),
|
||||
'roomID' => (int) $room->roomID,
|
||||
'active' => $this->parameters['room'] && $room->roomID == $this->parameters['room']->roomID,
|
||||
'userCount' => count($room->getUsers()),
|
||||
'maxUsers' => (int) $room->maxUsers,
|
||||
'permissions' => array(
|
||||
'canBan' => (boolean) $room->canBan(),
|
||||
'canMute' => (boolean) $room->canMute()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates parameters and permissions.
|
||||
*/
|
||||
public function validateJoin() {
|
||||
if (!MODULE_CHAT) throw new exception\IllegalLinkException();
|
||||
|
||||
unset($this->parameters['user']);
|
||||
$this->readInteger('roomID');
|
||||
|
||||
$room = RoomCache::getInstance()->getRoom($this->parameters['roomID']);
|
||||
if ($room === null) throw new exception\UserInputException('roomID');
|
||||
if (!$room->canEnter()) throw new exception\PermissionDeniedException();
|
||||
|
||||
if ($room->maxUsers && count($room->getUsers()) >= $room->maxUsers && !$room->canAlwaysEnter()) {
|
||||
$errorMessage = WCF::getLanguage()->getDynamicVariable('chat.global.error.join.full', array('room' => $room));
|
||||
|
||||
throw new exception\UserInputException('room', $errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins the room.
|
||||
*/
|
||||
public function join() {
|
||||
// user cannot be set during an AJAX request but may be set by the chat itself
|
||||
if (!isset($this->parameters['user'])) {
|
||||
$this->parameters['user'] = WCF::getUser();
|
||||
}
|
||||
|
||||
$room = RoomCache::getInstance()->getRoom($this->parameters['roomID']);
|
||||
if ($room === null) throw new exception\UserInputException();
|
||||
|
||||
if (CHAT_DISPLAY_JOIN_LEAVE) {
|
||||
if ($this->parameters['user']->chatRoomID) {
|
||||
// leave message
|
||||
$messageAction = new message\MessageAction(array(), 'create', array(
|
||||
'data' => array(
|
||||
'roomID' => $this->parameters['user']->chatRoomID,
|
||||
'sender' => $this->parameters['user']->userID,
|
||||
'username' => $this->parameters['user']->username,
|
||||
'time' => TIME_NOW,
|
||||
'type' => message\Message::TYPE_LEAVE,
|
||||
'message' => '',
|
||||
'color1' => $this->parameters['user']->chatColor1,
|
||||
'color2' => $this->parameters['user']->chatColor2,
|
||||
'additionalData' => serialize(array('room' => $room))
|
||||
)
|
||||
));
|
||||
$messageAction->executeAction();
|
||||
}
|
||||
|
||||
$ipAddress = '';
|
||||
if (LOG_IP_ADDRESS && $this->parameters['user']->userID == WCF::getUser()->userID) $ipAddress = \wcf\util\UserUtil::convertIPv6To4(\wcf\util\UserUtil::getIpAddress());
|
||||
|
||||
// join message
|
||||
$messageAction = new message\MessageAction(array(), 'create', array(
|
||||
'data' => array(
|
||||
'roomID' => $room->roomID,
|
||||
'sender' => $this->parameters['user']->userID,
|
||||
'username' => $this->parameters['user']->username,
|
||||
'time' => TIME_NOW,
|
||||
'type' => message\Message::TYPE_JOIN,
|
||||
'message' => '',
|
||||
'color1' => $this->parameters['user']->chatColor1,
|
||||
'color2' => $this->parameters['user']->chatColor2,
|
||||
'additionalData' => serialize(array('ipAddress' => $ipAddress))
|
||||
)
|
||||
));
|
||||
$messageAction->executeAction();
|
||||
}
|
||||
|
||||
$newestMessages = message\ViewableMessageList::getNewestMessages($room, CHAT_LASTMESSAGES + CHAT_DISPLAY_JOIN_LEAVE);
|
||||
|
||||
// update last seen message
|
||||
$sql = "SELECT
|
||||
MAX(messageID)
|
||||
FROM
|
||||
chat".WCF_N."_message";
|
||||
$stmt = WCF::getDB()->prepareStatement($sql);
|
||||
$stmt->execute();
|
||||
|
||||
$editor = new \wcf\data\user\UserEditor($this->parameters['user']);
|
||||
$editor->update(array(
|
||||
'chatRoomID' => $room->roomID,
|
||||
'chatAway' => null,
|
||||
'chatLastActivity' => TIME_NOW,
|
||||
'chatLastSeen' => $stmt->fetchColumn() ?: 0
|
||||
));
|
||||
|
||||
// add activity points
|
||||
$microtime = microtime(true) * 1000;
|
||||
$result = $microtime & 0xFFFFFFFF;
|
||||
if ($result > 0x7FFFFFFF) $result -= 0x80000000;
|
||||
\wcf\system\user\activity\point\UserActivityPointHandler::getInstance()->fireEvent('be.bastelstu.chat.activityPointEvent.join', $result, WCF::getUser()->userID);
|
||||
|
||||
// send push message about join
|
||||
\wcf\system\push\PushHandler::getInstance()->sendMessage('be.bastelstu.chat.join');
|
||||
|
||||
$messages = array();
|
||||
foreach ($newestMessages as $message) $messages[] = $message->jsonify(true);
|
||||
return array(
|
||||
'title' => (string) $room,
|
||||
'topic' => $room->getTopic(),
|
||||
'link' => \wcf\system\request\LinkHandler::getInstance()->getLink('Chat', array(
|
||||
'application' => 'chat',
|
||||
'object' => $room
|
||||
)),
|
||||
'roomID' => (int) $room->roomID,
|
||||
'userCount' => count($room->getUsers()),
|
||||
'maxUsers' => (int) $room->maxUsers,
|
||||
'permissions' => array(
|
||||
'canBan' => (boolean) $room->canBan(),
|
||||
'canMute' => (boolean) $room->canMute()
|
||||
),
|
||||
'messages' => $messages,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates parameters and permissions.
|
||||
*/
|
||||
public function validateLeave() {
|
||||
if (!MODULE_CHAT) throw new exception\IllegalLinkException();
|
||||
|
||||
unset($this->parameters['user']);
|
||||
|
||||
if (RoomCache::getInstance()->getRoom(WCF::getUser()->chatRoomID) === null) throw new exception\IllegalLinkException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Leaves the room.
|
||||
*/
|
||||
public function leave() {
|
||||
// user cannot be set during an AJAX request but may be set by the chat itself
|
||||
if (!isset($this->parameters['user'])) {
|
||||
$this->parameters['user'] = WCF::getUser();
|
||||
}
|
||||
|
||||
$room = RoomCache::getInstance()->getRoom($this->parameters['user']->chatRoomID);
|
||||
if ($room === null) throw new exception\UserInputException();
|
||||
|
||||
if (CHAT_DISPLAY_JOIN_LEAVE) {
|
||||
// leave message
|
||||
$messageAction = new message\MessageAction(array(), 'create', array(
|
||||
'data' => array(
|
||||
'roomID' => $room->roomID,
|
||||
'sender' => $this->parameters['user']->userID,
|
||||
'username' => $this->parameters['user']->username,
|
||||
'time' => TIME_NOW,
|
||||
'type' => message\Message::TYPE_LEAVE,
|
||||
'message' => '',
|
||||
'color1' => $this->parameters['user']->chatColor1,
|
||||
'color2' => $this->parameters['user']->chatColor2
|
||||
)
|
||||
));
|
||||
$messageAction->executeAction();
|
||||
}
|
||||
|
||||
// set current room to null
|
||||
$editor = new \wcf\data\user\UserEditor($this->parameters['user']);
|
||||
$editor->update(array(
|
||||
'chatRoomID' => null
|
||||
));
|
||||
|
||||
\wcf\system\push\PushHandler::getInstance()->sendMessage('be.bastelstu.chat.leave');
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces dead users to leave the chat.
|
||||
*/
|
||||
public function removeDeadUsers() {
|
||||
$deadUsers = Room::getDeadUsers();
|
||||
|
||||
foreach ($deadUsers as $deadUser) {
|
||||
$roomAction = new self(array(), 'leave', array(
|
||||
'user' => $deadUser
|
||||
));
|
||||
$roomAction->executeAction();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates permissions.
|
||||
*/
|
||||
public function validateGetBoxRoomList() {
|
||||
if (!MODULE_CHAT) throw new \wcf\system\exception\IllegalLinkException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns dashboard roomlist.
|
||||
*/
|
||||
public function getBoxRoomList() {
|
||||
$rooms = RoomCache::getInstance()->getRooms();
|
||||
|
||||
foreach ($rooms as $key => $room) {
|
||||
if (!$room->canEnter()) unset($rooms[$key]);
|
||||
}
|
||||
|
||||
$this->readBoolean('showEmptyRooms', true);
|
||||
\wcf\system\WCF::getTPL()->assign(array(
|
||||
'rooms' => $rooms,
|
||||
'showEmptyRooms' => $this->parameters['showEmptyRooms']
|
||||
));
|
||||
|
||||
return array(
|
||||
'template' => \wcf\system\WCF::getTPL()->fetch('boxRoomList', 'chat')
|
||||
);
|
||||
}
|
||||
}
|
49
file/lib/data/room/RoomCache.class.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
namespace chat\data\room;
|
||||
|
||||
/**
|
||||
* Manages the room cache.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage data.room
|
||||
*/
|
||||
class RoomCache extends \wcf\system\SingletonFactory {
|
||||
/**
|
||||
* list of cached rooms
|
||||
* @var array<\chat\data\room\Room>
|
||||
*/
|
||||
protected $rooms = array();
|
||||
|
||||
/**
|
||||
* @see wcf\system\SingletonFactory::init()
|
||||
*/
|
||||
protected function init() {
|
||||
$this->rooms = \chat\system\cache\builder\RoomCacheBuilder::getInstance()->getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specific room.
|
||||
*
|
||||
* @param integer $roomID
|
||||
* @return \chat\data\room\Room
|
||||
*/
|
||||
public function getRoom($roomID) {
|
||||
if (isset($this->rooms[$roomID])) {
|
||||
return $this->rooms[$roomID];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all rooms.
|
||||
*
|
||||
* @return array<\chat\data\room\Room>
|
||||
*/
|
||||
public function getRooms() {
|
||||
return $this->rooms;
|
||||
}
|
||||
}
|
66
file/lib/data/room/RoomEditor.class.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
namespace chat\data\room;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Provides functions to edit chat rooms.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage data.room
|
||||
*/
|
||||
class RoomEditor extends \wcf\data\DatabaseObjectEditor implements \wcf\data\IEditableCachedObject {
|
||||
/**
|
||||
* @see \wcf\data\DatabaseObjectDecorator::$baseClass
|
||||
*/
|
||||
protected static $baseClass = '\chat\data\room\Room';
|
||||
|
||||
|
||||
/**
|
||||
* @see \wcf\data\DatabaseObjectEditor::deleteAll()
|
||||
*/
|
||||
public static function deleteAll(array $objectIDs = array()) {
|
||||
WCF::getDB()->beginTransaction();
|
||||
foreach ($objectIDs as $objectID) {
|
||||
\wcf\system\language\I18nHandler::getInstance()->remove('chat.room.title'.$objectID);
|
||||
\wcf\system\language\I18nHandler::getInstance()->remove('chat.room.topic'.$objectID);
|
||||
}
|
||||
|
||||
$sql = "SELECT
|
||||
showOrder
|
||||
FROM
|
||||
chat".WCF_N."_room
|
||||
WHERE
|
||||
roomID = ?
|
||||
FOR UPDATE";
|
||||
$select = WCF::getDB()->prepareStatement($sql);
|
||||
|
||||
$sql = "UPDATE
|
||||
chat".WCF_N."_room
|
||||
SET
|
||||
showOrder = showOrder - 1
|
||||
WHERE
|
||||
showOrder > ?";
|
||||
$update = WCF::getDB()->prepareStatement($sql);
|
||||
|
||||
foreach ($objectIDs as $objectID) {
|
||||
$select->execute(array($objectID));
|
||||
$update->execute(array($select->fetchColumn()));
|
||||
}
|
||||
|
||||
$return = parent::deleteAll($objectIDs);
|
||||
WCF::getDB()->commitTransaction();
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the room cache.
|
||||
*/
|
||||
public static function resetCache() {
|
||||
\chat\system\cache\builder\RoomCacheBuilder::getInstance()->reset();
|
||||
\chat\system\cache\builder\PermissionCacheBuilder::getInstance()->reset();
|
||||
\wcf\system\push\PushHandler::getInstance()->sendDeferredMessage('be.bastelstu.chat.roomChange');
|
||||
}
|
||||
}
|
18
file/lib/data/room/RoomList.class.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
namespace chat\data\room;
|
||||
|
||||
/**
|
||||
* Represents a list of chat rooms.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage data.room
|
||||
*/
|
||||
class RoomList extends \wcf\data\DatabaseObjectList {
|
||||
/**
|
||||
* @see \wcf\data\DatabaseObjectList::$className
|
||||
*/
|
||||
public $className = 'chat\data\room\Room';
|
||||
}
|
139
file/lib/data/suspension/Suspension.class.php
Normal file
@ -0,0 +1,139 @@
|
||||
<?php
|
||||
namespace chat\data\suspension;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Represents a chat suspension.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage data.suspension
|
||||
*/
|
||||
class Suspension extends \chat\data\CHATDatabaseObject {
|
||||
/**
|
||||
* @see \wcf\data\DatabaseObject::$databaseTableName
|
||||
*/
|
||||
protected static $databaseTableName = 'suspension';
|
||||
|
||||
/**
|
||||
* @see \wcf\data\DatabaseObject::$databaseTableIndexName
|
||||
*/
|
||||
protected static $databaseTableIndexName = 'suspensionID';
|
||||
|
||||
const TYPE_MUTE = 'mute';
|
||||
const TYPE_BAN = 'ban';
|
||||
|
||||
/**
|
||||
* Returns whether the suspension still is valid.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isValid() {
|
||||
return $this->expires > TIME_NOW;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given user may view this suspension.
|
||||
*
|
||||
* @param \wcf\data\user\User $user
|
||||
* @return boolean
|
||||
*/
|
||||
public function isVisible($user = null) {
|
||||
if ($user === null) $user = WCF::getUser();
|
||||
$user = new \wcf\data\user\UserProfile($user);
|
||||
$ph = new \chat\system\permission\PermissionHandler($user->getDecoratedObject());
|
||||
|
||||
if ($user->getPermission('admin.chat.canManageSuspensions')) return true;
|
||||
if ($user->getPermission('mod.chat.canG'.$this->type)) return true;
|
||||
if (!$this->roomID) return false;
|
||||
if ($ph->getPermission($this->getRoom(), 'mod.can'.ucfirst($this->type))) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the room of this suspension.
|
||||
*
|
||||
* @return \chat\data\room\Room
|
||||
*/
|
||||
public function getRoom() {
|
||||
if (!$this->roomID) return new \chat\data\room\Room(null, array('roomID' => null));
|
||||
|
||||
return \chat\data\room\RoomCache::getInstance()->getRoom($this->roomID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the suspensions for the specified user (current user if no user was specified).
|
||||
*
|
||||
* @param \wcf\data\user\User $user
|
||||
* @return array
|
||||
*/
|
||||
public static function getSuspensionsForUser(\wcf\data\user\User $user = null) {
|
||||
if ($user === null) $user = WCF::getUser();
|
||||
$ush = \wcf\system\user\storage\UserStorageHandler::getInstance();
|
||||
|
||||
// load storage
|
||||
$ush->loadStorage(array($user->userID));
|
||||
$data = $ush->getStorage(array($user->userID), 'chatSuspensions');
|
||||
|
||||
try {
|
||||
$suspensions = unserialize($data[$user->userID]);
|
||||
if ($suspensions === false) throw new \wcf\system\exception\SystemException();
|
||||
}
|
||||
catch (\wcf\system\exception\SystemException $e) {
|
||||
$condition = new \wcf\system\database\util\PreparedStatementConditionBuilder();
|
||||
$condition->add('userID = ?', array($user->userID));
|
||||
$condition->add('expires > ?', array(TIME_NOW));
|
||||
|
||||
$sql = "SELECT
|
||||
*
|
||||
FROM
|
||||
chat".WCF_N."_suspension
|
||||
".$condition;
|
||||
$stmt = WCF::getDB()->prepareStatement($sql);
|
||||
$stmt->execute($condition->getParameters());
|
||||
|
||||
$suspensions = array();
|
||||
while ($suspension = $stmt->fetchObject('\chat\data\suspension\Suspension')) {
|
||||
$suspensions[$suspension->roomID][$suspension->type] = $suspension;
|
||||
}
|
||||
|
||||
$ush->update($user->userID, 'chatSuspensions', serialize($suspensions));
|
||||
}
|
||||
|
||||
return $suspensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the appropriate suspension for user, room and type.
|
||||
* Returns false if no active suspension was found.
|
||||
*
|
||||
* @param \wcf\data\user\User $user
|
||||
* @param \chat\data\room\Room $room
|
||||
* @param integer $type
|
||||
* @return \chat\data\suspension\Suspension
|
||||
*/
|
||||
public static function getSuspensionByUserRoomAndType(\wcf\data\user\User $user, \chat\data\room\Room $room, $type) {
|
||||
$condition = new \wcf\system\database\util\PreparedStatementConditionBuilder();
|
||||
$condition->add('userID = ?', array($user->userID));
|
||||
$condition->add('type = ?', array($type));
|
||||
$condition->add('expires > ?', array(TIME_NOW));
|
||||
if ($room->roomID) $condition->add('roomID = ?', array($room->roomID));
|
||||
else $condition->add('roomID IS NULL');
|
||||
|
||||
$sql = "SELECT
|
||||
*
|
||||
FROM
|
||||
chat".WCF_N."_suspension
|
||||
".$condition;
|
||||
|
||||
$statement = WCF::getDB()->prepareStatement($sql);
|
||||
$statement->execute($condition->getParameters());
|
||||
$row = $statement->fetchArray();
|
||||
if (!$row) return false;
|
||||
|
||||
return new self(null, $row);
|
||||
}
|
||||
}
|
51
file/lib/data/suspension/SuspensionAction.class.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
namespace chat\data\suspension;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Executes chat-suspension-related actions.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage data.suspension
|
||||
*/
|
||||
class SuspensionAction extends \wcf\data\AbstractDatabaseObjectAction {
|
||||
/**
|
||||
* @see \wcf\data\AbstractDatabaseObjectAction::$className
|
||||
*/
|
||||
protected $className = '\chat\data\suspension\SuspensionEditor';
|
||||
|
||||
/**
|
||||
* @see \wcf\data\AbstractDatabaseObjectAction::$requireACP
|
||||
*/
|
||||
protected $requireACP = array('revoke');
|
||||
|
||||
/**
|
||||
* Validates permissions and parameters
|
||||
*/
|
||||
public function validateRevoke() {
|
||||
WCF::getSession()->checkPermissions((array) 'admin.chat.canManageSuspensions');
|
||||
|
||||
$this->parameters['revoker'] = WCF::getUser()->userID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Revokes suspensions.
|
||||
*/
|
||||
public function revoke() {
|
||||
// TODO: ignore revokes if suspension already is revoked
|
||||
if (!isset($this->parameters['revoker'])) {
|
||||
$this->parameters['revoker'] = null;
|
||||
}
|
||||
|
||||
$objectAction = new self($this->objectIDs, 'update', array(
|
||||
'data' => array(
|
||||
'expires' => TIME_NOW,
|
||||
'revoker' => $this->parameters['revoker']
|
||||
)
|
||||
));
|
||||
$objectAction->executeAction();
|
||||
}
|
||||
}
|
28
file/lib/data/suspension/SuspensionEditor.class.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
namespace chat\data\suspension;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Provides functions to edit chat suspensions.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage data.chat.suspension
|
||||
*/
|
||||
class SuspensionEditor extends \wcf\data\DatabaseObjectEditor implements \wcf\data\IEditableCachedObject {
|
||||
/**
|
||||
* @see \wcf\data\DatabaseObjectDecorator::$baseClass
|
||||
*/
|
||||
protected static $baseClass = '\chat\data\suspension\Suspension';
|
||||
|
||||
/**
|
||||
* Clears the suspension cache.
|
||||
*/
|
||||
public static function resetCache() {
|
||||
$ush = \wcf\system\user\storage\UserStorageHandler::getInstance();
|
||||
|
||||
$ush->resetAll('chatSuspensions');
|
||||
}
|
||||
}
|
18
file/lib/data/suspension/SuspensionList.class.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
namespace chat\data\suspension;
|
||||
|
||||
/**
|
||||
* Represents a list of chat suspensions.
|
||||
*
|
||||
* @author Maximilian Mader
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage data.suspension
|
||||
*/
|
||||
class SuspensionList extends \wcf\data\DatabaseObjectList {
|
||||
/**
|
||||
* @see wcf\data\DatabaseObjectList::$className
|
||||
*/
|
||||
public $className = 'chat\data\suspension\Suspension';
|
||||
}
|
128
file/lib/data/user/UserAction.class.php
Normal file
@ -0,0 +1,128 @@
|
||||
<?php
|
||||
namespace chat\data\user;
|
||||
use wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* User related chat actions.
|
||||
*
|
||||
* @author Maximilian Mader
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage data.user
|
||||
*/
|
||||
class UserAction extends \wcf\data\AbstractDatabaseObjectAction {
|
||||
/**
|
||||
* @see \wcf\data\AbstractDatabaseObjectAction::$className
|
||||
*/
|
||||
protected $className = 'wcf\data\user\UserEditor';
|
||||
|
||||
/**
|
||||
* Validates updating of chat user options
|
||||
*/
|
||||
public function validateUpdateOption() {
|
||||
$this->readString('optionName');
|
||||
$this->readBoolean('optionValue');
|
||||
|
||||
if (!preg_match('~^chat[A-Z]~', $this->parameters['optionName'])) throw new \wcf\system\exception\UserInputException('optionName');
|
||||
|
||||
$this->optionID = \wcf\data\user\User::getUserOptionID($this->parameters['optionName']);
|
||||
|
||||
if (!$this->optionID) throw new \wcf\system\exception\UserInputException('optionName');
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates chat user options
|
||||
*/
|
||||
public function updateOption() {
|
||||
$userAction = new \wcf\data\user\UserAction(array(WCF::getUser()), 'update', array(
|
||||
'options' => array(
|
||||
$this->optionID => $this->parameters['optionValue'] ? 1 : 0
|
||||
)
|
||||
));
|
||||
$userAction->executeAction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates invite preparation.
|
||||
*/
|
||||
public function validatePrepareInvite() {
|
||||
WCF::getSession()->checkPermissions(array('user.chat.canInvite'));
|
||||
|
||||
if (!WCF::getUser()->chatRoomID) throw new \wcf\system\exception\PermissionDeniedException();
|
||||
|
||||
$room = \chat\data\room\RoomCache::getInstance()->getRoom(WCF::getUser()->chatRoomID);
|
||||
|
||||
if ($room === null) throw new \wcf\system\exception\IllegalLinkException();
|
||||
if (!$room->canEnter()) throw new \wcf\system\exception\PermissionDeniedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares invites.
|
||||
*/
|
||||
public function prepareInvite() {
|
||||
$followingList = new \wcf\data\user\follow\UserFollowingList();
|
||||
$followingList->getConditionBuilder()->add('user_follow.userID = ?', array(WCF::getUser()->userID));
|
||||
$followingList->sqlOrderBy = 'username ASC';
|
||||
$followingList->readObjects();
|
||||
$users = $followingList->getObjects();
|
||||
|
||||
$json = array();
|
||||
foreach ($users as $user) {
|
||||
$json[] = array(
|
||||
'userID' => $user->userID,
|
||||
'username' => $user->username
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'users' => $json
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates invites.
|
||||
*/
|
||||
public function validateInvite() {
|
||||
WCF::getSession()->checkPermissions(array('user.chat.canInvite'));
|
||||
|
||||
if (!WCF::getUser()->chatRoomID) throw new \wcf\system\exception\PermissionDeniedException();
|
||||
|
||||
$this->room = \chat\data\room\RoomCache::getInstance()->getRoom(WCF::getUser()->chatRoomID);
|
||||
|
||||
if ($this->room === null) throw new \wcf\system\exception\IllegalLinkException();
|
||||
if (!$this->room->canEnter()) throw new \wcf\system\exception\PermissionDeniedException();
|
||||
|
||||
if (!isset($this->parameters['recipients'])) throw new \wcf\system\exception\UserInputException("recipients");
|
||||
|
||||
$this->parameters['recipients'] = \wcf\util\ArrayUtil::toIntegerArray($this->parameters['recipients']);
|
||||
|
||||
$ignoredByList = new \wcf\data\user\ignore\UserIgnoreList();
|
||||
$ignoredByList->getConditionBuilder()->add('user_ignore.ignoreUserID = ?', array(WCF::getUser()->userID));
|
||||
$ignoredByList->getConditionBuilder()->add('user_ignore.userID IN (?)', array($this->parameters['recipients']));
|
||||
|
||||
if (!empty($ignoredByList->sqlSelects)) $ignoredByList->sqlSelects .= ',';
|
||||
$ignoredByList->sqlSelects .= "user_ignore.ignoreID";
|
||||
$ignoredByList->sqlSelects .= ", user_table.username";
|
||||
$ignoredByList->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user user_table ON (user_table.userID = user_ignore.userID)";
|
||||
|
||||
$ignoredByList->readObjects();
|
||||
$ignoredByUsers = $ignoredByList->getObjects();
|
||||
|
||||
if (!empty($ignoredByUsers)) {
|
||||
$usernames = array();
|
||||
foreach ($ignoredByUsers as $user) {
|
||||
$usernames[] = $user->username;
|
||||
}
|
||||
|
||||
throw new \wcf\system\exception\UserInputException("recipients", WCF::getLanguage()->getDynamicVariable('chat.error.invite.ignored', array('users' => $ignoredByUsers, 'usernames' => $usernames)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invites users.
|
||||
*/
|
||||
public function invite() {
|
||||
\wcf\system\user\notification\UserNotificationHandler::getInstance()->fireEvent('invited', 'be.bastelstu.chat.room', new \chat\system\user\notification\object\RoomUserNotificationObject($this->room), $this->parameters['recipients'], array('userID' => WCF::getUser()->userID));
|
||||
}
|
||||
}
|
230
file/lib/page/ChatPage.class.php
Normal file
@ -0,0 +1,230 @@
|
||||
<?php
|
||||
namespace chat\page;
|
||||
use \chat\data;
|
||||
use \wcf\system\exception;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Shows the chat-interface
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage page
|
||||
*/
|
||||
class ChatPage extends \wcf\page\AbstractPage {
|
||||
/**
|
||||
* @see wcf\page\AbstractPage::$loginRequired
|
||||
*/
|
||||
public $loginRequired = true;
|
||||
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::$neededModules
|
||||
*/
|
||||
public $neededModules = array('MODULE_CHAT');
|
||||
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::$neededPermissions
|
||||
*/
|
||||
public $neededPermissions = array();
|
||||
|
||||
/**
|
||||
* The current room.
|
||||
*
|
||||
* @var \chat\data\room\Room
|
||||
*/
|
||||
public $room = null;
|
||||
|
||||
/**
|
||||
* The given roomID.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $roomID = 0;
|
||||
|
||||
/**
|
||||
* List of accessible rooms.
|
||||
*
|
||||
* @var \chat\data\room\RoomList
|
||||
*/
|
||||
public $rooms = array();
|
||||
|
||||
/**
|
||||
* List of installed commands.
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
public $commands = array();
|
||||
|
||||
/**
|
||||
* List of smilies in the default category.
|
||||
*
|
||||
* @var array<\wcf\data\smiley\Smiley>
|
||||
* @see \wcf\data\smiley\SmileyCache
|
||||
*/
|
||||
public $defaultSmilies = array();
|
||||
|
||||
/**
|
||||
* List of all smiley categories.
|
||||
*
|
||||
* @var array<\wcf\data\smiley\SmileyCategory>
|
||||
* @see \wcf\data\smiley\SmileyCache
|
||||
*/
|
||||
public $smileyCategories = array();
|
||||
|
||||
/**
|
||||
* attachment handler
|
||||
* @see \wcf\system\attachment\AttachmentHandler
|
||||
*/
|
||||
public $attachmentHandler = null;
|
||||
|
||||
/**
|
||||
* @see wcf\page\AbstractPage::$enableTracking
|
||||
*/
|
||||
public $enableTracking = true;
|
||||
|
||||
/**
|
||||
* @see \wcf\page\IPage::assignVariables()
|
||||
*/
|
||||
public function assignVariables() {
|
||||
parent::assignVariables();
|
||||
|
||||
$reflection = new \ReflectionClass('\chat\data\message\Message');
|
||||
|
||||
WCF::getTPL()->assign(array(
|
||||
'room' => $this->room,
|
||||
'roomID' => $this->roomID,
|
||||
'rooms' => $this->rooms,
|
||||
'commands' => $this->commands,
|
||||
'messageTypes' => $reflection->getConstants(),
|
||||
'defaultSmilies' => $this->defaultSmilies,
|
||||
'smileyCategories' => $this->smileyCategories,
|
||||
'attachmentHandler' => $this->attachmentHandler,
|
||||
'sidebarCollapsed' => \wcf\system\user\collapsible\content\UserCollapsibleContentHandler::getInstance()->isCollapsed('com.woltlab.wcf.collapsibleSidebar', 'be.bastelstu.chat.ChatPage'),
|
||||
'sidebarName' => 'be.bastelstu.chat.ChatPage'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \wcf\page\IPage::readData()
|
||||
*/
|
||||
public function readData() {
|
||||
parent::readData();
|
||||
|
||||
$this->readRoom();
|
||||
$this->readCommands();
|
||||
|
||||
// get default smilies
|
||||
if (MODULE_SMILEY) {
|
||||
$this->smileyCategories = \wcf\data\smiley\SmileyCache::getInstance()->getCategories();
|
||||
foreach ($this->smileyCategories as $index => $category) {
|
||||
$category->loadSmilies();
|
||||
|
||||
// remove empty categories
|
||||
if (!count($category) || $category->isDisabled) {
|
||||
unset($this->smileyCategories[$index]);
|
||||
}
|
||||
}
|
||||
|
||||
$firstCategory = reset($this->smileyCategories);
|
||||
if ($firstCategory) {
|
||||
$this->defaultSmilies = \wcf\data\smiley\SmileyCache::getInstance()->getCategorySmilies($firstCategory->categoryID ?: null);
|
||||
}
|
||||
}
|
||||
|
||||
if (MODULE_ATTACHMENT) {
|
||||
$this->attachmentHandler = new \wcf\system\attachment\AttachmentHandler('be.bastelstu.chat.message', 0, \wcf\util\StringUtil::getRandomID(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \wcf\page\IPage::readParameters()
|
||||
*/
|
||||
public function readParameters() {
|
||||
parent::readParameters();
|
||||
|
||||
if (isset($_REQUEST['id'])) $this->roomID = (int) $_REQUEST['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads installed commands.
|
||||
*/
|
||||
public function readCommands() {
|
||||
$regex = new \wcf\system\Regex('Command.class.php$');
|
||||
$directory = \wcf\util\DirectoryUtil::getInstance(CHAT_DIR.'lib/system/command/commands/', false);
|
||||
$files = $directory->getFiles(SORT_ASC, $regex);
|
||||
|
||||
foreach ($files as $file) {
|
||||
$command = $regex->replace(basename($file), '');
|
||||
if ($command == 'Plain') continue;
|
||||
$this->commands[] = mb_strtolower($command);
|
||||
}
|
||||
|
||||
$this->commands = array_merge($this->commands, array_keys(\chat\system\command\CommandHandler::getAliasMap()));
|
||||
sort($this->commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads room data.
|
||||
*/
|
||||
public function readRoom() {
|
||||
$this->rooms = data\room\RoomCache::getInstance()->getRooms();
|
||||
|
||||
if ($this->roomID === 0) {
|
||||
// no room given
|
||||
if (CHAT_FORCE_ROOM_SELECT) {
|
||||
$this->rooms = array_filter($this->rooms, function ($room) {
|
||||
return $room->canEnter();
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
else {
|
||||
$room = reset($this->rooms);
|
||||
if ($room === null) {
|
||||
// no valid room found
|
||||
throw new exception\IllegalLinkException();
|
||||
}
|
||||
// redirect to first chat-room
|
||||
\wcf\util\HeaderUtil::redirect(\wcf\system\request\LinkHandler::getInstance()->getLink('Chat', array(
|
||||
'application' => 'chat',
|
||||
'object' => $room
|
||||
)));
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($this->rooms[$this->roomID])) throw new exception\IllegalLinkException();
|
||||
$this->room = $this->rooms[$this->roomID];
|
||||
if (!$this->room->canEnter()) throw new exception\PermissionDeniedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \wcf\page\IPage::show()
|
||||
*/
|
||||
public function show() {
|
||||
\wcf\system\menu\page\PageMenu::getInstance()->setActiveMenuItem('chat.header.menu.chat');
|
||||
|
||||
// remove index breadcrumb
|
||||
WCF::getBreadcrumbs()->remove(0);
|
||||
|
||||
parent::show();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see wcf\page\ITrackablePage::getObjectType()
|
||||
*/
|
||||
public function getObjectType() {
|
||||
return 'be.bastelstu.chat.room';
|
||||
}
|
||||
|
||||
/**
|
||||
* @see wcf\page\ITrackablePage::getObjectID()
|
||||
*/
|
||||
public function getObjectID() {
|
||||
if ($this->room === null) return 0;
|
||||
|
||||
return $this->room->roomID;
|
||||
}
|
||||
}
|
91
file/lib/page/CopyrightPage.class.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
namespace chat\page;
|
||||
|
||||
/**
|
||||
* Shows information about Tims chat.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage page
|
||||
*/
|
||||
class CopyrightPage extends \wcf\page\AbstractPage {
|
||||
/**
|
||||
* @see wcf\page\AbstractPage::$loginRequired
|
||||
*/
|
||||
public $loginRequired = true;
|
||||
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::$neededModules
|
||||
*/
|
||||
public $neededModules = array('MODULE_CHAT');
|
||||
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::$neededPermissions
|
||||
*/
|
||||
public $neededPermissions = array();
|
||||
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::$templateName
|
||||
*/
|
||||
public $templateName = '__copyright';
|
||||
|
||||
/**
|
||||
* @see \wcf\page\IPage::assignVariables()
|
||||
*/
|
||||
public function assignVariables() {
|
||||
parent::assignVariables();
|
||||
|
||||
$images = explode("\n\n", file_get_contents(__FILE__, null, null, __COMPILER_HALT_OFFSET__ + 2));
|
||||
|
||||
\wcf\system\WCF::getTPL()->assign(array(
|
||||
'background' => str_replace("\n", '', $images[array_rand($images)])
|
||||
));
|
||||
}
|
||||
}
|
||||
// @codingStandardsIgnoreStart
|
||||
__halt_compiler();/*iVBORw0KGgoAAAANSUhEUgAAAJAAAACQCAYAAADnRuK4AAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A
|
||||
/wD/oL2nkwAAAAlwSFlzAAAOwgAADsIBFShKgAAAAAd0SU1FB9wBEhQiMYMbjeYAAARlSURBVHja
|
||||
7d2/i5RHHMfxfS6b+AO54qocYrBQPAMxXSBF2hRiYWEl6QzBSmyMleBhFUNyxBQGNRDwR6O1iK1d
|
||||
bNRAPNAiEJazSXMY7gy661+Qm4EdZ+eZeX3q4WaeZ97P+zs7O7dPN+hnFgd1Zq1vA54biABIACQA
|
||||
EgCJAEgAJACSFtJl7i/JBuBkMkkymJ3LV4uajI3z36T6U9k2JId9pH48Hnv0C0kvAUplIGEgARAD
|
||||
AQhAAFLChIEEQAzULkDBTcL19fWiDNRt31GlWbuui9mwXSsNIKWnQbMO3SAAMRCAGEgAxEAAAhCA
|
||||
lDAAMVCb6eP9iT2RGNyYGo1GRV3Y7guXw432HSpqzB88ehBs8+LScpK+FhYWYpoFNxuH1T49hcER
|
||||
k/f2fdK7MpcMIOubNtdJ9RoIQAASJUwAxEAAYiAAMdA7yPMnZY3nw496d597CdCBlevhRhH7QJPL
|
||||
F4qajO6H2+FrP/djsM3T5dNK2LRw1GrN0jYbmy5hta7beglQHyej1k+ODAQgAAEIQEoYgBioRYBy
|
||||
Xle9BorYJJxMjvRuzDGbjTnnohtEnDbccf5KeDL+fhZss/n+tjSjjtgHennycJV22fXL3WCb7U8f
|
||||
hiF7tRls89+Nn/MZaG5/xObecFu2G93yl7sxc9FtbpRVwqxv2gyABEAAAhCAAAQgAAFIZgXQ+FnE
|
||||
JljMPlCisz6O2PYMoI1rF5P8nZhTeQxUo4EKe+IB1DOASpswADEQgBgIQAACkLRYwnyMZyAGqgWg
|
||||
N8//yPfEx5zKi/mvUwBNPacxiTqRmOolKakyf+VesM1fxz6rcuL33vk92Gbn61fBNv+e/SoMRxf+
|
||||
Cc0oAzkwX19SVYxhzs4AVN/9YSAGYiAAMVCxTxiAGEhmXcKsgRgIQC3ZJeJ06Hh8tN0SFrNRdvCn
|
||||
m8E2f546XtR1fXzpVvja9x4Itnmxco6BpoYs4kaXdl0xYy5tvqpdRLdc5or7fSA32oMBIA+GEgYg
|
||||
BgIQAwHIdTGQ68oJ0KHvrgbbPP726yQD+vTitWCbbs/+JH19vvJbURMf8x6MXpawmAlLNehUcOSc
|
||||
MAZSDiyiZw2Q8zcMxEAAYiDxrgxRwoSBZjTo4RdfImCLvH5wv6iHOevLVmKy+ev3KMkwF4/OnAi2
|
||||
WVpaymegnBuAMv1cZD3SKhbaAJJ3s2Z1KxkIQMJAwkACoP9pZHOvmKSai/H4nzRbBpHtFvv2ZMT8
|
||||
vl+tfSXMWu9KWM7vcWrtK6sRa63NLffVNEAMBCBWYCAAAUgJU8IYSF8AYgUGGkRsKA0SvbSFgaa/
|
||||
h/Pz86nmtCwDtfxOMSWsQo0rYQzEQAzEQABiIAZiIAZiIAYCEIAAVITGR6NRtvHk7IuBBEAWksJA
|
||||
AiBRwgRADAQgBhIGklmky9xf8NTi6uqqWdkiMb9bOEh02rA4A7GUEgYgKRsgC20AMRCAGEgYSAAk
|
||||
AFLCqk5X4JgWTcuWWStpMHPmQwAkABIACYBEACQAEgBJE3kLMDdR/zhAlCMAAAAASUVORK5CYII=
|
||||
|
||||
iVBORw0KGgoAAAANSUhEUgAAAJYAAACWCAYAAAFLBkF0AAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A
|
||||
/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oMEgkcFcTqZcUAAAQDSURBVHja
|
||||
7d3ddas6GIRh4uUm6MP9V5A+1Ma+OTkr8cKWkIT197x3sWMQw2j4JAu8bb3yFXl/f/o75Gxs37Zt
|
||||
+/7+/vPi4/F4u9Gjje3PG3nm1UbvCR/4w7sdfR216vF4vPzQ7/f+2+H/rbvFDuenha9a+ptbTWvc
|
||||
3735+1BjJ+Vly350e6fXaWs8b/Dg9ZB1mCXdaY98Llx+Nm+Jew8pHf1jLcNKsR2SI6g0tvff8ROL
|
||||
7aPW3RIO50989xXbqbnWTWyHrMNcI7ZDakcX232n9plET7LiFQ3bz3S0g5gItRu25/T4SEPDsO6/
|
||||
Fx55lFyloxn7fCU4u6Ojz8WqlSzFjpQ7uoyVejK7YUc7Lm1MVsPOntLcU18cF7FOEPn/heLiCj9V
|
||||
vSRlcOqSdMvcQch8bfyCTKUIzDwAKRp83EZWaj9zXXxRZYSplaoyPEut5btWqstGXTpezD3tQxl9
|
||||
rzH+i4wlwxpGP5owT51EFwldjglrjRPHVepoPiqlSlgiPKNVwruuH/l/VUKfkTC1UtkDhwzGHjhM
|
||||
Y/TwdErDwWkOJafd6dOoJRoFANlVVU1KKrTQUizRTqwxumG0i5UMHxMnDQNnTeCsvZZralH6XR9n
|
||||
NRzRX5EzWXzayZxFrPYBH11UcdTlruwqqfsrXe7OWT0GfEU3NC9NOKtnZ6W6o4cCl7OINWA3TAnq
|
||||
mrMOKnizDnXGigXbN+ugdHA1VDoI+JqB3whfWKwS8CHBfSHRpaGlkzmLWMQiFrGIBQAAgBOMtA4+
|
||||
tBZLUUosYhFr5YC/7A6LE99k+8JCNySWzErKp07v3QmcpRsSi1grculahytvn2txQeEsYhGLWDNW
|
||||
8EnV+qfvgEi5za7munjOIhax5i5Ka+ZMDzManEUsYhFLwBfOFPR6mx1nEYtYxFo24K+sxHuo6jmL
|
||||
WMRqzsfXOuR+PZaaT9Y66IbEIhYuKEprBjVn6YbEArHaVfBJVX0D3GGhGxKLWPhABV/ziWup2+Is
|
||||
3ZBYxAKxiEUsYhGLWCAWsQAAAAAAQGu+FjjGFkugwurGMpUFxgJjgbGAtYr3KkV3i5vPKj/wd8iB
|
||||
gMQCY4GxwFjAPMX7ZT+5NhuJA4HuCnyJBcYCY4GxgPrcR2781T9pdyWzD04kFhgLjIXFafIkxFrP
|
||||
PB+5TkmtDys+H/6jk6gSC4wFxgJjAfW5z36ADYpkKzMkFhgLjAVMX2PVrHfUThILjAXGAhgLivfM
|
||||
QrnXFRCzr8yQWGAsMBbAWGjD9M9uaHGLWM3C3LMbAMYCY4GxgB8sm4HEAmOBsYD6TP/LFBPglykA
|
||||
xgJjgbGAbdvGnyBNKWz3wbclsQDGAmOBsQDGAmOBsQDGAmOBscBYJABjgbEAAAAAAAPwD1TbcSbk
|
||||
TnGiAAAAAElFTkSuQmCC
|
169
file/lib/page/NewMessagesPage.class.php
Normal file
@ -0,0 +1,169 @@
|
||||
<?php
|
||||
namespace chat\page;
|
||||
use \chat\data;
|
||||
use \wcf\system\exception\IllegalLinkException;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Loads new messages.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage page
|
||||
*/
|
||||
class NewMessagesPage extends \wcf\page\AbstractPage {
|
||||
/**
|
||||
* @see wcf\page\AbstractPage::$loginRequired
|
||||
*/
|
||||
public $loginRequired = true;
|
||||
|
||||
/**
|
||||
* The new and unseen messages.
|
||||
*
|
||||
* @var array<\wcf\data\chat\message\ChatMessage>
|
||||
*/
|
||||
public $messages = array();
|
||||
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::$neededModules
|
||||
*/
|
||||
public $neededModules = array('MODULE_CHAT');
|
||||
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::$neededPermissions
|
||||
*/
|
||||
public $neededPermissions = array();
|
||||
|
||||
/**
|
||||
* The room the user joined.
|
||||
*
|
||||
* @var \chat\data\room\Room
|
||||
*/
|
||||
public $room = null;
|
||||
|
||||
/**
|
||||
* All the users that are currently in the room $this->room.
|
||||
*
|
||||
* @var array<\wcf\data\user\UserProfile>
|
||||
*/
|
||||
public $users = array();
|
||||
|
||||
/**
|
||||
* @see \wcf\page\AbstractPage::$useTemplate
|
||||
*/
|
||||
public $useTemplate = false;
|
||||
|
||||
/**
|
||||
* @see \wcf\page\Page::readData()
|
||||
*/
|
||||
public function readData() {
|
||||
parent::readData();
|
||||
|
||||
$this->readRoom();
|
||||
$this->readMessages();
|
||||
$this->users = $this->room->getUsers();
|
||||
|
||||
$roomAction = new data\room\RoomAction(array(), 'removeDeadUsers');
|
||||
$roomAction->executeAction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the new messages
|
||||
*/
|
||||
public function readMessages() {
|
||||
$this->messages = data\message\ViewableMessageList::getMessagesSince($this->room, WCF::getUser()->chatLastSeen);
|
||||
|
||||
// update last seen message
|
||||
$sql = "SELECT
|
||||
MAX(messageID)
|
||||
FROM
|
||||
chat".WCF_N."_message";
|
||||
$stmt = WCF::getDB()->prepareStatement($sql);
|
||||
$stmt->execute();
|
||||
|
||||
$editor = new \wcf\data\user\UserEditor(WCF::getUser());
|
||||
$editor->update(array(
|
||||
'chatLastSeen' => $stmt->fetchColumn(),
|
||||
'chatLastActivity' => TIME_NOW
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the room databaseobject.
|
||||
*/
|
||||
public function readRoom() {
|
||||
if (\wcf\system\WCF::getSession()->getPermission('admin.chat.isInAllRooms')) {
|
||||
$this->room = new \chat\data\room\Room(null, array('roomID' => \chat\data\room\Room::GLOBAL_ROOM));
|
||||
}
|
||||
else {
|
||||
$this->room = \chat\data\room\RoomCache::getInstance()->getRoom(WCF::getUser()->chatRoomID);
|
||||
}
|
||||
|
||||
if (!$this->room) throw new IllegalLinkException();
|
||||
if (!$this->room->canEnter()) throw new \wcf\system\exception\PermissionDeniedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \wcf\page\IPage::show()
|
||||
*/
|
||||
public function show() {
|
||||
parent::show();
|
||||
|
||||
@header('Content-type: application/json');
|
||||
\wcf\util\HeaderUtil::sendNoCacheHeaders();
|
||||
|
||||
$json = array('users' => array(), 'messages' => array());
|
||||
|
||||
foreach ($this->messages as $message) {
|
||||
$json['messages'][] = $message->jsonify(true);
|
||||
}
|
||||
|
||||
\wcf\system\user\storage\UserStorageHandler::getInstance()->loadStorage(array_keys($this->users));
|
||||
|
||||
foreach ($this->users as $user) {
|
||||
$json['users'][] = array(
|
||||
'userID' => (int) $user->userID,
|
||||
'username' => $user->username,
|
||||
'roomID' => (int) $user->chatRoomID,
|
||||
'awayStatus' => $user->chatAway,
|
||||
'suspended' => (boolean) !$this->room->canWrite($user->getDecoratedObject()),
|
||||
'mod' => $this->room->canBan($user->getDecoratedObject()) || $this->room->canMute($user->getDecoratedObject()),
|
||||
'avatar' => array(
|
||||
16 => $user->getAvatar()->getImageTag(16),
|
||||
24 => $user->getAvatar()->getImageTag(24),
|
||||
32 => $user->getAvatar()->getImageTag(32),
|
||||
48 => $user->getAvatar()->getImageTag(48)
|
||||
),
|
||||
'link' => \wcf\system\request\LinkHandler::getInstance()->getLink('User', array(
|
||||
'object' => $user->getDecoratedObject()
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
if (ENABLE_BENCHMARK) {
|
||||
$b = \wcf\system\benchmark\Benchmark::getInstance();
|
||||
$items = array();
|
||||
if (ENABLE_DEBUG_MODE) {
|
||||
foreach ($b->getItems() as $item) {
|
||||
$items[] = array(
|
||||
'text' => $item['text'],
|
||||
'use' => $item['use'],
|
||||
'trace' => $item['trace']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$json['benchmark'] = array(
|
||||
'time' => $b->getExecutionTime(),
|
||||
'queryTime' => $b->getQueryExecutionTime(),
|
||||
'queryPercent' => $b->getQueryExecutionTime() / $b->getExecutionTime(),
|
||||
'items' => $items
|
||||
);
|
||||
}
|
||||
|
||||
echo \wcf\util\JSON::encode($json);
|
||||
exit;
|
||||
}
|
||||
}
|
23
file/lib/system/CHATCore.class.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
namespace chat\system;
|
||||
|
||||
/**
|
||||
* Chat core
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system
|
||||
*/
|
||||
class CHATCore extends \wcf\system\application\AbstractApplication {
|
||||
/**
|
||||
* @see wcf\system\application\AbstractApplication::$abbreviation
|
||||
*/
|
||||
protected $abbreviation = 'chat';
|
||||
|
||||
/**
|
||||
* @see wcf\system\application\AbstractApplication::$primaryController
|
||||
*/
|
||||
protected $primaryController = 'chat\\page\\Chat';
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
namespace chat\system\attachment;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Attachment object type implementation for chat messages.
|
||||
*
|
||||
* @author Maximilian Mader
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.attachment
|
||||
*/
|
||||
class MessageAttachmentObjectType extends \wcf\system\attachment\AbstractAttachmentObjectType {
|
||||
/**
|
||||
* @see wcf\system\attachment\IAttachmentObjectType::getMaxSize()
|
||||
*/
|
||||
public function getMaxSize() {
|
||||
return WCF::getSession()->getPermission('user.chat.maxAttachmentSize');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see wcf\system\attachment\IAttachmentObjectType::getAllowedExtensions()
|
||||
*/
|
||||
public function getAllowedExtensions() {
|
||||
return \wcf\util\ArrayUtil::trim(explode("\n", WCF::getSession()->getPermission('user.chat.allowedAttachmentExtensions')));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see wcf\system\attachment\IAttachmentObjectType::getMaxCount()
|
||||
*/
|
||||
public function getMaxCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see wcf\system\attachment\IAttachmentObjectType::canDownload()
|
||||
*/
|
||||
public function canDownload($objectID) {
|
||||
if ($objectID) {
|
||||
$message = new \chat\data\message\Message($objectID);
|
||||
if (isset($message->roomID) && $message->roomID) {
|
||||
$room = \chat\data\room\RoomCache::getInstance()->getRoom($message->roomID);
|
||||
if ($room && $room->canEnter()) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see wcf\system\attachment\IAttachmentObjectType::canUpload()
|
||||
*/
|
||||
public function canUpload($objectID, $parentObjectID = 0) {
|
||||
if ($objectID) {
|
||||
$room = \chat\data\room\RoomCache::getInstance()->getRoom($parentObjectID);
|
||||
if (!$room || !$room->canWrite()) return false;
|
||||
}
|
||||
|
||||
return WCF::getSession()->getPermission('user.chat.canUploadAttachment');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see wcf\system\attachment\IAttachmentObjectType::canDelete()
|
||||
*/
|
||||
public function canDelete($objectID) {
|
||||
return false;
|
||||
}
|
||||
}
|
41
file/lib/system/cache/builder/PermissionCacheBuilder.class.php
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
namespace chat\system\cache\builder;
|
||||
use wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Caches the chat permissions for a combination of user groups.
|
||||
*
|
||||
* @author Tim Düsterhus, Marcel Werk
|
||||
* @copyright 2010-2014 WoltLab GmbH
|
||||
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.cache.builder
|
||||
*/
|
||||
class PermissionCacheBuilder extends \wcf\system\cache\builder\AbstractCacheBuilder {
|
||||
/**
|
||||
* @see wcf\system\cache\AbstractCacheBuilder::rebuild()
|
||||
*/
|
||||
public function rebuild(array $parameters) {
|
||||
$data = array();
|
||||
|
||||
if (!empty($parameters)) {
|
||||
$conditionBuilder = new \wcf\system\database\util\PreparedStatementConditionBuilder();
|
||||
$conditionBuilder->add('acl_option.objectTypeID = ?', array(\wcf\system\acl\ACLHandler::getInstance()->getObjectTypeID('be.bastelstu.chat.room')));
|
||||
$conditionBuilder->add('option_to_group.optionID = acl_option.optionID');
|
||||
$conditionBuilder->add('option_to_group.groupID IN (?)', array($parameters));
|
||||
$sql = "SELECT option_to_group.groupID, option_to_group.objectID AS roomID, option_to_group.optionValue,
|
||||
acl_option.optionName AS permission
|
||||
FROM wcf".WCF_N."_acl_option acl_option,
|
||||
wcf".WCF_N."_acl_option_to_group option_to_group
|
||||
".$conditionBuilder;
|
||||
$stmt = WCF::getDB()->prepareStatement($sql);
|
||||
$stmt->execute($conditionBuilder->getParameters());
|
||||
while ($row = $stmt->fetchArray()) {
|
||||
if (!isset($data[$row['roomID']][$row['permission']])) $data[$row['roomID']][$row['permission']] = $row['optionValue'];
|
||||
else $data[$row['roomID']][$row['permission']] = $row['optionValue'] || $data[$row['roomID']][$row['permission']];
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
25
file/lib/system/cache/builder/RoomCacheBuilder.class.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
namespace chat\system\cache\builder;
|
||||
|
||||
/**
|
||||
* Caches all chat rooms.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.cache.builder
|
||||
*/
|
||||
class RoomCacheBuilder extends \wcf\system\cache\builder\AbstractCacheBuilder {
|
||||
/**
|
||||
* @see \wcf\system\cache\AbstractCacheBuilder::rebuild()
|
||||
*/
|
||||
public function rebuild(array $parameters) {
|
||||
// get all chat rooms
|
||||
$roomList = new \chat\data\room\RoomList();
|
||||
$roomList->sqlOrderBy = "room.showOrder";
|
||||
$roomList->readObjects();
|
||||
|
||||
return $roomList->getObjects();
|
||||
}
|
||||
}
|
69
file/lib/system/command/AbstractCommand.class.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
namespace chat\system\command;
|
||||
use \wcf\system\event\EventHandler;
|
||||
|
||||
/**
|
||||
* Default implementation for commands.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command
|
||||
*/
|
||||
abstract class AbstractCommand implements ICommand {
|
||||
/**
|
||||
* Instance of the CommandHandler
|
||||
*
|
||||
* @var \chat\system\command\CommandHandler
|
||||
*/
|
||||
public $commandHandler = null;
|
||||
|
||||
/**
|
||||
* Should HTML be enabled?
|
||||
*
|
||||
* @var integer
|
||||
* @see \chat\system\command\ICommand::SETTING_OFF
|
||||
* @see \chat\system\command\ICommand::SETTING_ON
|
||||
*/
|
||||
public $enableHTML = ICommand::SETTING_OFF;
|
||||
|
||||
/**
|
||||
* Should smilies be enabled?
|
||||
*
|
||||
* @var integer
|
||||
* @see \chat\system\command\ICommand::SETTING_OFF
|
||||
* @see \chat\system\command\ICommand::SETTING_ON
|
||||
* @see \chat\system\command\ICommand::SETTING_USER
|
||||
*/
|
||||
public $enableSmilies = ICommand::SETTING_OFF;
|
||||
|
||||
public function __construct(CommandHandler $commandHandler) {
|
||||
EventHandler::getInstance()->fireAction($this, 'shouldInit');
|
||||
$this->commandHandler = $commandHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires the didInit-event.
|
||||
* You should call this when everything is properly inserted.
|
||||
*/
|
||||
public function didInit() {
|
||||
EventHandler::getInstance()->fireAction($this, 'didInit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Default-Receiver: Everyone
|
||||
*
|
||||
* @see \chat\system\command\ICommand::getReceiver()
|
||||
*/
|
||||
public function getReceiver() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* No additionaldata by default.
|
||||
*/
|
||||
public function getAdditionalData() {
|
||||
return null;
|
||||
}
|
||||
}
|
29
file/lib/system/command/AbstractRestrictedCommand.class.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
namespace chat\system\command;
|
||||
use \wcf\system\event\EventHandler;
|
||||
|
||||
/**
|
||||
* Default implementation for restricted commands
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command
|
||||
*/
|
||||
abstract class AbstractRestrictedCommand extends AbstractCommand implements IRestrictedCommand {
|
||||
public function __construct(CommandHandler $commandHandler) {
|
||||
parent::__construct($commandHandler);
|
||||
|
||||
$this->checkPermission();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires checkPermission event.
|
||||
*
|
||||
* @see \chat\system\command\IRestrictedCommand
|
||||
*/
|
||||
public function checkPermission() {
|
||||
EventHandler::getInstance()->fireAction($this, 'checkPermission');
|
||||
}
|
||||
}
|
126
file/lib/system/command/AbstractSuspensionCommand.class.php
Normal file
@ -0,0 +1,126 @@
|
||||
<?php
|
||||
namespace chat\system\command;
|
||||
use \chat\data\suspension;
|
||||
use \chat\util\ChatUtil;
|
||||
use \wcf\data\user\User;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Default implementation for suspension commands
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command
|
||||
*/
|
||||
abstract class AbstractSuspensionCommand extends AbstractRestrictedCommand {
|
||||
public $user = null;
|
||||
public $expires = 0;
|
||||
public $suspensionAction = null;
|
||||
public $link = '';
|
||||
public $room = null;
|
||||
public $reason = '';
|
||||
|
||||
public function __construct(\chat\system\command\CommandHandler $commandHandler) {
|
||||
parent::__construct($commandHandler);
|
||||
|
||||
try {
|
||||
$parameters = explode(',', $commandHandler->getParameters(), 3);
|
||||
list($username, $modifier) = $parameters;
|
||||
|
||||
if (isset($parameters[2])) {
|
||||
$this->reason = \wcf\util\StringUtil::trim($parameters[2]);
|
||||
}
|
||||
|
||||
$modifier = ChatUtil::timeModifier(\wcf\util\StringUtil::trim($modifier));
|
||||
$expires = strtotime($modifier, TIME_NOW);
|
||||
$this->expires = min(max(-0x80000000, $expires), 0x7FFFFFFF);
|
||||
}
|
||||
catch (\wcf\system\exception\SystemException $e) {
|
||||
throw new \InvalidArgumentException();
|
||||
}
|
||||
|
||||
$this->user = User::getUserByUsername($username);
|
||||
if (!$this->user->userID) throw new \chat\system\command\UserNotFoundException($username);
|
||||
|
||||
$profile = \wcf\system\request\LinkHandler::getInstance()->getLink('User', array(
|
||||
'object' => $this->user
|
||||
));
|
||||
$this->link = "[url='".$profile."']".$this->user->username.'[/url]';
|
||||
|
||||
$this->executeAction();
|
||||
|
||||
$this->didInit();
|
||||
}
|
||||
|
||||
public function executeAction() {
|
||||
if (static::IS_GLOBAL) $room = new \chat\data\room\Room(null, array('roomID' => null));
|
||||
else $room = $this->room;
|
||||
|
||||
if ($suspension = suspension\Suspension::getSuspensionByUserRoomAndType($this->user, $room, static::SUSPENSION_TYPE)) {
|
||||
if ($suspension->expires >= $this->expires) {
|
||||
throw new \wcf\system\exception\UserInputException('text', WCF::getLanguage()->get('chat.suspension.exists'));
|
||||
}
|
||||
|
||||
$action = new suspension\SuspensionAction(array($suspension), 'revoke', array(
|
||||
'revoker' => WCF::getUser()->userID
|
||||
));
|
||||
$action->executeAction();
|
||||
}
|
||||
|
||||
$this->suspensionAction = new suspension\SuspensionAction(array(), 'create', array(
|
||||
'data' => array(
|
||||
'userID' => $this->user->userID,
|
||||
'roomID' => $room->roomID ?: null,
|
||||
'type' => static::SUSPENSION_TYPE,
|
||||
'expires' => $this->expires,
|
||||
'time' => TIME_NOW,
|
||||
'issuer' => WCF::getUser()->userID,
|
||||
'reason' => $this->reason
|
||||
)
|
||||
));
|
||||
$this->suspensionAction->executeAction();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\IRestrictedChatCommand::checkPermission()
|
||||
*/
|
||||
public function checkPermission() {
|
||||
parent::checkPermission();
|
||||
|
||||
$this->room = $this->commandHandler->getRoom();
|
||||
if (WCF::getSession()->getPermission('admin.chat.canManageSuspensions')) return;
|
||||
|
||||
$ph = new \chat\system\permission\PermissionHandler();
|
||||
if (static::IS_GLOBAL) {
|
||||
WCF::getSession()->checkPermissions(array('mod.chat.canG'.static::SUSPENSION_TYPE));
|
||||
}
|
||||
else {
|
||||
if (!WCF::getSession()->getPermission('mod.chat.canG'.static::SUSPENSION_TYPE)) {
|
||||
if (!$ph->getPermission($this->room, 'mod.can'.ucfirst(static::SUSPENSION_TYPE))) {
|
||||
throw new \wcf\system\exception\PermissionDeniedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getType()
|
||||
*/
|
||||
public function getType() {
|
||||
return \chat\data\message\Message::TYPE_MODERATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getMessage()
|
||||
*/
|
||||
public function getMessage() {
|
||||
return serialize(array(
|
||||
'link' => $this->link,
|
||||
'expires' => $this->expires,
|
||||
'type' => (static::IS_GLOBAL ? 'g' : '').static::SUSPENSION_TYPE,
|
||||
'reason' => $this->reason
|
||||
));
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
namespace chat\system\command;
|
||||
use \chat\data\suspension;
|
||||
use \chat\util\ChatUtil;
|
||||
use \wcf\data\user\User;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Default implementation for suspension commands
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command
|
||||
*/
|
||||
abstract class AbstractUnsuspensionCommand extends AbstractRestrictedCommand {
|
||||
public $user = null;
|
||||
public $suspensionAction = null;
|
||||
public $link = '';
|
||||
public $room = null;
|
||||
|
||||
public function __construct(\chat\system\command\CommandHandler $commandHandler) {
|
||||
parent::__construct($commandHandler);
|
||||
|
||||
$username = rtrim($commandHandler->getParameters(), ',');
|
||||
$this->user = User::getUserByUsername($username);
|
||||
if (!$this->user->userID) throw new \chat\system\command\UserNotFoundException($username);
|
||||
|
||||
$profile = \wcf\system\request\LinkHandler::getInstance()->getLink('User', array(
|
||||
'object' => $this->user
|
||||
));
|
||||
$this->link = "[url='".$profile."']".$this->user->username.'[/url]';
|
||||
|
||||
$this->executeAction();
|
||||
|
||||
$this->didInit();
|
||||
}
|
||||
|
||||
public function executeAction() {
|
||||
if (static::IS_GLOBAL) $room = new \chat\data\room\Room(null, array('roomID' => null));
|
||||
else $room = $this->room;
|
||||
|
||||
if ($suspension = suspension\Suspension::getSuspensionByUserRoomAndType($this->user, $room, static::SUSPENSION_TYPE)) {
|
||||
$action = new suspension\SuspensionAction(array($suspension), 'revoke', array(
|
||||
'revoker' => WCF::getUser()->userID
|
||||
));
|
||||
$action->executeAction();
|
||||
}
|
||||
else {
|
||||
throw new \wcf\system\exception\UserInputException('text', WCF::getLanguage()->get('chat.suspension.notExists'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\IRestrictedChatCommand::checkPermission()
|
||||
*/
|
||||
public function checkPermission() {
|
||||
parent::checkPermission();
|
||||
|
||||
$this->room = $this->commandHandler->getRoom();
|
||||
if (WCF::getSession()->getPermission('admin.chat.canManageSuspensions')) return;
|
||||
|
||||
$ph = new \chat\system\permission\PermissionHandler();
|
||||
if (static::IS_GLOBAL) {
|
||||
WCF::getSession()->checkPermission(array('mod.chat.canG'.static::SUSPENSION_TYPE));
|
||||
}
|
||||
else {
|
||||
if (!WCF::getSession()->getPermission('mod.chat.canG'.static::SUSPENSION_TYPE)) {
|
||||
if (!$ph->getPermission($this->room, 'mod.can'.ucfirst(static::SUSPENSION_TYPE))) {
|
||||
throw new \wcf\system\exception\PermissionDeniedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getType()
|
||||
*/
|
||||
public function getType() {
|
||||
return \chat\data\message\Message::TYPE_MODERATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getMessage()
|
||||
*/
|
||||
public function getMessage() {
|
||||
return serialize(array(
|
||||
'link' => $this->link,
|
||||
'type' => 'un'.(static::IS_GLOBAL ? 'g' : '').static::SUSPENSION_TYPE,
|
||||
));
|
||||
}
|
||||
}
|
126
file/lib/system/command/CommandHandler.class.php
Normal file
@ -0,0 +1,126 @@
|
||||
<?php
|
||||
namespace chat\system\command;
|
||||
use \wcf\util\StringUtil;
|
||||
|
||||
/**
|
||||
* Handles commands
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command
|
||||
*/
|
||||
final class CommandHandler {
|
||||
/**
|
||||
* char that indicates a command
|
||||
* @var string
|
||||
*/
|
||||
const COMMAND_CHAR = '/';
|
||||
|
||||
/**
|
||||
* message text
|
||||
* @var string
|
||||
*/
|
||||
private $text = '';
|
||||
|
||||
/**
|
||||
* current room
|
||||
* @var \chat\data\room\Room
|
||||
*/
|
||||
private $room = null;
|
||||
|
||||
/**
|
||||
* Initialises the CommandHandler
|
||||
*
|
||||
* @param string $text
|
||||
* @param \chat\data\room\Room $room
|
||||
*/
|
||||
public function __construct($text, \chat\data\room\Room $room = null) {
|
||||
$this->text = $text;
|
||||
$this->room = $room;
|
||||
|
||||
$aliases = self::getAliasMap();
|
||||
foreach ($aliases as $search => $replace) {
|
||||
$this->text = \wcf\system\Regex::compile('^'.preg_quote(self::COMMAND_CHAR.$search).'( |$)')->replace($this->text, self::COMMAND_CHAR.$replace.' ');
|
||||
}
|
||||
|
||||
$this->text = \wcf\system\Regex::compile('^//')->replace($this->text, '/plain ');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the alias map. Key is the alias, value is the target.
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
public static function getAliasMap() {
|
||||
if (StringUtil::trim(CHAT_COMMAND_ALIASES) === '') return array();
|
||||
|
||||
try {
|
||||
$result = array();
|
||||
foreach (explode("\n", StringUtil::unifyNewlines(StringUtil::toLowerCase(CHAT_COMMAND_ALIASES))) as $line) {
|
||||
list($key, $val) = explode(':', $line, 2);
|
||||
|
||||
$result[StringUtil::trim($key)] = StringUtil::trim($val);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
catch (\wcf\system\exception\SystemException $e) {
|
||||
throw new \wcf\system\exception\SystemException("Invalid alias specified: '".$line."'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given text is a command.
|
||||
*/
|
||||
public function isCommand($text = null) {
|
||||
if ($text === null) $text = $this->text;
|
||||
|
||||
return StringUtil::startsWith($text, static::COMMAND_CHAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the whole message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getText() {
|
||||
return $this->text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current room.
|
||||
*
|
||||
* @return \chat\data\room\Room
|
||||
*/
|
||||
public function getRoom() {
|
||||
return $this->room;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameter-string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getParameters() {
|
||||
$parts = explode(' ', mb_substr($this->text, mb_strlen(static::COMMAND_CHAR)), 2);
|
||||
|
||||
if (!isset($parts[1])) return '';
|
||||
return $parts[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the command.
|
||||
*/
|
||||
public function loadCommand() {
|
||||
$parts = explode(' ', mb_substr($this->text, mb_strlen(static::COMMAND_CHAR)), 2);
|
||||
|
||||
$class = '\chat\system\command\commands\\'.ucfirst(strtolower($parts[0])).'Command';
|
||||
if (!class_exists($class)) {
|
||||
throw new NotFoundException($parts[0]);
|
||||
}
|
||||
|
||||
return new $class($this);
|
||||
}
|
||||
}
|
54
file/lib/system/command/ICommand.class.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
namespace chat\system\command;
|
||||
|
||||
/**
|
||||
* Interface for chat-commands.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command
|
||||
*/
|
||||
interface ICommand {
|
||||
/**
|
||||
* Setting is forced to be disabled.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const SETTING_OFF = 0;
|
||||
|
||||
/**
|
||||
* Setting is forced to be enabled.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const SETTING_ON = 1;
|
||||
|
||||
/**
|
||||
* The user may decide whether this setting is on or off.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const SETTING_USER = 2;
|
||||
|
||||
/**
|
||||
* Returns the message-type for this command.
|
||||
*/
|
||||
public function getType();
|
||||
|
||||
/**
|
||||
* Returns the message-text for this command.
|
||||
*/
|
||||
public function getMessage();
|
||||
|
||||
/**
|
||||
* Returns additionalData to be saved within database
|
||||
*/
|
||||
public function getAdditionalData();
|
||||
|
||||
/**
|
||||
* Returns the receiver for this command.
|
||||
*/
|
||||
public function getReceiver();
|
||||
}
|
20
file/lib/system/command/IRestrictedCommand.class.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
namespace chat\system\command;
|
||||
|
||||
/**
|
||||
* Interface for Restricted commands.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command
|
||||
*/
|
||||
interface IRestrictedCommand {
|
||||
/**
|
||||
* Checks the permission to use this command. Has to throw
|
||||
* \wcf\system\exception\PermissionDeniedException when the
|
||||
* user is not allowed to use the command.
|
||||
*/
|
||||
public function checkPermission();
|
||||
}
|
32
file/lib/system/command/NotFoundException.class.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
namespace chat\system\command;
|
||||
|
||||
/**
|
||||
* Thrown when a command is not found.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command
|
||||
*/
|
||||
class NotFoundException extends \Exception {
|
||||
/**
|
||||
* given command
|
||||
* @var string
|
||||
*/
|
||||
private $command = '';
|
||||
|
||||
public function __construct($command) {
|
||||
$this->command = $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given command
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCommand() {
|
||||
return $this->command;
|
||||
}
|
||||
}
|
32
file/lib/system/command/UserNotFoundException.class.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
namespace chat\system\command;
|
||||
|
||||
/**
|
||||
* Thrown when a user is not found.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command
|
||||
*/
|
||||
class UserNotFoundException extends \Exception {
|
||||
/**
|
||||
* given username
|
||||
* @var string
|
||||
*/
|
||||
private $username = '';
|
||||
|
||||
public function __construct($username) {
|
||||
$this->username = $username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given username
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUsername() {
|
||||
return $this->username;
|
||||
}
|
||||
}
|
38
file/lib/system/command/commands/AwayCommand.class.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
namespace chat\system\command\commands;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Marks the user as away.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command.commands
|
||||
*/
|
||||
class AwayCommand extends \chat\system\command\AbstractCommand {
|
||||
public function __construct(\chat\system\command\CommandHandler $commandHandler) {
|
||||
parent::__construct($commandHandler);
|
||||
|
||||
$editor = new \wcf\data\user\UserEditor(WCF::getUser());
|
||||
$editor->update(array(
|
||||
'chatAway' => $commandHandler->getParameters()
|
||||
));
|
||||
$this->didInit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getType()
|
||||
*/
|
||||
public function getType() {
|
||||
return \chat\data\message\Message::TYPE_AWAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getMessage()
|
||||
*/
|
||||
public function getMessage() {
|
||||
return \wcf\system\bbcode\PreParser::getInstance()->parse($this->commandHandler->getParameters(), explode(',', WCF::getSession()->getPermission('user.chat.allowedBBCodes')));
|
||||
}
|
||||
}
|
16
file/lib/system/command/commands/BanCommand.class.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace chat\system\command\commands;
|
||||
|
||||
/**
|
||||
* Bans a user.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command.commands
|
||||
*/
|
||||
class BanCommand extends \chat\system\command\AbstractSuspensionCommand {
|
||||
const IS_GLOBAL = false;
|
||||
const SUSPENSION_TYPE = \chat\data\suspension\Suspension::TYPE_BAN;
|
||||
}
|
223
file/lib/system/command/commands/ColorCommand.class.php
Normal file
@ -0,0 +1,223 @@
|
||||
<?php
|
||||
namespace chat\system\command\commands;
|
||||
|
||||
/**
|
||||
* Changes the color of the username
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command.commands
|
||||
*/
|
||||
class ColorCommand extends \chat\system\command\AbstractCommand {
|
||||
/**
|
||||
* Map names to hexcodes
|
||||
*
|
||||
* @var array<integer>
|
||||
*/
|
||||
public static $colors = array(
|
||||
'aliceblue' => 0xF0F8FF,
|
||||
'antiquewhite' => 0xFAEBD7,
|
||||
'aqua' => 0x00FFFF,
|
||||
'aquamarine' => 0x7FFFD4,
|
||||
'azure' => 0xF0FFFF,
|
||||
'beige' => 0xF5F5DC,
|
||||
'bisque' => 0xFFE4C4,
|
||||
'black' => 0x000000,
|
||||
'blanchedalmond' => 0xFFEBCD,
|
||||
'blue' => 0x0000FF,
|
||||
'bluescreenblue' => 0x0000AA,
|
||||
'blueviolet' => 0x8A2BE2,
|
||||
'brown' => 0xA52A2A,
|
||||
'burlywood' => 0xDEB887,
|
||||
'cadetblue' => 0x5F9EA0,
|
||||
'chartreuse' => 0x7FFF00,
|
||||
'chocolate' => 0xD2691E,
|
||||
'coral' => 0xFF7F50,
|
||||
'cornflowerblue' => 0x6495ED,
|
||||
'cornsilk' => 0xFFF8DC,
|
||||
'crimson' => 0xDC143C,
|
||||
'cyan' => 0x00FFFF,
|
||||
'darkblue' => 0x00008B,
|
||||
'darkcyan' => 0x008B8B,
|
||||
'darkgoldenrod' => 0xB8860B,
|
||||
'darkgray' => 0xA9A9A9,
|
||||
'darkgrey' => 0xA9A9A9,
|
||||
'darkgreen' => 0x006400,
|
||||
'darkkhaki' => 0xBDB76B,
|
||||
'darkmagenta' => 0x8B008B,
|
||||
'darkolivegreen' => 0x556B2F,
|
||||
'darkorange' => 0xFF8C00,
|
||||
'darkorchid' => 0x9932CC,
|
||||
'darkred' => 0x8B0000,
|
||||
'darksalmon' => 0xE9967A,
|
||||
'darkseagreen' => 0x8FBC8F,
|
||||
'darkslateblue' => 0x483D8B,
|
||||
'darkslategray' => 0x2F4F4F,
|
||||
'darkslategrey' => 0x2F4F4F,
|
||||
'darkturquoise' => 0x00CED1,
|
||||
'darkviolet' => 0x9400D3,
|
||||
'deeppink' => 0xFF1493,
|
||||
'deepskyblue' => 0x00BFFF,
|
||||
'dimgray' => 0x696969,
|
||||
'dimgrey' => 0x696969,
|
||||
'dodgerblue' => 0x1E90FF,
|
||||
'firebrick' => 0xB22222,
|
||||
'floralwhite' => 0xFFFAF0,
|
||||
'forestgreen' => 0x228B22,
|
||||
'fuchsia' => 0xFF00FF,
|
||||
'gainsboro' => 0xDCDCDC,
|
||||
'ghostwhite' => 0xF8F8FF,
|
||||
'gold' => 0xFFD700,
|
||||
'goldenrod' => 0xDAA520,
|
||||
'gray' => 0x808080,
|
||||
'grey' => 0x808080,
|
||||
'green' => 0x008000,
|
||||
'greenyellow' => 0xADFF2F,
|
||||
'honeydew' => 0xF0FFF0,
|
||||
'hotpink' => 0xFF69B4,
|
||||
'indianred' => 0xCD5C5C,
|
||||
'indigo' => 0x4B0082,
|
||||
'ivory' => 0xFFFFF0,
|
||||
'khaki' => 0xF0E68C,
|
||||
'lavender' => 0xE6E6FA,
|
||||
'lavenderblush' => 0xFFF0F5,
|
||||
'lawngreen' => 0x7CFC00,
|
||||
'lemonchiffon' => 0xFFFACD,
|
||||
'lightblue' => 0xADD8E6,
|
||||
'lightcoral' => 0xF08080,
|
||||
'lightcyan' => 0xE0FFFF,
|
||||
'lightgoldenrodyellow' => 0xFAFAD2,
|
||||
'lightgray' => 0xD3D3D3,
|
||||
'lightgrey' => 0xD3D3D3,
|
||||
'lightgreen' => 0x90EE90,
|
||||
'lightpink' => 0xFFB6C1,
|
||||
'lightsalmon' => 0xFFA07A,
|
||||
'lightseagreen' => 0x20B2AA,
|
||||
'lightskyblue' => 0x87CEFA,
|
||||
'lightslategray' => 0x778899,
|
||||
'lightslategrey' => 0x778899,
|
||||
'lightsteelblue' => 0xB0C4DE,
|
||||
'lightyellow' => 0xFFFFE0,
|
||||
'lime' => 0x00FF00,
|
||||
'limegreen' => 0x32CD32,
|
||||
'linen' => 0xFAF0E6,
|
||||
'magenta' => 0xFF00FF,
|
||||
'maroon' => 0x800000,
|
||||
'mediumaquamarine' => 0x66CDAA,
|
||||
'mediumblue' => 0x0000CD,
|
||||
'mediumorchid' => 0xBA55D3,
|
||||
'mediumpurple' => 0x9370D8,
|
||||
'mediumseagreen' => 0x3CB371,
|
||||
'mediumslateblue' => 0x7B68EE,
|
||||
'mediumspringgreen' => 0x00FA9A,
|
||||
'mediumturquoise' => 0x48D1CC,
|
||||
'mediumvioletred' => 0xC71585,
|
||||
'midnightblue' => 0x191970,
|
||||
'mintcream' => 0xF5FFFA,
|
||||
'mistyrose' => 0xFFE4E1,
|
||||
'moccasin' => 0xFFE4B5,
|
||||
'navajowhite' => 0xFFDEAD,
|
||||
'navy' => 0x000080,
|
||||
'oldlace' => 0xFDF5E6,
|
||||
'olive' => 0x808000,
|
||||
'olivedrab' => 0x6B8E23,
|
||||
'orange' => 0xFFA500,
|
||||
'orangered' => 0xFF4500,
|
||||
'orchid' => 0xDA70D6,
|
||||
'oxford' => 0xF02D, // looks like green
|
||||
'palegoldenrod' => 0xEEE8AA,
|
||||
'palegreen' => 0x98FB98,
|
||||
'paleturquoise' => 0xAFEEEE,
|
||||
'palevioletred' => 0xD87093,
|
||||
'papayawhip' => 0xFFEFD5,
|
||||
'peachpuff' => 0xFFDAB9,
|
||||
'peru' => 0xCD853F,
|
||||
'pink' => 0xFFC0CB,
|
||||
'plum' => 0xDDA0DD,
|
||||
'powderblue' => 0xB0E0E6,
|
||||
'purple' => 0x800080,
|
||||
'red' => 0xFF0000,
|
||||
'rosybrown' => 0xBC8F8F,
|
||||
'royalblue' => 0x4169E1,
|
||||
'saddlebrown' => 0x8B4513,
|
||||
'sadwin' => 0x2067B2,
|
||||
'salmon' => 0xFA8072,
|
||||
'sandybrown' => 0xF4A460,
|
||||
'seagreen' => 0x2E8B57,
|
||||
'seashell' => 0xFFF5EE,
|
||||
'sienna' => 0xA0522D,
|
||||
'silver' => 0xC0C0C0,
|
||||
'skyblue' => 0x87CEEB,
|
||||
'slateblue' => 0x6A5ACD,
|
||||
'slategray' => 0x708090,
|
||||
'slategrey' => 0x708090,
|
||||
'snow' => 0xFFFAFA,
|
||||
'springgreen' => 0x00FF7F,
|
||||
'steelblue' => 0x4682B4,
|
||||
'tan' => 0xD2B48C,
|
||||
'teal' => 0x008080,
|
||||
'thistle' => 0xD8BFD8,
|
||||
'tomato' => 0xFF6347,
|
||||
'turquoise' => 0x40E0D0,
|
||||
'violet' => 0xEE82EE,
|
||||
'wheat' => 0xF5DEB3,
|
||||
'white' => 0xFFFFFF,
|
||||
'whitesmoke' => 0xF5F5F5,
|
||||
'yellow' => 0xFFFF00,
|
||||
'yellowgreen' => 0x9ACD32
|
||||
);
|
||||
|
||||
public function __construct(\chat\system\command\CommandHandler $commandHandler) {
|
||||
parent::__construct($commandHandler);
|
||||
|
||||
try {
|
||||
list($color[1], $color[2]) = explode(' ', $commandHandler->getParameters(), 2);
|
||||
}
|
||||
catch (\wcf\system\exception\SystemException $e) {
|
||||
$color[1] = $color[2] = $commandHandler->getParameters();
|
||||
}
|
||||
|
||||
$regex = new \wcf\system\Regex('^#?([a-f0-9]{3}|[a-f0-9]{6})$', \wcf\system\Regex::CASE_INSENSITIVE);
|
||||
foreach ($color as $key => $val) {
|
||||
if (isset(self::$colors[$val])) $color[$key] = self::$colors[$val];
|
||||
else {
|
||||
if (!$regex->match($val)) throw new \InvalidArgumentException();
|
||||
|
||||
$matches = $regex->getMatches();
|
||||
$val = $matches[1];
|
||||
if (strlen($val) == 3) $val = $val[0].$val[0].$val[1].$val[1].$val[2].$val[2];
|
||||
$color[$key] = hexdec($val);
|
||||
}
|
||||
}
|
||||
|
||||
$editor = new \wcf\data\user\UserEditor(\wcf\system\WCF::getUser());
|
||||
$editor->update(array(
|
||||
'chatColor1' => $color[1],
|
||||
'chatColor2' => $color[2]
|
||||
));
|
||||
$this->didInit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getType()
|
||||
*/
|
||||
public function getType() {
|
||||
return \chat\data\message\Message::TYPE_INFORMATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getMessage()
|
||||
*/
|
||||
public function getMessage() {
|
||||
return \wcf\system\WCF::getLanguage()->get('chat.message.color.success');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getReceiver()
|
||||
*/
|
||||
public function getReceiver() {
|
||||
return \wcf\system\WCF::getUser()->userID;
|
||||
}
|
||||
}
|
30
file/lib/system/command/commands/FreeCommand.class.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
namespace chat\system\command\commands;
|
||||
|
||||
/**
|
||||
* Informs everyone that the fish was freed. OH A NOEZ.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command.commands
|
||||
*/
|
||||
class FreeCommand extends MeCommand {
|
||||
public function __construct(\chat\system\command\CommandHandler $commandHandler) {
|
||||
parent::__construct($commandHandler);
|
||||
|
||||
if (mb_strtolower($this->commandHandler->getParameters()) != 'the fish') {
|
||||
throw new \InvalidArgumentException();
|
||||
}
|
||||
|
||||
$this->didInit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getMessage()
|
||||
*/
|
||||
public function getMessage() {
|
||||
return 'freed the fish. OH A NOEZ';
|
||||
}
|
||||
}
|
16
file/lib/system/command/commands/GbanCommand.class.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace chat\system\command\commands;
|
||||
|
||||
/**
|
||||
* Globally bans a user.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command.commands
|
||||
*/
|
||||
class GbanCommand extends \chat\system\command\AbstractSuspensionCommand {
|
||||
const IS_GLOBAL = true;
|
||||
const SUSPENSION_TYPE = \chat\data\suspension\Suspension::TYPE_BAN;
|
||||
}
|
16
file/lib/system/command/commands/GmuteCommand.class.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace chat\system\command\commands;
|
||||
|
||||
/**
|
||||
* Globally mutes a user.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command.commands
|
||||
*/
|
||||
class GmuteCommand extends \chat\system\command\AbstractSuspensionCommand {
|
||||
const IS_GLOBAL = true;
|
||||
const SUSPENSION_TYPE = \chat\data\suspension\Suspension::TYPE_MUTE;
|
||||
}
|
116
file/lib/system/command/commands/InfoCommand.class.php
Normal file
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
namespace chat\system\command\commands;
|
||||
use \chat\util\ChatUtil;
|
||||
use \wcf\data\user\User;
|
||||
use \wcf\system\WCF;
|
||||
use \wcf\util\DateUtil;
|
||||
|
||||
/**
|
||||
* Shows information about the specified user.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command.commands
|
||||
*/
|
||||
class InfoCommand extends \chat\system\command\AbstractCommand {
|
||||
public $lines = array();
|
||||
public $user = null;
|
||||
|
||||
public function __construct(\chat\system\command\CommandHandler $commandHandler) {
|
||||
parent::__construct($commandHandler);
|
||||
|
||||
$username = rtrim($commandHandler->getParameters(), ',');
|
||||
$this->user = User::getUserByUsername($username);
|
||||
if (!$this->user->userID) throw new \chat\system\command\UserNotFoundException($username);
|
||||
|
||||
// Username + link to profile
|
||||
$profile = \wcf\system\request\LinkHandler::getInstance()->getLink('User', array(
|
||||
'object' => $this->user
|
||||
));
|
||||
$this->lines[WCF::getLanguage()->get('wcf.user.username')] = "[url='".$profile."']".$this->user->username.'[/url]';
|
||||
|
||||
// Away-Status
|
||||
if ($this->user->chatAway !== null) {
|
||||
$this->lines[WCF::getLanguage()->get('wcf.chat.away')] = $this->user->chatAway;
|
||||
}
|
||||
|
||||
// Room
|
||||
$room = \chat\data\room\RoomCache::getInstance()->getRoom($this->user->chatRoomID);
|
||||
if ($room !== null && $room->canEnter()) {
|
||||
$this->lines[WCF::getLanguage()->get('chat.global.room')] = $room->getTitle();
|
||||
}
|
||||
|
||||
// Suspensions
|
||||
$suspensions = \chat\data\suspension\Suspension::getSuspensionsForUser($this->user);
|
||||
foreach ($suspensions as $roomSuspensions) {
|
||||
foreach ($roomSuspensions as $typeSuspension) {
|
||||
if (!$typeSuspension->isValid()) continue;
|
||||
if (!$typeSuspension->isVisible()) continue;
|
||||
|
||||
$dateTime = DateUtil::getDateTimeByTimestamp($typeSuspension->expires);
|
||||
$name = WCF::getLanguage()->getDynamicVariable('chat.global.information.suspension', array(
|
||||
'suspension' => $typeSuspension,
|
||||
'room' => \chat\data\room\RoomCache::getInstance()->getRoom($typeSuspension->roomID)
|
||||
));
|
||||
$this->lines[$name] = str_replace('%time%', DateUtil::format($dateTime, DateUtil::TIME_FORMAT), str_replace('%date%', DateUtil::format($dateTime, DateUtil::DATE_FORMAT), WCF::getLanguage()->get('wcf.date.dateTimeFormat')));
|
||||
}
|
||||
}
|
||||
|
||||
// ip address
|
||||
if (WCF::getSession()->getPermission('admin.user.canViewIpAddress')) {
|
||||
$session = $this->fetchSession();
|
||||
if ($session) {
|
||||
$this->lines[WCF::getLanguage()->get('wcf.user.ipAddress')] = \wcf\util\UserUtil::convertIPv6To4($session->ipAddress);
|
||||
}
|
||||
}
|
||||
|
||||
$this->didInit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the sessiondatabase object for the specified user.
|
||||
*
|
||||
* @return \wcf\data\session\Session
|
||||
*/
|
||||
public function fetchSession() {
|
||||
$sql = "SELECT
|
||||
*
|
||||
FROM
|
||||
wcf".WCF_N."_session
|
||||
WHERE
|
||||
userID = ?";
|
||||
$stmt = WCF::getDB()->prepareStatement($sql);
|
||||
$stmt->execute(array($this->user->userID));
|
||||
$row = $stmt->fetchArray();
|
||||
if (!$row) return false;
|
||||
|
||||
return new \wcf\data\session\Session(null, $row);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getType()
|
||||
*/
|
||||
public function getType() {
|
||||
return \chat\data\message\Message::TYPE_INFORMATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getMessage()
|
||||
*/
|
||||
public function getMessage() {
|
||||
$lines = array();
|
||||
foreach ($this->lines as $key => $val) {
|
||||
$lines[] = '[b]'.$key.':[/b] '.$val;
|
||||
}
|
||||
return '[list][*]'.implode('[*]', $lines).'[/list]';
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getReceiver()
|
||||
*/
|
||||
public function getReceiver() {
|
||||
return \wcf\system\WCF::getUser()->userID;
|
||||
}
|
||||
}
|
76
file/lib/system/command/commands/InviteCommand.class.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
namespace chat\system\command\commands;
|
||||
use \wcf\data\user\User;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Invites a user into a temproom.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command.commands
|
||||
*/
|
||||
class InviteCommand extends \chat\system\command\AbstractRestrictedCommand {
|
||||
public $user = null;
|
||||
public $link = '';
|
||||
public $room = null;
|
||||
|
||||
public function __construct(\chat\system\command\CommandHandler $commandHandler) {
|
||||
parent::__construct($commandHandler);
|
||||
|
||||
$username = rtrim($commandHandler->getParameters(), ',');
|
||||
$this->user = User::getUserByUsername($username);
|
||||
if (!$this->user->userID) throw new \chat\system\command\UserNotFoundException($username);
|
||||
|
||||
$acl = \wcf\system\acl\ACLHandler::getInstance();
|
||||
$permissions = $acl->getPermissions($acl->getObjectTypeID('be.bastelstu.chat.room'), array($this->room->roomID));
|
||||
|
||||
$newPermission = array();
|
||||
foreach ($permissions['options'] as $option) {
|
||||
$newPermission[$option->optionID] = ($option->categoryName == 'user') ? 1 : 0;
|
||||
}
|
||||
|
||||
$_POST['aclValues'] = array(
|
||||
'user' => $permissions['user'][$this->room->roomID],
|
||||
'group' => $permissions['group'][$this->room->roomID]
|
||||
);
|
||||
$_POST['aclValues']['user'][$this->user->userID] = $newPermission;
|
||||
|
||||
$acl->save($this->room->roomID, $acl->getObjectTypeID('be.bastelstu.chat.room'));
|
||||
\chat\system\permission\PermissionHandler::clearCache();
|
||||
$this->didInit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\IRestrictedChatCommand::checkPermission()
|
||||
*/
|
||||
public function checkPermission() {
|
||||
parent::checkPermission();
|
||||
|
||||
$this->room = $this->commandHandler->getRoom();
|
||||
if ($this->room->owner != WCF::getUser()->userID) throw new \wcf\system\exception\PermissionDeniedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getType()
|
||||
*/
|
||||
public function getType() {
|
||||
return \chat\data\message\Message::TYPE_INFORMATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getMessage()
|
||||
*/
|
||||
public function getMessage() {
|
||||
return \wcf\system\WCF::getLanguage()->getDynamicVariable('chat.message.invite.success', array('user' => $this->user, 'room' => $this->room));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getReceiver()
|
||||
*/
|
||||
public function getReceiver() {
|
||||
return \wcf\system\WCF::getUser()->userID;
|
||||
}
|
||||
}
|
38
file/lib/system/command/commands/MeCommand.class.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
namespace chat\system\command\commands;
|
||||
|
||||
/**
|
||||
* Indicates an action. The message is shown without the colon.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command.commands
|
||||
*/
|
||||
class MeCommand extends \chat\system\command\AbstractCommand {
|
||||
/**
|
||||
* @see \chat\system\command\AbstractCommand::$enableSmilies
|
||||
*/
|
||||
public $enableSmilies = self::SETTING_USER;
|
||||
|
||||
public function __construct(\chat\system\command\CommandHandler $commandHandler) {
|
||||
parent::__construct($commandHandler);
|
||||
|
||||
$this->didInit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getType()
|
||||
*/
|
||||
public function getType() {
|
||||
return \chat\data\message\Message::TYPE_ME;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getMessage()
|
||||
*/
|
||||
public function getMessage() {
|
||||
return $this->commandHandler->getParameters();
|
||||
}
|
||||
}
|
16
file/lib/system/command/commands/MuteCommand.class.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace chat\system\command\commands;
|
||||
|
||||
/**
|
||||
* Mutes a user.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command.commands
|
||||
*/
|
||||
class MuteCommand extends \chat\system\command\AbstractSuspensionCommand {
|
||||
const IS_GLOBAL = false;
|
||||
const SUSPENSION_TYPE = \chat\data\suspension\Suspension::TYPE_MUTE;
|
||||
}
|
36
file/lib/system/command/commands/PlainCommand.class.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
namespace chat\system\command\commands;
|
||||
|
||||
/**
|
||||
* Sends a message that starts with a slash.
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command.commands
|
||||
*/
|
||||
class PlainCommand extends \chat\system\command\AbstractCommand {
|
||||
public $enableSmilies = \chat\system\command\ICommand::SETTING_USER;
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getType()
|
||||
*/
|
||||
public function getType() {
|
||||
return \chat\data\message\Message::TYPE_NORMAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getMessage()
|
||||
*/
|
||||
public function getMessage() {
|
||||
return \wcf\system\bbcode\PreParser::getInstance()->parse(\chat\system\command\CommandHandler::COMMAND_CHAR.$this->commandHandler->getParameters(), explode(',', \wcf\system\WCF::getSession()->getPermission('user.chat.allowedBBCodes')));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getReceiver()
|
||||
*/
|
||||
public function getReceiver() {
|
||||
return null;
|
||||
}
|
||||
}
|
66
file/lib/system/command/commands/RestoreCommand.class.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
namespace chat\system\command\commands;
|
||||
use \wcf\data\user\User;
|
||||
use \wcf\system\WCF;
|
||||
use \wcf\util\ChatUtil;
|
||||
|
||||
/**
|
||||
* Resets the color of a user
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command.commands
|
||||
*/
|
||||
class RestoreCommand extends \chat\system\command\AbstractRestrictedCommand {
|
||||
public $enableHTML = 1;
|
||||
public $user = null;
|
||||
public $link = '';
|
||||
|
||||
public function __construct(\chat\system\command\CommandHandler $commandHandler) {
|
||||
parent::__construct($commandHandler);
|
||||
|
||||
$username = rtrim($commandHandler->getParameters(), ',');
|
||||
$this->user = User::getUserByUsername($username);
|
||||
if (!$this->user->userID) throw new \chat\system\command\UserNotFoundException($username);
|
||||
|
||||
$profile = \wcf\system\request\LinkHandler::getInstance()->getLink('User', array(
|
||||
'object' => $this->user
|
||||
));
|
||||
$this->link = "[url='".$profile."']".$this->user->username.'[/url]';
|
||||
|
||||
$editor = new \wcf\data\user\UserEditor($this->user);
|
||||
$editor->update(array(
|
||||
'chatColor1' => null,
|
||||
'chatColor2' => null
|
||||
));
|
||||
$this->didInit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\IRestrictedChatCommand::checkPermission()
|
||||
*/
|
||||
public function checkPermission() {
|
||||
parent::checkPermission();
|
||||
|
||||
WCF::getSession()->checkPermissions(array('mod.chat.canRestore'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getType()
|
||||
*/
|
||||
public function getType() {
|
||||
return \chat\data\message\Message::TYPE_MODERATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getMessage()
|
||||
*/
|
||||
public function getMessage() {
|
||||
return serialize(array(
|
||||
'link' => $this->link,
|
||||
'type' => str_replace(array('chat\system\command\commands\\', 'command'), '', strtolower(get_class($this)))
|
||||
));
|
||||
}
|
||||
}
|
97
file/lib/system/command/commands/TemproomCommand.class.php
Normal file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
namespace chat\system\command\commands;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Creates a temporary room
|
||||
*
|
||||
* @author Tim Düsterhus
|
||||
* @copyright 2010-2014 Tim Düsterhus
|
||||
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
|
||||
* @package be.bastelstu.chat
|
||||
* @subpackage system.chat.command.commands
|
||||
*/
|
||||
class TemproomCommand extends \chat\system\command\AbstractRestrictedCommand {
|
||||
public $roomName = '';
|
||||
public $roomID = 0;
|
||||
|
||||
public function __construct(\chat\system\command\CommandHandler $commandHandler) {
|
||||
parent::__construct($commandHandler);
|
||||
|
||||
// create room
|
||||
$this->objectAction = new \chat\data\room\RoomAction(array(), 'create', array('data' => array(
|
||||
'title' => 'Temproom',
|
||||
'topic' => '',
|
||||
'permanent' => 0,
|
||||
'owner' => WCF::getUser()->userID
|
||||
)));
|
||||
$this->objectAction->executeAction();
|
||||
$returnValues = $this->objectAction->getReturnValues();
|
||||
$chatRoomEditor = new \chat\data\room\RoomEditor($returnValues['returnValues']);
|
||||
$this->roomID = $returnValues['returnValues']->roomID;
|
||||
$this->roomName = WCF::getLanguage()->getDynamicVariable('chat.room.titleTemp', array('roomID' => $this->roomID));
|
||||
|
||||
// set accurate title
|
||||
$chatRoomEditor->update(array(
|
||||
'title' => $this->roomName
|
||||
));
|
||||
|
||||
// set permissions
|
||||
$acl = \wcf\system\acl\ACLHandler::getInstance();
|
||||
$options = $acl->getOptions($acl->getObjectTypeID('be.bastelstu.chat.room'))->getObjects();
|
||||
$_POST['aclValues'] = array(
|
||||
'user' => array(
|
||||
// creators may do everything
|
||||
WCF::getUser()->userID => array_fill_keys(array_keys($options), 1)
|
||||
),
|
||||
'group' => array(
|
||||
// anyone else may do nothing
|
||||
\wcf\data\user\group\UserGroup::EVERYONE => array_fill_keys(array_keys($options), 0)
|
||||
)
|
||||
);
|
||||
|
||||
$acl->save($this->roomID, $acl->getObjectTypeID('be.bastelstu.chat.room'));
|
||||
\chat\system\permission\PermissionHandler::clearCache();
|
||||
$this->didInit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\IRestrictedCommand::checkPermission()
|
||||
*/
|
||||
public function checkPermission() {
|
||||
parent::checkPermission();
|
||||
|
||||
WCF::getSession()->checkPermissions(array('user.chat.canTempRoom'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getType()
|
||||
*/
|
||||
public function getType() {
|
||||
return \chat\data\message\Message::TYPE_INFORMATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getMessage()
|
||||
*/
|
||||
public function getMessage() {
|
||||
return WCF::getLanguage()->getDynamicVariable('chat.message.temproom.success', array('roomName' => $this->roomName));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getReceiver()
|
||||
*/
|
||||
public function getReceiver() {
|
||||
return \wcf\system\WCF::getUser()->userID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\command\ICommand::getAdditionalData()
|
||||
*/
|
||||
public function getAdditionalData() {
|
||||
return array(
|
||||
'roomID' => (int) $this->roomID,
|
||||
'roomName' => $this->roomName
|
||||
);
|
||||
}
|
||||
}
|