Compare commits

...

79 Commits

Author SHA1 Message Date
shish
3cf59cc545 version bump
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@1012 7f39781d-f577-437e-ae19-be835c7a54ca
2008-09-01 12:57:23 +00:00
shish
327d0dd51f realpath() fix from trunk
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@1011 7f39781d-f577-437e-ae19-be835c7a54ca
2008-09-01 12:56:48 +00:00
shish
90fcccdab0 various fix backports
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@1006 7f39781d-f577-437e-ae19-be835c7a54ca
2008-08-26 09:06:29 +00:00
shish
9d868750e2 merge some fixes
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@984 7f39781d-f577-437e-ae19-be835c7a54ca
2008-08-12 02:39:08 +00:00
shish
770e313da1 and in 2.2...
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@941 7f39781d-f577-437e-ae19-be835c7a54ca
2008-07-27 15:56:45 +00:00
shish
2002d555c1 and stable
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@939 7f39781d-f577-437e-ae19-be835c7a54ca
2008-07-26 07:06:42 +00:00
shish
36064595f5 moo
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@937 7f39781d-f577-437e-ae19-be835c7a54ca
2008-07-25 17:56:34 +00:00
shish
2c4582f147 memcache api, for anyone who wants it :3
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@935 7f39781d-f577-437e-ae19-be835c7a54ca
2008-07-25 12:44:16 +00:00
shish
9993370fc6 sql compliance
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@934 7f39781d-f577-437e-ae19-be835c7a54ca
2008-07-25 12:06:13 +00:00
shish
5d42ee21de debreak
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@933 7f39781d-f577-437e-ae19-be835c7a54ca
2008-07-25 11:56:46 +00:00
shish
6e0b3bca6d back again
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@931 7f39781d-f577-437e-ae19-be835c7a54ca
2008-07-25 11:44:05 +00:00
shish
32d12602cf back
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@929 7f39781d-f577-437e-ae19-be835c7a54ca
2008-07-24 16:22:15 +00:00
shish
058f2ff1ed more compat
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@927 7f39781d-f577-437e-ae19-be835c7a54ca
2008-07-24 15:35:57 +00:00
shish
79767033b7 backport
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@924 7f39781d-f577-437e-ae19-be835c7a54ca
2008-07-24 14:06:47 +00:00
shish
8f05de4b66 backport by request~
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@922 7f39781d-f577-437e-ae19-be835c7a54ca
2008-07-24 07:51:35 +00:00
shish
34d2165dfa to 2.2
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@920 7f39781d-f577-437e-ae19-be835c7a54ca
2008-07-23 10:58:50 +00:00
shish
593dc2f694 version bump
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@918 7f39781d-f577-437e-ae19-be835c7a54ca
2008-07-21 19:07:52 +00:00
shish
a1199c3bd4 and 2.2
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@917 7f39781d-f577-437e-ae19-be835c7a54ca
2008-07-21 15:18:37 +00:00
shish
4b666a8f1a backport
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@915 7f39781d-f577-437e-ae19-be835c7a54ca
2008-07-21 11:14:17 +00:00
shish
9044abdfc2 backport
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@913 7f39781d-f577-437e-ae19-be835c7a54ca
2008-07-21 11:05:20 +00:00
shish
e17c85d379 backport to 2.2
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@911 7f39781d-f577-437e-ae19-be835c7a54ca
2008-07-17 08:14:52 +00:00
shish
554ff9051c broken in 2.2? :S Removing for a minimal release, 2.2.1 will be for extra features and things again \o/
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@906 7f39781d-f577-437e-ae19-be835c7a54ca
2008-06-20 14:33:52 +00:00
shish
04f335b797 backport
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@905 7f39781d-f577-437e-ae19-be835c7a54ca
2008-06-19 14:56:13 +00:00
shish
661b5eac78 add the last couple of fixes
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@903 7f39781d-f577-437e-ae19-be835c7a54ca
2008-06-16 11:30:46 +00:00
shish
763538c096 2.2 too
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@900 7f39781d-f577-437e-ae19-be835c7a54ca
2008-06-14 18:45:42 +00:00
shish
5f473aff6d tentative release
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@898 7f39781d-f577-437e-ae19-be835c7a54ca
2008-06-14 17:23:17 +00:00
shish
c4fdf771ee backports
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@895 7f39781d-f577-437e-ae19-be835c7a54ca
2008-06-09 11:23:02 +00:00
shish
94725f1266 subtitles
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@888 7f39781d-f577-437e-ae19-be835c7a54ca
2008-06-08 15:08:24 +00:00
shish
f1ce267015 stable
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@886 7f39781d-f577-437e-ae19-be835c7a54ca
2008-05-28 22:39:41 +00:00
shish
25bfb82653 now that flash file dimentions are detected, it's good enough for stable \o/
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@884 7f39781d-f577-437e-ae19-be835c7a54ca
2008-05-26 22:08:11 +00:00
shish
0c334f05ed backports~
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@881 7f39781d-f577-437e-ae19-be835c7a54ca
2008-05-25 23:06:10 +00:00
shish
bea09d836d to 2.2
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@878 7f39781d-f577-437e-ae19-be835c7a54ca
2008-05-22 20:42:20 +00:00
shish
384e8bbdda backport
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@876 7f39781d-f577-437e-ae19-be835c7a54ca
2008-05-20 19:35:23 +00:00
shish
96509995a8 2.2 merge
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@871 7f39781d-f577-437e-ae19-be835c7a54ca
2008-05-20 03:07:26 +00:00
shish
642a3d02e1 fixes / reworking to 2.2
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@868 7f39781d-f577-437e-ae19-be835c7a54ca
2008-05-19 17:11:08 +00:00
shish
f180624ebf get_random_image in 2.2 also
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@866 7f39781d-f577-437e-ae19-be835c7a54ca
2008-05-19 13:07:16 +00:00
shish
482312b11e featured image for 2.2
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@862 7f39781d-f577-437e-ae19-be835c7a54ca
2008-05-19 02:21:47 +00:00
shish
aaa8ccf874 2.2 also
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@857 7f39781d-f577-437e-ae19-be835c7a54ca
2008-05-18 03:33:11 +00:00
shish
c2ab5e5fcd xmldb removal changes to 2.2
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@855 7f39781d-f577-437e-ae19-be835c7a54ca
2008-05-18 02:38:36 +00:00
shish
3f0d6562ef data dir is unused, and could be a security hole in the way I'd intended it to be used...
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@854 7f39781d-f577-437e-ae19-be835c7a54ca
2008-05-18 02:32:04 +00:00
shish
d1ce3db7e2 2.2 also
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@841 7f39781d-f577-437e-ae19-be835c7a54ca
2008-05-04 21:00:29 +00:00
shish
24a35c37ea same weird non-bug
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@838 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-30 12:33:36 +00:00
shish
457d5d8ad9 a couple more bbcode tags
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@837 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-30 12:33:19 +00:00
shish
56ccd7df40 2.2 merge
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@828 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-19 18:59:00 +00:00
shish
f8b414a15f 2.2 too
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@825 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-16 10:02:11 +00:00
shish
51f6c486a2 backport :3
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@820 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-14 11:21:38 +00:00
shish
367546fe06 back to 2.2
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@818 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-14 10:51:25 +00:00
shish
ffde804f24 SVG should be fit for stable \o/
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@815 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-11 06:59:23 +00:00
shish
b57ba4d484 backport
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@813 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-11 06:27:28 +00:00
shish
ce8d6f71fd and 2.2
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@811 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-11 06:14:59 +00:00
shish
1fd2fe084b apply cleanups to 2.2
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@807 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-11 05:47:16 +00:00
shish
7e92bdbd8e backport
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@802 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-11 05:26:02 +00:00
shish
4c5f415da7 2.2 too
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@798 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-11 01:49:55 +00:00
shish
b7fc28e17f changed include file
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@795 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-09 01:10:29 +00:00
shish
b2f8165a59 remove user enable / disable in 2.2 too
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@794 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-09 00:34:08 +00:00
shish
57b50d8881 all those into 2.2
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@793 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-08 21:59:20 +00:00
shish
9f595e6273 backport
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@788 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-08 17:16:56 +00:00
shish
0c9fff3d11 backport
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@786 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-08 16:58:31 +00:00
shish
d3ceb8ef97 changes to 2.2, and remove broken text score
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@784 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-08 16:56:12 +00:00
shish
64db094721 2.2 too, as this is probably useful to a lot of people
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@780 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-08 16:03:30 +00:00
shish
d47fd5f25c regex thing in index in 2.2 too
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@778 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-08 15:42:05 +00:00
shish
f7d1df2727 both of those into 2.2
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@775 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-07 23:18:32 +00:00
shish
67455583e5 This feature freeze is more of a feature mild chill...
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@769 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-06 21:07:29 +00:00
shish
2e40bc73c8 I wonder if 2.2 should have branched this early <_<;;
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@767 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-06 18:42:52 +00:00
shish
c012717bce readme update
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@765 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-06 18:00:35 +00:00
shish
7b4dde4918 and, again, 2.2~
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@764 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-06 17:57:04 +00:00
shish
5ad77079a6 2.2.too
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@762 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-06 17:44:02 +00:00
shish
43028ebd67 both of them to 2.2
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@760 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-06 16:47:44 +00:00
shish
f821e752fc back to 2.2
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@757 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-06 16:38:32 +00:00
shish
73d5fe129a UploadingImageEvent -> DataUploadEvent
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@754 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-04 22:16:48 +00:00
shish
a226a17787 and in 2.2
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@751 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-04 10:38:41 +00:00
shish
03c9d6b298 better cache dir in 2.2
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@748 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-01 11:02:30 +00:00
shish
37a0aeb8ae ban by range in 2.2
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@747 7f39781d-f577-437e-ae19-be835c7a54ca
2008-04-01 11:00:19 +00:00
shish
47361369ff pull a couple of mostly cosmetic changes into stable
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@741 7f39781d-f577-437e-ae19-be835c7a54ca
2008-03-31 03:01:35 +00:00
shish
6c53088929 version number
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@736 7f39781d-f577-437e-ae19-be835c7a54ca
2008-03-30 06:06:00 +00:00
shish
a6d68c6f1b and commit it to 2.2...
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@735 7f39781d-f577-437e-ae19-be835c7a54ca
2008-03-29 04:13:54 +00:00
shish
57a6c39f2a stable too
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@733 7f39781d-f577-437e-ae19-be835c7a54ca
2008-03-29 04:00:09 +00:00
shish
a5f7b400f0 remove broken / non-gpl extensions
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@731 7f39781d-f577-437e-ae19-be835c7a54ca
2008-03-29 03:42:48 +00:00
shish
2a990735a0 branch for 2.2 stabilisation work
git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.2@730 7f39781d-f577-437e-ae19-be835c7a54ca
2008-03-29 03:38:54 +00:00
113 changed files with 1843 additions and 2564 deletions

View File

@ -6,11 +6,12 @@
/_______ /|___| /__|__|_| /__|_| /__|\___ >_______ \
\/ \/ \/ \/ \/ \/
Shimmie 2.1 Release Candidate
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RSS, BBCode + Emoticons, Wiki, Theme engine 2 + Danbooru theme, UTF8 support,
Word filter, LOTS of database optimisations, Removal of ConfigSaveEvent and
many small fixes and improvements \o/
Shimmie 2.2
~~~~~~~~~~~
Integrated extension management, tag history, RSS for search results, unified
image info editor, extensible file format support (ZIP, SWF, SVG, MP3, ...),
wget transloader, event log filtering and sorting, as well as the usual misc
improvements and bug fixes~
Requirements
@ -19,12 +20,9 @@ MySQL 4.1+
PHP 5.0+
GD or ImageMagick
PHP 4 support has currently been dropped, because
a) It's a pain in the ass to support
b) Nobody has told me they want it
If you want PHP 4 support, mail me, and I'll see if I can get it working for
version 2.2...
PHP 4 support has currently been dropped, because it's a pain in the ass to
support. If you are unfortunate enough to be stuck on a PHP4-only host, I'd
be glad to host your image board for you :3
Installation
@ -38,40 +36,13 @@ Installation
not, you should be given instructions on how to fix any errors~
Upgrade from 2.0.X
Upgrade from 2.1.X
~~~~~~~~~~~~~~~~~~
Should be automatic, just unzip and copy across config.php, images and thumbs
folders from the old version. This includes automatically messing with the
database -- back it up first!
Upgrade from 0.8.4
~~~~~~~~~~~~~~~~~~
BIG NOTE: 0.8.4 is the only version the upgrader supports; please upgrade to
that before going any further! Feel free to try other versions, just don't
complain when it doesn't work :P
Upgrade process:
1) Make backups of everything. The most important things are your database
data, and your images folder. config.php and the thumbs folder are also
very helpful.
2) Check that your backups actually contain the important data, they aren't
just empty files with the right names...
3) Create a new, blank database, separate from the old one
4) Unzip shimmie2 into a different folder than shimmie1
5) Visit the URL of shimmie2
6) Fill in the old database location, the new database location, and the full
path to the old installation folder (the folder where the old "images" and
"thumbs" can be found)
7) Click "upgrade"
8) Wait a couple of minutes while data is copied from the old install into the
new one. You may wish to spend these minutes in prayer :P
9) Log in with an existing admin account and set things up to taste
The old installation can now be removed, but you may wish to keep it around
until you're sure everything in v2 is working properly~
Contact
~~~~~~~
http://forum.shishnet.org/viewforum.php?f=6 -- discussion forum

View File

@ -1,69 +0,0 @@
<?php
/**
* Name: Misc Admin Utils
* Author: Shish <webmaster@shishnet.org>
* Link: http://trac.shishnet.org/shimmie2/
* License: GPLv2
* Description: Various non-essential utilities
*/
class AdminUtils extends Extension {
var $theme;
public function receive_event($event) {
if(is_null($this->theme)) $this->theme = get_theme_object("admin_utils", "AdminUtilsTheme");
if(is_a($event, 'PageRequestEvent') && ($event->page_name == "admin_utils")) {
if($event->user->is_admin()) {
set_time_limit(0);
switch($_POST['action']) {
case 'lowercase all tags':
$this->lowercase_all_tags();
break;
case 'recount tag use':
$this->recount_tag_use();
break;
case 'purge unused tags':
$this->purge_unused_tags();
break;
}
$event->page->set_mode("redirect");
$event->page->set_redirect(make_link("admin"));
}
}
if(is_a($event, 'AdminBuildingEvent')) {
global $page;
$this->theme->display_form($page);
}
}
private function lowercase_all_tags() {
global $database;
$database->execute("UPDATE tags SET tag=lower(tag)");
}
private function recount_tag_use() {
global $database;
$database->Execute("UPDATE tags SET count=(SELECT COUNT(image_id) FROM image_tags WHERE tag_id=tags.id GROUP BY tag_id)");
}
private function purge_unused_tags() {
global $database;
$this->recount_tag_use();
$database->Execute("DELETE FROM tags WHERE count=0");
}
private function check_for_orphanned_images() {
$orphans = array();
foreach(glob("images/*") as $dir) {
foreach(glob("$dir/*") as $file) {
$hash = str_replace("$dir/", "", $file);
if(!$this->db_has_hash($hash)) {
$orphans[] = $hash;
}
}
}
}
}
add_event_listener(new AdminUtils());
?>

View File

@ -1,24 +0,0 @@
<?php
class AdminUtilsTheme extends Themelet {
/*
* Show a form which links to admin_utils with POST[action] set to one of:
* 'lowercase all tags'
* 'recount tag use'
* 'purge unused tags'
*/
public function display_form($page) {
$html = "
<p><form action='".make_link("admin_utils")."' method='POST'>
<select name='action'>
<option value='lowercase all tags'>All tags to lowercase</option>
<option value='recount tag use'>Recount tag use</option>
<option value='purge unused tags'>Purge unused tags</option>
</select>
<input type='submit' value='Go'>
</form>
";
$page->add_block(new Block("Misc Admin Tools", $html));
}
}
?>

View File

@ -1,29 +0,0 @@
<?php
/**
* Name: Autocomplete
* Author: Shish <webmaster@shishnet.org>
* Link: http://trac.shishnet.org/shimmie2/
* License: GPLv2
* Description: Auto-complete for search and upload tags
*/
class AutoComplete extends Extension {
public function receive_event($event) {
if(is_a($event, 'PageRequestEvent') && ($event->page_name == "index" || $event->page_name == "view")) {
$event->page->add_header("<script>autocomplete_url='".html_escape(make_link("autocomplete"))."';</script>");
}
if(is_a($event, 'PageRequestEvent') && ($event->page_name == "autocomplete")) {
$event->page->set_mode("data");
$event->page->set_type("text/plain");
$event->page->set_data($this->get_completions($event->get_arg(0)));
}
}
private function get_completions($start) {
global $database;
$tags = $database->db->GetCol("SELECT tag,count FROM tags WHERE tag LIKE ? ORDER BY count DESC", array($start.'%'));
return implode("\n", $tags);
}
}
add_event_listener(new AutoComplete());
?>

View File

@ -1,98 +0,0 @@
// addEvent(window, "load", function() {
// initAjax("searchBox", "search_completions");
// initAjax("tagBox", "upload_completions");
// });
function endWord(sentance) {
words = sentance.split(" ");
return words[words.length-1];
}
var resultCache = new Array();
resultCache[""] = new Array();
function complete(boxname, text) {
box = byId(boxname);
words = box.value.split(" ");
box.value = "";
for(n=0; n<words.length-1; n++) {
box.value += words[n]+" ";
}
box.value += text+" ";
box.focus();
return false;
}
function fillCompletionZone(boxname, areaname, results) {
byId(areaname).innerHTML = "";
for(i=0; i<results.length; i++) {
byId(areaname).innerHTML += "<br><a href=\"#\" onclick=\"complete('"+boxname+"', '"+results[i]+"');\">"+results[i]+"</a>";
}
}
function initAjax(boxname, areaname) {
var box = byId(boxname);
if(!box) return;
addEvent(
box,
"keyup",
function f() {
starter = endWord(box.value);
if(resultCache[starter]) {
fillCompletionZone(boxname, areaname, resultCache[starter]);
}
else {
ajaxRequest(
"ajax.php?start="+starter,
function g(text) {
resultCache[starter] = text.split("\n");
fillCompletionZone(boxname, areaname, resultCache[starter]);
}
);
}
},
false
);
}
//completion_cache = new array();
input = byId("search_input");
output = byId("search_completions");
function get_cached_completions(start) {
// if(completion_cache[start]) {
// return completion_cache[start];
// }
// else {
return null;
// }
}
function get_completions(start) {
cached = get_cached_completions(start);
if(cached) {
output.innerHTML = cached;
}
else {
ajaxRequest(autocomplete_url+"/"+start, function(data) {set_completions(start, data);});
}
}
function set_completions(start, data) {
// completion_cache[start] = data;
output.innerHTML = data;
}
if(input) {
input.onkeyup = function() {
if(input.value.length < 3) {
output.innerHTML = "";
}
else {
get_completions(input.value);
}
};
}

View File

@ -2,7 +2,6 @@
/**
* Name: Comment Word Ban
* Author: Shish <webmaster@shishnet.org>
* Link: http://trac.shishnet.org/shimmie2/
* License: GPLv2
* Description: For stopping spam and other comment abuse
*/

View File

@ -1,4 +1,10 @@
<?php
/**
* Name: Bulk Add
* Author: Shish <webmaster@shishnet.org>
* License: GPLv2
* Description: Bulk add server-side images
*/
class BulkAdd extends Extension {
var $theme;

View File

@ -52,7 +52,7 @@ class DanbooruApi extends Extension
if(preg_match("/md5:([0-9a-fA-F]*)/i", $event->term, $matches))
{
$hash = strtolower($matches[1]);
$event->set_querylet(new Querylet("AND (images.hash = '$hash')"));
$event->set_querylet(new Querylet("images.hash = '$hash'"));
}
}
}

View File

@ -1,4 +1,10 @@
<?php
/**
* Name: Downtime
* Author: Shish <webmaster@shishnet.org>
* License: GPLv2
* Description: Show a "down for maintenance" page
*/
class Downtime extends Extension {
var $theme;

View File

@ -2,7 +2,6 @@
/**
* Name: Emoticon Filter
* Author: Shish <webmaster@shishnet.org>
* Link: http://trac.shishnet.org/shimmie2/
* License: GPLv2
* Description: Turn :smile: into a link to smile.gif
*/

View File

@ -1,4 +1,10 @@
<?php
/**
* Name: System Info
* Author: Shish <webmaster@shishnet.org>
* License: GPLv2
* Description: Show various bits of system information, for debugging
*/
class ET extends Extension {
var $theme;

View File

@ -2,7 +2,6 @@
/**
* Name: EventLog
* Author: Shish <webmaster@shishnet.org>
* Link: http://trac.shishnet.org/shimmie2/
* License: GPLv2
* Description: A log of things that happen, for abuse tracking
*/

View File

@ -1,95 +0,0 @@
<?php
/**
* Name: Extension Manager
* Author: Shish <webmaster@shishnet.org>
* Link: http://trac.shishnet.org/shimmie2/
* License: GPLv2
* Description: A thing for point & click extension management
*/
class ExtManager extends Extension {
var $theme;
public function receive_event($event) {
if(is_null($this->theme)) $this->theme = get_theme_object("ext_manager", "ExtManagerTheme");
if(is_a($event, 'PageRequestEvent') && ($event->page_name == "ext_manager")) {
if($event->user->is_admin()) {
if($event->get_arg(0) == "set") {
$this->set_things($_POST);
$event->page->set_mode("redirect");
$event->page->set_redirect("ext_manager");
}
else {
$this->theme->display_table($event->page, $this->get_extensions());
}
}
}
if(is_a($event, 'UserBlockBuildingEvent')) {
if($event->user->is_admin()) {
$event->add_link("Extension Manager", make_link("ext_manager"));
}
}
}
private function get_extensions() {
$extensions = array();
foreach(glob("contrib/*/main.php") as $main) {
$extension = array();
$matches = array();
$data = file_get_contents($main);
preg_match("#contrib/(.*)/main.php#", $main, $matches);
$extension["ext_name"] = $matches[1];
if(preg_match("/Name: (.*)/", $data, $matches)) {
$extension["name"] = $matches[1];
}
if(preg_match("/Link: (.*)/", $data, $matches)) {
$extension["link"] = $matches[1];
}
if(preg_match("/Author: (.*) [<\(](.*@.*)[>\)]/", $data, $matches)) {
$extension["author"] = $matches[1];
$extension["email"] = $matches[2];
}
else if(preg_match("/Author: (.*)/", $data, $matches)) {
$extension["author"] = $matches[1];
}
if(preg_match("/Description: (.*)/", $data, $matches)) {
$extension["description"] = $matches[1];
}
$extension["enabled"] = $this->is_enabled($extension["ext_name"]);
$extensions[] = $extension;
}
return $extensions;
}
private function is_enabled($fname) {
return file_exists("ext/$fname");
}
private function set_things($settings) {
foreach(glob("contrib/*/main.php") as $main) {
$matches = array();
preg_match("#contrib/(.*)/main.php#", $main, $matches);
$fname = $matches[1];
$this->set_enabled($fname, $settings["ext_$fname"]);
}
}
private function set_enabled($fname, $enabled) {
if($enabled) {
// enable if currently disabled
if(!file_exists("ext/$fname")) {
symlink("../contrib/$fname", "ext/$fname");
}
}
else {
// disable if currently enabled
if(file_exists("ext/$fname")) {
unlink("ext/$fname");
}
}
}
}
add_event_listener(new ExtManager());
?>

60
contrib/featured/main.php Normal file
View File

@ -0,0 +1,60 @@
<?php
/**
* Name: Featured Image
* Author: Shish <webmaster@shishnet.org>
* License: GPLv2
* Description: Bring a specific image to the users' attentions
*/
class Featured extends Extension {
var $theme;
public function receive_event($event) {
if(is_null($this->theme)) $this->theme = get_theme_object("featured", "FeaturedTheme");
if(is_a($event, 'InitExtEvent')) {
global $config;
$config->set_default_int('featured_id', 0);
}
if(is_a($event, 'PageRequestEvent') && ($event->page_name == "set_feature")) {
global $user;
if($user->is_admin() && isset($_POST['image_id'])) {
global $config;
$id = int_escape($_POST['image_id']);
if($id > 0) {
$config->set_int("featured_id", $id);
$event->page->set_mode("redirect");
$event->page->set_redirect(make_link("post/view/$id"));
}
}
}
if(is_a($event, 'PostListBuildingEvent')) {
global $config, $database;
$fid = $config->get_int("featured_id");
if($fid > 0) {
$image = $database->get_image($fid);
if(!is_null($image)) {
$this->theme->display_featured($event->page, $image);
}
}
}
/*
if(is_a($event, 'SetupBuildingEvent')) {
$sb = new SetupBlock("Featured Image");
$sb->add_int_option("featured_id", "Image ID: ");
$event->panel->add_block($sb);
}
*/
if(is_a($event, 'ImageAdminBlockBuildingEvent')) {
if($event->user->is_admin()) {
$event->add_part($this->theme->get_buttons_html($event->image->id));
}
}
}
}
add_event_listener(new Featured());
?>

View File

@ -0,0 +1,20 @@
<?php
class FeaturedTheme extends Themelet {
/*
* Show $text on the $page
*/
public function display_featured($page, $image) {
$page->add_block(new Block("Featured Image", $this->build_thumb_html($image), "left", 3));
}
public function get_buttons_html($image_id) {
return "
<form action='".make_link("set_feature")."' method='POST'>
<input type='hidden' name='image_id' value='$image_id'>
<input type='submit' value='Feature This'>
</form>
";
}
}
?>

View File

@ -36,11 +36,7 @@ class ArchiveFileHandler extends Extension {
private function supported_ext($ext) {
$exts = array("zip");
$ext = strtolower($ext);
foreach($exts as $supported) {
if($ext == $supported) return true;
}
return false;
return array_contains($exts, strtolower($ext));
}
// copied from bulk add extension

View File

@ -11,43 +11,42 @@ class FlashFileHandler extends Extension {
public function receive_event($event) {
if(is_null($this->theme)) $this->theme = get_theme_object("handle_flash", "FlashFileHandlerTheme");
if(is_a($event, 'DataUploadEvent') && $event->type == "swf" && $this->check_contents($event->tmpname)) {
if(is_a($event, 'DataUploadEvent') && $this->supported_ext($event->type) && $this->check_contents($event->tmpname)) {
$hash = $event->hash;
$ha = substr($hash, 0, 2);
if(!copy($event->tmpname, "images/$ha/$hash")) {
$event->veto("Flash Handler failed to move file from uploads to archive");
return;
}
if(!move_upload_to_archive($event)) return;
send_event(new ThumbnailGenerationEvent($event->hash, $event->type));
$image = $this->create_image_from_data("images/$ha/$hash", $event->metadata);
if(is_null($image)) {
$event->veto("Flash Handler failed to create image object from data");
$event->veto("Flash Handler failed to create image object from data. ".
"Note: compressed flash files are currently unsupported");
return;
}
send_event(new ImageAdditionEvent($event->user, $image));
}
if(is_a($event, 'ThumbnailGenerationEvent') && $event->type == "swf") {
if(is_a($event, 'ThumbnailGenerationEvent') && $this->supported_ext($event->type)) {
$hash = $event->hash;
$ha = substr($hash, 0, 2);
// FIXME: scale image, as not all boards use 192x192
copy("ext/handle_flash/thumb.jpg", "thumbs/$ha/$hash");
}
if(is_a($event, 'DisplayingImageEvent') && $event->image->ext == "swf") {
if(is_a($event, 'DisplayingImageEvent') && $this->supported_ext($event->image->ext)) {
$this->theme->display_image($event->page, $event->image);
}
}
private function supported_ext($ext) {
$exts = array("swf");
return array_contains($exts, strtolower($ext));
}
private function create_image_from_data($filename, $metadata) {
global $config;
$image = new Image();
// FIXME: need more flash format specs :|
$image->width = 0;
$image->height = 0;
$image->filesize = $metadata['size'];
$image->hash = $metadata['hash'];
$image->filename = $metadata['filename'];
@ -55,12 +54,77 @@ class FlashFileHandler extends Extension {
$image->tag_array = tag_explode($metadata['tags']);
$image->source = $metadata['source'];
// redundant, since getimagesize() works on SWF o_O
// $rect = $this->swf_get_bounds($filename);
// if(is_null($rect)) {
// return $null;
// }
// $image->width = $rect[1];
// $image->height = $rect[3];
if(!($info = getimagesize($filename))) return null;
$image->width = $info[0];
$image->height = $info[1];
return $image;
}
private function str_to_binarray($string) {
$binary = array();
for($j=0; $j<strlen($string); $j++) {
$c = ord($string[$j]);
for($i=7; $i>=0; $i--) {
$binary[] = ($c >> $i) & 0x01;
}
}
return $binary;
}
private function binarray_to_int($binarray, $start=0, $length=32) {
$int = 0;
for($i=$start; $i<$start + $length; $i++) {
$int = $int << 1;
$int = $int + ($binarray[$i] == "1" ? 1 : 0);
}
return $int;
}
private function swf_get_bounds($filename) {
$fp = fopen($filename, "r");
$head = fread($fp, 3);
$version = fread($fp, 1);
$length = fread($fp, 4);
if($head == "FWS") {
$data = fread($fp, 16);
}
else if($head == "CWS") {
$data = fread($fp, 128*1024);
$data = gzuncompress($data);
$data = substr($data, 0, 16);
}
$bounds = array();
$rect_bin = $this->str_to_binarray($data);
$nbits = $this->binarray_to_int($rect_bin, 0, 5);
$bounds[] = $this->binarray_to_int($rect_bin, 5 + 0 * $nbits, $nbits) / 20;
$bounds[] = $this->binarray_to_int($rect_bin, 5 + 1 * $nbits, $nbits) / 20;
$bounds[] = $this->binarray_to_int($rect_bin, 5 + 2 * $nbits, $nbits) / 20;
$bounds[] = $this->binarray_to_int($rect_bin, 5 + 3 * $nbits, $nbits) / 20;
return $bounds;
}
private function check_contents($file) {
// FIXME: flash magic header?
return (file_exists($file));
if(!file_exists($file)) return false;
$fp = fopen($file, "r");
$head = fread($fp, 3);
fclose($fp);
if(!array_contains(array("CWS", "FWS"), $head)) return false;
return true;
}
}
add_event_listener(new FlashFileHandler());

View File

@ -6,11 +6,16 @@ class FlashFileHandlerTheme extends Themelet {
// FIXME: object and embed have "height" and "width"
$html = "
<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'
codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0'>
codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0'
height='{$image->height}'
width='{$image->width}'
>
<param name='movie' value='$ilink'/>
<param name='quality' value='high' />
<embed src='$ilink' quality='high'
pluginspage='http://www.macromedia.com/go/getflashplayer'
height='{$image->height}'
width='{$image->width}'
type='application/x-shockwave-flash'></embed>
</object>";
$page->add_block(new Block("Image", $html, "main", 0));

116
contrib/handle_ico/main.php Normal file
View File

@ -0,0 +1,116 @@
<?php
/**
* Name: ICO File Handler
* Author: Shish <webmaster@shishnet.org>
* Description: Handle windows icons
*/
class IcoFileHandler extends Extension {
var $theme;
public function receive_event($event) {
if(is_null($this->theme)) $this->theme = get_theme_object("handle_ico", "IcoFileHandlerTheme");
if(is_a($event, 'DataUploadEvent') && $this->supported_ext($event->type) && $this->check_contents($event->tmpname)) {
$hash = $event->hash;
$ha = substr($hash, 0, 2);
if(!move_upload_to_archive($event)) return;
send_event(new ThumbnailGenerationEvent($event->hash, $event->type));
$image = $this->create_image_from_data("images/$ha/$hash", $event->metadata);
if(is_null($image)) {
$event->veto("Handler failed to create image object from data");
return;
}
$iae = new ImageAdditionEvent($event->user, $image);
send_event($iae);
if($iae->vetoed) {
$event->veto($iae->veto_reason);
return;
}
}
if(is_a($event, 'ThumbnailGenerationEvent') && $this->supported_ext($event->type)) {
$this->create_thumb($event->hash);
}
if(is_a($event, 'DisplayingImageEvent') && $this->supported_ext($event->image->ext)) {
$this->theme->display_image($event->page, $event->image);
}
if(is_a($event, 'PageRequestEvent') && ($event->page_name == "get_ico")) {
global $database;
$id = int_escape($event->get_arg(0));
$image = $database->get_image($id);
$hash = $image->hash;
$ha = substr($hash, 0, 2);
$event->page->set_type("image/x-icon");
$event->page->set_mode("data");
$event->page->set_data(file_get_contents("images/$ha/$hash"));
}
}
private function supported_ext($ext) {
$exts = array("ico", "ani", "cur");
return array_contains($exts, strtolower($ext));
}
private function create_image_from_data($filename, $metadata) {
global $config;
$image = new Image();
$info = "";
$fp = fopen($filename, "r");
$header = unpack("snull/stype/scount", fread($fp, 6));
$subheader = unpack("cwidth/cheight/ccolours/cnull/splanes/sbpp/lsize/loffset", fread($fp, 16));
fclose($fp);
$image->width = $subheader['width'];
$image->height = $subheader['height'];
$image->filesize = $metadata['size'];
$image->hash = $metadata['hash'];
$image->filename = $metadata['filename'];
$image->ext = $metadata['extension'];
$image->tag_array = tag_explode($metadata['tags']);
$image->source = $metadata['source'];
return $image;
}
private function check_contents($file) {
if(!file_exists($file)) return false;
$fp = fopen($file, "r");
$header = unpack("snull/stype/scount", fread($fp, 6));
fclose($fp);
return ($header['null'] == 0 && ($header['type'] == 0 || $header['type'] == 1));
}
private function create_thumb($hash) {
global $config;
$ha = substr($hash, 0, 2);
$inname = "images/$ha/$hash";
$outname = "thumbs/$ha/$hash";
$w = $config->get_int("thumb_width");
$h = $config->get_int("thumb_height");
$q = $config->get_int("thumb_quality");
$mem = $config->get_int("thumb_max_memory") / 1024 / 1024; // IM takes memory in MB
if($config->get_bool("ico_convert")) {
// "-limit memory $mem" broken?
exec("convert {$inname}[0] -geometry {$w}x{$h} -quality {$q} jpg:$outname");
}
else {
copy($inname, $outname);
}
return true;
}
}
add_event_listener(new IcoFileHandler());
?>

View File

@ -0,0 +1,12 @@
<?php
class IcoFileHandlerTheme extends Themelet {
public function display_image($page, $image) {
$ilink = make_link("get_ico/{$image->id}/{$image->id}.ico");
$html = "
<img id='main_image' src='$ilink'>
";
$page->add_block(new Block("Image", $html, "main", 0));
}
}
?>

View File

@ -1,67 +0,0 @@
<?php
/**
* Name: MP3 File Handler
* Author: Shish <webmaster@shishnet.org>
* Description: Handle MP3 files
*/
class MP3FileHandler extends Extension {
var $theme;
public function receive_event($event) {
if(is_null($this->theme)) $this->theme = get_theme_object("handle_mp3", "MP3FileHandlerTheme");
if(is_a($event, 'DataUploadEvent') && $event->type == "mp3" && $this->check_contents($event->tmpname)) {
$hash = $event->hash;
$ha = substr($hash, 0, 2);
if(!copy($event->tmpname, "images/$ha/$hash")) {
$event->veto("MP3 Handler failed to move file from uploads to archive");
return;
}
send_event(new ThumbnailGenerationEvent($event->hash, $event->type));
$image = $this->create_image_from_data("images/$ha/$hash", $event->metadata);
if(is_null($image)) {
$event->veto("MP3 Handler failed to create image object from data");
return;
}
send_event(new ImageAdditionEvent($event->user, $image));
}
if(is_a($event, 'ThumbnailGenerationEvent') && $event->type == "mp3") {
$hash = $event->hash;
$ha = substr($hash, 0, 2);
// FIXME: scale image, as not all boards use 192x192
copy("ext/handle_mp3/thumb.jpg", "thumbs/$ha/$hash");
}
if(is_a($event, 'DisplayingImageEvent') && $event->image->ext == "mp3") {
$this->theme->display_image($event->page, $event->image);
}
}
private function create_image_from_data($filename, $metadata) {
global $config;
$image = new Image();
// FIXME: need more flash format specs :|
$image->width = 0;
$image->height = 0;
$image->filesize = $metadata['size'];
$image->hash = $metadata['hash'];
$image->filename = $metadata['filename'];
$image->ext = $metadata['extension'];
$image->tag_array = tag_explode($metadata['tags']);
$image->source = $metadata['source'];
return $image;
}
private function check_contents($file) {
// FIXME: mp3 magic header?
return (file_exists($file));
}
}
add_event_listener(new MP3FileHandler());
?>

View File

@ -1,22 +0,0 @@
<?php
class MP3FileHandlerTheme extends Themelet {
public function display_image($page, $image) {
$data_href = get_base_href();
$ilink = $image->get_image_link();
$html = "
<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'
codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0'
width='400' height='170'>
<param name='movie' value='$data_href/ext/handle_mp3/xspf_player.swf?song_url=$ilink'/>
<param name='quality' value='high' />
<embed src='$data_href/ext/handle_mp3/xspf_player.swf?song_url=$ilink' quality='high'
pluginspage='http://www.macromedia.com/go/getflashplayer'
width='400' height='170'
type='application/x-shockwave-flash'></embed>
</object>
<p><a href='$ilink'>Download</a>";
$page->add_block(new Block("Music", $html, "main", 0));
}
}
?>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

View File

@ -1,448 +0,0 @@
/*
Copyright (c) 2005, Fabricio Zuardi
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
stop();
//autoplay=true
//repeat_playlist = true;
//playlist_size = 3;
//player_title = "customizeable title test"
//song_url = "http://downloads.betterpropaganda.com/music/Imperial_Teen-Ivanka_128.mp3";
//playlist_url = "http://cchits.ning.com/recent/xspf/?xn_auth=no";
//playlist_url = "http://hideout.com.br/shows/radio-test.xspf";
//radio_mode = true;
//song_title = "Imperial Teen - Ivanka";
autoload=true;
//info_button_text = "Add to Cart"
//playlist_url = "http%3A%2F%2Fwebjay%2Eorg%2Fby%2Flucas%5Fgonze%2Flaconic%2Exspf"
//playlist_url= "http://hideout.com.br/tests/hideout2325.xspf"
//constants
DEFAULT_PLAYLIST_URL = "http://hideout.com.br/shows/allshows.xspf";
DEFAULT_WELCOME_MSG = "Hideout XSPF Music Player - by Fabricio Zuardi";
LOADING_PLAYLIST_MSG = "Loading Playlist...";
DEFAULT_LOADED_PLAYLIST_MSG = "- click to start"
DEFAULT_INFOBUTTON_TXT = "Info"
//playlists has priority over songs, if a playlist_url parameter is found the song_url is ignored
//default playlist if none is passed through query string
if(!playlist_url){
if(!song_url){
playlist_url = DEFAULT_PLAYLIST_URL;
}else{
single_music_playlist = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><playlist version=\"1\" xmlns = \"http://xspf.org/ns/0/\"><trackList>";
single_music_playlist += "<track><location>"+song_url+"</location><annotation>"+song_title+"</annotation></track>"
single_music_playlist += "</trackList></playlist>"
}
}
info_mc._visible=false;
if(!info_button_text){
info_button_text = DEFAULT_INFOBUTTON_TXT;
}
info_mc.display_txt.text = info_button_text;
//variables initialization
playlist_array = [];
track_index = 0;
playlist_mc.track_count = 0;
pause_position = 0;
volume_level = 100;
playlist_xml = new XML();
playlist_xml.ignoreWhite = true;
playlist_xml.onLoad = playlistLoaded;
mysound = new Sound(this);
playlist_listener = new Object();
playlist_list.addEventListener("change", playlist_listener)
//play_btn.onPress = playTrack;
//functions
//xml parser
function playlistLoaded (success){
if(success){
var root_node = this.firstChild;
for(var node = root_node.firstChild; node != null; node = node.nextSibling){
if(node.nodeName == "title"){
playlist_title = node.firstChild.nodeValue;
}
if(node.nodeName == "trackList"){
//tracks
var tracks_array = [];
for(var track_node = node.firstChild; track_node != null; track_node = track_node.nextSibling){
var track_obj = new Object()
//track attributes
for(var track_child = track_node.firstChild; track_child != null; track_child = track_child.nextSibling){
if(track_child.nodeName=="location"){
track_obj.location = track_child.firstChild.nodeValue
}
if(track_child.nodeName=="image"){
track_obj.image = track_child.firstChild.nodeValue
}
if(track_child.nodeName=="title"){
track_obj.title = track_child.firstChild.nodeValue
}
if(track_child.nodeName=="creator"){
track_obj.creator = track_child.firstChild.nodeValue
}
if(track_child.nodeName=="annotation"){
track_obj.annotation = track_child.firstChild.nodeValue
}
if(track_child.nodeName=="info"){
track_obj.info = track_child.firstChild.nodeValue
}
}
track_obj.label = (tracks_array.length+1) +". ";
if(track_obj.title) {
if(track_obj.creator) {
track_obj.label += track_obj.creator+' - ';
}
track_obj.label += track_obj.title;
} else {
track_obj.label += track_obj.annotation;
}
tracks_array.push(track_obj)
addTrack(track_obj.label);
}
}
}
playlist_array = tracks_array;
if(!playlist_size) playlist_size = playlist_array.length;
playlist_mc.tracks_mc["track_"+track_index+"_mc"].bg_mc.gotoAndStop(2)
if(autoplay){
loadTrack()
}else{
start_btn_mc.start_btn.onPress = loadTrack;
track_display_mc.display_txt.text = playlist_title+" "+DEFAULT_LOADED_PLAYLIST_MSG;
if(track_display_mc.display_txt._width>track_display_mc.mask_mc._width){
track_display_mc.onEnterFrame = scrollTitle;
}else{
track_display_mc.onEnterFrame = null;
track_display_mc.display_txt._x = 0;
}
}
}else{
annotation_txt.text = "Error opening "+playlist_url;
}
}
playlist_listener.change = function(eventObject){
annotation_txt.text = playlist_list.selectedItem.annotation;
location_txt.text = playlist_list.selectedItem.location;
}
function loadTrack(){
//Radio Mode feature by nosferathoo, more info in: https://sourceforge.net/tracker/index.php?func=detail&aid=1341940&group_id=128363&atid=711474
if (radio_mode && track_index==playlist_size-1) {
playlist_url=playlist_array[track_index].location;
for (i=0;i<playlist_mc.track_count;++i) {
removeMovieClip(playlist_mc.tracks_mc["track_"+i+"_mc"]);
}
playlist_mc.track_count=0;
playlist_size=0;
track_index=0;
autoload=true;
autoplay=true;
loadPlaylist();
return(0);
}
start_btn_mc.start_btn._visible = false;
track_display_mc.display_txt.text = playlist_array[track_index].label;
if(track_display_mc.display_txt._width>track_display_mc.mask_mc._width){
track_display_mc.onEnterFrame = scrollTitle;
}else{
track_display_mc.onEnterFrame = null;
track_display_mc.display_txt._x = 0;
}
cover_mc.content_mc["photo"+last_track_index].removeMovieClip();
mysound.loadSound(playlist_array[track_index].location,true);
play_mc.gotoAndStop(2)
//image from playlist
if(playlist_array[track_index].image!=undefined){
cover_mc.content_mc.createEmptyMovieClip("photo"+track_index,track_index)
cover_mc.content_mc["photo"+track_index].loadMovie(playlist_array[track_index].image)
}else{
}
//info button
if(playlist_array[track_index].info!=undefined){
info_mc._visible = true;
info_mc.info_btn.onPress = function(){
getURL(playlist_array[track_index].info,"_blank")
}
}else{
info_mc._visible = false;
}
_root.onEnterFrame=function(){
//HACK doesnt need to set the volume at every enterframe
mysound.setVolume(this.volume_level)
var sound_load_percent = (mysound.getBytesLoaded()/mysound.getBytesTotal())*100
track_display_mc.loader_mc.load_bar_mc._xscale = sound_load_percent;
var image_load_percent = (cover_mc.content_mc["photo"+track_index].getBytesLoaded()/cover_mc.content_mc["photo"+track_index].getBytesTotal())*100
cover_mc.load_bar_mc._xscale = image_load_percent;
if((cover_mc.content_mc["photo"+track_index].getBytesLoaded()>4)&&(image_load_percent==100)){
//image loaded
//make image fit
cover_mc.content_mc["photo"+track_index]._width = cover_mc.load_bar_mc._width
cover_mc.content_mc["photo"+track_index]._height = cover_mc.load_bar_mc._height
}
}
}
stop_btn.onRelease = stopTrack;
play_mc.play_btn.onRelease = playTrack
next_btn.onRelease = nextTrack
prev_btn.onRelease = prevTrack
mysound.onSoundComplete = nextTrack;
volume_mc.volume_btn.onPress = volumeChange;
volume_mc.volume_btn.onRelease = volume_mc.volume_btn.onReleaseOutside = function(){
this._parent.onMouseMove = this._parent.onMouseDown = null;
}
function volumeChange(){
this._parent.onMouseMove = this._parent.onMouseDown = function(){
var percent = (this._xmouse/this._width)*100
if(percent>100)percent=100;
if(percent<0)percent=0;
this.volume_bar_mc._xscale = percent
this._parent.volume_level = percent;
mysound.setVolume(percent)
}
}
function stopTrack() {
mysound.stop();
play_mc.gotoAndStop(1)
mysound.stop();
mysound.start();
mysound.stop();
_root.pause_position = 0;
};
function playTrack() {
if(play_mc._currentframe==1){ //play
seekTrack(_root.pause_position)
play_mc.gotoAndStop(2)
}else if(play_mc._currentframe==2){
_root.pause_position = mysound.position;
mysound.stop();
play_mc.gotoAndStop(1)
}
};
function seekTrack(p_offset:Number){
mysound.stop()
mysound.start(int((p_offset)/1000),1)
}
function nextTrack(){
if(track_index<playlist_size-1){
last_track_index = track_index;
track_index ++;
loadTrack();
}else{
if(repeat_playlist){
last_track_index = track_index;
track_index = 0;
loadTrack()
}
}
playlist_mc.tracks_mc["track_"+last_track_index+"_mc"].bg_mc.gotoAndStop(1)
playlist_mc.tracks_mc["track_"+track_index+"_mc"].bg_mc.gotoAndStop(2)
}
function prevTrack(){
if(track_index>0){
last_track_index = track_index;
track_index --;
loadTrack();
}
playlist_mc.tracks_mc["track_"+last_track_index+"_mc"].bg_mc.gotoAndStop(1)
playlist_mc.tracks_mc["track_"+track_index+"_mc"].bg_mc.gotoAndStop(2)
}
function scrollTitle(){
track_display_mc.display_txt._x -= 5;
if (track_display_mc.display_txt._x+track_display_mc.display_txt._width<0){
track_display_mc.display_txt._x = track_display_mc.mask_mc._width;
}
}
function resizeUI(){
bg_mc._width = Stage.width;
track_display_mc.loader_mc._width = Stage.width - track_display_mc._x - 2;
track_display_mc.mask_mc._width = track_display_mc.loader_mc._width-3;
if(track_display_mc.display_txt._width>track_display_mc.mask_mc._width){
track_display_mc.onEnterFrame = scrollTitle;
}else{
track_display_mc.onEnterFrame = null;
track_display_mc.display_txt._x = 0;
}
volume_mc._x = Stage.width - 22;
start_btn_mc._xscale = Stage.width;
//playlist area tinnier that the album cover
if(Stage.width<2.5*cover_mc._width){
//
if (Stage.height>2.5*cover_mc._height){
//send album cover to bottom
cover_mc._y = Stage.height - cover_mc._height -2- info_mc._height -2;
info_mc._y = Stage.height - info_mc._height -2;
var covervisible =1;
}else{
var covervisible =0;
//hide album cover
cover_mc._y = Stage.height;
}
//send playlist to left
playlist_mc._x = cover_mc._x;
scrollbar_mc.bg_mc._height = Stage.height - (19+(cover_mc._height+info_mc._height+4)*covervisible);
playlist_mc.bg_mc._height = Stage.height - (19+(cover_mc._height+info_mc._height+4)*covervisible);
playlist_mc.mask_mc._height = Stage.height - (23+(cover_mc._height+info_mc._height+4)*covervisible);
}else{
cover_mc._y = 17;
info_mc._y = 153;
playlist_mc._x = 138;
scrollbar_mc.bg_mc._height = Stage.height -19;
playlist_mc.bg_mc._height = Stage.height - 19;
playlist_mc.mask_mc._height = Stage.height - 23;
}
scrollbar_mc._x = Stage.width - 12;
playlist_mc.mask_mc._width = Stage.width - (playlist_mc._x + 19);
playlist_mc.bg_mc._width = Stage.width - (playlist_mc._x + 14);
}
function addTrack(track_label){
if(playlist_mc.track_count>0) {
playlist_mc.tracks_mc.track_0_mc.duplicateMovieClip("track_"+playlist_mc.track_count+"_mc",playlist_mc.track_count);
}
playlist_mc.tracks_mc["track_"+playlist_mc.track_count+"_mc"]._y += playlist_mc.track_count*14;
playlist_mc.tracks_mc["track_"+playlist_mc.track_count+"_mc"].display_txt.autoSize = "left";
playlist_mc.tracks_mc["track_"+playlist_mc.track_count+"_mc"].display_txt.text = track_label;
playlist_mc.tracks_mc["track_"+playlist_mc.track_count+"_mc"].bg_mc.index = playlist_mc.track_count;
playlist_mc.tracks_mc["track_"+playlist_mc.track_count+"_mc"].bg_mc.select_btn.onPress = function(){
last_track_index = track_index;
playlist_mc.tracks_mc["track_"+track_index+"_mc"].bg_mc.gotoAndStop(1)
track_index = this._parent.index;
playlist_mc.tracks_mc["track_"+track_index+"_mc"].bg_mc.gotoAndStop(2)
loadTrack();
}
playlist_mc.track_count ++;
}
//scroll
scrollbar_mc.up_btn.onPress = function(){
this._parent.v = -1;
this._parent.onEnterFrame = scrollTracks;
}
scrollbar_mc.down_btn.onPress = function(){
this._parent.v = 1;
this._parent.onEnterFrame = scrollTracks;
}
scrollbar_mc.up_btn.onRelease = scrollbar_mc.down_btn.onRelease = function(){
this._parent.onEnterFrame = null;
}
scrollbar_mc.handler_mc.drag_btn.onPress = function(){
var scroll_top_limit = 19;
var scroll_bottom_limit = scrollbar_mc.bg_mc._height - scrollbar_mc.handler_mc._height - 2;
this._parent.startDrag(false,this._parent._x,scroll_top_limit,this._parent._x,scroll_bottom_limit)
this._parent.isdragging = true;
this._parent.onEnterFrame = scrollTracks;
}
scrollbar_mc.handler_mc.drag_btn.onRelease = scrollbar_mc.handler_mc.drag_btn.onReleaseOutside = function(){
stopDrag()
this._parent.isdragging = false;
this._parent.onEnterFrame = null;
}
function scrollTracks(){
var scroll_top_limit = 19;
var scroll_bottom_limit = scrollbar_mc.bg_mc._height - scrollbar_mc.handler_mc._height - 2;
var list_bottom_limit = 1;
var list_top_limit = (1-Math.round(playlist_mc.tracks_mc._height))+Math.floor(playlist_mc.mask_mc._height/14)*14
if(playlist_mc.tracks_mc._height>playlist_mc.mask_mc._height){
if(scrollbar_mc.handler_mc.isdragging){
var percent = (scrollbar_mc.handler_mc._y-scroll_top_limit)/(scroll_bottom_limit-scroll_top_limit)
playlist_mc.tracks_mc._y = (list_top_limit-list_bottom_limit)*percent+list_bottom_limit;
}else{
if(scrollbar_mc.v==-1){
if(playlist_mc.tracks_mc._y+14<list_bottom_limit){
playlist_mc.tracks_mc._y += 14;
}else{
playlist_mc.tracks_mc._y = list_bottom_limit;
}
var percent = (playlist_mc.tracks_mc._y-1)/(list_top_limit-1)
scrollbar_mc.handler_mc._y = percent*(scroll_bottom_limit - scroll_top_limit)+scroll_top_limit;
}else if(scrollbar_mc.v==1){
if(playlist_mc.tracks_mc._y-14>list_top_limit){
playlist_mc.tracks_mc._y -= 14;
}else{
playlist_mc.tracks_mc._y = list_top_limit;
}
var percent = (playlist_mc.tracks_mc._y-1)/(list_top_limit-1)
scrollbar_mc.handler_mc._y = percent*(scroll_bottom_limit - scroll_top_limit)+scroll_top_limit;
}
}
}
}
function loadPlaylist(){
track_display_mc.display_txt.text = LOADING_PLAYLIST_MSG;
if(track_display_mc.display_txt._width>track_display_mc.mask_mc._width){
track_display_mc.onEnterFrame = scrollTitle;
}else{
track_display_mc.onEnterFrame = null;
track_display_mc.display_txt._x = 0;
}
//playlist
if(playlist_url){
playlist_xml.load(unescape(playlist_url))
}else{
//single track
playlist_xml.parseXML(single_music_playlist)
playlist_xml.onLoad(true);
}
}
//first click - load playlist
start_btn_mc.start_btn.onPress = function(){
autoplay = true;
loadPlaylist();
}
//main
Stage.scaleMode = "noScale"
Stage.align = "LT";
this.onResize = resizeUI;
Stage.addListener(this);
if(!player_title) player_title = DEFAULT_WELCOME_MSG;
track_display_mc.display_txt.autoSize = "left";
track_display_mc.display_txt.text = player_title;
if(track_display_mc.display_txt._width>track_display_mc.mask_mc._width){
track_display_mc.onEnterFrame = scrollTitle;
}else{
track_display_mc.onEnterFrame = null;
track_display_mc.display_txt._x = 0;
}
//start to play automatically if parameter autoplay is present
if(autoplay){
start_btn_mc.start_btn.onPress();
} else if (autoload){
loadPlaylist()
}
//customized menu
var my_cm:ContextMenu = new ContextMenu();
my_cm.customItems.push(new ContextMenuItem("Stop", stopTrack));
my_cm.customItems.push(new ContextMenuItem("Play!", playTrack));
my_cm.customItems.push(new ContextMenuItem("Next", nextTrack));
my_cm.customItems.push(new ContextMenuItem("Previous", prevTrack));
my_cm.customItems.push(new ContextMenuItem("Download this song", function(){getURL(playlist_array[track_index].location,"_blank")},true));
my_cm.customItems.push(new ContextMenuItem("Add song to Webjay playlist", function(){getURL("http://webjay.org/poster?media="+escape(playlist_array[track_index].location),"_blank")}));
my_cm.customItems.push(new ContextMenuItem("About Hideout", function(){getURL("http://www.hideout.com.br","_blank")},true));
//my_cm.customItems.push(new ContextMenuItem("Crossfade", function(){}));
//my_cm.customItems.push(new ContextMenuItem("Mando Diao - Paralyzed", function(){}));
my_cm.hideBuiltInItems();
this.menu = my_cm;
resizeUI();

Binary file not shown.

View File

@ -1,10 +0,0 @@
Copyright (c) 2005, Fabricio Zuardi
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -11,13 +11,10 @@ class SVGFileHandler extends Extension {
public function receive_event($event) {
if(is_null($this->theme)) $this->theme = get_theme_object("handle_svg", "SVGFileHandlerTheme");
if(is_a($event, 'DataUploadEvent') && $event->type == "svg" && $this->check_contents($event->tmpname)) {
if(is_a($event, 'DataUploadEvent') && $this->supported_ext($event->type) && $this->check_contents($event->tmpname)) {
$hash = $event->hash;
$ha = substr($hash, 0, 2);
if(!copy($event->tmpname, "images/$ha/$hash")) {
$event->veto("SVG Handler failed to move file from uploads to archive");
return;
}
if(!move_upload_to_archive($event)) return;
send_event(new ThumbnailGenerationEvent($event->hash, $event->type));
$image = $this->create_image_from_data("images/$ha/$hash", $event->metadata);
if(is_null($image)) {
@ -27,7 +24,7 @@ class SVGFileHandler extends Extension {
send_event(new ImageAdditionEvent($event->user, $image));
}
if(is_a($event, 'ThumbnailGenerationEvent') && $event->type == "svg") {
if(is_a($event, 'ThumbnailGenerationEvent') && $this->supported_ext($event->type)) {
$hash = $event->hash;
$ha = substr($hash, 0, 2);
@ -47,7 +44,7 @@ class SVGFileHandler extends Extension {
// }
}
if(is_a($event, 'DisplayingImageEvent') && $event->image->ext == "svg") {
if(is_a($event, 'DisplayingImageEvent') && $this->supported_ext($event->image->ext)) {
$this->theme->display_image($event->page, $event->image);
}
@ -64,14 +61,19 @@ class SVGFileHandler extends Extension {
}
}
private function supported_ext($ext) {
$exts = array("svg");
return array_contains($exts, strtolower($ext));
}
private function create_image_from_data($filename, $metadata) {
global $config;
$image = new Image();
// FIXME: ugh, xml parsing :|
$image->width = 0;
$image->height = 0;
$msp = new MiniSVGParser($filename);
$image->width = $msp->width;
$image->height = $msp->height;
$image->filesize = $metadata['size'];
$image->hash = $metadata['hash'];
@ -84,9 +86,33 @@ class SVGFileHandler extends Extension {
}
private function check_contents($file) {
// FIXME: magic header?
return (file_exists($file));
if(!file_exists($file)) return false;
$msp = new MiniSVGParser($file);
return $msp->valid;
}
}
class MiniSVGParser {
var $valid=false, $width=0, $height=0;
function MiniSVGParser($file) {
$xml_parser = xml_parser_create();
xml_set_element_handler($xml_parser, array($this, "startElement"), array($this, "endElement"));
$this->valid = xml_parse($xml_parser, file_get_contents($file), true);
xml_parser_free($xml_parser);
}
function startElement($parser, $name, $attrs) {
if($name == "SVG") {
$this->width = int_escape($attrs["WIDTH"]);
$this->height = int_escape($attrs["HEIGHT"]);
}
}
function endElement($parser, $name) {
}
}
add_event_listener(new SVGFileHandler());
?>

View File

@ -2,12 +2,11 @@
class SVGFileHandlerTheme extends Themelet {
public function display_image($page, $image) {
$link = make_link("get_svg/{$image->id}/{$image->id}.svg");
$ilink = $image->get_image_link();
// FIXME: object and embed have "height" and "width"
$ilink = make_link("get_svg/{$image->id}/{$image->id}.svg");
// $ilink = $image->get_image_link();
$html = "
<object data='$ilink' type='image/svg+xml' width='300' height='300'>
<embed src='$ilink' type='image/svg+xml' width='300' height='300' />
<object data='$ilink' type='image/svg+xml' width='{$image->width}' height='{$image->height}'>
<embed src='$ilink' type='image/svg+xml' width='{$image->width}' height='{$image->height}' />
</object>
";
$page->add_block(new Block("Image", $html, "main", 0));

View File

@ -2,7 +2,6 @@
/**
* Name: Home Extension
* Author: Bzchan <bzchan@animemahou.com>
* Link: http://trac.shishnet.org/shimmie2/
* License: GPLv2
* Description: Extension adds a page "home" containing user specified
* links and a counter showing total number of posts. The

View File

@ -36,6 +36,7 @@ EOD
<div class='space'>
<form action='".make_link("post/list")."' method='GET'>
<input id='search_input' name='search' size='55' type='text' value='' autocomplete='off' /><br/>
<input type='hidden' name='q' value='/post/list'>
<input type='submit' value='Search'/>
</form>
</div>

View File

@ -29,40 +29,30 @@ class AddImageHashBanEvent extends Event {
$this->reason = $reason;
}
}
// }}}
class Image_Hash_Ban extends Extension {
var $theme;
public function receive_event($event) {
if(is_null($this->theme)) $this->theme = get_theme_object("Image_Hash_Ban", "ImageBanTheme");
if(is_a($event, 'InitExtEvent')) {
if(is_null($this->theme)) $this->theme = get_theme_object("Image_Hash_Ban", "ImageBanTheme");
if(is_a($event, 'InitExtEvent')) {
global $config;
if($config->get_int("ext_imageban_version") < 1) {
$this->install();
}
}
if(is_a($event, 'UploadingImageEvent')) {
global $database;
$image = $event->image;
$tmp_hash = $image->hash;
if ($database->db->GetOne("SELECT COUNT(*) FROM image_bans WHERE hash = ?", $tmp_hash) == 1) {
$event->veto("This image has been banned!");
}
if(is_a($event, 'DataUploadEvent')) {
global $database;
if ($database->db->GetOne("SELECT COUNT(*) FROM image_bans WHERE hash = ?", $event->hash) == 1) {
$event->veto("This image has been banned!");
}
}
if(is_a($event, 'PageRequestEvent') && ($event->page_name == "image_hash_ban")) {
global $user;
if($user->is_admin()) {
if($event->user->is_admin()) {
if($event->get_arg(0) == "add") {
if(isset($_POST['hash']) && isset($_POST['reason'])) {
send_event(new AddImageHashBanEvent($_POST['hash'], $_POST['reason']));
@ -70,7 +60,15 @@ class Image_Hash_Ban extends Extension {
global $page;
$page->set_mode("redirect");
$page->set_redirect(make_link("admin"));
}
if(isset($_POST['image_id'])) {
global $database;
$image = $database->get_image($_POST['image_id']);
if($image) {
send_event(new ImageDeletionEvent($image));
$event->page->set_mode("redirect");
$event->page->set_redirect(make_link("post/list"));
}
}
}
else if($event->get_arg(0) == "remove") {
@ -84,60 +82,48 @@ class Image_Hash_Ban extends Extension {
}
}
}
if(is_a($event, 'AdminBuildingEvent')) {
global $page;
$this->theme->display_Image_hash_Bans($page, $this->get_image_hash_bans());
}
if(is_a($event, 'AddImageHashBanEvent')) {
if(is_a($event, 'AddImageHashBanEvent')) {
$this->add_image_hash_ban($event->hash, $event->reason);
}
if(is_a($event, 'RemoveImageHashBanEvent')) {
$this->remove_image_hash_ban($event->hash);
}
if(is_a($event, 'DisplayingImageEvent')) {
global $user;
if($user->is_admin()) {
$this->theme->display_image_banner($event->page, $event->image->hash);
if(is_a($event, 'ImageAdminBlockBuildingEvent')) {
if($event->user->is_admin()) {
$event->add_part($this->theme->get_buttons_html($event->image));
}
}
}
protected function install() {
global $database;
global $config;
$database->Execute("CREATE TABLE image_bans (
id int(11) NOT NULL auto_increment,
hash char(32) default NULL,
date datetime default NULL,
reason varchar(255) default NULL,
PRIMARY KEY (id)
)");
hash char(32) default NULL,
date datetime default NULL,
reason varchar(255) default NULL,
PRIMARY KEY (id)
)");
$config->set_int("ext_imageban_version", 1);
}
// DB funness
public function get_image_hash_bans() {
public function get_image_hash_bans() {
// FIXME: many
global $database;
$bans = $database->get_all("SELECT * FROM image_bans");
if($bans) {return $bans;}
else {return array();}
}
public function get_image_hash_ban($hash) {
global $database;
// yes, this is "? LIKE var", because ? is the thing with matching tokens
// actually, slow
// return $database->db->GetRow("SELECT * FROM bans WHERE ? LIKE ip AND date < now() AND (end > now() OR isnull(end))", array($ip));
return $database->db->GetRow("SELECT * FROM image_bans WHERE hash = ? AND date < now()", array($hash));
}
public function add_image_hash_ban($hash, $reason) {
@ -151,7 +137,7 @@ class Image_Hash_Ban extends Extension {
global $database;
$database->Execute("DELETE FROM image_bans WHERE hash = ?", array($hash));
}
}
add_event_listener(new Image_Hash_Ban(), 30); // in before resolution limit plugin
?>

View File

@ -64,19 +64,16 @@ class ImageBanTheme extends Themelet {
*
* $image_id = the image to delete
*/
public function display_image_banner($page, $image_hash) {
/* I'll fix this soon
$i_image_hash = int_escape($image_hash);
public function get_buttons_html($image) {
$html = "
<form action='".make_link("admin/image_hash_ban")."' method='POST'>
<input type='hidden' name='image_hash' value='$i_image_hash'>
<input type='field' name='reason'>
<form action='".make_link("image_hash_ban/add")."' method='POST'>
<input type='hidden' name='hash' value='{$image->hash}'>
<input type='hidden' name='image_id' value='{$image->id}'>
<input type='text' name='reason'>
<input type='submit' value='Ban and Delete'>
</form>
";
$page->add_block(new Block("Image Ban", $html, "left"));
*/
return $html;
}
}
?>
?>

208
contrib/ipban/main.php Normal file
View File

@ -0,0 +1,208 @@
<?php
/**
* Name: IP Ban
* Author: Shish <webmaster@shishnet.org>
* License: GPLv2
* Description: Ban IP addresses
* Link: http://trac.shishnet.org/shimmie2/wiki/Contrib/Extensions/IPBan
*/
// RemoveIPBanEvent {{{
class RemoveIPBanEvent extends Event {
var $id;
public function RemoveIPBanEvent($id) {
$this->id = $id;
}
}
// }}}
// AddIPBanEvent {{{
class AddIPBanEvent extends Event {
var $ip;
var $reason;
var $end;
public function AddIPBanEvent($ip, $reason, $end) {
$this->ip = $ip;
$this->reason = $reason;
$this->end = $end;
}
}
// }}}
class IPBan extends Extension {
var $theme;
// event handler {{{
public function receive_event($event) {
if(is_null($this->theme)) $this->theme = get_theme_object("ipban", "IPBanTheme");
if(is_a($event, 'InitExtEvent')) {
global $config;
if($config->get_int("ext_ipban_version") < 5) {
$this->install();
}
$this->check_ip_ban();
}
if(is_a($event, 'PageRequestEvent') && ($event->page_name == "ip_ban")) {
global $user;
if($user->is_admin()) {
if($event->get_arg(0) == "add") {
if(isset($_POST['ip']) && isset($_POST['reason']) && isset($_POST['end'])) {
if(empty($_POST['end'])) $end = null;
else $end = $_POST['end'];
send_event(new AddIPBanEvent($_POST['ip'], $_POST['reason'], $end));
$event->page->set_mode("redirect");
$event->page->set_redirect(make_link("ip_ban/list"));
}
}
else if($event->get_arg(0) == "remove") {
if(isset($_POST['id'])) {
send_event(new RemoveIPBanEvent($_POST['id']));
$event->page->set_mode("redirect");
$event->page->set_redirect(make_link("ip_ban/list"));
}
}
else if($event->get_arg(0) == "list") {
$this->theme->display_bans($event->page, $this->get_bans());
}
}
}
if(is_a($event, 'UserBlockBuildingEvent')) {
if($event->user->is_admin()) {
$event->add_link("IP Bans", make_link("ip_ban/list"));
}
}
if(is_a($event, 'AddIPBanEvent')) {
global $user;
$this->add_ip_ban($event->ip, $event->reason, $event->end, $user);
}
if(is_a($event, 'RemoveIPBanEvent')) {
global $database;
$database->Execute("DELETE FROM bans WHERE id = ?", array($event->id));
}
}
// }}}
// installer {{{
protected function install() {
global $database;
global $config;
// shortcut to latest
if($config->get_int("ext_ipban_version") < 1) {
$database->execute("
CREATE TABLE bans (
id {$database->engine->auto_increment},
banner_id INTEGER NOT NULL,
ip CHAR(15) NOT NULL,
end_timestamp INTEGER,
reason TEXT NOT NULL,
INDEX (end_timestamp)
) {$database->engine->create_table_extras};
");
$config->set_int("ext_ipban_version", 5);
}
// ===
if($config->get_int("ext_ipban_version") < 1) {
$database->Execute("CREATE TABLE bans (
id int(11) NOT NULL auto_increment,
ip char(15) default NULL,
date datetime default NULL,
end datetime default NULL,
reason varchar(255) default NULL,
PRIMARY KEY (id)
)");
$config->set_int("ext_ipban_version", 1);
}
if($config->get_int("ext_ipban_version") == 1) {
$database->execute("ALTER TABLE bans ADD COLUMN banner_id INTEGER NOT NULL AFTER id");
$config->set_int("ext_ipban_version", 2);
}
if($config->get_int("ext_ipban_version") == 2) {
$database->execute("ALTER TABLE bans DROP COLUMN date");
$database->execute("ALTER TABLE bans CHANGE ip ip CHAR(20) NOT NULL");
$database->execute("ALTER TABLE bans CHANGE reason reason TEXT NOT NULL");
$database->execute("CREATE INDEX bans__end ON bans(end)");
$config->set_int("ext_ipban_version", 3);
}
if($config->get_int("ext_ipban_version") == 3) {
$database->execute("ALTER TABLE bans CHANGE end old_end DATE NOT NULL");
$database->execute("ALTER TABLE bans ADD COLUMN end INTEGER");
$database->execute("UPDATE bans SET end = UNIX_TIMESTAMP(old_end)");
$database->execute("ALTER TABLE bans DROP COLUMN old_end");
$database->execute("CREATE INDEX bans__end ON bans(end)");
$config->set_int("ext_ipban_version", 4);
}
if($config->get_int("ext_ipban_version") == 4) {
$database->execute("ALTER TABLE bans CHANGE end end_timestamp INTEGER");
$config->set_int("ext_ipban_version", 5);
}
}
// }}}
// deal with banned person {{{
private function check_ip_ban() {
global $config;
global $database;
$remote = $_SERVER['REMOTE_ADDR'];
$bans = $this->get_active_bans();
foreach($bans as $row) {
if(
(strstr($row['ip'], '/') && ip_in_range($remote, $row['ip'])) ||
($row['ip'] == $remote)
) {
$admin = $database->get_user_by_id($row['banner_id']);
$date = date("Y-m-d", $row['end_timestamp']);
print "IP <b>{$row['ip']}</b> has been banned until <b>$date</b> by <b>{$admin->name}</b> because of <b>{$row['reason']}</b>";
$contact_link = $config->get_string("contact_link");
if(!empty($contact_link)) {
print "<p><a href='$contact_link'>Contact The Admin</a>";
}
exit;
}
}
}
// }}}
// database {{{
private function get_bans() {
global $database;
$bans = $database->get_all("
SELECT bans.*, users.name as banner_name
FROM bans
JOIN users ON banner_id = users.id
ORDER BY end_timestamp, id");
if($bans) {return $bans;}
else {return array();}
}
private function get_active_bans() {
global $database;
$bans = $database->get_all("
SELECT * FROM bans
WHERE (end_timestamp > now()) OR (end_timestamp IS NULL)
");
if($bans) {return $bans;}
else {return array();}
}
private function add_ip_ban($ip, $reason, $end, $user) {
global $database;
$sql = "INSERT INTO bans (ip, reason, end_timestamp, banner_id) VALUES (?, ?, ?, ?)";
$database->Execute($sql, array($ip, $reason, strtotime($end), $user->id));
}
// }}}
}
add_event_listener(new IPBan(), 10);
?>

View File

@ -12,13 +12,16 @@ class IPBanTheme extends Themelet {
* )
*/
public function display_bans($page, $bans) {
global $user;
$h_bans = "";
foreach($bans as $ban) {
$end_human = date('Y-m-d', $ban['end_timestamp']);
$h_bans .= "
<tr>
<td>{$ban['ip']}</td>
<td>{$ban['reason']}</td>
<td>{$ban['end']}</td>
<td>{$ban['banner_name']}</td>
<td>{$end_human}</td>
<td>
<form action='".make_link("ip_ban/remove")."' method='POST'>
<input type='hidden' name='id' value='{$ban['id']}'>
@ -30,18 +33,22 @@ class IPBanTheme extends Themelet {
}
$html = "
<table border='1'>
<thead><td>IP</td><td>Reason</td><td>Until</td><td>Action</td></thead>
<thead><td>IP</td><td>Reason</td><td>By</td><td>Until</td><td>Action</td></thead>
$h_bans
<tr>
<form action='".make_link("ip_ban/add")."' method='POST'>
<td><input type='text' name='ip'></td>
<td><input type='text' name='reason'></td>
<td>{$user->name}</td>
<td><input type='text' name='end'></td>
<td><input type='submit' value='Ban'></td>
</form>
</tr>
</table>
";
$page->set_title("IP Bans");
$page->set_heading("IP Bans");
$page->add_block(new NavBlock());
$page->add_block(new Block("Edit IP Bans", $html));
}
}

View File

@ -1,4 +1,10 @@
<?php
/**
* Name: News
* Author: Shish <webmaster@shishnet.org>
* License: GPLv2
* Description: Show a short amonut of text in a block on the post list
*/
class News extends Extension {
var $theme;

View File

@ -1,52 +0,0 @@
<?php
/**
* Name: Image Notes
* Author: Shish <webmaster@shishnet.org>
* Link: http://trac.shishnet.org/shimmie2/
* License: GPLv2
* Description: Adds notes overlaid on the images
*/
class Notes extends Extension {
var $theme;
public function receive_event($event) {
if(is_null($this->theme)) $this->theme = get_theme_object("notes", "NotesTheme");
if(is_a($event, 'InitExtEvent')) {
global $config;
if($config->get_int("ext_notes_version") < 1) {
$this->install();
}
}
if(is_a($event, 'DisplayingImageEvent')) {
global $database;
$notes = $database->get_all("SELECT * FROM image_notes WHERE image_id = ?", array($event->image->id));
$this->theme->display_notes($event->page, $notes);
}
}
protected function install() {
global $database;
global $config;
$database->Execute("CREATE TABLE image_notes (
id int(11) NOT NULL auto_increment PRIMARY KEY,
image_id int(11) NOT NULL,
user_id int(11) NOT NULL,
owner_ip char(15) NOT NULL,
created_at datetime NOT NULL,
updated_at datetime NOT NULL,
version int(11) DEFAULT 1 NOT NULL,
is_active enum('Y', 'N') DEFAULT 'Y' NOT NULL,
x int(11) NOT NULL,
y int(11) NOT NULL,
w int(11) NOT NULL,
h int(11) NOT NULL,
body text NOT NULL
)");
$config->set_int("ext_notes_version", 1);
}
}
add_event_listener(new Notes());
?>

View File

@ -1,13 +0,0 @@
<?php
class NotesTheme extends Themelet {
public function display_notes($page, $notes) {
$html = <<<EOD
<script type="text/javascript">
img = byId("main_image");
</script>
EOD;
$page->add_block(new Block(null, $html));
}
}
?>

View File

@ -2,7 +2,6 @@
/**
* Name: Image Scores (Numeric)
* Author: Shish <webmaster@shishnet.org>
* Link: http://trac.shishnet.org/shimmie2/
* License: GPLv2
* Description: Allow users to score images
*/
@ -28,52 +27,59 @@ class NumericScore extends Extension {
if($config->get_int("ext_numeric_score_version", 0) < 1) {
$this->install();
}
$config->set_default_bool("numeric_score_anon", true);
}
if(is_a($event, 'PageRequestEvent') && $event->page_name == "numeric_score" &&
$event->get_arg(0) == "vote" &&
isset($_POST['score']) && isset($_POST['image_id'])) {
$i_score = int_escape($_POST['score']);
$i_image_id = int_escape($_POST['image_id']);
if($i_score >= -1 || $i_score <= 1) {
send_event(new NumericScoreSetEvent($i_image_id, $event->user, $i_score));
if(is_a($event, 'DisplayingImageEvent')) {
global $user;
if(!$user->is_anonymous()) {
$html = $this->theme->get_voter_html($event->image);
$event->page->add_block(new Block("Image Score", $html, "left", 20));
}
$event->page->set_mode("redirect");
$event->page->set_redirect(make_link("post/view/$i_image_id"));
}
if(is_a($event, 'PageRequestEvent') && ($event->page_name == "numeric_score_vote")) {
if(!$event->user->is_anonymous()) {
$image_id = int_escape($_POST['image_id']);
$char = $_POST['vote'];
$score = 0;
if($char == "up") $score = 1;
else if($char == "down") $score = -1;
if($score != 0) send_event(new NumericScoreSetEvent($image_id, $event->user, $score));
$event->page->set_mode("redirect");
$event->page->set_redirect(make_link("post/view/$image_id"));
}
}
if(is_a($event, 'ImageInfoSetEvent')) {
global $user;
$char = $_POST['numeric_score'];
$score = 0;
if($char == "u") $score = 1;
else if($char == "d") $score = -1;
if($score != 0) send_event(new NumericScoreSetEvent($event->image_id, $user, $score));
}
if(is_a($event, 'NumericScoreSetEvent')) {
if(!$event->user->is_anonymous() || $config->get_bool("numeric_score_anon")) {
$this->add_vote($event->image_id, $event->user->id, $event->score);
}
$this->add_vote($event->image_id, $event->user->id, $event->score);
}
if(is_a($event, 'ImageInfoBoxBuildingEvent')) {
global $user;
global $config;
if(!$user->is_anonymous() || $config->get_bool("numeric_score_anon")) {
$event->add_part($this->theme->get_voter_html($event->image));
}
}
if(is_a($event, 'ImageDeletionEvent')) {
global $database;
$database->execute("DELETE FROM numeric_score_votes WHERE image_id=?", array($event->image->id));
}
if(is_a($event, 'SetupBuildingEvent')) {
$sb = new SetupBlock("Numeric Score");
$sb->add_bool_option("numeric_score_anon", "Allow anonymous votes: ");
$event->panel->add_block($sb);
}
if(is_a($event, 'ParseLinkTemplateEvent')) {
$event->replace('$score', $event->image->numeric_score);
}
if(is_a($event, 'SearchTermParseEvent')) {
$matches = array();
if(preg_match("/score(<|<=|=|>=|>)(\d+)/", $event->term, $matches)) {
$cmp = $matches[1];
$score = $matches[2];
$event->set_querylet(new Querylet("numeric_score $cmp $score"));
}
}
}
private function install() {
@ -99,7 +105,10 @@ class NumericScore extends Extension {
private function add_vote($image_id, $user_id, $score) {
global $database;
$database->Execute(
"REPLACE INTO numeric_score_votes(image_id, user_id, score) VALUES(?, ?, ?)",
"DELETE FROM numeric_score_votes WHERE image_id=? AND user_id=?",
array($image_id, $user_id));
$database->Execute(
"INSERT INTO numeric_score_votes(image_id, user_id, score) VALUES(?, ?, ?)",
array($image_id, $user_id, $score));
$database->Execute(
"UPDATE images SET numeric_score=(SELECT SUM(score) FROM numeric_score_votes WHERE image_id=?) WHERE id=?",

View File

@ -6,26 +6,19 @@ class NumericScoreTheme extends Themelet {
$i_score = int_escape($image->numeric_score);
$html = "
<table style='width: 400px;'>
<tr>
<td>Current score is $i_score</td>
<td>
<!--
<form action='".make_link("numeric_score/vote")."' method='POST'>
<input type='hidden' name='image_id' value='$i_image_id' />
<input type='hidden' name='score' value='1'>
<input type='submit' value='Vote Up' />
Current Score: $i_score
<p><form action='".make_link("numeric_score_vote")."' method='POST'>
<input type='hidden' name='image_id' value='$i_image_id'>
<input type='hidden' name='vote' value='up'>
<input type='submit' value='Vote Up'>
</form>
<p><form action='".make_link("numeric_score_vote")."' method='POST'>
<input type='hidden' name='image_id' value='$i_image_id'>
<input type='hidden' name='vote' value='down'>
<input type='submit' value='Vote Down'>
</form>
</td>
<td>
<form action='".make_link("numeric_score/vote")."' method='POST'>
<input type='hidden' name='image_id' value='$i_image_id' />
<input type='hidden' name='score' value='-1'>
<input type='submit' value='Vote Down' />
</form>-->
</td>
</tr>
</table>
";
return $html;
}

24
contrib/piclens/main.php Normal file
View File

@ -0,0 +1,24 @@
<?php
/**
* Name: PicLens Button
* Author: Shish <webmaster@shishnet.org>
* License: GPLv2
* Description: Adds a link to piclensify the gallery
*/
class PicLens extends Extension {
public function receive_event($event) {
if(is_a($event, 'PageRequestEvent')) {
$event->page->add_header("<script type=\"text/javascript\" src=\"http://lite.piclens.com/current/piclens.js\"></script>");
}
if(is_a($event, 'PostListBuildingEvent')) {
$foo='
<a href="javascript:PicLensLite.start();">Start Slideshow
<img src="http://lite.piclens.com/images/PicLensButton.png"
alt="PicLens" width="16" height="12" border="0"
align="absmiddle"></a>';
$event->page->add_block(new Block("PicLens", $foo, "left", 20));
}
}
}
add_event_listener(new PicLens());
?>

View File

@ -0,0 +1,41 @@
<?php
/**
* Name: Random Image
* Author: Shish <webmaster@shishnet.org>
* License: GPLv2
* Description: Do things with a random image
* Link: http://trac.shishnet.org/shimmie2/wiki/Contrib/Extensions/RandomImage
*/
class RandomImage extends Extension {
public function receive_event($event) {
if(is_a($event, 'PageRequestEvent') && ($event->page_name == "random_image")) {
global $database;
if($event->count_args() == 1) {
$action = $event->get_arg(0);
$search_terms = array();
}
else if($event->count_args() == 2) {
$action = $event->get_arg(0);
$search_terms = explode(' ', $event->get_arg(1));
}
$image = $database->get_random_image($search_terms);
if($event->get_arg(0) == "download") {
if(!is_null($image)) {
$event->page->set_mode("data");
$event->page->set_type("image/jpeg");
$event->page->set_data(file_get_contents($image->get_image_filename()));
}
}
if($event->get_arg(0) == "view") {
if(!is_null($image)) {
send_event(new DisplayingImageEvent($image, $event->page));
}
}
}
}
}
add_event_listener(new RandomImage());
?>

View File

@ -1,106 +0,0 @@
<?php
/**
* Name: Image Ratings
* Author: Shish <webmaster@shishnet.org>
* Link: http://trac.shishnet.org/shimmie2/
* License: GPLv2
* Description: Allow users to rate images
*/
class RatingSetEvent extends Event {
var $image_id, $user, $rating;
public function RatingSetEvent($image_id, $user, $rating) {
$this->image_id = $image_id;
$this->user = $user;
$this->rating = $rating;
}
}
class Ratings extends Extension {
var $theme;
public function receive_event($event) {
if(is_null($this->theme)) $this->theme = get_theme_object("rating", "RatingsTheme");
if(is_a($event, 'InitExtEvent')) {
global $config;
if($config->get_int("ext_ratings2_version") < 2) {
$this->install();
}
global $config;
$config->set_default_string("ext_rating_anon_privs", 'sq');
$config->set_default_string("ext_rating_user_privs", 'sq');
}
if(is_a($event, 'RatingSetEvent')) {
$this->set_rating($event->image_id, $event->rating);
}
if(is_a($event, 'ImageInfoBoxBuildingEvent')) {
global $user;
if($user->is_admin()) {
$event->add_part($this->theme->get_rater_html($event->image->id, $event->image->rating), 80);
}
}
if(is_a($event, 'ImageInfoSetEvent')) {
global $user;
if($user->is_admin()) {
send_event(new RatingSetEvent($event->image_id, $user, $_POST['rating']));
}
}
if(is_a($event, 'SetupBuildingEvent')) {
$privs = array();
$privs['Safe Only'] = 's';
$privs['Safe and Questionable'] = 'sq';
$privs['All'] = 'sqe';
$sb = new SetupBlock("Image Ratings");
$sb->add_choice_option("ext_rating_anon_privs", $privs, "Anonymous: ");
$sb->add_choice_option("ext_rating_user_privs", $privs, "<br>Logged in: ");
$event->panel->add_block($sb);
}
if(is_a($event, 'ParseLinkTemplateEvent')) {
$event->replace('$rating', $this->theme->rating_to_name($event->image->rating));
}
if(is_a($event, 'SearchTermParseEvent')) {
$matches = array();
if(preg_match("/rating=([sqe]+)/", $event->term, $matches)) {
$sqes = $matches[1];
$arr = array();
for($i=0; $i<strlen($sqes); $i++) {
$arr[] = "'" . $sqes[$i] . "'";
}
$set = join(', ', $arr);
$event->set_querylet(new Querylet("AND (rating IN ($set))"));
}
}
}
private function install() {
global $database;
global $config;
if($config->get_int("ext_ratings2_version") < 1) {
$database->Execute("ALTER TABLE images ADD COLUMN rating ENUM('s', 'q', 'e') NOT NULL DEFAULT 'q'");
$config->set_int("ext_ratings2_version", 1);
}
if($config->get_int("ext_ratings2_version") < 2) {
$database->Execute("CREATE INDEX images__rating ON images(rating)");
$config->set_int("ext_ratings2_version", 2);
}
}
private function set_rating($image_id, $rating) {
global $database;
$database->Execute("UPDATE images SET rating=? WHERE id=?", array($rating, $image_id));
}
}
add_event_listener(new Ratings());
?>

View File

@ -1,28 +0,0 @@
<?php
class RatingsTheme extends Themelet {
public function get_rater_html($image_id, $rating) {
$i_image_id = int_escape($image_id);
$s_checked = $rating == 's' ? " checked" : "";
$q_checked = $rating == 'q' ? " checked" : "";
$e_checked = $rating == 'e' ? " checked" : "";
$html = "
<input type='hidden' name='image_id' value='$i_image_id' />
<input type='radio' name='rating' value='s' id='s'$s_checked><label for='s'>Safe</label>
<input type='radio' name='rating' value='q' id='q'$q_checked><label for='q'>Questionable</label>
<input type='radio' name='rating' value='e' id='e'$e_checked><label for='e'>Explicit</label>
";
return $html;
}
public function rating_to_name($rating) {
switch($rating) {
case 's': return "Safe";
case 'q': return "Questionable";
case 'e': return "Explicit";
default: return "Unknown";
}
}
}
?>

View File

@ -1,4 +1,10 @@
<?php
/**
* Name: Regen Thumb
* Author: Shish <webmaster@shishnet.org>
* License: GPLv2
* Description: Regenerate a thumbnail image
*/
class RegenThumb extends Extension {
var $theme;
@ -16,10 +22,9 @@ class RegenThumb extends Extension {
}
}
if(is_a($event, 'DisplayingImageEvent')) {
global $user;
if($user->is_admin()) {
$this->theme->display_buttons($event->page, $event->image->id);
if(is_a($event, 'ImageAdminBlockBuildingEvent')) {
if($event->user->is_admin()) {
$event->add_part($this->theme->get_buttons_html($event->image->id));
}
}
}

View File

@ -4,14 +4,13 @@ class RegenThumbTheme extends Themelet {
/*
* Show a form which offers to regenerate the thumb of an image with ID #$image_id
*/
public function display_buttons($page, $image_id) {
$html = "
public function get_buttons_html($image_id) {
return "
<form action='".make_link("regen_thumb")."' method='POST'>
<input type='hidden' name='image_id' value='$image_id'>
<input type='submit' value='Regenerate'>
</form>
";
$page->add_block(new Block("Regen Thumb", $html, "left"));
}
/*

View File

@ -1,5 +1,4 @@
<?php
/*
* Name: Report Images
* Author: ATravelingGeek <atg@atravelinggeek.com>

View File

@ -2,7 +2,6 @@
/**
* Name: Resolution Limiter
* Author: Shish <webmaster@shishnet.org>
* Link: http://trac.shishnet.org/shimmie2/
* License: GPLv2
* Description: Allows the admin to set min / max image dimentions
*/
@ -15,6 +14,7 @@ class ResolutionLimit extends Extension {
$max_w = $config->get_int("upload_max_width", -1);
$max_h = $config->get_int("upload_max_height", -1);
$ratios = explode(" ", $config->get_string("upload_ratios", ""));
$ratios = array_filter($ratios, "strlen");
$image = $event->image;
@ -27,6 +27,7 @@ class ResolutionLimit extends Extension {
$ok = false;
foreach($ratios as $ratio) {
$parts = explode(":", $ratio);
if(count($parts) < 2) continue;
$width = $parts[0];
$height = $parts[1];
if($image->width / $width == $image->height / $height) {

View File

@ -2,7 +2,6 @@
/**
* Name: RSS for Comments
* Author: Shish <webmaster@shishnet.org>
* Link: http://trac.shishnet.org/shimmie2/
* License: GPLv2
* Description: Self explanitory
*/

View File

@ -1,4 +1,11 @@
<?php
/**
* Name: RSS for Images
* Author: Shish <webmaster@shishnet.org>
* License: GPLv2
* Description: Self explanitory
*/
class RSS_Images extends Extension {
// event handling {{{
@ -43,6 +50,8 @@ class RSS_Images extends Extension {
$link = make_link("post/view/{$image->id}");
$tags = $image->get_tag_list();
$owner = $image->get_owner();
$thumb_url = $image->get_thumb_link();
$image_url = $image->get_image_link();
$posted = strftime("%a, %d %b %Y %T %Z", $image->posted_timestamp);
$content = html_escape(
"<p>" . Themelet::build_thumb_html($image) . "</p>" .
@ -56,6 +65,8 @@ class RSS_Images extends Extension {
<guid isPermaLink=\"true\">$link</guid>
<pubDate>$posted</pubDate>
<description>$content</description>
<media:thumbnail url=\"$thumb_url\"/>
<media:content url=\"$image_url\"/>
</item>
";
}
@ -64,7 +75,7 @@ class RSS_Images extends Extension {
$base_href = $config->get_string('base_href');
$version = VERSION;
$xml = "<"."?xml version=\"1.0\" encoding=\"utf-8\" ?".">
<rss version=\"2.0\">
<rss version=\"2.0\" xmlns:media=\"http://search.yahoo.com/mrss\">
<channel>
<title>$title</title>
<description>The latest uploads to the image board</description>

View File

@ -2,12 +2,9 @@
/**
* Name: Site Description
* Author: Shish <webmaster@shishnet.org>
* Link: http://trac.shishnet.org/shimmie2/
* License: GPLv2
* Description: Sets the "description" meta-info in the page header, for
* eg search engines to read
*
* This is currently the only example of a user-contributed extension~
*/
class SiteDescription extends Extension {
public function receive_event($event) {

View File

@ -1,44 +0,0 @@
<?php
/**
* Name: Spoiler Filter
* Author: Shish <webmaster@shishnet.org>
* Link: http://trac.shishnet.org/shimmie2/
* License: GPLv2
* Description: Adds a [spoiler] tag to rot13 text inside it
*/
class Spoiler extends Extension {
public function receive_event($event) {
if(is_a($event, 'TextFormattingEvent')) {
$event->formatted = $this->filter($event->formatted);
$event->stripped = $this->strip($event->stripped);
}
}
private function filter($text) {
return str_replace(
array("[spoiler]","[/spoiler]"),
array("<span style=\"background-color:#000; color:#000;\">","</span>"),
$text);
}
private function strip($text) {
$l1 = strlen("[spoiler]");
$l2 = strlen("[/spoiler]");
while(true) {
$start = strpos($text, "[spoiler]");
if($start === false) break;
$end = strpos($text, "[/spoiler]");
if($end === false) break;
$beginning = substr($text, 0, $start);
$middle = str_rot13(substr($text, $start+$l1, ($end-$start-$l1)));
$ending = substr($text, $end + $l2, (strlen($text)-$end+$l2));
$text = $beginning . $middle . $ending;
}
return $text;
}
}
add_event_listener(new Spoiler(), 45); // before bbcode, so before <br>s are inserted
?>

View File

@ -1,79 +0,0 @@
<?php
/**
* Name: Subversion Updater
* Author: Shish <webmaster@shishnet.org>
* Link: http://trac.shishnet.org/shimmie2/
* License: GPLv2
* Description: Provides a button to check for updates
*/
class SVNUpdate extends Extension {
var $theme;
public function receive_event($event) {
if(is_null($this->theme)) $this->theme = get_theme_object("svn_update", "SVNUpdateTheme");
if(is_a($event, 'PageRequestEvent') && ($event->page_name == "update")) {
if($event->user->is_admin()) {
if($event->get_arg(0) == "view_changes") {
$this->theme->display_update_todo($event->page,
$this->get_update_log(),
$this->get_branches());
}
if($event->get_arg(0) == "update") {
$this->theme->display_update_log($event->page, $this->run_update());
}
if($event->get_arg(0) == "dump") {
$this->theme->display_update_log($event->page, $this->run_dump());
}
//if($event->get_arg(0) == "switch") {
// $this->theme->display_update_log($event->page, $this->run_update());
//}
}
}
if(is_a($event, 'AdminBuildingEvent')) {
global $page;
$this->theme->display_form($page);
}
}
private function get_update_log() {
return shell_exec("svn log -r HEAD:BASE .");
}
private function run_update() {
return shell_exec("svn update");
}
private function run_dump() {
global $database_dsn;
$matches = array();
// FIXME: MySQL specific
if(preg_match("#^mysql://([^:]+):([^@]+)@([^/]+)/([^\?]+)#", $database_dsn, $matches)) {
$date = date("Ymd");
return
shell_exec("mysqldump -uUSER -pPASS -hHOST DATABASE | gzip > db-$date.sql.gz") .
"\n\nDatabase dump should now be sitting in db-$date.sql.gz in the shimmie folder";
}
else {
return "Couldn't parse database connection string";
}
}
private function get_branches() {
$data = shell_exec("svn ls http://svn.shishnet.org/shimmie2/branches/");
$list = array();
foreach(split("\n", $data) as $line) {
$matches = array();
if(preg_match("/branch_(\d.\d+)/", $line, $matches)) {
$ver = $matches[1];
$list["branch_$ver"] = "Stable ($ver.X)";
}
}
ksort($list);
$list = array_reverse($list, true);
$list["trunk"] = "Unstable (Trunk)";
return $list;
}
}
add_event_listener(new SVNUpdate());
?>

View File

@ -1,52 +0,0 @@
<?php
class SVNUpdateTheme extends Themelet {
public function display_form($page) {
$html = "
<a href='".make_link("update/view_changes")."'>Check for Updates</a>
";
$page->add_block(new Block("Update", $html));
}
public function display_update_todo($page, $log, $branches) {
$h_log = html_escape($log);
$updates = "
<textarea rows='20' cols='80'>$h_log</textarea>
<br/>
<form action='".make_link("update/update")."' method='POST'>
<input type='submit' value='Install Updates'>
</form>
";
$options = "";
foreach($branches as $name => $nice) {
$options .= "<option value='$name'>$nice</option>";
}
$branches = "
<form action='".make_link("update/switch")."' method='POST'>
<select name='branch'>
$options
</select>
<input type='submit' value='Change Branch'>
</form>
";
$page->set_title("Updates Available");
$page->set_heading("Updates Available");
$page->add_block(new NavBlock());
$page->add_block(new Block("Updates For Current Branch", $updates));
$page->add_block(new Block("Available Branches", $branches));
}
public function display_update_log($page, $log) {
$h_log = html_escape($log);
$html = "
<textarea rows='20' cols='80'>$h_log</textarea>
";
$page->set_title("Update Log");
$page->set_heading("Update Log");
$page->add_block(new NavBlock());
$page->add_block(new Block("Update Log", $html));
}
}
?>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

View File

@ -1,174 +0,0 @@
<?php
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Name: Tagger *
* Description: Advanced Tagging v2 *
* Author: Artanis (Erik Youngren) <artanis.00@gmail.com> *
* Do not remove this notice. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
class Tagger extends Extension {
var $theme;
public function receive_event ($event) {
if(is_null($this->theme))
$this->theme = get_theme_object("tagger", "taggerTheme");
if(is_a($event,'DisplayingImageEvent')) {
global $page, $config, $user;
if($config->get_bool("tag_edit_anon")
|| ($user->id != $config->get_int("anon_id"))
&& $config->get_bool("ext_tagger_enabled"))
{
$this->theme->build_tagger($page,$event);
}
}
if(is_a($event,'SetupBuildingEvent')) {
$sb = new SetupBlock("Tagger");
$sb->add_bool_option("ext_tagger_enabled","Enable Tagger");
$sb->add_int_option("ext_tagger_search_delay","<br/>Delay queries by ");
$sb->add_label(" milliseconds.");
$sb->add_label("<br/>Limit queries returning more than ");
$sb->add_int_option("ext_tagger_tag_max");
$sb->add_label(" tags to ");
$sb->add_int_option("ext_tagger_limit");
$event->panel->add_block($sb);
}
}
} add_event_listener( new tagger());
// Tagger AJAX back-end
class TaggerXML extends Extension {
public function receive_event($event) {
if(is_a($event,'PageRequestEvent')
&& $event->page_name == "tagger"
&& $event->get_arg(0) == "tags")
{
global $page;
//$match_tags = null;
//$image_tags = null;
$tags=null;
if (isset($_GET['s'])) { // tagger/tags[/...]?s=$string
// return matching tags in XML form
$tags = $this->match_tag_list($_GET['s']);
} else if($event->get_arg(1)) { // tagger/tags/$int
// return arg[1] AS image_id's tag list in XML form
$tags = $this->image_tag_list($event->get_arg(1));
}
$xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n".
"<tags>".
$tags.
"</tags>";
$page->set_mode("data");
$page->set_type("text/xml");
$page->set_data($xml);
}
}
private function match_tag_list ($s) {
global $database, $config, $event;
$max_rows = $config->get_int("ext_tagger_tag_max",30);
$limit_rows = $config->get_int("ext_tagger_limit",30);
$values = array();
// Match
$p = strlen($s) == 1? " ":"\_";
$sq = "%".$p.mysql_real_escape_string($s)."%";
$match = "concat(?,tag) LIKE ?";
array_push($values,$p,$sq);
// Exclude
// $exclude = $event->get_arg(1)? "AND NOT IN ".$this->image_tags($event->get_arg(1)) : null;
// Hidden Tags
$hidden = $config->get_string('ext-tagger_show-hidden','N')=='N' ?
"AND substring(tag,1,1) != '.'" : null;
$q_where = "WHERE {$match} {$hidden} AND count > 0";
// FROM based on return count
$q_from = null;
$count = $this->count($q_where,$values);
if ($count > $max_rows) {
$q_from = "FROM (SELECT * FROM `tags` {$q_where} ".
"ORDER BY count DESC LIMIT 0, {$limit_rows}) AS `c_tags`";
$q_where = null;
$count = array("max"=>$count);
} else {
$q_from = "FROM `tags`";
$count = null;
}
$tags = $database->Execute("
SELECT *
{$q_from}
{$q_where}
ORDER BY tag",
$values);
return $this->list_to_xml($tags,"search",$s,$count);
}
private function image_tag_list ($image_id) {
global $database;
$tags = $database->Execute("
SELECT tags.*
FROM image_tags JOIN tags ON image_tags.tag_id = tags.id
WHERE image_id=? ORDER BY tag", array($image_id));
return $this->list_to_xml($tags,"image",$image_id);
}
private function list_to_xml ($tags,$type,$query,$misc=null) {
$r = $tags->_numOfRows;
$s_misc = "";
if(!is_null($misc))
foreach($misc as $attr => $val) $s_misc .= " ".$attr."=\"".$val."\"";
$result = "<list id=\"$type\" query=\"$query\" rows=\"$r\"{$s_misc}>";
foreach($tags as $tag) {
$result .= $this->tag_to_xml($tag);
}
return $result."</list>";
}
private function tag_to_xml ($tag) {
return
"<tag ".
"id=\"".$tag['id']."\" ".
"count=\"".$tag['count']."\">".
html_escape($tag['tag']).
"</tag>";
}
private function count($query,$values) {
global $database;
return $database->Execute(
"SELECT COUNT(*) FROM `tags` $query",$values)->fields['COUNT(*)'];
}
private function image_tags ($image_id) {
global $database;
$list = "(";
$i_tags = $database->Execute(
"SELECT tag_id FROM `image_tags` WHERE image_id=?",
array($image_id));
$b = false;
foreach($i_tags as $tag) {
if($b)
$list .= ",";
$b = true;
$list .= $tag['tag_id'];
}
$list .= ")";
return $list;
}
} add_event_listener( new taggerXML(),10);
?>

View File

@ -1,218 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Tagger - Advanced Tagging v2 *
* Author: Artanis (Erik Youngren <artanis.00@gmail.com>) *
* Do not remove this notice. *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
var Tagger = {
initialize : function (image_id) {
// object navigation
this.tag.parent = this;
this.position.parent = this;
// components
this.editor.container = byId('tagger_parent');
this.editor.titlebar = byId('tagger_titlebar');
this.editor.toolbar = byId('tagger_toolbar');
//this.editor.menu = byId('tagger_p-menu');
this.editor.body = byId('tagger_body');
this.editor.tags = byId('tagger_tags');
this.editor.form = this.editor.tags.parentNode;
this.editor.statusbar = byId('tagger_statusbar');
// initial data
this.tag.image = image_id;
this.tag.query = config.make_link("tagger/tags");
this.tag.list = null;
this.tag.suggest = null;
this.tag.image_tags();
// reveal
this.editor.container.style.display = "";
// dragging
DragHandler.attach(this.editor.titlebar);
// positioning
this.position.load();
// events
window.onunload = function () { Tagger.position.save(); };
},
alert : function (type,text,timeout) {
var id = "tagger_alert-"+type
var t_alert = byId(id);
if (t_alert) {
if(text == false) {
// remove
t_alert.parentNode.removeChild(t_alert);
} else {
// update
t_alert.innerHTML = text;
}
} else if (text) {
// create
var t_alert = document.createElement("div");
t_alert.setAttribute("id",id);
t_alert.appendChild(document.createTextNode(text));
this.editor.statusbar.appendChild(t_alert);
if(timeout>1) {
console.log("Tagger.alert('"+type+"',false,0)");
setTimeout("Tagger.alert('"+type+"',false,0)",timeout);
}
}
},
editor : {},
tag : {
submit : function () {
var l = this.list.childNodes.length;
var tags = Array();
for(var i=0; i<l; i++) {
var s_tag = this.list.childNodes[i].firstChild.data;
tags.push(s_tag);
}
tags = tags.join(" ");
this.parent.editor.tags.value = tags;
return true;
},
search : function(s,ms) {
clearTimeout(Tagger.tag.timer);
Tagger.tag.timer = setTimeout(
"Tagger.tag.ajax('"+Tagger.tag.query+"?s="+s+"',Tagger.tag.receive)",
ms);
},
receive : function (xml) {
if(xml) {
Tagger.tag.suggest = document.importNode(
xml.responseXML.getElementsByTagName("list")[0],true);
Tagger.tag.publish(Tagger.tag.suggest,byId("tagger_p-search"));
}
if(Tagger.tag.suggest.getAttribute("max")) {
var rows = Tagger.tag.suggest.getAttribute("rows");
var max = Tagger.tag.suggest.getAttribute("max");
Tagger.alert("maxout","Showing "+rows+" of "+max+" tags",0);
} else {
Tagger.alert("maxout",false);
}
},
image_tags : function(xml) {
if (!xml) {
this.ajax(this.query+"/"+this.image,this.image_tags);
return true;
} else {
Tagger.tag.list = document.importNode(
xml.responseXML.getElementsByTagName("list")[0],true);
Tagger.tag.publish(Tagger.tag.list,byId("tagger_p-applied"));
}
},
publish : function (list, page) {
list.setAttribute("xmlns","http://www.w3.org/1999/xhtml");
var l = list.childNodes.length;
for(var i=0; i<l; i++) {
var tag = list.childNodes[i];
tag.onclick = function () {
Tagger.tag.toggle(this);
byId("tagger_filter").select();
};
tag.setAttribute("title",tag.getAttribute("count")+" uses");
}
page.innerHTML = "";
page.appendChild(list);
},
create : function (tag_name) {
if(tag_name.length > 0) {
var tag = document.createElement("tag");
tag.setAttribute("count","0");
tag.setAttribute("id","newTag_"+tag_name);
tag.setAttribute("title","New - 0 uses");
tag.onclick = function() {
Tagger.tag.toggle(this);
};
tag.appendChild(document.createTextNode(tag_name));
Tagger.tag.list.appendChild(tag);
}
},
toggle : function (tag) {
if(tag.parentNode == this.list) {
this.list.removeChild(tag);
} else {
this.list.appendChild(tag);
}
},
ajax : function (url, callback) {
var http = (new XMLHttpRequest || new ActiveXObject("Microsoft.XMLHTTP"));
http.open("GET",url,true);
http.onreadystatechange = function () {
if(http.readyState == 4) callback(http);
};
http.send(null);
}
},
position : {
set : function (x,y) {
if (!x || !y) {
with(this.parent.editor.container.style) {
top = "25px";
left = "";
right = "25px";
bottom = "";
}
var xy = this.get();
x = xy[0];
y = xy[1];
}
with(this.parent.editor.container.style) {
top = y+"px";
left = x+"px";
right = "";
bottom = "";
}
},
get : function () {
// http://www.quirksmode.org/js/findpos.html
var left = 0;
var top = 0;
var obj = this.parent.editor.container;
if(obj.offsetParent) {
left = obj.offsetLeft;
top = obj.offsetTop;
while (obj = obj.offsetParent) {
left += obj.offsetLeft;
top += obj.offsetTop;
}
}
return [left,top];
},
save : function (x,y) {
if (!x || !y) {
var xy = this.get();
x = xy[0];
y = xy[1];
}
setCookie(config.title+"_tagger-position",x+" "+y,14);
},
load : function () {
var p = getCookie(config.title+"_tagger-position");
if(p) {
var xy = p.split(" ");
this.set(xy[0],xy[1]);
} else {
this.set();
}
}
}
};

View File

@ -1,104 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tagger - Advanced Tagging v2 *
* Author: Artanis (Erik Youngren <artanis.00@gmail.com>) *
* Do not remove this notice. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#tagger_parent {
text-align:left;
position:fixed;
max-width:300px;
}
#tagger_parent * {
background-color:#EEE;
}
#tagger_titlebar {
background-color:#ddd;
border:2px solid;
cursor:move;
font-weight:bold;
-moz-border-radius:5px 5px 0 0;
padding:.25em;
text-align:center;
}
#tagger_toolbar, #tagger_body {
padding:2px 2px 0 2px;
border-style:solid;
border-width: 0px 2px 0px 2px;
}
#tagger_body {
max-height:175px;
overflow:auto;
overflow-x:hidden;
overflow-y:auto;
}
#tagger_statusbar {
background-color:#ddd;
border:2px solid;
font-weight: bold;
min-height:16px;
-moz-border-radius:0 0 5px 5px;
padding:.25em;
} #tagger_statusbar * { background-color:#ddd; }
#tagger_body div {
padding-top:2px;
margin-top:2px;
border-top:1px solid;
}
/* Tagger Styling
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#tagger_parent form {
display:inline;
}
#tagger_parent input {
width:auto;
}
#tagger_parent input[type=text] {
background-color:white;
}
/* Custom Element Base Styles
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#tagger_parent list {
display: block;
}
#tagger_parent tag {
font-size:1.25em;
display:block;
}
#tagger_parent list[id=image] tag:before {
content:url('./images/active.png');
}
#tagger_parent list[id=search] tag:before {
content:url('./images/inactive.png');
}
/* Hovering */
#tagger_parent tag:hover {
cursor:pointer;
background-color:#ddd;
}
/*#tagger_parent list[id=image] tag:hover {
background-color:#faa;
}
#tagger_parent list[id=search] tag:hover {
background-color:#afa;
}*/
#tagger_parent list[id=image] tag:hover:before {
content:url('./images/rem-tag.png');
}
#tagger_parent list[id=search] tag:hover:before {
content:url('./images/add-tag.png');
}

View File

@ -1,65 +0,0 @@
<?php
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tagger - Advanced Tagging v2 *
* Author: Artanis (Erik Youngren <artanis.00@gmail.com>) *
* Do not remove this notice. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
class taggerTheme extends Themelet {
public function build_tagger ($page, $event) {
global $config;
// Initialization code
$base_href = $config->get_string('base_href');
// TODO: AJAX test and fallback.
$page->add_header("<script src='$base_href/ext/tagger/webtoolkit.drag.js' type='text/javascript'></script>");
$page->add_block(new Block(null,
"<script type='text/javascript'>Tagger.initialize("
.$event->get_image()->id.");</script>","main",1000));
// Tagger block
$page->add_block( new Block(
null,
$this->html($event->get_image()),
"main"));
}
private function html($image) {
global $config;
$i_image_id = int_escape($image->id);
$h_source = html_escape($image->source);
$h_query = isset($_GET['search'])? $h_query= "search=".url_escape($_GET['search']) : "";
$delay = $config->get_string("ext_tagger_search_delay","250");
$url_form = make_link("tag_edit/set");
// TODO: option for initial Tagger window placement.
$html = <<< EOD
<div id="tagger_parent" style="display:none; top:25px; right:25px;">
<div id="tagger_titlebar">Tagger</div>
<div id="tagger_toolbar">
<input type="text" value="" id="tagger_filter" onkeyup="Tagger.tag.search(this.value, $delay);"></input>
<input type="button" value="Add" onclick="Tagger.tag.create(byId('tagger_filter').value);"></input>
<form action="$url_form" method="POST" onsubmit="Tagger.tag.submit();">
<input type='hidden' name='image_id' value='$i_image_id' id="image_id"></input>
<input type='hidden' name='query' value='$h_query'></input>
<input type='hidden' name='source' value='$h_source'></input>
<input type="hidden" name="tags" value="" id="tagger_tags"></input>
<input type="submit" value="Set"></input>
</form>
<!--<ul id="tagger_p-menu"></ul>
<br style="clear:both;"/>-->
</div>
<div id="tagger_body">
<div id="tagger_p-search" name="Searched Tags"></div>
<div id="tagger_p-applied" name="Applied Tags"></div>
</div>
<div id="tagger_statusbar"></div>
</div>
EOD;
return $html;
}
}
?>

View File

@ -1,85 +0,0 @@
/**
*
* Crossbrowser Drag Handler
* http://www.webtoolkit.info/
*
* Modified by Erik Youngren to move parent node
**/
var DragHandler = {
// private property.
_oElem : null,
// public method. Attach drag handler to an element.
attach : function(oElem) {
oElem.onmousedown = DragHandler._dragBegin;
// callbacks
oElem.dragBegin = new Function();
oElem.drag = new Function();
oElem.dragEnd = new Function();
return oElem;
},
// private method. Begin drag process.
_dragBegin : function(e) {
var oElem = DragHandler._oElem = this;
if (isNaN(parseInt(oElem.parentNode.style.left))) { oElem.parentNode.style.left = '0px'; }
if (isNaN(parseInt(oElem.parentNode.style.top))) { oElem.parentNode.style.top = '0px'; }
var x = parseInt(oElem.parentNode.style.left);
var y = parseInt(oElem.parentNode.style.top);
e = e ? e : window.event;
oElem.mouseX = e.clientX;
oElem.mouseY = e.clientY;
oElem.dragBegin(oElem, x, y);
document.onmousemove = DragHandler._drag;
document.onmouseup = DragHandler._dragEnd;
return false;
},
// private method. Drag (move) element.
_drag : function(e) {
var oElem = DragHandler._oElem;
var x = parseInt(oElem.parentNode.style.left);
var y = parseInt(oElem.parentNode.style.top);
e = e ? e : window.event;
oElem.parentNode.style.left = x + (e.clientX - oElem.mouseX) + 'px';
oElem.parentNode.style.top = y + (e.clientY - oElem.mouseY) + 'px';
oElem.mouseX = e.clientX;
oElem.mouseY = e.clientY;
oElem.drag(oElem, x, y);
return false;
},
// private method. Stop drag process.
_dragEnd : function() {
var oElem = DragHandler._oElem;
var x = parseInt(oElem.parentNode.style.left);
var y = parseInt(oElem.parentNode.style.top);
oElem.dragEnd(oElem, x, y);
document.onmousemove = null;
document.onmouseup = null;
DragHandler._oElem = null;
}
}

View File

@ -1,105 +0,0 @@
<?php
/**
* Name: Image Scores (Text)
* Author: Shish <webmaster@shishnet.org>
* Link: http://trac.shishnet.org/shimmie2/
* License: GPLv2
* Description: Allow users to score images
*/
class TextScoreSetEvent extends Event {
var $image_id, $user, $score;
public function TextScoreSetEvent($image_id, $user, $score) {
$this->image_id = $image_id;
$this->user = $user;
$this->score = $score;
}
}
class TextScore extends Extension {
var $theme;
public function receive_event($event) {
if(is_null($this->theme)) $this->theme = get_theme_object("text_score", "TextScoreTheme");
if(is_a($event, 'InitExtEvent')) {
global $config;
if($config->get_int("ext_text_score_version", 0) < 1) {
$this->install();
}
$config->set_default_bool("text_score_anon", true);
}
if(is_a($event, 'ImageInfoBoxBuildingEvent')) {
global $user;
global $config;
if(!$user->is_anonymous() || $config->get_bool("text_score_anon")) {
$event->add_part($this->theme->get_scorer_html($event->image));
}
}
if(is_a($event, 'ImageInfoSetEvent')) {
global $user;
$i_score = int_escape($_POST['text_score__score']);
if($i_score >= -2 || $i_score <= 2) {
send_event(new TextScoreSetEvent($event->image_id, $user, $i_score));
}
}
if(is_a($event, 'TextScoreSetEvent')) {
if(!$event->user->is_anonymous() || $config->get_bool("text_score_anon")) {
$this->add_vote($event->image_id, $event->user->id, $event->score);
}
}
if(is_a($event, 'ImageDeletionEvent')) {
global $database;
$database->execute("DELETE FROM text_score_votes WHERE image_id=?", array($event->image->id));
}
if(is_a($event, 'SetupBuildingEvent')) {
$sb = new SetupBlock("Text Score");
$sb->add_bool_option("text_score_anon", "Allow anonymous votes: ");
$event->panel->add_block($sb);
}
if(is_a($event, 'ParseLinkTemplateEvent')) {
$event->replace('$text_score', $this->theme->score_to_name($event->image->text_score));
}
}
private function install() {
global $database;
global $config;
if($config->get_int("ext_text_score_version") < 1) {
$database->Execute("ALTER TABLE images ADD COLUMN text_score INTEGER NOT NULL DEFAULT 0");
$database->Execute("CREATE INDEX images__text_score ON images(text_score)");
$database->Execute("
CREATE TABLE text_score_votes (
image_id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
score INTEGER NOT NULL,
UNIQUE(image_id, user_id),
INDEX(image_id)
)
");
$config->set_int("ext_text_score_version", 1);
}
}
private function add_vote($image_id, $user_id, $score) {
global $database;
// TODO: update if already voted
$database->Execute(
"REPLACE INTO text_score_votes(image_id, user_id, score) VALUES(?, ?, ?)",
array($image_id, $user_id, $score));
$database->Execute(
"UPDATE images SET text_score=(SELECT AVG(score) FROM text_score_votes WHERE image_id=?) WHERE id=?",
array($image_id, $image_id));
}
}
add_event_listener(new TextScore());
?>

View File

@ -1,33 +0,0 @@
<?php
class TextScoreTheme extends Themelet {
public function get_scorer_html($image) {
$i_image_id = int_escape($image->id);
$s_score = $this->score_to_name($image->text_score);
$html = "
Current score is \"$s_score\"
<br/>
<input type='hidden' name='image_id' value='$i_image_id' />
<input type='radio' name='text_score__score' value='-2' id='-2'><label for='-2'>Delete</label>
<input type='radio' name='text_score__score' value='-1' id='-1'><label for='-1'>Bad</label>
<input type='radio' name='text_score__score' value='0' id='0' ><label for='0' >Ok</label>
<input type='radio' name='text_score__score' value='1' id='1' ><label for='1' >Good</label>
<input type='radio' name='text_score__score' value='2' id='2' ><label for='2' >Favourite</label>
";
return $html;
}
public function score_to_name($score) {
$words = array();
$words[-2] = "Delete";
$words[-1] = "Bad";
$words[ 0] = "Ok";
$words[ 1] = "Good";
$words[ 2] = "Favourite";
$s_score = $words[$score];
return $s_score;
}
}
?>

View File

@ -2,10 +2,8 @@
/**
* Name: Simple Wiki
* Author: Shish <webmaster@shishnet.org>
* Link: http://trac.shishnet.org/shimmie2/
* License: GPLv2
* Description: A simple wiki, for those who don't want the
* hugeness of mediawiki
* Description: A simple wiki, for those who don't want the hugeness of mediawiki
*/
// WikiUpdateEvent {{{

View File

@ -2,7 +2,6 @@
/**
* Name: Word Filter
* Author: Shish <webmaster@shishnet.org>
* Link: http://trac.shishnet.org/shimmie2/
* License: GPLv2
* Description: Simple search and replace
*/

View File

@ -1,4 +1,10 @@
<?php
/**
* Name: Image Zoom
* Author: Shish <webmaster@shishnet.org>
* License: GPLv2
* Description: Scales down too-large images using browser based scaling
*/
class Zoom extends Extension {
var $theme;

View File

@ -12,15 +12,19 @@ class ZoomTheme extends Themelet {
<script type="text/javascript">
img = document.getElementById("main_image");
img.onclick = function() {scale(img);};
if(img) {
img.onclick = function() {scale(img);};
msg_div = document.createElement("div");
msg_div.id = "msg_div";
msg_div.appendChild(document.createTextNode("Note: Image has been scaled to fit the screen; click to enlarge"));
msg_div.style.display="none";
img.parentNode.insertBefore(msg_div, img);
msg_div = document.createElement("div");
msg_div.id = "msg_div";
msg_div.appendChild(document.createTextNode("Note: Image has been scaled to fit the screen; click to enlarge"));
msg_div.style.display="none";
img.parentNode.insertBefore(msg_div, img);
orig_width = $image_width;
orig_width = $image_width;
$default
}
function scale(img) {
if(orig_width >= img.parentNode.clientWidth * 0.9) {
@ -34,8 +38,6 @@ function scale(img) {
}
}
}
$default
</script>
EOD;
}

93
core/compat.inc.php Normal file
View File

@ -0,0 +1,93 @@
<?php
/*
* Functions which are only in some versions of PHP,
* or only implemented on some platforms
*/
# (PHP 5 >= 5.2.1)
# Based on http://www.phpit.net/
# article/creating-zip-tar-archives-dynamically-php/2/
if(!function_exists('sys_get_temp_dir')) {
function sys_get_temp_dir() {
// Try to get from environment variable
if(!empty($_ENV['TMP'])) {
return realpath($_ENV['TMP']);
}
else if(!empty($_ENV['TMPDIR'])) {
return realpath($_ENV['TMPDIR']);
}
else if(!empty($_ENV['TEMP'])) {
return realpath($_ENV['TEMP']);
}
// Detect by creating a temporary file
else {
// Try to use system's temporary directory
// as random name shouldn't exist
$temp_file = tempnam(md5(uniqid(rand(), TRUE)), '');
if($temp_file) {
$temp_dir = realpath(dirname($temp_file));
unlink($temp_file);
return $temp_dir;
}
else {
return FALSE;
}
}
}
}
# (PHP >= 5.1)
# from http://www.php.net/inet_pton
if(!function_exists('inet_pton')) {
function inet_pton($ip) {
# ipv4
if(strpos($ip, '.') !== FALSE) {
$ip = pack('N',ip2long($ip));
}
# ipv6
else if(strpos($ip, ':') !== FALSE) {
$ip = explode(':', $ip);
$res = str_pad('', (4*(8-count($ip))), '0000', STR_PAD_LEFT);
foreach($ip as $seg) {
$res .= str_pad($seg, 4, '0', STR_PAD_LEFT);
}
$ip = pack('H'.strlen($res), $res);
}
return $ip;
}
}
# (PHP >= 5.1)
# from http://www.php.net/inet_ntop
if(!function_exists('inet_ntop')) {
function inet_ntop($ip) {
if (strlen($ip)==4) {
// ipv4
list(,$ip)=unpack('N',$ip);
$ip=long2ip($ip);
} elseif(strlen($ip)==16) {
// ipv6
$ip=bin2hex($ip);
$ip=substr(chunk_split($ip,4,':'),0,-1);
$ip=explode(':',$ip);
$res='';
foreach($ip as $seg) {
while($seg{0}=='0') $seg=substr($seg,1);
if ($seg!='') {
$res.=($res==''?'':':').$seg;
} else {
if (strpos($res,'::')===false) {
if (substr($res,-1)==':') continue;
$res.=':';
continue;
}
$res.=($res==''?'':':').'0';
}
}
$ip=$res;
}
return $ip;
}
}
?>

View File

@ -1,5 +1,6 @@
<?php
$ADODB_CACHE_DIR="./data";
require_once "compat.inc.php";
$ADODB_CACHE_DIR=sys_get_temp_dir();
require_once "lib/adodb/adodb.inc.php";
/* Querylet {{{
@ -27,7 +28,42 @@ class Querylet {
public function add_variable($var) {
$this->variables[] = $var;
}
} // }}}
}
class TagQuerylet {
var $tag;
var $positive;
public function TagQuerylet($tag, $positive) {
$this->tag = $tag;
$this->positive = $positive;
}
}
class ImgQuerylet {
var $qlet;
var $positive;
public function ImgQuerylet($qlet, $positive) {
$this->qlet = $qlet;
$this->positive = $positive;
}
}
// }}}
// {{{ dbengines
class DBEngine {
var $name = null;
var $auto_increment = null;
var $create_table_extras = "";
}
class MySQL extends DBEngine {
var $name = "mysql";
var $auto_increment = "INTEGER PRIMARY KEY auto_increment";
var $create_table_extras = "TYPE=INNODB DEFAULT CHARSET='utf8'";
}
class PostgreSQL extends DBEngine {
var $name = "pgsql";
var $auto_increment = "SERIAL PRIMARY KEY";
}
//}}}
/*
* A class for controlled database access, available through "global $database"
@ -36,6 +72,8 @@ class Database {
var $db;
var $extensions;
var $get_images = "SELECT images.*,UNIX_TIMESTAMP(posted) AS posted_timestamp FROM images ";
var $engine = null;
var $cache_hits = 0, $cache_misses = 0;
/*
* Create a new database object using connection info
@ -44,7 +82,9 @@ class Database {
public function Database() {
if(is_readable("config.php")) {
require_once "config.php";
$this->engine = new MySQL();
$this->db = @NewADOConnection($database_dsn);
$this->use_memcache = isset($memcache);
if($this->db) {
$this->db->SetFetchMode(ADODB_FETCH_ASSOC);
$this->db->Execute("SET NAMES utf8"); // FIXME: mysql specific :|
@ -63,6 +103,10 @@ class Database {
";
exit;
}
if($this->use_memcache) {
$this->memcache = new Memcache;
$this->memcache->pconnect('localhost', 11211) or ($this->use_memcache = false);
}
}
else {
header("Location: install.php");
@ -70,20 +114,54 @@ class Database {
}
}
// memcache {{{
public function cache_get($key) {
assert(!is_null($key));
if($this->use_memcache) {
$val = $this->memcache->get($key);
if($val) {
$this->cache_hits++;
return $val;
}
else {
$this->cache_misses++;
}
}
return false;
}
public function cache_set($key, $val, $time=0) {
assert(!is_null($key));
if($this->use_memcache) {
$this->memcache->set($key, $val, false, $time);
}
}
public function cache_delete($key) {
assert(!is_null($key));
if($this->use_memcache) {
$this->memcache->delete($key);
}
}
// }}}
// misc {{{
public function count_pages($tags=array()) {
global $config;
$images_per_page = $config->get_int('index_width') * $config->get_int('index_height');
public function count_images($tags=array()) {
if(count($tags) == 0) {
return ceil($this->db->GetOne("SELECT COUNT(*) FROM images") / $images_per_page);
return $this->db->GetOne("SELECT COUNT(*) FROM images");
}
else {
$querylet = $this->build_search_querylet($tags);
$result = $this->execute($querylet->sql, $querylet->variables);
return ceil($result->RecordCount() / $images_per_page);
return $result->RecordCount();
}
}
public function count_pages($tags=array()) {
global $config;
$images_per_page = $config->get_int('index_width') * $config->get_int('index_height');
return ceil($this->count_images($tags) / $images_per_page);
}
public function execute($query, $args=array()) {
$result = $this->db->Execute($query, $args);
if($result === False) {
@ -107,6 +185,10 @@ class Database {
}
public function upgrade_schema($filename) {
$this->install_schema($filename);
}
public function install_schema($filename) {
//print "<br>upgrading $filename";
global $config;
@ -128,6 +210,7 @@ class Database {
// }}}
// tags {{{
public function resolve_alias($tag) {
assert(is_string($tag));
$newtag = $this->db->GetOne("SELECT newtag FROM aliases WHERE oldtag=?", array($tag));
if(!empty($newtag)) {
return $newtag;
@ -137,6 +220,7 @@ class Database {
}
public function sanitise($tag) {
assert(is_string($tag));
$tag = preg_replace("/[\s?*]/", "", $tag);
$tag = preg_replace("/\.+/", ".", $tag);
$tag = preg_replace("/^(\.+[\/\\\\])+/", "", $tag);
@ -144,11 +228,13 @@ class Database {
}
private function build_search_querylet($terms) {
$tag_search = new Querylet("0");
$tag_querylets = array();
$img_querylets = array();
$positive_tag_count = 0;
$negative_tag_count = 0;
$img_search = new Querylet("");
// turn each term into a specific type of querylet
foreach($terms as $term) {
$negative = false;
if((strlen($term) > 0) && ($term[0] == '-')) {
@ -161,28 +247,54 @@ class Database {
$stpe = new SearchTermParseEvent($term);
send_event($stpe);
if($stpe->is_querylet_set()) {
$img_search->append($stpe->get_querylet());
$img_querylets[] = new ImgQuerylet($stpe->get_querylet(), !$negative);
}
else {
$term = str_replace("*", "%", $term);
$term = str_replace("?", "_", $term);
if(!preg_match("/^[%_]+$/", $term)) {
$sign = $negative ? "-" : "+";
if($sign == "+") $positive_tag_count++;
else $negative_tag_count++;
$tag_search->append(new Querylet(" $sign (tag LIKE ?)", array($term)));
$tag_querylets[] = new TagQuerylet($term, !$negative);
}
}
}
// merge all the tag querylets into one generic one
$sql = "0";
$terms = array();
foreach($tag_querylets as $tq) {
$sign = $tq->positive ? "+" : "-";
$sql .= " $sign (tag LIKE ?)";
$terms[] = $tq->tag;
if($sign == "+") $positive_tag_count++;
else $negative_tag_count++;
}
$tag_search = new Querylet($sql, $terms);
// merge all the image metadata searches into one generic querylet
$n = 0;
$sql = "";
$terms = array();
foreach($img_querylets as $iq) {
if($n++ > 0) $sql .= " AND";
if(!$iq->positive) $sql .= " NOT";
$sql .= " (" . $iq->qlet->sql . ")";
$terms = array_merge($terms, $iq->qlet->variables);
}
$img_search = new Querylet($sql, $terms);
// no tags, do a simple search (+image metadata if we have any)
if($positive_tag_count + $negative_tag_count == 0) {
$query = new Querylet($this->get_images);
if(strlen($img_search->sql) > 0) {
$query->append_sql("WHERE 1=1 ");
$query->append_sql(" WHERE ");
$query->append($img_search);
}
}
// one positive tag (a common case), do an optimised search
else if($positive_tag_count == 1 && $negative_tag_count == 0) {
$query = new Querylet(
// MySQL is braindead, and does a full table scan on images, running the subquery once for each row -_-
@ -198,9 +310,12 @@ class Database {
$tag_search->variables);
if(strlen($img_search->sql) > 0) {
$query->append_sql(" AND ");
$query->append($img_search);
}
}
// more than one positive tag, or more than zero negative tags
else {
$s_tag_array = array_map("sql_escape", $tag_search->variables);
$s_tag_list = join(', ', $s_tag_array);
@ -232,38 +347,38 @@ class Database {
$query = new Querylet("
SELECT *, UNIX_TIMESTAMP(posted) AS posted_timestamp
FROM ({$subquery->sql}) AS images ", $subquery->variables);
if(strlen($img_search->sql) > 0) {
$query->append_sql(" WHERE ");
$query->append($img_search);
}
}
else {
# there are no results, "where 1=0" should shortcut things
$query = new Querylet("
SELECT images.*
FROM images
LEFT JOIN image_tags ON image_tags.image_id = images.id
JOIN tags ON image_tags.tag_id = tags.id
WHERE 1=0
");
}
if(strlen($img_search->sql) > 0) {
$query->append_sql("WHERE 1=1 ");
$query->append($img_search);
}
}
return $query;
}
public function delete_tags_from_image($image_id) {
assert(is_numeric($image_id));
$this->execute("UPDATE tags SET count = count - 1 WHERE id IN (SELECT tag_id FROM image_tags WHERE image_id = ?)", array($image_id));
$this->execute("DELETE FROM image_tags WHERE image_id=?", array($image_id));
}
public function set_tags($image_id, $tags) {
assert(is_numeric($image_id));
$tags = tag_explode($tags);
$tags = array_map(array($this, 'resolve_alias'), $tags);
$tags = array_map(array($this, 'sanitise'), $tags);
$tags = array_unique($tags); // remove any duplicate tags
$tags = array_iunique($tags); // remove any duplicate tags
// delete old
$this->delete_tags_from_image($image_id);
@ -277,6 +392,7 @@ class Database {
}
public function set_source($image_id, $source) {
assert(is_numeric($image_id));
if(empty($source)) $source = null;
$this->execute("UPDATE images SET source=? WHERE id=?", array($source, $image_id));
}
@ -285,8 +401,8 @@ class Database {
public function get_images($start, $limit, $tags=array()) {
$images = array();
assert($start >= 0);
assert($limit > 0);
assert(is_numeric($start) && $start >= 0);
assert(is_numeric($limit) && $limit > 0);
if($start < 0) $start = 0;
if($limit < 1) $limit = 1;
@ -307,6 +423,10 @@ class Database {
}
public function get_next_image($id, $tags=array(), $next=true) {
assert(is_numeric($id));
assert(is_array($tags));
assert(is_bool($next));
if($next) {
$gtlt = "<";
$dir = "DESC";
@ -334,12 +454,22 @@ class Database {
}
public function get_image($id) {
assert(is_numeric($id));
$image = null;
$row = $this->db->GetRow("{$this->get_images} WHERE images.id=?", array($id));
return ($row ? new Image($row) : null);
}
public function get_random_image($tags=array()) {
$max = $this->count_images($tags);
$rand = mt_rand(0, $max);
$set = $this->get_images($rand, 1, $tags);
if(count($set) > 0) return $set[0];
else return null;
}
public function get_image_by_hash($hash) {
assert(is_string($hash));
$image = null;
$row = $this->db->GetRow("{$this->get_images} WHERE hash=?", array($hash));
return ($row ? new Image($row) : null);
@ -354,21 +484,26 @@ class Database {
public function get_user_session($name, $session) {
$row = $this->db->GetRow("{$this->SELECT_USER} WHERE name LIKE ? AND md5(concat(pass, ?)) = ?",
array($name, $_SERVER['REMOTE_ADDR'], $session));
array($name, get_session_ip(), $session));
return $row ? new User($row) : null;
}
public function get_user_by_id($id) {
assert(is_numeric($id));
$row = $this->db->GetRow("{$this->SELECT_USER} WHERE id=?", array($id));
return $row ? new User($row) : null;
}
public function get_user_by_name($name) {
assert(is_string($name));
$row = $this->db->GetRow("{$this->SELECT_USER} WHERE name=?", array($name));
return $row ? new User($row) : null;
}
public function get_user_by_name_and_hash($name, $hash) {
assert(is_string($name));
assert(is_string($hash));
assert(strlen($hash) == 32);
$row = $this->db->GetRow("{$this->SELECT_USER} WHERE name LIKE ? AND pass = ?", array($name, $hash));
return $row ? new User($row) : null;
}

View File

@ -16,10 +16,15 @@ class GenericPage {
// data
var $data = "";
var $filename = null;
public function set_data($data) {
$this->data = $data;
}
public function set_filename($filename) {
$this->filename = $filename;
}
// ==============================================
@ -66,8 +71,6 @@ class GenericPage {
// ==============================================
public function display() {
global $config;
header("Content-type: {$this->type}");
switch($this->mode) {
@ -78,6 +81,9 @@ class GenericPage {
$layout->display_page($this);
break;
case "data":
if(!is_null($this->filename)) {
header('Content-Disposition: attachment; filename='.$this->filename);
}
print $this->data;
break;
case "redirect":

View File

@ -8,7 +8,6 @@ class User {
var $email;
var $join_date;
var $days_old;
var $enabled;
var $admin;
public function User($row) {
@ -17,7 +16,6 @@ class User {
$this->email = $row['email'];
$this->join_date = $row['joindate'];
$this->days_old = $row['days_old'];
$this->enabled = ($row['enabled'] == 'Y');
$this->admin = ($row['admin'] == 'Y');
}
@ -26,17 +24,6 @@ class User {
return ($this->id == $config->get_int('anon_id'));
}
public function is_enabled() {
return $this->enabled;
}
public function set_enabled($enabled) {
global $database;
$yn = $enabled ? 'Y' : 'N';
$database->Execute("UPDATE users SET enabled=? WHERE id=?", array($yn, $this->id));
}
public function is_admin() {
return $this->admin;
}

View File

@ -117,6 +117,25 @@ function make_link($page=null, $query=null) {
* Misc *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
function version_check() {
if(version_compare(PHP_VERSION, "5.0.0") == -1) {
print <<<EOD
Currently Shimmie 2 doesn't support versions of PHP lower than 5.0.0. Please
either upgrade your PHP, or tell Shish that PHP 4 support is a big deal for
you...
EOD;
exit;
}
}
function check_cli() {
if(isset($_SERVER['REMOTE_ADDR'])) {
print "This script is to be run from the command line only.";
exit;
}
$_SERVER['REMOTE_ADDR'] = "127.0.0.1";
}
function get_thumbnail_size($orig_width, $orig_height) {
global $config;
@ -155,8 +174,6 @@ function _count_execs($db, $sql, $inputarray) {
}
function get_theme_object($file, $class) {
global $config;
$theme = $config->get_string("theme", "default");
if(class_exists("Custom$class")) {
$class = "Custom$class";
return new $class();
@ -199,6 +216,21 @@ function get_memory_limit() {
return $memory;
}
function get_session_ip() {
global $config;
$mask = $config->get_string("session_hash_mask");
if(!$mask) {
$config->set_string("session_hash_mask", "255.255.0.0");
$mask = "255.255.0.0";
}
$addr = $_SERVER['REMOTE_ADDR'];
$addr = inet_ntop(inet_pton($addr) & inet_pton($mask));
return $addr;
}
/*
* PHP really, really sucks.
*/
@ -218,6 +250,17 @@ function get_base_href() {
}
function move_upload_to_archive($event) {
$hash = $event->hash;
$ha = substr($hash, 0, 2);
if(!@copy($event->tmpname, "images/$ha/$hash")) {
$event->veto("Failed to copy file from uploads ({$event->tmpname}) to archive (images/$ha/$hash)");
return false;
}
return true;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Debugging functions *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@ -317,6 +360,115 @@ function array_contains($array, $target) {
return false;
}
// case insensetive uniqueness
function array_iunique($array) {
$ok = array();
foreach($array as $element) {
$found = false;
foreach($ok as $existing) {
if(strtolower($element) == strtolower($existing)) {
$found = true; break;
}
}
if(!$found) {
$ok[] = $element;
}
}
return $ok;
}
// from http://uk.php.net/network
function ip_in_range($IP, $CIDR) {
list ($net, $mask) = split ("/", $CIDR);
$ip_net = ip2long ($net);
$ip_mask = ~((1 << (32 - $mask)) - 1);
$ip_ip = ip2long ($IP);
$ip_ip_net = $ip_ip & $ip_mask;
return ($ip_ip_net == $ip_net);
}
// from a patch by Christian Walde; only intended for use in the
// "extension manager" extension, but it seems to fit better here
function deltree($f) {
if (is_link($f)) {
unlink($f);
}
else if(is_dir($f)) {
foreach(glob($f.'/*') as $sf) {
if (is_dir($sf) && !is_link($sf)) {
deltree($sf);
} else {
unlink($sf);
}
}
rmdir($f);
}
}
// from a comment on http://uk.php.net/copy
function full_copy($source, $target) {
if(is_dir($source)) {
@mkdir($target);
$d = dir($source);
while(FALSE !== ($entry = $d->read())) {
if($entry == '.' || $entry == '..') {
continue;
}
$Entry = $source . '/' . $entry;
if(is_dir($Entry)) {
full_copy($Entry, $target . '/' . $entry);
continue;
}
copy($Entry, $target . '/' . $entry);
}
$d->close();
}
else {
copy($source, $target);
}
}
function stripslashes_r($arr) {
return is_array($arr) ? array_map('stripslashes_r', $arr) : stripslashes($arr);
}
function sanitise_environment() {
if(DEBUG) {
error_reporting(E_ALL);
assert_options(ASSERT_ACTIVE, 1);
assert_options(ASSERT_BAIL, 1);
}
ob_start();
if(get_magic_quotes_gpc()) {
$_GET = stripslashes_r($_GET);
$_POST = stripslashes_r($_POST);
$_COOKIE = stripslashes_r($_COOKIE);
}
}
function weighted_random($weights) {
$total = 0;
foreach($weights as $k => $w) {
$total += $w;
}
$r = mt_rand(0, $total);
foreach($weights as $k => $w) {
$r -= $w;
if($r <= 0) {
return $k;
}
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Event API *
@ -424,7 +576,7 @@ function _get_user() {
$user = null;
if(isset($_COOKIE["shm_user"]) && isset($_COOKIE["shm_session"])) {
$tmp_user = $database->get_user_session($_COOKIE["shm_user"], $_COOKIE["shm_session"]);
if(!is_null($tmp_user) && $tmp_user->is_enabled()) {
if(!is_null($tmp_user)) {
$user = $tmp_user;
}

View File

@ -40,15 +40,45 @@ class AdminPage extends Extension {
}
}
if(is_a($event, 'DisplayingImageEvent')) {
global $user;
if($user->is_admin()) {
$this->theme->display_deleter($event->page, $event->image->id);
if(is_a($event, 'PageRequestEvent') && ($event->page_name == "admin_utils")) {
if($event->user->is_admin()) {
set_time_limit(0);
$redirect = false;
switch($_POST['action']) {
case 'lowercase all tags':
$this->lowercase_all_tags();
$redirect = true;
break;
case 'recount tag use':
$this->recount_tag_use();
$redirect = true;
break;
case 'purge unused tags':
$this->purge_unused_tags();
$redirect = true;
break;
case 'database dump':
$this->dbdump($event->page);
break;
}
if($redirect) {
$event->page->set_mode("redirect");
$event->page->set_redirect(make_link("admin"));
}
}
}
if(is_a($event, 'ImageAdminBlockBuildingEvent')) {
if($event->user->is_admin()) {
$event->add_part($this->theme->get_deleter_html($event->image->id));
}
}
if(is_a($event, 'AdminBuildingEvent')) {
$this->theme->display_page($event->page);
$this->theme->display_form($event->page);
}
if(is_a($event, 'UserBlockBuildingEvent')) {
@ -57,6 +87,57 @@ class AdminPage extends Extension {
}
}
}
private function lowercase_all_tags() {
global $database;
$database->execute("UPDATE tags SET tag=lower(tag)");
}
private function recount_tag_use() {
global $database;
$database->Execute("UPDATE tags SET count=(SELECT COUNT(image_id) FROM image_tags WHERE tag_id=tags.id GROUP BY tag_id)");
}
private function purge_unused_tags() {
global $database;
$this->recount_tag_use();
$database->Execute("DELETE FROM tags WHERE count=0");
}
private function dbdump($page) {
include "config.php";
$matches = array();
preg_match("#(\w+)://(\w+):(\w+)@([\w\.\-]+)/([\w_]+)(\?.*)?#", $database_dsn, $matches);
$software = $matches[1];
$username = $matches[2];
$password = $matches[3];
$hostname = $matches[4];
$database = $matches[5];
switch($software) {
case 'mysql':
$cmd = "mysqldump -h$hostname -u$username -p$password $database";
break;
}
$page->set_mode("data");
$page->set_type("application/x-unknown");
$page->set_filename('shimmie-'.date('Ymd').'.sql');
$page->set_data(shell_exec($cmd));
}
private function check_for_orphanned_images() {
$orphans = array();
foreach(glob("images/*") as $dir) {
foreach(glob("$dir/*") as $file) {
$hash = str_replace("$dir/", "", $file);
if(!$this->db_has_hash($hash)) {
$orphans[] = $hash;
}
}
}
}
}
add_event_listener(new AdminPage());
?>

View File

@ -15,7 +15,7 @@ class AdminPageTheme extends Themelet {
*
* $image_id = the image to delete
*/
public function display_deleter($page, $image_id) {
public function get_deleter_html($image_id) {
$i_image_id = int_escape($image_id);
$html = "
<form action='".make_link("admin/delete_image")."' method='POST'>
@ -23,7 +23,28 @@ class AdminPageTheme extends Themelet {
<input type='submit' value='Delete'>
</form>
";
$page->add_block(new Block("Admin", $html, "left"));
return $html;
}
/*
* Show a form which links to admin_utils with POST[action] set to one of:
* 'lowercase all tags'
* 'recount tag use'
* 'purge unused tags'
*/
public function display_form($page) {
$html = "
<p><form action='".make_link("admin_utils")."' method='POST'>
<select name='action'>
<option value='lowercase all tags'>All tags to lowercase</option>
<option value='recount tag use'>Recount tag use</option>
<option value='purge unused tags'>Purge unused tags</option>
<option value='database dump'>Download database contents</option>
</select>
<input type='submit' value='Go'>
</form>
";
$page->add_block(new Block("Misc Admin Tools", $html));
}
}
?>

View File

@ -40,7 +40,9 @@ class AliasEditor extends Extension {
}
else if($event->get_arg(0) == "list") {
global $database;
$this->theme->display_aliases($event->page, $database->db->GetAssoc("SELECT oldtag, newtag FROM aliases"), $event->user->is_admin());
$this->theme->display_aliases($event->page,
$database->db->GetAssoc("SELECT oldtag, newtag FROM aliases ORDER BY newtag"),
$event->user->is_admin());
}
else if($event->get_arg(0) == "export") {
global $database;
@ -71,7 +73,8 @@ class AliasEditor extends Extension {
if(is_a($event, 'AddAliasEvent')) {
global $database;
$database->Execute("INSERT INTO aliases(oldtag, newtag) VALUES(?, ?)", array($event->oldtag, $event->newtag));
$database->Execute("INSERT INTO aliases(oldtag, newtag) VALUES(?, ?)",
array($event->oldtag, $event->newtag));
}
if(is_a($event, 'UserBlockBuildingEvent')) {

View File

@ -45,6 +45,7 @@ class AliasEditorTheme extends Themelet {
$html = "
<table border='1'>
<thead><td>From</td><td>To</td>$action</thead>
$add
$h_aliases
$add
</table>

View File

@ -12,12 +12,14 @@ class BBCode extends Extension {
$text = preg_replace("/\[b\](.*?)\[\/b\]/s", "<b>\\1</b>", $text);
$text = preg_replace("/\[i\](.*?)\[\/i\]/s", "<i>\\1</i>", $text);
$text = preg_replace("/\[u\](.*?)\[\/u\]/s", "<u>\\1</u>", $text);
$text = preg_replace("/\[s\](.*?)\[\/s\]/s", "<s>\\1</s>", $text);
$text = preg_replace("/\[code\](.*?)\[\/code\]/s", "<pre>\\1</pre>", $text);
$text = preg_replace("/&gt;&gt;(\d+)/s", "<a href='".make_link("post/view/\\1")."'>&gt;&gt;\\1</a>", $text);
$text = preg_replace("/&gt;&gt;([^\d].+)/", "<blockquote><small>\\1</small></blockquote>", $text);
$text = preg_replace("/\[url=((?:https?|ftp|irc):\/\/.*?)\](.*?)\[\/url\]/s", "<a href='\\1'>\\2</a>", $text);
$text = preg_replace("/\[url\]((?:https?|ftp|irc):\/\/.*?)\[\/url\]/s", "<a href='\\1'>\\1</a>", $text);
$text = preg_replace("/\[\[(.*?)\]\]/s", "<a href='".make_link("wiki/\\1")."'>\\1</a>", $text);
$text = preg_replace("/\[url=((?:https?|ftp|irc|mailto):\/\/.*?)\](.*?)\[\/url\]/s", "<a href='\\1'>\\2</a>", $text);
$text = preg_replace("/\[url\]((?:https?|ftp|irc|mailto):\/\/.*?)\[\/url\]/s", "<a href='\\1'>\\1</a>", $text);
$text = preg_replace("/\[\[([^\|\]]+)\|([^\]]+)\]\]/s", "<a href='".make_link("wiki/\\1")."'>\\2</a>", $text);
$text = preg_replace("/\[\[([^\]]+)\]\]/s", "<a href='".make_link("wiki/\\1")."'>\\1</a>", $text);
$text = str_replace("\n", "\n<br>", $text);
$text = preg_replace("/\[quote\](.*?)\[\/quote\]/s", "<blockquote><small>\\1</small></blockquote>", $text);
$text = preg_replace("/\[quote=(.*?)\](.*?)\[\/quote\]/s", "<small><small>Quoting \\1</small></small><blockquote><small>\\2</small></blockquote>", $text);
@ -25,11 +27,13 @@ class BBCode extends Extension {
$text = preg_replace("/\[h2\](.*?)\[\/h2\]/s", "<h2>\\1</h2>", $text);
$text = preg_replace("/\[h3\](.*?)\[\/h3\]/s", "<h3>\\1</h3>", $text);
$text = preg_replace("/\[h4\](.*?)\[\/h4\]/s", "<h4>\\1</h4>", $text);
$text = preg_replace("/\[list\](.*?)\[\/list\]/s", "<ul>\\1</ul>", $text);
$text = preg_replace("/\[ul\](.*?)\[\/ul\]/s", "<ul>\\1</ul>", $text);
$text = preg_replace("/\[ol\](.*?)\[\/ol\]/s", "<ol>\\1</ol>", $text);
$text = preg_replace("/\[li\](.*?)\[\/li\]/s", "<li>\\1</li>", $text);
$text = preg_replace("#\[\*\]#s", "<li>", $text);
$text = preg_replace("#<br><(li|ul|ol|/ul|/ol)>#s", "<\\1>", $text);
$text = $this->filter_spoiler($text);
return $text;
}
@ -37,20 +41,50 @@ class BBCode extends Extension {
$text = preg_replace("/\[b\](.*?)\[\/b\]/s", "\\1", $text);
$text = preg_replace("/\[i\](.*?)\[\/i\]/s", "\\1", $text);
$text = preg_replace("/\[u\](.*?)\[\/u\]/s", "\\1", $text);
$text = preg_replace("/\[s\](.*?)\[\/s\]/s", "\\1", $text);
$text = preg_replace("/\[code\](.*?)\[\/code\]/s", "\\1", $text);
$text = preg_replace("/\[url=(.*?)\](.*?)\[\/url\]/s", "\\2", $text);
$text = preg_replace("/\[url\](.*?)\[\/url\]/s", "\\1", $text);
$text = preg_replace("/\[\[(.*?)\]\]/s", "\\1", $text);
$text = preg_replace("/\[\[([^\|\]]+)\|([^\]]+)\]\]/s", "\\2", $text);
$text = preg_replace("/\[\[([^\]]+)\]\]/s", "\\1", $text);
$text = preg_replace("/\[quote\](.*?)\[\/quote\]/s", "", $text);
$text = preg_replace("/\[quote=(.*?)\](.*?)\[\/quote\]/s", "", $text);
$text = preg_replace("/\[h1\](.*?)\[\/h1\]/s", "\\1", $text);
$text = preg_replace("/\[h2\](.*?)\[\/h2\]/s", "\\1", $text);
$text = preg_replace("/\[h3\](.*?)\[\/h3\]/s", "\\1", $text);
$text = preg_replace("/\[h4\](.*?)\[\/h4\]/s", "\\1", $text);
$text = preg_replace("/\[list\](.*?)\[\/list\]/s", "\\1", $text);
$text = preg_replace("/\[ul\](.*?)\[\/ul\]/s", "\\1", $text);
$text = preg_replace("/\[ol\](.*?)\[\/ol\]/s", "\\1", $text);
$text = preg_replace("/\[li\](.*?)\[\/li\]/s", "\\1", $text);
$text = preg_replace("/\[\*\](.*?)/s", "\\1", $text);
$text = $this->strip_spoiler($text);
return $text;
}
private function filter_spoiler($text) {
return str_replace(
array("[spoiler]","[/spoiler]"),
array("<span style=\"background-color:#000; color:#000;\">","</span>"),
$text);
}
private function strip_spoiler($text) {
$l1 = strlen("[spoiler]");
$l2 = strlen("[/spoiler]");
while(true) {
$start = strpos($text, "[spoiler]");
if($start === false) break;
$end = strpos($text, "[/spoiler]");
if($end === false) break;
$beginning = substr($text, 0, $start);
$middle = str_rot13(substr($text, $start+$l1, ($end-$start-$l1)));
$ending = substr($text, $end + $l2, (strlen($text)-$end+$l2));
$text = $beginning . $middle . $ending;
}
return $text;
}
}

View File

@ -84,7 +84,12 @@ class CommentList extends Extension {
if($event->count_args() == 3) {
send_event(new CommentDeletionEvent($event->get_arg(1)));
$event->page->set_mode("redirect");
$event->page->set_redirect(make_link("post/view/".$event->get_arg(2)));
if(!empty($_SERVER['HTTP_REFERER'])) {
$event->page->set_redirect($_SERVER['HTTP_REFERER']);
}
else {
$event->page->set_redirect(make_link("post/view/".$event->get_arg(2)));
}
}
}
else {
@ -144,8 +149,40 @@ class CommentList extends Extension {
global $database;
global $config;
// shortcut to latest
if($config->get_int("ext_comments_version") < 1) {
$database->upgrade_schema("ext/comment/schema.xml");
$database->Execute("CREATE TABLE comments (
id {$database->engine->auto_increment},
image_id INTEGER NOT NULL,
owner_id INTEGER NOT NULL,
owner_ip CHAR(16) NOT NULL,
posted DATETIME DEFAULT NULL,
comment TEXT NOT NULL,
INDEX (image_id),
INDEX (owner_ip),
INDEX (posted)
) {$database->engine->create_table_extras}");
$config->set_int("ext_comments_version", 2);
}
// ===
if($config->get_int("ext_comments_version") < 1) {
$database->Execute("CREATE TABLE comments (
id {$database->engine->auto_increment},
image_id INTEGER NOT NULL,
owner_id INTEGER NOT NULL,
owner_ip CHAR(16) NOT NULL,
posted DATETIME DEFAULT NULL,
comment TEXT NOT NULL,
INDEX (image_id)
) {$database->engine->create_table_extras}");
$config->set_int("ext_comments_version", 1);
}
if($config->get_int("ext_comments_version") == 1) {
$database->Execute("CREATE INDEX comments_owner_ip ON comments(owner_ip)");
$database->Execute("CREATE INDEX comments_posted ON comments(posted)");
$config->set_int("ext_comments_version", 2);
}
}
// }}}
@ -166,9 +203,9 @@ class CommentList extends Extension {
FROM comments
GROUP BY image_id
ORDER BY latest DESC
LIMIT ?,?
LIMIT ? OFFSET ?
";
$result = $database->Execute($get_threads, array($start, $threads_per_page));
$result = $database->Execute($get_threads, array($threads_per_page, $start));
$total_pages = (int)($database->db->GetOne("SELECT COUNT(distinct image_id) AS count FROM comments") / 10);

View File

@ -1,21 +0,0 @@
<?xml version="1.0"?>
<schema version="0.3">
<!-- FIXME: mysql utf8ness -->
<table name="comments">
<field name="id" type="I"><key/><autoincrement/></field>
<field name="image_id" type="I"><notnull/></field><!-- references -->
<field name="owner_id" type="I"><notnull/></field><!-- references -->
<field name="owner_ip" type="C" size="15"><notnull/></field>
<field name="posted" type="T"><notnull/></field>
<field name="comment" type="X" size="4000"><notnull/></field>
<index name="comments__image_id"><col>image_id</col></index>
<index name="comments__owner_ip"><col>owner_ip</col></index>
<index name="comments__posted"><col>posted</col></index>
<opt platform="mysql">DEFAULT CHARSET='utf8'</opt>
</table>
<sql>
<query>DELETE FROM config WHERE name='ext_comments_version'</query>
<query>INSERT INTO config(name, value) VALUES('ext_comments_version', 3)</query>
</sql>
</schema>

128
ext/ext_manager/main.php Normal file
View File

@ -0,0 +1,128 @@
<?php
/**
* Name: Extension Manager
* Author: Shish <webmaster@shishnet.org>
* Link: http://trac.shishnet.org/shimmie2/
* License: GPLv2
* Description: A thing for point & click extension management
*/
class ExtensionInfo { // {{{
var $ext_name, $name, $link, $author, $email, $description;
function ExtensionInfo($main) {
$matches = array();
$lines = file($main);
preg_match("#contrib/(.*)/main.php#", $main, $matches);
$this->ext_name = $matches[1];
$this->name = $this->ext_name;
$this->enabled = $this->is_enabled($this->ext_name);
for($i=0; $i<count($lines); $i++) {
$line = $lines[$i];
if(preg_match("/Name: (.*)/", $line, $matches)) {
$this->name = $matches[1];
}
if(preg_match("/Link: (.*)/", $line, $matches)) {
$this->link = $matches[1];
}
if(preg_match("/Author: (.*) [<\(](.*@.*)[>\)]/", $line, $matches)) {
$this->author = $matches[1];
$this->email = $matches[2];
}
else if(preg_match("/Author: (.*)/", $line, $matches)) {
$this->author = $matches[1];
}
if(preg_match("/(.*)Description: (.*)/", $line, $matches)) {
$this->description = $matches[2];
$start = $matches[1]." ";
$start_len = strlen($start);
while(substr($lines[$i+1], 0, $start_len) == $start) {
$this->description .= substr($lines[$i+1], $start_len);
$i++;
}
}
if(preg_match("/\*\//", $line, $matches)) {
break;
}
}
}
private function is_enabled($fname) {
return file_exists("ext/$fname");
}
} // }}}
class ExtManager extends Extension {
var $theme;
public function receive_event($event) {
if(is_null($this->theme)) $this->theme = get_theme_object("ext_manager", "ExtManagerTheme");
if(is_a($event, 'PageRequestEvent') && ($event->page_name == "ext_manager")) {
if($event->user->is_admin()) {
if($event->get_arg(0) == "set") {
if(is_writable("ext")) {
$this->set_things($_POST);
$event->page->set_mode("redirect");
$event->page->set_redirect(make_link("ext_manager"));
}
else {
$this->theme->display_error($event->page, "File Operation Failed",
"The extension folder isn't writable by the web server :(");
}
}
else {
$this->theme->display_table($event->page, $this->get_extensions());
}
}
}
if(is_a($event, 'UserBlockBuildingEvent')) {
if($event->user->is_admin()) {
$event->add_link("Extension Manager", make_link("ext_manager"));
}
}
}
private function get_extensions() {
$extensions = array();
foreach(glob("contrib/*/main.php") as $main) {
$extensions[] = new ExtensionInfo($main);
}
return $extensions;
}
private function set_things($settings) {
foreach(glob("contrib/*/main.php") as $main) {
$matches = array();
preg_match("#contrib/(.*)/main.php#", $main, $matches);
$fname = $matches[1];
if(!isset($settings["ext_$fname"])) $settings["ext_$fname"] = 0;
$this->set_enabled($fname, $settings["ext_$fname"]);
}
}
private function set_enabled($fname, $enabled) {
if($enabled) {
// enable if currently disabled
if(!file_exists("ext/$fname")) {
if(function_exists("symlink")) {
symlink("../contrib/$fname", "ext/$fname");
}
else {
full_copy("contrib/$fname", "ext/$fname");
}
}
}
else {
// disable if currently enabled
if(file_exists("ext/$fname")) {
deltree("ext/$fname");
}
}
}
}
add_event_listener(new ExtManager());
?>

View File

@ -8,13 +8,13 @@ class ExtManagerTheme extends Themelet {
<tr><th>Name</th><th>Author</th><th>Description</th><th>Enabled</th></tr>
";
foreach($extensions as $extension) {
$ext_name = $extension["ext_name"];
$h_name = empty($extension["name"]) ? $ext_name : html_escape($extension["name"]);
$h_email = html_escape($extension["email"]);
$h_link = isset($extension["link"]) ? html_escape($extension["link"]) : "";
$h_author = html_escape($extension["author"]);
$h_description = html_escape($extension["description"]);
$h_enabled = $extension["enabled"] ? " checked='checked'" : "";
$ext_name = $extension->ext_name;
$h_name = empty($extension->name) ? $ext_name : html_escape($extension->name);
$h_email = html_escape($extension->email);
$h_link = isset($extension->link) ? html_escape($extension->link) : "";
$h_author = html_escape($extension->author);
$h_description = html_escape($extension->description);
$h_enabled = $extension->enabled ? " checked='checked'" : "";
$html .= "
<tr>
" . (

View File

@ -14,10 +14,7 @@ class PixelFileHandler extends Extension {
if(is_a($event, 'DataUploadEvent') && $this->supported_ext($event->type) && $this->check_contents($event->tmpname)) {
$hash = $event->hash;
$ha = substr($hash, 0, 2);
if(!copy($event->tmpname, "images/$ha/$hash")) {
$event->veto("Pixel Handler failed to copy file from uploads ({$event->tmpname}) to archive (images/$ha/$hash)");
return;
}
if(!move_upload_to_archive($event)) return;
send_event(new ThumbnailGenerationEvent($event->hash, $event->type));
$image = $this->create_image_from_data("images/$ha/$hash", $event->metadata);
if(is_null($image)) {
@ -44,10 +41,7 @@ class PixelFileHandler extends Extension {
private function supported_ext($ext) {
$exts = array("jpg", "jpeg", "gif", "png");
foreach($exts as $supported) {
if($ext == $supported) return true;
}
return false;
return array_contains($exts, strtolower($ext));
}
private function create_image_from_data($filename, $metadata) {
@ -72,7 +66,12 @@ class PixelFileHandler extends Extension {
}
private function check_contents($file) {
return (file_exists($file) && !is_null(getimagesize($file)));
$valid = Array(IMAGETYPE_PNG, IMAGETYPE_GIF, IMAGETYPE_JPEG);
if(!file_exists($file)) return false;
$info = getimagesize($file);
if(is_null($info)) return false;
if(array_contains($valid, $info[2])) return true;
return false;
}
private function create_thumb($hash) {

View File

@ -164,7 +164,7 @@ class ImageIO extends Extension {
else {
$page->set_title("Not Found");
$page->set_heading("Not Found");
$page->add_block(new Block("Navigation", "<a href='".index."'>Index</a>", "left", 0));
$page->add_block(new Block("Navigation", "<a href='".make_link()."'>Index</a>", "left", 0));
$page->add_block(new Block("Image not in database",
"The requested image was not found in the database"));
}

View File

@ -85,26 +85,30 @@ class Index extends Extension {
if(preg_match("/size(<|>|<=|>=|=)(\d+)x(\d+)/", $event->term, $matches)) {
$cmp = $matches[1];
$args = array(int_escape($matches[2]), int_escape($matches[3]));
$event->set_querylet(new Querylet("AND (width $cmp ? AND height $cmp ?)", $args));
$event->set_querylet(new Querylet("width $cmp ? AND height $cmp ?", $args));
}
else if(preg_match("/ratio(<|>|<=|>=|=)(\d+):(\d+)/", $event->term, $matches)) {
$cmp = $matches[1];
$args = array(int_escape($matches[2]), int_escape($matches[3]));
$event->set_querylet(new Querylet("AND (width / height $cmp ? / ?)", $args));
$event->set_querylet(new Querylet("width / height $cmp ? / ?", $args));
}
else if(preg_match("/(filesize|id)(<|>|<=|>=|=)(\d+[kmg]?b?)/i", $event->term, $matches)) {
$col = $matches[1];
$cmp = $matches[2];
$val = parse_shorthand_int($matches[3]);
$event->set_querylet(new Querylet("AND (images.$col $cmp $val)"));
$event->set_querylet(new Querylet("images.$col $cmp ?", array($val)));
}
else if(preg_match("/hash=([0-9a-fA-F]*)/i", $event->term, $matches)) {
$hash = strtolower($matches[2]);
$event->set_querylet(new Querylet("AND (images.hash = '$hash')"));
$event->set_querylet(new Querylet("images.hash = '$hash'"));
}
else if(preg_match("/(filetype|ext)=([a-zA-Z0-9]*)/i", $event->term, $matches)) {
$ext = strtolower($matches[2]);
$event->set_querylet(new Querylet("AND (images.ext = '$ext')"));
$event->set_querylet(new Querylet("images.ext = '$ext'"));
}
else if(preg_match("/(filename|name)=([a-zA-Z0-9]*)/i", $event->term, $matches)) {
$filename = strtolower($matches[2]);
$event->set_querylet(new Querylet("images.filename LIKE '%$filename%'"));
}
}
}

View File

@ -64,6 +64,7 @@ class IndexTheme extends Themelet {
<p><form action='$h_search_link' method='GET'>
<input id='search_input' name='search' type='text'
value='$h_search_string' autocomplete='off' />
<input type='hidden' name='q' value='/post/list'>
<input type='submit' value='Find' style='display: none;' />
</form>
<div id='search_completions'></div>";

View File

@ -1,136 +0,0 @@
<?php
// RemoveIPBanEvent {{{
class RemoveIPBanEvent extends Event {
var $id;
public function RemoveIPBanEvent($id) {
$this->id = $id;
}
}
// }}}
// AddIPBanEvent {{{
class AddIPBanEvent extends Event {
var $ip;
var $reason;
var $end;
public function AddIPBanEvent($ip, $reason, $end) {
$this->ip = $ip;
$this->reason = $reason;
$this->end = $end;
}
}
// }}}
class IPBan extends Extension {
var $theme;
// event handler {{{
public function receive_event($event) {
if(is_null($this->theme)) $this->theme = get_theme_object("ipban", "IPBanTheme");
if(is_a($event, 'InitExtEvent')) {
global $config;
if($config->get_int("ext_ipban_version") < 2) {
$this->install();
}
$this->check_ip_ban();
}
if(is_a($event, 'PageRequestEvent') && ($event->page_name == "ip_ban")) {
global $user;
if($user->is_admin()) {
if($event->get_arg(0) == "add") {
if(isset($_POST['ip']) && isset($_POST['reason']) && isset($_POST['end'])) {
if(empty($_POST['end'])) $end = null;
else $end = $_POST['end'];
send_event(new AddIPBanEvent($_POST['ip'], $_POST['reason'], $end));
global $page;
$page->set_mode("redirect");
$page->set_redirect(make_link("admin"));
}
}
else if($event->get_arg(0) == "remove") {
if(isset($_POST['id'])) {
send_event(new RemoveIPBanEvent($_POST['id']));
global $page;
$page->set_mode("redirect");
$page->set_redirect(make_link("admin"));
}
}
}
}
if(is_a($event, 'AddIPBanEvent')) {
global $user;
$this->add_ip_ban($event->ip, $event->reason, $event->end, $user);
}
if(is_a($event, 'RemoveIPBanEvent')) {
$this->remove_ip_ban($event->id);
}
if(is_a($event, 'AdminBuildingEvent')) {
global $page;
$this->theme->display_bans($page, $this->get_bans());
}
}
// }}}
// installer {{{
protected function install() {
global $database;
global $config;
if($config->get_int("ext_ipban_version") < 3) {
$database->upgrade_schema("ext/ipban/schema.xml");
}
}
// }}}
// deal with banned person {{{
private function check_ip_ban() {
$row = $this->get_ip_ban($_SERVER['REMOTE_ADDR']);
if($row) {
global $config;
global $database;
$admin = $database->get_user_by_id($row['banner_id']);
print "IP <b>{$row['ip']}</b> has been banned by <b>{$admin->name}</b> because of <b>{$row['reason']}</b>";
$contact_link = $config->get_string("contact_link");
if(!empty($contact_link)) {
print "<p><a href='$contact_link'>Contact The Admin</a>";
}
exit;
}
}
// }}}
// database {{{
private function get_bans() {
global $database;
$bans = $database->get_all("SELECT * FROM bans");
if($bans) {return $bans;}
else {return array();}
}
private function get_ip_ban($ip) {
global $database;
return $database->db->GetRow("SELECT * FROM bans WHERE ip = ? AND date < now() AND (end > now() OR isnull(end))", array($ip));
}
private function add_ip_ban($ip, $reason, $end, $user) {
global $database;
$database->Execute(
"INSERT INTO bans (ip, reason, date, end, banner_id) VALUES (?, ?, now(), ?, ?)",
array($ip, $reason, $end, $user->id));
}
private function remove_ip_ban($id) {
global $database;
$database->Execute("DELETE FROM bans WHERE id = ?", array($id));
}
// }}}
}
add_event_listener(new IPBan(), 10);
?>

View File

@ -1,19 +0,0 @@
<?xml version="1.0"?>
<schema version="0.3">
<!-- FIXME: mysql utf8ness -->
<table name="bans">
<field name="id" type="I"><key/><autoincrement/></field>
<field name="banner_id" type="I"><notnull/></field>
<field name="ip" type="C" size="15"><notnull/></field>
<field name="date" type="T"><notnull/></field>
<field name="end" type="T"><notnull/></field>
<field name="reason" type="C" size="255"><notnull/></field>
<index name="bans__ip"><col>ip</col></index>
<opt platform="mysql">DEFAULT CHARSET='utf8'</opt>
</table>
<sql>
<query>DELETE FROM config WHERE name='ext_ipban_version'</query>
<query>INSERT INTO config(name, value) VALUES('ext_ipban_version', 3)</query>
</sql>
</schema>

View File

@ -152,6 +152,10 @@ class Setup extends Extension {
$page->set_mode("redirect");
$page->set_redirect(make_link("setup"));
}
else if($event->get_arg(0) == "advanced") {
global $config;
$this->theme->display_advanced($event->page, $config->values);
}
else {
$panel = new SetupPanel();
send_event(new SetupBuildingEvent($panel));

View File

@ -52,10 +52,41 @@ class SetupTheme extends Themelet {
$page->add_block(new Block("Setup", $table));
}
public function display_advanced($page, $options) {
$rows = "";
foreach($options as $name => $value) {
$h_value = html_escape($value);
$len = strlen($h_value);
$box = "";
if($len < 50) {
$box .= "<input type='text' name='_config_$name' value='$h_value'>";
}
else {
$box .= "<textarea cols='50' rows='4' name='_config_$name'>$h_value</textarea>";
}
$box .= "<input type='hidden' name='_type_$name' value='string'>";
$rows .= "<tr><td>$name</td><td>$box</td></tr>";
}
$table = "
<form action='".make_link("setup/save")."' method='POST'><table>
<tr><th width='25%'>Name</th><th>Value</th></tr>
$rows
<tr><td colspan='2'><input type='submit' value='Save Settings'></td></tr>
</table></form>
";
$page->set_title("Shimmie Setup");
$page->set_heading("Shimmie Setup");
$page->add_block(new Block("Navigation", $this->build_navigation(), "left", 0));
$page->add_block(new Block("Setup", $table));
}
protected function build_navigation() {
return "
<a href='".make_link()."'>Index</a>
<br><a href='http://trac.shishnet.org/shimmie2/wiki/Settings'>Help</a>
<br><a href='".make_link("setup/advanced")."'>Advanced</a>
";
}

View File

@ -34,10 +34,8 @@ class TagEditTheme extends Themelet {
}
$html .= "
<table style='width: 500px;'>
<tr><td width='50px'>Tags</td><td width='300px'><input type='text' name='tag_edit__tags' value='$h_tags'></td></tr>
$source_edit
</table>
";
}

View File

@ -12,6 +12,7 @@ class TagList extends Extension {
$config->set_default_int("tag_list_length", 15);
$config->set_default_int("tags_min", 3);
$config->set_default_string("info_link", 'http://en.wikipedia.org/wiki/$tag');
$config->set_default_string("tag_list_image_type", 'related');
}
if(is_a($event, 'PageRequestEvent') && ($event->page_name == "tags")) {
@ -51,18 +52,27 @@ class TagList extends Extension {
if(is_a($event, 'DisplayingImageEvent')) {
global $config;
if($config->get_int('tag_list_length') > 0) {
$this->add_related_block($event->page, $event->image);
if($config->get_string('tag_list_image_type') == 'related') {
$this->add_related_block($event->page, $event->image);
}
else {
$this->add_tags_block($event->page, $event->image);
}
}
}
if(is_a($event, 'SetupBuildingEvent')) {
$sb = new SetupBlock("Tag Map Options");
$sb->add_int_option("tags_min", "Ignore tags used fewer than "); $sb->add_label(" times");
$sb->add_int_option("tags_min", "Only show tags used at least "); $sb->add_label(" times");
$event->panel->add_block($sb);
$sb = new SetupBlock("Popular / Related Tag List");
$sb->add_int_option("tag_list_length", "Show top "); $sb->add_label(" tags");
$sb->add_text_option("info_link", "<br>Tag info link: ");
$sb->add_choice_option("tag_list_image_type", array(
"Image's tags only" => "tags",
"Show related" => "related"
), "<br>Image tag list: ");
$sb->add_bool_option("tag_list_numbers", "<br>Show tag counts: ");
$event->panel->add_block($sb);
}
@ -91,9 +101,9 @@ class TagList extends Extension {
$result = $database->execute("
SELECT
tag,
FLOOR(LOG(LOG(count - ? + 1)+1)*1.5*100)/100 AS scaled
FLOOR(LOG(2.7, LOG(2.7, count - ? + 1)+1)*1.5*100)/100 AS scaled
FROM tags
WHERE count > ?
WHERE count >= ?
ORDER BY tag
", array($tags_min, $tags_min));
$tag_data = $result->GetArray();
@ -114,7 +124,7 @@ class TagList extends Extension {
$tags_min = $config->get_int('tags_min');
$result = $database->execute(
"SELECT tag,count FROM tags WHERE count > ? ORDER BY tag",
"SELECT tag,count FROM tags WHERE count >= ? ORDER BY tag",
array($tags_min));
$tag_data = $result->GetArray();
@ -140,7 +150,7 @@ class TagList extends Extension {
$tags_min = $config->get_int('tags_min');
$result = $database->execute(
"SELECT tag,count,FLOOR(LOG(count)) AS scaled FROM tags WHERE count > ? ORDER BY count DESC, tag ASC",
"SELECT tag,count,FLOOR(LOG(count)) AS scaled FROM tags WHERE count >= ? ORDER BY count DESC, tag ASC",
array($tags_min));
$tag_data = $result->GetArray();
@ -194,6 +204,26 @@ class TagList extends Extension {
}
}
private function add_tags_block($page, $image) {
global $database;
global $config;
$query = "
SELECT tags.tag, tags.count
FROM tags, image_tags
WHERE tags.id = image_tags.tag_id
AND image_tags.image_id = ?
ORDER BY count DESC
LIMIT ?
";
$args = array($image->id, $config->get_int('tag_list_length'));
$tags = $database->get_all($query, $args);
if(count($tags) > 0) {
$this->theme->display_related_block($page, $tags);
}
}
private function add_popular_block($page) {
global $database;
global $config;

View File

@ -2,14 +2,14 @@
<schema version="0.3">
<!-- FIXME: mysql utf8ness -->
<table name="aliases">
<field name="oldtag" type="C" size="255"><key/><notnull/></field>
<field name="newtag" type="C" size="255"><notnull/></field>
<field name="oldtag" type="C" size="128"><key/><notnull/></field>
<field name="newtag" type="C" size="128"><notnull/></field>
<index name="aliases__unique"><col>oldtag</col><col>newtag</col><unique/></index>
<opt platform="mysql">DEFAULT CHARSET='utf8'</opt>
</table>
<table name="config">
<field name="name" type="C" size="255"><key/><notnull/></field>
<field name="name" type="C" size="128"><key/><notnull/></field>
<field name="value" type="X" size="4000"></field>
<opt platform="mysql">DEFAULT CHARSET='utf8'</opt>
</table>
@ -22,7 +22,7 @@
<field name="filesize" type="I"><notnull/></field>
<field name="hash" type="C" size="32"><notnull/></field>
<field name="ext" type="C" size="4"><notnull/></field>
<field name="source" type="C" size="255"></field>
<field name="source" type="C" size="249"></field>
<field name="width" type="I"><notnull/></field>
<field name="height" type="I"><notnull/></field>
<field name="posted" type="T"><notnull/></field>
@ -38,9 +38,8 @@
<field name="name" type="C" size="32"><notnull/></field>
<field name="pass" type="C" size="32"></field>
<field name="joindate" type="T"><notnull/></field>
<field name="enabled" type="C" size="1"><notnull/><default value="Y"/></field>
<field name="admin" type="C" size="1"><notnull/><default value="N"/></field>
<field name="email" type="C" size="255"></field>
<field name="email" type="C" size="249"></field>
<index name="users__name"><col>name</col><unique/></index>
<opt platform="mysql">DEFAULT CHARSET='utf8'</opt>
</table>

View File

@ -5,6 +5,8 @@ class Upload extends Extension {
// event handling {{{
public function receive_event($event) {
if(is_null($this->theme)) $this->theme = get_theme_object("upload", "UploadTheme");
$is_full = (disk_free_space(realpath("./images/")) < 100*1024*1024);
if(is_a($event, 'InitExtEvent')) {
global $config;
@ -16,7 +18,12 @@ class Upload extends Extension {
if(is_a($event, 'PostListBuildingEvent')) {
global $user;
if($this->can_upload($user)) {
$this->theme->display_block($event->page);
if($is_full) {
$this->theme->display_full($event->page);
}
else {
$this->theme->display_block($event->page);
}
}
}
@ -58,7 +65,9 @@ class Upload extends Extension {
}
}
else {
$this->theme->display_page($event->page);
if(!$is_full) {
$this->theme->display_page($event->page);
}
}
}
@ -79,6 +88,9 @@ class Upload extends Extension {
if(is_a($event, "DataUploadEvent")) {
global $config;
if($is_full) {
$event->veto("Upload failed; disk nearly full");
}
if(filesize($event->tmpname) > $config->get_int('upload_size')) {
$event->veto("File too large (".filesize($event->tmpname)." &gt; ".($config->get_int('upload_size')).")");
}
@ -188,7 +200,7 @@ class Upload extends Extension {
$event = new DataUploadEvent($user, $tmp_filename, $metadata);
send_event($event);
if($event->vetoed) {
$this->theme->display_upload_error($page, "Error with ".html_escape($file['name']),
$this->theme->display_upload_error($page, "Error with ".html_escape($url),
$event->veto_reason);
$ok = false;
}

Some files were not shown because too many files have changed in this diff Show More