[from now] 2012/05/23 21:37:03

diff --git a/src/main/java/org/ryu22e/nico2cal/controller/GenerateNicoliveController.java b/src/main/java/org/ryu22e/nico2cal/controller/GenerateNicoliveController.java
index 6913dde..7b4bcab 100644
--- a/src/main/java/org/ryu22e/nico2cal/controller/GenerateNicoliveController.java
+++ b/src/main/java/org/ryu22e/nico2cal/controller/GenerateNicoliveController.java
@@ -3,6 +3,8 @@ package org.ryu22e.nico2cal.controller;
 import java.util.List;
 import java.util.logging.Logger;

+import org.ryu22e.nico2cal.model.MyCalendar;
+import org.ryu22e.nico2cal.service.CalendarService;
 import org.ryu22e.nico2cal.service.NicoliveRssService;
 import org.ryu22e.nico2cal.service.NicoliveService;
 import org.slim3.controller.Controller;
@@ -45,20 +47,54 @@ public final class GenerateNicoliveController extends Controller {
     private NicoliveService nicoliveService = new NicoliveService();

     /**
-     * 全文検索用インデックスを作成するTaskQueueを追加する。
+     * @see CalendarService
+     */
+    private CalendarService calendarService = new CalendarService();
+
+    /**
+     * TaskQueueを追加する。
      * @param keys NicoliveのキーのList
      */
     private void addTaskQueue(List<Key> keys) {
         if (0 < keys.size()) {
-            TaskOptions options =
+            // 全文検索用インデックスを作成する。
+            TaskOptions optiotnForNicoIndex =
                     TaskOptions.Builder
                         .withUrl("/GenerateNicoliveIndex")
                         .method(Method.POST);
             for (Key key : keys) {
-                options = options.param("keys[]", Datastore.keyToString(key));
+                optiotnForNicoIndex =
+                        optiotnForNicoIndex.param(
+                            "keys[]",
+                            Datastore.keyToString(key));
             }
+            QueueFactory.getQueue("generate-nicoliveindex").add(
+                optiotnForNicoIndex);

-            QueueFactory.getQueue("generate-nicoliveindex").add(options);
+            // マイカレンダー（Google Calendar）にニコニコ生放送放送予定日をインポートする。
+            List<MyCalendar> myCalendars = calendarService.getMyCalendars();
+            for (MyCalendar myCalendar : myCalendars) {
+                TaskOptions optiotnForMyCalendarImport =
+                        TaskOptions.Builder
+                            .withUrl("/myCalendar/import")
+                            .method(Method.POST);
+                for (Key key : keys) {
+                    optiotnForMyCalendarImport =
+                            optiotnForMyCalendarImport.param(
+                                "keys[]",
+                                Datastore.keyToString(key));
+                }
+                optiotnForMyCalendarImport =
+                        optiotnForMyCalendarImport.param(
+                            "calendarId",
+                            myCalendar.getCalendarId());
+                optiotnForMyCalendarImport =
+                        optiotnForMyCalendarImport.param("userId", myCalendar
+                            .getUser()
+                            .getUserId());
+                QueueFactory.getQueue("mycalendar-import").add(
+                    optiotnForMyCalendarImport);
+            }
         }
     }

diff --git a/src/main/java/org/ryu22e/nico2cal/controller/myCalendar/ImportController.java b/src/main/java/org/ryu22e/nico2cal/controller/myCalendar/ImportController.java
new file mode 100644
index 0000000..3f202f4
--- /dev/null
+++ b/src/main/java/org/ryu22e/nico2cal/controller/myCalendar/ImportController.java
@@ -0,0 +1,21 @@
+package org.ryu22e.nico2cal.controller.myCalendar;
+
+import org.ryu22e.nico2cal.model.Nicolive;
+import org.slim3.controller.Controller;
+import org.slim3.controller.Navigation;
+
+/**
+ * Google Calendarに{@link Nicolive}の内容をインポートするコントローラー。
+ * @author ryu22e
+ *
+ */
+public final class ImportController extends Controller {
+
+    /*
+     * (non-Javadoc) {@inheritDoc}
+     */
+    @Override
+    public Navigation run() throws Exception {
+        return null;
+    }
+}
diff --git a/src/main/java/org/ryu22e/nico2cal/service/CalendarService.java b/src/main/java/org/ryu22e/nico2cal/service/CalendarService.java
index 2ba59bc..43c450d 100644
--- a/src/main/java/org/ryu22e/nico2cal/service/CalendarService.java
+++ b/src/main/java/org/ryu22e/nico2cal/service/CalendarService.java
@@ -313,4 +313,21 @@ public class CalendarService {
             Datastore.delete(keys);
         }
     }
+
+    /**
+     * {@link MyCalendar}のリストを取得する。
+     * @return {@link MyCalendar}のリスト
+     */
+    public List<MyCalendar> getMyCalendars() {
+        return Datastore.query(MyCalendarMeta.get()).asList();
+    }
+
+    /**
+     * マイカレンダー（Google Calendar）にニコニコ生放送の放送予定日をインポートする。
+     * @param myCalendar マイカレンダー
+     * @param key {@link Nicolive}の{@link Key}
+     */
+    public void importToMyCalendar(MyCalendar myCalendar, Key key) {
+        throw new AssertionError();
+    }
 }
diff --git a/src/test/java/org/ryu22e/nico2cal/controller/myCalendar/ImportControllerTest.java b/src/test/java/org/ryu22e/nico2cal/controller/myCalendar/ImportControllerTest.java
new file mode 100644
index 0000000..e6e5298
--- /dev/null
+++ b/src/test/java/org/ryu22e/nico2cal/controller/myCalendar/ImportControllerTest.java
@@ -0,0 +1,26 @@
+package org.ryu22e.nico2cal.controller.myCalendar;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.slim3.tester.ControllerTestCase;
+
+/**
+ * @author ryu22e
+ *
+ */
+public final class ImportControllerTest extends ControllerTestCase {
+
+    /**
+     * @throws Exception
+     */
+    @Test
+    public void run() throws Exception {
+        tester.start("/myCalendar/import");
+        ImportController controller = tester.getController();
+        assertThat(controller, is(notNullValue()));
+        assertThat(tester.isRedirect(), is(false));
+        assertThat(tester.response.getStatus(), is(200));
+    }
+}
diff --git a/src/test/java/org/ryu22e/nico2cal/service/CalendarServiceTest.java b/src/test/java/org/ryu22e/nico2cal/service/CalendarServiceTest.java
index 3d613bd..8953d35 100644
--- a/src/test/java/org/ryu22e/nico2cal/service/CalendarServiceTest.java
+++ b/src/test/java/org/ryu22e/nico2cal/service/CalendarServiceTest.java
@@ -5,6 +5,7 @@ import static org.junit.Assert.*;
 import static org.mockito.Mockito.*;

 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.LinkedList;
@@ -36,6 +37,7 @@ import com.google.appengine.api.NamespaceManager;
 import com.google.appengine.api.datastore.Key;
 import com.google.appengine.api.datastore.Link;
 import com.google.appengine.api.datastore.Text;
+import com.google.appengine.api.users.User;
 import com.google.appengine.api.users.UserServiceFactory;

 public final class CalendarServiceTest extends AppEngineTestCase {
@@ -484,4 +486,66 @@ public final class CalendarServiceTest extends AppEngineTestCase {
             new AppEngineCredentialStore().load("42", credential),
             is(true));
     }
+
+    /**
+     * @throws Exception
+     */
+    @Test
+    public void 連携対象カレンダーのリストを取得する() throws Exception {
+        assertThat(service, is(notNullValue()));
+
+        // テストデータの登録。
+        List<MyCalendar> testDataList = new ArrayList<MyCalendar>();
+        for (int i = 0; i < 10; i++) {
+            MyCalendar myCalendar = new MyCalendar();
+            myCalendar.setCalendarId("test" + 1);
+            myCalendar.setUser(new User(
+                "test" + 1 + "@gmail.com",
+                "example.com",
+                "test" + 1));
+            testDataList.add(myCalendar);
+        }
+        List<Key> testDatakeys = Datastore.put(testDataList);
+
+        List<MyCalendar> result = service.getMyCalendars();
+        assertThat(result, is(notNullValue()));
+        List<Key> resultKeys = new ArrayList<Key>();
+        for (MyCalendar myCalendar : result) {
+            resultKeys.add(myCalendar.getKey());
+        }
+        assertThat(resultKeys, is(testDatakeys));
+    }
+
+    /**
+     * @throws Exception
+     */
+    @Test
+    public void 連携対象カレンダーのリストを取得する_データが存在しない場合() throws Exception {
+        assertThat(service, is(notNullValue()));
+
+        List<MyCalendar> result = service.getMyCalendars();
+        assertThat(result, is(notNullValue()));
+        assertThat(result.size(), is(0));
+    }
+
+    /**
+     * @throws Exception
+     */
+    @Test
+    public void GoogleCalendarにニコニコ生放送の放送予定日をインポートする() throws Exception {
+        assertThat(service, is(notNullValue()));
+
+        Nicolive nicolinve = new Nicolive();
+        nicolinve.setTitle("ほげほげ");
+        nicolinve.setDescription(new Text("ほげほげ説明文"));
+        DateTime datetime = new DateTime(2011, 1, 1, 0, 0, 0, 0);
+        nicolinve.setOpenTime(datetime.toDate());
+        nicolinve.setLink(new Link("http://ryu22e.org/"));
+        Key key = Datastore.put(nicolinve);
+
+        MyCalendar myCalendar = new MyCalendar();
+        myCalendar.setCalendarId("calendar1");
+        myCalendar.setUser(new User("test1@gmail.com", "example.com", "test1"));
+        service.importToMyCalendar(myCalendar, key);
+    }
 }
diff --git a/war/WEB-INF/appengine-generated/datastore-indexes-auto.xml b/war/WEB-INF/appengine-generated/datastore-indexes-auto.xml
index be626f8..488e981 100644
--- a/war/WEB-INF/appengine-generated/datastore-indexes-auto.xml
+++ b/war/WEB-INF/appengine-generated/datastore-indexes-auto.xml
@@ -1,4 +1,4 @@
-<!-- Indices written at Wed, 23 May 2012 19:44:08 JST -->
+<!-- Indices written at Wed, 23 May 2012 20:42:05 JST -->

 <datastore-indexes/>

diff --git a/war/WEB-INF/queue.xml b/war/WEB-INF/queue.xml
index 9ad594c..3037253 100644
--- a/war/WEB-INF/queue.xml
+++ b/war/WEB-INF/queue.xml
@@ -13,4 +13,9 @@
     <rate>10/s</rate>
     <bucket-size>10</bucket-size>
   </queue>
+  <queue>
+    <name>mycalendar-import</name>
+    <rate>10/s</rate>
+    <bucket-size>10</bucket-size>
+  </queue>
 </queue-entries>
\ No newline at end of file
diff --git a/war/WEB-INF/web.xml b/war/WEB-INF/web.xml
index 0cc61d1..22ae295 100644
--- a/war/WEB-INF/web.xml
+++ b/war/WEB-INF/web.xml
@@ -173,6 +173,14 @@
     </security-constraint>
     <security-constraint>
         <web-resource-collection>
+            <url-pattern>/myCalendar/import</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>admin</role-name>
+        </auth-constraint>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
             <url-pattern>/myCalendar/*</url-pattern>
         </web-resource-collection>
         <auth-constraint>
diff --git a/war/js/nico2ical.js b/war/js/nico2ical.js
index d03dd0c..759cb53 100644
--- a/war/js/nico2ical.js
+++ b/war/js/nico2ical.js
@@ -29,7 +29,7 @@ $(function () {

     change();

-    $('#my-calendar-tab a').click(function (e) {
+    $('#mycalendar-tab a').click(function (e) {
         if ($(this).attr('data-disabled')) {
             return;
         }
@@ -48,7 +48,7 @@ $(function () {
         this.updateCalendar = function() {
             var s = this;
             $('#save-calendar').button('loading');
-            $('#my-calendar-tab a').attr('data-disabled', 'true');
+            $('#mycalendar-tab a').attr('data-disabled', 'true');
             $('input[name=calendarSummaries]').attr('disabled', 'disabled');
             $.ajax(
                     '/myCalendar/save',
@@ -68,7 +68,7 @@ $(function () {
                 s.isSavaError(true);
             }).complete(function() {
                 $('input[name=calendarSummaries]').removeAttr('disabled');
-                $('#my-calendar-tab a').removeAttr('data-disabled');
+                $('#mycalendar-tab a').removeAttr('data-disabled');
             });
         }.bind(this);
         this.disConnectCalendar = function() {
@@ -76,7 +76,7 @@ $(function () {
             if (confirm('実行すると連携が解除されます。よろしいですか？')) {
                 s.isDisconnectError(false);
                 $('#disconnect-calendar').button('loading');
-                $('#my-calendar-tab a').attr('data-disabled', 'true');
+                $('#mycalendar-tab a').attr('data-disabled', 'true');
                 $.ajax(
                         '/myCalendar/disConnect',
                         {
@@ -94,7 +94,7 @@ $(function () {
                     $('#disconnect-calendar').addClass('btn-danger').button('error');
                     s.isDisconnectError(true);
                 }).complete(function() {
-                    $('#my-calendar-tab a').removeAttr('data-disabled');
+                    $('#mycalendar-tab a').removeAttr('data-disabled');
                 });
             }
         }.bind(this);
diff --git a/war/myCalendar/index.jsp b/war/myCalendar/index.jsp
index 0513443..0dfbbc4 100644
--- a/war/myCalendar/index.jsp
+++ b/war/myCalendar/index.jsp
@@ -11,25 +11,25 @@
         </p>
       </header>

-      <ul class="nav nav-tabs" id="my-calendar-tab">
+      <ul class="nav nav-tabs" id="mycalendar-tab">
         <c:if test="${storedCredential}">
           <li id="nav-calendar-select" class="active">
-            <a data-target="#my-calendar-select" href="#">連携先の選択</a>
+            <a data-target="#mycalendar-select" href="#">連携先の選択</a>
           </li>
           <li>
-            <a data-target="#my-calendar-on-off" href="#">連携のON/OFF</a>
+            <a data-target="#mycalendar-on-off" href="#">連携のON/OFF</a>
           </li>
         </c:if>
         <c:if test="${!storedCredential}">
           <li class="active">
-            <a data-target="#my-calendar-on-off" href="#">連携のON/OFF</a>
+            <a data-target="#mycalendar-on-off" href="#">連携のON/OFF</a>
           </li>
         </c:if>
       </ul>

       <div class="tab-content">
         <c:if test="${storedCredential}">
-          <div class="tab-pane<c:if test="${storedCredential}"> active</c:if>" id="my-calendar-select">
+          <div class="tab-pane<c:if test="${storedCredential}"> active</c:if>" id="mycalendar-select">
             <form class="well">
               <div class="control-group">
                 <label class="control-label">連携するカレンダー名を選択して下さい（Google Calendar API利用上限の関係上、複数カレンダーの連携はできないようにしていますm(__)m）。</label>
@@ -54,9 +54,9 @@
                 </div><!-- /.controls -->
               </div><!-- /.control-group -->
             </form>
-          </div><!-- /#my-calendar-select -->
+          </div><!-- /#mycalendar-select -->
         </c:if>
-        <div class="tab-pane<c:if test="${!storedCredential}"> active</c:if>" id="my-calendar-on-off">
+        <div class="tab-pane<c:if test="${!storedCredential}"> active</c:if>" id="mycalendar-on-off">
           <form class="well">
             <div class="control-group">
               <div class="controls">
@@ -78,7 +78,7 @@
               </div>
             </div><!-- /.control-group -->
           </form>
-        </div><!-- /#my-calendar-on-off -->
+        </div><!-- /#mycalendar-on-off -->
       </div><!-- /.tab-content -->
     </div><!-- /.container -->
   </c:param>