/* * Copyright 2014 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.samples.apps.iosched.server.schedule.server.servlet; import com.google.appengine.api.mail.MailService.Message; import com.google.appengine.api.mail.MailServiceFactory; import com.google.appengine.api.users.UserService; import com.google.appengine.api.users.UserServiceFactory; import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.stream.JsonWriter; import com.google.samples.apps.iosched.server.schedule.Config; import com.google.samples.apps.iosched.server.schedule.model.JsonDataSource; import com.google.samples.apps.iosched.server.schedule.model.JsonDataSources; import com.google.samples.apps.iosched.server.schedule.server.cloudstorage.CloudFileManager; import com.google.samples.apps.iosched.server.schedule.server.input.VendorDynamicInput; import java.io.IOException; import java.io.Writer; import java.nio.channels.Channels; import java.util.HashSet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet that runs the Updater flow. Can be called from a cron job or directly. * The parameter force="true" forces a new update, even if the API session data has * not changed since the last run. * */ public class CMSUpdateServlet extends HttpServlet { private static final HashSet<String> nonAdminUsers = new HashSet<String>(); static { nonAdminUsers.add("ldale@google.com"); } private final UserService userService = UserServiceFactory.getUserService(); @Override public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { if ("true".equals(req.getParameter("cron"))) { // Request is triggered by cron script, treat as POST doPost(req, resp); return; } if (!performBasicChecking(req, resp)) { return; } boolean showOnly = "true".equals(req.getParameter("show")); if (showOnly) { process(resp, true); } else { redirectToConfirmationPage(req, resp); } } @Override public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { if (!performBasicChecking(req, resp)) { return; } String userConfirmation = req.getParameter("user_confirmation"); if (userConfirmation == null) { redirectToConfirmationPage(req, resp); return; } process(resp, false); } private void process(HttpServletResponse resp, boolean showOnly) throws IOException { // everything ok, let's update StringBuilder summary = new StringBuilder(); JsonObject contents = new JsonObject(); JsonDataSources sources = new VendorDynamicInput().fetchAllDataSources(); for (String entity: sources) { JsonArray array = new JsonArray(); JsonDataSource source = sources.getSource(entity); for (JsonObject obj: source) { array.add(obj); } summary.append(entity).append(": ").append(source.size()).append("\n"); contents.add(entity, array); } if (showOnly) { // Show generated contents to the output resp.setContentType("application/json"); Writer writer = Channels.newWriter(Channels.newChannel(resp.getOutputStream()), "UTF-8"); JsonWriter outputWriter = new JsonWriter(writer); outputWriter.setIndent(" "); new Gson().toJson(contents, outputWriter); outputWriter.flush(); } else { // Write file to cloud storage CloudFileManager fileManager = new CloudFileManager(); fileManager.createOrUpdate("__raw_session_data.json", contents, true); // send email Message message = new Message(); message.setSender(Config.EMAIL_FROM); message.setSubject("[iosched-data-update] Manual sync from CMS"); message.setTextBody( "Hey,\n\n" + "(this message is autogenerated)\n" + "This is a heads up that "+userService.getCurrentUser().getEmail()+" has just updated the IOSched 2015 data from the Vendor CMS.\n\n" + "Here is a brief status of what has been extracted from the Vendor API:\n" + summary + "\n\n" + "If you want to check the most current data that will soon be sync'ed to the IOSched Android app, " + "check this link: http://storage.googleapis.com/iosched-updater-dev.appspot.com/__raw_session_data.json\n" + "This data will remain unchanged until someone with proper privileges updates it again on https://iosched-updater-dev.appspot.com/cmsupdate\n\n" + "Thanks!\n\n" + "A robot on behalf of the IOSched team!\n\n" + "PS: you are receiving this either because you are an admin of the IOSched project or " + "because you are in a hard-coded list of I/O organizers. If you don't want to " + "receive it anymore, pay me a beer and ask kindly."); // TODO(arthurthompson): Reimplement mailing, it currently fails due to invalid sender. //MailServiceFactory.getMailService().sendToAdmins(message); resp.sendRedirect("/admin/schedule/updateok.html"); } } private void redirectToConfirmationPage(HttpServletRequest req, HttpServletResponse resp) throws IOException { try { req.getRequestDispatcher("/admin/schedule/cmsupdate.html").forward(req, resp); } catch (ServletException e) { throw new RuntimeException(e); } } private boolean performBasicChecking(HttpServletRequest req, HttpServletResponse resp) throws IOException { if (!userService.isUserLoggedIn()) { resp.sendRedirect(userService.createLoginURL(req.getRequestURI())); return false; } if (!isValidUser()) { resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Sorry, your user has no permission. If you think you should have, you know who to contact to get it."); return false; } // Ignore cron when running in production. if ("true".equals(req.getParameter("cron")) && !Config.STAGING) { return false; } return true; } private boolean isValidUser() { return userService.isUserLoggedIn() && ( userService.isUserAdmin() || nonAdminUsers.contains(userService.getCurrentUser().getEmail())); } }