From: Ben Hutchings Date: Tue, 4 Nov 2008 04:25:24 +0000 (+0000) Subject: Merge commit 'Memories as 1.3' X-Git-Url: https://git.decadent.org.uk/gitweb/?a=commitdiff_plain;h=5acf53e85633363aa8a207e9e08448f27a4544f9;hp=293d891079d7545676d0a880b3b8c4f0ebacfd2c;p=memories.git Merge commit 'Memories as 1.3' --- diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..5737856 --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,21 @@ +use ExtUtils::MakeMaker; +WriteMakefile( + 'NAME' => 'Memories', + 'VERSION_FROM' => 'Memories.pm', # finds $VERSION + 'PREREQ_PM' => { + Maypole => 1.1, + HTML::TagCloud => 0, + URI::Escape => 0, + Calendar::Simple => 0, + XML::RSS => 0, + Time::Piece => 0, + Class::DBI::Plugin::Pager => 0, + Class::DBI::Plugin::AbstractCount => 0, + Cache::MemoryCache => 0, + Image::Info => 0, + Image::ExifTool => 0, + File::Path => 0, + Image::Imlib2 => 0, + Text::Balanced => 0, + } +); diff --git a/Memories.pm b/Memories.pm deleted file mode 100644 index eaf5fe3..0000000 --- a/Memories.pm +++ /dev/null @@ -1,178 +0,0 @@ -package Memories; -use strict; -our $VERSION = "1.2"; -use Maypole::Application qw(Upload Authentication::UserSessionCookie); -use HTML::TagCloud; -use URI; -use Memories::Config; -use Memories::DBI; -use Memories::Photo; -use Memories::Comment; -use Memories::Tag; -use Memories::SystemTag; -use Memories::User; -use Memories::Album; -use URI::Escape; -use Calendar::Simple; -use XML::RSS; - -Memories->config->auth->{ user_field } = "name"; -Memories->config->model("Maypole::Model::CDBI::Plain"); -Memories->setup([qw/ Memories::Photo Memories::User Memories::Tag -Memories::Album Memories::SystemTag/]); - -sub message { - my ($self, $message) = @_; - push @{$self->{template_args}{messages}}, $message; -} - -sub do_rss { - my $r = shift; - $r->model_class->process($r); - my $rss = XML::RSS->new(version => "2.0"); - $rss->channel( - title => ($r->config->{application_name}. " : ".ucfirst($r->action)." ".ucfirst($r->table)." ".($r->objects||[])->[0]) , - link => $r->config->{uri_base}."/".$r->path - ); - my $maybe_photos = $r->{objects}||[]; - my $photos = - (@$maybe_photos && $maybe_photos->[0]->isa("Memories::Photo")) - ? $maybe_photos : - ($r->{template_args}->{photos} || []); - for my $item (@$photos) { - my $link = $r->config->{uri_base}."photo/view/".$item->id; - $rss->add_item( title => $item->title, link => $link, - description => - " - thumb_url."\" alt=\"".$item->title."\">", - dc => { subject => join " ", $item->tags }, - pubDate => $item->uploaded->strftime("%a, %d %b %Y %H:%M:%S %z") - ) - } - $r->output($rss->as_string); - $r->content_type("application/rss+xml"); - return -} - -sub additional_data { - my $r = shift; - if ($r->params->{view_cal}) { - $r->{template_args}{view_cal} = eval { - Time::Piece->strptime($r->{params}{view_cal}, "%Y-%m-%d") }; - } - $r->{template_args}{now} = Time::Piece->new; - return $r->do_rss if ($r->params->{format} =~ /rss/) -} - -use Maypole::Constants; -sub authenticate { - my ($self, $r) = @_; - return DECLINED if $self->path =~/static|store/; # XXX - $r->get_user; - return OK; -} - - -use Cache::SharedMemoryCache; -my %cache_options = ( 'namespace' => 'MemoriesStuff', - 'default_expires_in' => 600 ); -my $cache = - new Cache::SharedMemoryCache( \%cache_options ) or - croak( "Couldn't instantiate SharedMemoryCache" ); - -sub zap_cache { $cache->Clear } -use Storable qw(freeze); use MIME::Base64; -sub do_cached { - my ($self, $codeblock,$arg) = @_; - my $key = 0+$codeblock; if ($arg) { $key .=":".encode_base64(freeze(\$arg)); } - my $c = $cache->get(0+$codeblock); return @$c if $c; - my @stuff = $codeblock->($arg); - $cache->set(0+$codeblock, [ @stuff ]); - return @stuff; -} - -sub _recent_uploads { Memories::Photo->search_recent() } - -sub recent_uploads { shift->do_cached(\&_recent_uploads) } -sub tagcloud { shift->do_cached(\&_tagcloud) } - -sub _tagcloud { - my $cloud = HTML::TagCloud->new(); - my $base = Memories->config->uri_base."tag/view/"; - for my $tagging (Memories::Tagging->search_summary) { - my $name = $tagging->tag->name; - $cloud->add($name, - $base.uri_escape($name), - $tagging->{count} - ) - } - $cloud -} - -sub calendar { - # shift->do_cached(\&_calendar, shift ) } -#sub _calendar { - my $self = shift; - my $arg = shift; - my ($y, $m) = split /-/, ($arg || Time::Piece->new->ymd); - my @m = Calendar::Simple::calendar($m, $y); - my @month; - foreach my $week (@m) { - my @weekdays; - foreach my $day (@$week) { - my $d = { day => $day }; - if ($day) { - my $tag = "date:$y-$m-".sprintf("%02d", $day); - my ($x) = Memories::SystemTag->search(name => $tag); - if ($x) { $d->{tag} = "/system_tag/view/$tag" } - } - push(@weekdays, $d); - } - push(@month, \@weekdays); - } - return \@month; -} - -# THIS IS A HACK - -use Time::Seconds; -sub Time::Piece::next_month { - my $tp = shift; - my $month = $tp + ONE_MONTH; - return if $month > Time::Piece->new; - return $month -} -sub Time::Piece::prev_month { - my $tp = shift; - my $month = $tp - ONE_MONTH; - return $month -} - - -sub tag_select { - my ($r, $tags) = @_; - my %counter; - my @photos = Memories::Photo->sth_to_objects(Memories::Tag->multi_search(@$tags)); - for (map {$_->tags} @photos) { - $counter{$_->name}++; - } - delete $counter{$_->name} for @$tags; - my @super; - - my $cloud = HTML::TagCloud->new(); - my $base = $r->config->uri_base.$r->path."/"; - my $tags; - for my $name (sort {$a cmp $b} keys %counter) { - if ($counter{$name} == @photos) { - push @super, $name; - } else { - $cloud->add($name, $base.uri_escape($name), $counter{$name}); - $tags++; - } - } - my %res; - if (@super) { $res{super} = \@super } - if ($tags) { $res{cloud} = $cloud } - \%res; -} -1; diff --git a/Memories/Config.pm b/Memories/Config.pm index f874eff..9796ab0 100644 --- a/Memories/Config.pm +++ b/Memories/Config.pm @@ -38,6 +38,9 @@ Memories->config->{auth}{session_args} = { LockDirectory => "/var/lib/memories/sessionlock", }; +# This is where your Image::Seek library will be stored. +Memories->config->{image_seek} = "/var/lib/memories/imageseek.db"; + # DISPLAY PARAMETERS # # It's OK to leave these as they are. diff --git a/Memories/Photo.pm b/Memories/Photo.pm index 6997989..4e2a59d 100644 --- a/Memories/Photo.pm +++ b/Memories/Photo.pm @@ -3,6 +3,7 @@ use strict; use Carp qw(cluck confess); use base qw(Memories::DBI Maypole::Model::CDBI::Plain); use Time::Piece; +use Image::Seek; use constant PAGER_SYNTAX => "LimitXY"; __PACKAGE__->columns(Essential => qw(id title uploader uploaded x y)); __PACKAGE__->untaint_columns(printable => [qw/title/]); @@ -48,6 +49,7 @@ sub do_upload :Exported { $photo->make_thumb; $photo->add_tags($r->{params}{tags}); + $photo->add_to_imageseek_library; Memories->zap_cache(); # Add system tags here @@ -64,6 +66,24 @@ sub do_upload :Exported { ); } +sub view :Exported { + my ($self, $r) = @_; + if ($r->{session}{last_search}) { + my $photo = $r->{objects}[0]; + # This is slightly inefficient + my @search = split/,/, $r->{session}{last_search}; + my $found = -1; + for my $i (0..$#search) { + next unless $photo->id == $search[$i]; + $found = $i; + } + return unless $found > -1; + $r->{template_args}{next} = $self->retrieve($search[$found+1]) + if $found+1 <= $#search; + $r->{template_args}{prev} = $self->retrieve($search[$found-1]) + if $found-1 >= 0; + } +} sub upload :Exported {} use Class::DBI::Plugin::Pager; @@ -80,6 +100,7 @@ sub recent :Exported { ); $r->objects([$pager->retrieve_all ]); $r->{template_args}{pager} = $pager; + $r->last_search; } sub add_comment :Exported { @@ -100,6 +121,35 @@ use Image::Info qw(dim image_info); use Image::ExifTool; my $cache = new Cache::MemoryCache( { 'namespace' => 'MemoriesInfo' }); +sub add_to_imageseek_library { + my $self = shift; + Image::Seek::cleardb(); + my $img = Image::Imlib2->load($self->path("file")); + + Image::Seek::add_image($img, $self->id); + # Merge this new one into the main database; there is a bit of a + # race condition here. XXX + Image::Seek::loaddb(Memories->config->{image_seek}); + Image::Seek::savedb(Memories->config->{image_seek}); +} + +sub recommended_tags { + my $self = shift; + my %tags = map { $_->name => $_ } + map { $_->tags } + $self->find_similar(3); + values %tags; +} + +sub find_similar { + my ($self, $count) = @_; + Image::Seek::cleardb(); + Image::Seek::loaddb(Memories->config->{image_seek}); + my @res = map {$_->[0] } Image::Seek::query_id($self->id, $count); + shift @res; # $self + map { $self->retrieve($_) } @res; +} + sub unrotate { my $self = shift; my $orient = $self->exif_info->{EXIF}->{Orientation}; diff --git a/Memories/SystemTag.pm b/Memories/SystemTag.pm index d4f8439..cdb8e14 100644 --- a/Memories/SystemTag.pm +++ b/Memories/SystemTag.pm @@ -30,6 +30,7 @@ sub view :Exported { $r->{template_args}{tags} = [$tag]; # For selector $r->{template_args}{photos} = [$pager->search_sorted_by_system_tag($tag->id)]; + $r->last_search; } package Memories::SystemTagging; diff --git a/Memories/Tag.pm b/Memories/Tag.pm index e1afdd2..1140185 100644 --- a/Memories/Tag.pm +++ b/Memories/Tag.pm @@ -38,6 +38,7 @@ sub view :Exported { $r->{template_args}{photos} = [$pager->search_sorted_by_tag($tag->id)]; } + $r->last_search(); } sub multi_search { @@ -90,6 +91,14 @@ FROM tagging GROUP BY tag ORDER BY count DESC /); +__PACKAGE__->set_sql(user_summary => qq/ +SELECT tagging.id id, tag, count(*) AS count +FROM tagging, photo +WHERE tagging.photo = photo.id AND photo.uploader = ? +GROUP BY tag +ORDER BY count DESC +/); + Memories::Tagging->has_a("photo" => "Memories::Photo"); Memories::Tagging->has_a("tag" => "Memories::Tag"); diff --git a/Memories/User.pm b/Memories/User.pm index 2fa82ca..b0020a5 100644 --- a/Memories/User.pm +++ b/Memories/User.pm @@ -30,6 +30,7 @@ sub view :Exported { $user->id,{order_by => "uploaded desc"}) ]; $r->{template_args}{pager} = $pager; $r->{template_args}{albums} = [$user->albums(privacy => 0)]; + $r->last_search; } # Album support! @@ -64,4 +65,13 @@ sub edit_albums :Exported { } +sub api_taglist :Exported { + my ($self, $r) = @_; + my $user = $r->objects->[0]; + $r->{output} .= $_->{tag}.":".$_->{count}."\n" + for Memories::Tagging->search_user_summary($user->id); + $r->{output}.= "\n"; + $r->{content_type} = "text/plain"; +} + 1; diff --git a/README b/README index b58ec3e..5b1fc00 100644 --- a/README +++ b/README @@ -24,7 +24,7 @@ application, but you're on your own. You will also need a MySQL database. Again, in theory other databases can be used, but in practice, you're on your own again. -Configure Maypole/Config.pm to your site, and follow the instructions in +Configure /etc/memories/Config.pm to your site, and follow the instructions in there - it will require you to set other things up as well. Test that everything works: diff --git a/Tagtools.pm b/Tagtools.pm new file mode 100644 index 0000000..0fc2529 --- /dev/null +++ b/Tagtools.pm @@ -0,0 +1,76 @@ +package Tagtools; +use HTML::TagCloud; +use Carp; +use Cache::FileCache; +use Storable qw(freeze); use MIME::Base64; +use Calendar::Simple; +sub import { + my $whence = caller; + my ($class) = @_; + my %cache_options = ( 'namespace' => $whence.'TagTools', + 'default_expires_in' => 600 ); + my $cache = + new Cache::FileCache( \%cache_options ) or + croak( "Couldn't instantiate FileCache" ); + *{$whence."::zap_cache"} = sub { $cache->Clear }; + *{$whence."::do_cached"} = sub { + my ($self, $codeblock,$arg) = @_; + my $key = 0+$codeblock; if ($arg) { $key .=":".encode_base64(freeze(\$arg)); } + my $c = $cache->get(0+$codeblock); return @$c if $c; + my @stuff = $codeblock->($arg); + $cache->set(0+$codeblock, [ @stuff ]); + return @stuff; + }; + *{$whence."::_tagcloud"} = sub { + my $cloud = HTML::TagCloud->new(); + my $base = $whence->config->uri_base."tag/view/"; + for my $tagging (($whence."::Tagging")->search_summary) { + my $name = $tagging->tag->name; + $cloud->add($name, $base.uri_escape($name), $tagging->{count}) + } + $cloud + }; + *{$whence."::_calendar"} = sub { + my $self = shift; + my $arg = shift; + my ($y, $m) = split /-/, ($arg || Time::Piece->new->ymd); + my @m = Calendar::Simple::calendar($m, $y); + my @month; + foreach my $week (@m) { + my @weekdays; + foreach my $day (@$week) { + my $d = { day => $day }; + if ($day) { + my $tag = "date:$y-$m-".sprintf("%02d", $day); + my ($x) = ($whence."::SystemTag")->search(name => $tag); + if ($x) { $d->{tag} = "/system_tag/view/$tag" } + } + push(@weekdays, $d); + } + push(@month, \@weekdays); + } + return \@month; + }; + for my $thing (qw(tagcloud calendar)) { + *{$whence."::$thing"} = sub { shift->do_cached($thing, @_) } + } + +} + + +# THIS IS A HACK + +use Time::Seconds; +sub Time::Piece::next_month { + my $tp = shift; + my $month = $tp + ONE_MONTH; + return if $month > Time::Piece->new; + return $month +} +sub Time::Piece::prev_month { + my $tp = shift; + my $month = $tp - ONE_MONTH; + return $month +} + +1; diff --git a/tag_dates b/tag_dates deleted file mode 100644 index e44af81..0000000 --- a/tag_dates +++ /dev/null @@ -1,10 +0,0 @@ -use Memories; -my $it = Memories::Photo->retrieve_all; - -my $thing = $it->first; -do { - print $thing->title, " $tag\n"; - my $tag = "date:".$thing->shot->ymd; - $thing->add_to_system_tags({tag => Memories::SystemTag->find_or_create({name - =>$tag}) }); -} while $thing = $it->next; diff --git a/templates/frontpage b/templates/frontpage index 2b36f1e..9bd9576 100644 --- a/templates/frontpage +++ b/templates/frontpage @@ -2,8 +2,7 @@

Welcome to Memories

- Memories is a site where you can upload and share your photos of - college life with your friends. + Memories is a site where you can upload and share your photos.

To view other people's photos, look at the - Memories - ANCC Photo Sharing + Memories - Photo Sharing [% IF photo %] - [% photo.title; END%] + [% IF photos %] + + Memories - ANCC Photo Sharing + + [% IF photos %] + +[% END %] +[% IF request.params.active == "tagedit" %] + + + + +[% ELSE %] + + +[% END %] +[% INCLUDE nav %] + + +
+ [% IF messages %] +
+
    [% FOR m = messages %]
  • [%m%]
  • [% END %] +
+ [% END %] +
diff --git a/templates/login b/templates/login new file mode 100644 index 0000000..b875129 --- /dev/null +++ b/templates/login @@ -0,0 +1,34 @@ + [% INCLUDE header %] + +
+ [% IF request.user %] + Welcome, [% request.user.name %] + [% ELSE %] + + [% IF login_error %] +
[% login_error %]
+ [% END %] +
+
+ Login or register as a new user + + + + +
+ Username: + + +
+ Password: + + +
+ + +
+
+ [% END %] +
+ + [% INCLUDE footer %] diff --git a/templates/macros b/templates/macros index f97cdd3..05824ef 100644 --- a/templates/macros +++ b/templates/macros @@ -1,15 +1,20 @@ -[% MACRO thumb(photo, album) BLOCK %] - -
+[% MACRO minithumb(photo) BLOCK %] [%photo.title|html%] +[% END; MACRO thumb(photo, album) BLOCK %] + +
+ [% minithumb(photo) %]
[% photo.title |html%] +
+ [% FOR tag = photo.tags %] [%tag %] [% END %]
Uploaded by diff --git a/templates/photo/similar b/templates/photo/similar new file mode 100644 index 0000000..2743353 --- /dev/null +++ b/templates/photo/similar @@ -0,0 +1,9 @@ +

+[% PROCESS macros; FOR sim = photo.find_similar(4); minithumb(sim); END %] +

+ +

+Suggested tags: [% FOR tag = photo.recommended_tags; %] +[%tag.name%] +[% END %] +

diff --git a/templates/photo/upload b/templates/photo/upload index d17d3cb..ad88ff8 100644 --- a/templates/photo/upload +++ b/templates/photo/upload @@ -1,6 +1,6 @@ - Memories - ANCC Photo Sharing + Memories - Photo Sharing diff --git a/templates/photo/view b/templates/photo/view index 74f352a..b8a06bf 100644 --- a/templates/photo/view +++ b/templates/photo/view @@ -4,7 +4,13 @@
+ [% IF prev %] + << [% prev %] + [% END %]

[% photo.title %]

+ [% IF next %] + [% next %] >> + [% END %] [% IF request.user == photo.uploader %]

Delete this photo

@@ -57,6 +63,8 @@ photo.uploader %] [% IF photo.is_bigger(sizes.$i); %] [% IF i == size %] [% sizes.$i %] + [% ELSIF sizes.$i == "full" %] + full [% ELSE %] [% sizes.$i %] [% END %] @@ -81,11 +89,13 @@ photo.uploader %] [%do_tab("comment", "Comments") %] [%do_tab("exif", "Photo info") %] [%do_tab("tagedit", "Edit tags") %] + [%do_tab("similar", "Similar photos") %]
[% IF request.params.active == "tagedit"; INCLUDE tagedit; ELSIF request.params.active == "exif"; INCLUDE exif; +ELSIF request.params.active == "similar"; INCLUDE similar; ELSE; INCLUDE comment; END; %]
diff --git a/templates/robots.txt b/templates/robots.txt new file mode 100644 index 0000000..7e053ec --- /dev/null +++ b/templates/robots.txt @@ -0,0 +1,5 @@ +User-agent: NaverBot +Disallow: / + +User-agent: * +Disallow: /tag/view/ diff --git a/templates/static/memories.png b/templates/static/memories.png index 97847d1..c9207c0 100644 Binary files a/templates/static/memories.png and b/templates/static/memories.png differ diff --git a/templates/static/sitemap.gz b/templates/static/sitemap.gz new file mode 100644 index 0000000..1f3d4d3 Binary files /dev/null and b/templates/static/sitemap.gz differ diff --git a/templates/test b/templates/test new file mode 100644 index 0000000..b5f5031 --- /dev/null +++ b/templates/test @@ -0,0 +1,2 @@ +[% INCLUDE header %] +[% INCLUDE footer %]