OSDN Git Service

Model::Tags: fix error message in add()
[newslash/newslash.git] / src / newslash_web / lib / Newslash / Model / Tags.pm
index 480f037..06f77cb 100644 (file)
@@ -1,8 +1,87 @@
 package Newslash::Model::Tags;
 #use Newslash::Model::Base -base;
 use base Newslash::Model::LegacyDB;
+use Data::Dumper;
+use List::Util qw(any all);
+
+use constant RESERVED_TAG_NAMES => [qw(metanix
+                                       metanod
+                                       nix
+                                       nod
+                                       poll
+                                       おもしろおかしい
+                                       すばらしい洞察
+                                       オフトピック
+                                       フレームのもと
+                                       不当プラスモデ
+                                       不当マイナスモデ
+                                       余計なもの
+                                       参考になる
+                                       既出
+                                       興味深い
+                                       荒し
+                                       荒らし
+                                       story
+                                       journal
+                                       comment
+                                       submission
+                                     )];
+
+sub is_reserved_name {
+    my ($self, $tag_name) = @_;
+    return any { $tag_name eq $_ } @{RESERVED_TAG_NAMES()};
+}
+
+sub select_for_items {
+    my ($self, $type, $primary_key, $items) = @_;
+    return if !$items;
+
+    if (ref($items) ne "ARRAY") {
+        $items = [$items];
+    }
+    return if !@$items;
+
+    my $globjs = $self->new_instance_of("Globjs");
+    my $gtid = $globjs->get_gtid($type);
+    return if !$gtid;
+
+    my @target_ids = map { $_->{$primary_key} } @$items;
+
+    # convert primary_key to globjid
+    #my @target_globj_ids;
+    #for my $id (@target_ids) {
+    #    my $globj_id = $globjs->get_globjid_from_item($type, $id);
+    #    push @target_globj_ids, $globj_id;
+    #}
+
+    my @placeholders = map { "?" } @target_ids;
+    my $placeholder = join(", ", @placeholders);
 
 
+    my $sql = <<"EOSQL";
+SELECT * FROM globjs
+  JOIN tags ON globjs.globjid = tags.globjid
+  JOIN tagnames ON tags.tagnameid = tagnames.tagnameid
+  WHERE globjs.gtid = ? AND globjs.target_id IN ($placeholder)
+EOSQL
+
+    my $dbh = $self->connect_db;
+    my $sth = $dbh->prepare($sql);
+    $sth->execute($gtid, @target_ids);
+    my $rs = $sth->fetchall_arrayref({});
+    $self->disconnect_db;
+
+    return if !$rs;
+
+    my $tags_of = {};
+    for my $tag (@$rs) {
+        my $id = $tag->{target_id};
+        $tags_of->{$id} = [] if !$tags_of->{$id};
+        push @{$tags_of->{$id}}, $tag;
+    }
+    return $tags_of;
+}
+
 sub get_topics {
     my ($self, ) = @_;
     my $sql = <<"EOSQL";
@@ -20,12 +99,12 @@ EOSQL
     return $rs;
 }
 
-sub set_tag {
+sub add {
     my $self = shift;
     return if $self->check_readonly;
     my $params = {@_};
-
     my $globj_id = $params->{globj_id};
+
     my $uid = $params->{uid} || 1;
     my $name = $params->{name};
     my $private = $params->{private} ? "yes" : "no";
@@ -33,7 +112,7 @@ sub set_tag {
     my $tagname_id = $params->{tagname_id};
 
     if (!$globj_id) {
-        $self->set_error("no globj_id", 1);
+        $self->last_error("no globj_id");
         return;
     }
 
@@ -48,6 +127,7 @@ sub set_tag {
     }
 
     if (!$tagname_id) {
+        $self->last_error("no tagname id");
         return;
     }
 
@@ -59,18 +139,161 @@ INSERT IGNORE INTO tags
     (?,         ?,       ?,   NOW(),     $inactivated, ?,       ?)
 EOSQL
 
-    my $dbh = $params->{dbh} || $self->connect_db;
+    my $dbh = $self->connect_db;
     my $rs = $dbh->do($sql, undef, $tagname_id, $globj_id, $uid, $private, $active);
     if (!$rs) {
-        $self->set_errorno($dbh->{mysql_errorno});
-        $self->disconnect_db if !$params->{dbh};
+        $self->set_errorno($dbh->err);
+        $self->disconnect_db;
         return;
     }
     my $id = $dbh->last_insert_id(undef, undef, undef, undef);
-    $self->disconnect_db if !$params->{dbh};
+    $self->disconnect_db;
     return $id;
 }
 
+sub del {
+    my $self = shift;
+    return if $self->check_readonly;
+    my $params = {@_};
+
+    my $globj_id = $params->{globj_id};
+    my $uid = $params->{uid} || 1;
+    my $name = $params->{name};
+    my $tagname_id = $params->{tagname_id};
+
+    if (!$globj_id) {
+        $self->set_error("no globj_id", 1);
+        return;
+    }
+
+    if ($name) {
+        my $tagname = $self->select_tagnames(tagname => $name);
+        if ($tagname) {
+            $tagname_id = $tagname->{tagnameid};
+        }
+        else {
+            $self->set_error("tagname not found", 2);
+            return;
+        }
+    }
+
+    if (!$tagname_id) {
+        $self->set_error("no tagname_id found", 3);
+        return;
+    }
+
+    my $sql = <<"EOSQL";
+DELETE FROM tags
+  WHERE tagnameid = ? 
+    AND globjid = ? 
+    AND uid = ?
+EOSQL
+
+    my $dbh = $self->connect_db;
+    my $rs = $dbh->do($sql, undef, $tagname_id, $globj_id, $uid);
+    if (!defined $rs) {
+        $self->set_errorno($dbh->err);
+        $self->disconnect_db;
+        return;
+    }
+    $self->disconnect_db;
+    return $rs;
+}
+
+sub set {
+    my $self = shift;
+    return if $self->check_readonly;
+    my $params = {@_};
+    my $globj_id = $params->{globj_id} || $params->{globjid};
+
+    if (!$globj_id) {
+        $self->set_error("no globj_id", 1);
+        return;
+    }
+    my $tag_names = $params->{names} || $params->{tagnames} || $params->{tag_names};
+
+
+    if (!$tag_names) {
+        if (!$params->{name} && !$params->{tagname} && !$params->{tag_name}) {
+            $self->set_error("no names given", 1);
+            return;
+        }
+        $tag_names = [$params->{name} || $params->{tagname} || $params->{tag_name}];
+    }
+
+    my $uid = $params->{uid} || 1;
+    my $private = $params->{private} ? "yes" : "no";
+    my $active = defined $params->{active} ? $params->{active} : 1;
+    my $tagname_value_of = $self->select_tagnames(tagnames => $tag_names);
+
+    # get tags for globj_id
+    my $existing_tags = $self->select(globjid => $globj_id,
+                                      uid => $uid);
+    return if !$existing_tags;
+
+    # create tagname
+    my @ids_to_add;
+    my @ids;
+    for my $name (@$tag_names) {
+        my $tagname_id;
+        if (!$tagname_value_of->{$name}) {
+            $tagname_id = $self->create(tagname => $name);
+            $tagname_value_of->{$name} = { tagname => $name,
+                                           tagnameid => $tagname_id };
+        }
+        else {
+            $tagname_id = $tagname_value_of->{$name}->{tagnameid};
+        }
+
+        push @ids, $tagname_id;
+        if (all { $tagname_id != $_ } @$existing_tags) {
+            push @ids_to_add, $tagname_id;
+        }
+    }
+
+    # add tags
+    my $sql = <<"EOSQL";
+INSERT IGNORE INTO tags
+    (tagnameid, globjid, uid, created_at, inactivated, private, is_active)
+  VALUES
+    (?,         ?,       ?,   NOW(),      NULL,        ?,       ?)
+EOSQL
+
+    my $dbh = $self->start_transaction;
+
+    # add tags
+    for my $tnid (@ids_to_add) {
+        my $rs = $dbh->do($sql, undef, $tnid, $globj_id, $uid, $private, $active);
+        if (!defined $rs) {
+            $self->set_error($dbh->err);
+            $self->rollback;
+            return;
+        }
+    }
+
+    # remove tags
+    my @placeholders = map { "?" } @ids;
+    my $placeholder_str = join(", ", @placeholders);
+    $sql = <<"EOSQL";
+DELETE FROM tags
+  WHERE globjid = ?
+    AND uid = ?
+    AND tagnameid NOT IN ($placeholder_str)
+EOSQL
+    my $rs = $dbh->do($sql, undef, $globj_id, $uid, @ids);
+    if (!defined $rs) {
+        $self->set_error($dbh->err);
+        $self->rollback;
+        return;
+    }
+    $self->commit;
+    return 1;
+}
+
+sub set_tag {
+    return shift->add(@_);
+}
+
 sub create {
     my $self = shift;
     my $params = {@_};
@@ -92,16 +315,69 @@ sub create {
 
 sub select {
     my $self = shift;
-    return $self->generic_select('tags',
-                                 uniques => [qw(tagid)],
-                                 keys => [qw(tagnameid globjid uid private is_active)],
-                                 params => {@_});
+    my $params = {@_};
+    my $unique_keys = { id => "tags.tagid",
+                        tagid => "tags.tagid",
+                      };
+    my $keys = { tagnameid => "tags.tagnameid",
+                 globjid => "tags.globjid",
+                 globj_id => "tags.globjid",
+                 uid => "tags.uid",
+                 private => "tags.private",
+                 is_active => "tags.is_active",
+                 tagname => "tagnames.tagname",
+                 tag_name => "tagnames.tagname",
+               };
+    my $datetime_keys = { created_at => "tags.created_at",
+                          inactivated => "tags.inactivated",
+                        };
+    my $timestamp = "tags.created_at";
+
+    my ($where_clause, $where_values, $unique) = $self->build_where_clause(unique_keys => $unique_keys,
+                                                                           keys => $keys,
+                                                                           datetime_keys => $datetime_keys,
+                                                                           timestamp => $timestamp,
+                                                                           params => $params);
+    my ($limit_clause, $limit_values) = $self->build_limit_clause(params => $params);
+    my ($orderby_clause, $orderby_values) = $self->build_order_by_clause(keys => $keys,
+                                                                         params => $params);
+
+    my @attrs;
+    push @attrs, @$where_values, @$limit_values, @$orderby_values;
+
+    my $dbh = $self->connect_db;
+    my $sql = <<"EOSQL";
+SELECT tags.*, tagnames.*
+  FROM tags
+    LEFT JOIN tagnames ON tags.tagnameid = tagnames.tagnameid
+    $where_clause
+    $orderby_clause
+    $limit_clause
+EOSQL
+
+    my $sth = $dbh->prepare($sql);
+    $sth->execute(@attrs);
+    my $items = $sth->fetchall_arrayref({});
+
+    if (!$items) {
+        $self->disconnect_db();
+        return;
+    }
+    if (@$items == 0) {
+        $self->disconnect_db();
+        return $unique ? undef : [];
+    }
+    return $items;
+
 }
 
 sub select_tagnames {
     my $self = shift;
     my $params = {@_};
 
+    $params->{tagname} ||= $params->{tag_name};
+    $params->{tagnames} ||= $params->{tag_names};
+
     if ($params->{tagname}) {
         my $sql = "SELECT * FROM tagnames WHERE tagname = ?";
         my $dbh = $self->connect_db;
@@ -114,6 +390,22 @@ sub select_tagnames {
         }
         return;
     }
+
+    if ($params->{tagnames}) {
+        my @placeholders = map { "?" } @{$params->{tagnames}};
+        my $placeholder_str = join(", ", @placeholders);
+
+        my $sql = "SELECT * FROM tagnames WHERE tagname IN ($placeholder_str)";
+        my $dbh = $self->connect_db;
+        my $sth = $dbh->prepare($sql);
+        $sth->execute(@{$params->{tagnames}});
+        my $rs = $sth->fetchall_hashref("tagname");
+        $self->disconnect_db;
+        if ($rs) {
+            return $rs;
+        }
+        return;
+    }
 }