@FilterWith({XSRFFilter.class, AdminFilter.class})
  public Result delete(Context context) {
    FlashScope flash = context.getFlashScope();
    Group group = context.getAttribute("group", Group.class);

    // TODO FIX ME locking until database modification done
    if (taskManager.isGoogleRunning()) {
      flash.error("admin.google.errorTaskRunning");
      return Results.redirect(
          router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
    }

    List<GoogleTarget> targets = googleDB.target.list(Arrays.asList(group.getId()));
    for (GoogleTarget target : targets) {
      googleDB.targetSummary.deleteByTarget(target.getId());
      googleDB.rank.deleteByTarget(group.getId(), target.getId());
      googleDB.target.delete(target.getId());
    }

    List<GoogleSearch> searches = googleDB.search.listByGroup(Arrays.asList(group.getId()));
    for (GoogleSearch search : searches) {
      deleteSearch(group, search);
    }

    baseDB.event.delete(group);
    baseDB.user.delPerm(group);
    if (!baseDB.group.delete(group)) {
      flash.error("admin.google.failedDeleteGroup");
      return Results.redirect(
          router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
    } else {
      flash.success("admin.google.groupDeleted");
      return Results.redirect(router.getReverseRoute(GroupController.class, "groups"));
    }
  }
  @FilterWith({XSRFFilter.class, AdminFilter.class})
  public Result renameTarget(
      Context context, @Param("name") String name, @Param("id") Integer targetId) {

    FlashScope flash = context.getFlashScope();
    Group group = context.getAttribute("group", Group.class);

    GoogleTarget target = getTarget(context, targetId);
    if (target == null) {
      flash.error("error.invalidWebsite");
      return Results.redirect(
          router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
    }

    if (name != null) {
      name = name.replaceAll("(^\\s+)|(\\s+$)", "");
    }

    if (Validator.isEmpty(name)) {
      flash.error("error.invalidName");
      return Results.redirect(
          router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
    }

    target.setName(name);
    googleDB.target.rename(target);

    flash.success("google.group.websiteRenamed");
    return Results.redirect(
        router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
  }
  @FilterWith({XSRFFilter.class, AdminFilter.class})
  public Result exportSearches(Context context, @Params("id[]") String[] ids) {
    FlashScope flash = context.getFlashScope();
    Group group = context.getAttribute("group", Group.class);

    if (ids == null || ids.length == 0) {
      flash.error("error.noSearchSelected");
      return Results.redirect(
          router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
    }

    List<GoogleSearch> searches = new ArrayList<>();
    for (String id : ids) {
      GoogleSearch search = null;
      try {
        search = getSearch(context, Integer.parseInt(id));
      } catch (Exception ex) {
        search = null;
      }

      if (search == null) {
        flash.error("error.invalidSearch");
        return Results.redirect(
            router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
      }

      searches.add(search);
    }

    StringBuilder builder = new StringBuilder();
    for (GoogleSearch search : searches) {
      builder.append(StringEscapeUtils.escapeCsv(search.getKeyword())).append(",");
      builder.append(search.getTld() != null ? search.getTld() : "com").append(",");
      builder.append(search.getDatacenter() != null ? search.getDatacenter() : "").append(",");
      builder
          .append(
              search.getDevice() != null
                  ? (search.getDevice() == GoogleDevice.DESKTOP ? "desktop" : "mobile")
                  : "")
          .append(",");
      builder
          .append(StringEscapeUtils.escapeCsv(search.getLocal() != null ? search.getLocal() : ""))
          .append(",");
      builder
          .append(
              StringEscapeUtils.escapeCsv(
                  search.getCustomParameters() != null ? search.getCustomParameters() : ""))
          .append("\n");
    }

    return Results.ok().text().render(builder.toString());
  }
 @FilterWith(XSRFFilter.class)
 public Result reset(Context context) {
   GoogleSettings options = new GoogleSettings();
   googleDB.options.update(options);
   context.getFlashScope().success("label.settingsUpdated");
   return Results.redirect(router.getReverseRoute(GoogleSettingsController.class, "settings"));
 }
Esempio n. 5
0
  @FilterWith(XSRFFilter.class)
  public Result generate(
      Context context,
      @Param("groups") Integer groups,
      @Param("searchPerGroup") Integer searchPerGroup,
      @Param("targetPerGroup") Integer targetPerGroup) {
    FlashScope flash = context.getFlashScope();

    if (groups == null
        || groups < 1
        || searchPerGroup == null
        || searchPerGroup < 1
        || targetPerGroup == null
        || targetPerGroup < 1) {
      flash.put("error", "error.invalidParameters");
      return Results.redirect(router.getReverseRoute(DebugController.class, "debug"));
    }

    for (int i = 0; i < groups; i++) {
      Group group = new Group(Group.Module.GOOGLE, "group#" + i);
      baseDB.group.insert(group);

      List<GoogleSearch> searches = new ArrayList<>();
      for (int j = 0; j < searchPerGroup; j++) {
        GoogleSearch search = new GoogleSearch("search#" + j + "#" + group.getName());
        search.setTld("com");
        searches.add(search);
      }
      googleDB.search.insert(searches, group.getId());

      List<GoogleTarget> targets = new ArrayList<>();
      for (int j = 0; j < targetPerGroup; j++) {
        int targetFakeId = j + 1;
        GoogleTarget target =
            new GoogleTarget(
                group.getId(),
                "target#" + targetFakeId + "#" + group.getName(),
                PatternType.REGEX,
                "^https?://www.site" + targetFakeId + ".com.+");
        targets.add(target);
      }
      googleDB.target.insert(targets);
    }

    flash.put("warning", "admin.debug.generated");
    return Results.redirect(router.getReverseRoute(DebugController.class, "debug"));
  }
  @FilterWith({XSRFFilter.class, AdminFilter.class})
  public Result delSearch(Context context, @Params("id[]") String[] ids) {

    FlashScope flash = context.getFlashScope();
    Group group = context.getAttribute("group", Group.class);

    if (ids == null || ids.length == 0) {
      flash.error("error.noSearchSelected");
      return Results.redirect(
          router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
    }

    List<GoogleSearch> searches = new ArrayList<>();
    for (String id : ids) {
      GoogleSearch search = null;
      try {
        search = getSearch(context, Integer.parseInt(id));
      } catch (Exception ex) {
        search = null;
      }

      if (search == null) {
        flash.error("error.invalidSearch");
        return Results.redirect(
            router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
      }

      searches.add(search);
    }

    // TODO FIX ME locking until database modification done
    if (taskManager.isGoogleRunning()) {
      flash.error("admin.google.errorTaskRunning");
      return Results.redirect(
          router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
    }

    for (GoogleSearch search : searches) {
      deleteSearch(group, search);
    }

    return Results.redirect(
        router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId())
            + "#tab-searches");
  }
  @FilterWith({XSRFFilter.class, AdminFilter.class})
  public Result rename(Context context, @Param("name") String name) {
    FlashScope flash = context.getFlashScope();
    Group group = context.getAttribute("group", Group.class);

    if (Validator.isEmpty(name)) {
      flash.error("error.invalidName");
      return Results.redirect(
          router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
    }

    group.setName(name);
    baseDB.group.update(group);

    flash.success("google.group.groupRenamed");
    return Results.redirect(
        router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
  }
Esempio n. 8
0
    @Override
    public Result filter(FilterChain filterChain, Context context) {

      if (props.isProd()) {
        context.getFlashScope().error("error.unauthorizedAccess");
        return Results.redirect(router.getReverseRoute(AuthController.class, "login"));
      }

      return filterChain.next(context);
    }
Esempio n. 9
0
  @FilterWith(XSRFFilter.class)
  public Result wipeRankings(Context context) {
    FlashScope flash = context.getFlashScope();

    googleDB.targetSummary.wipe();
    googleDB.rank.wipe();
    googleDB.serp.wipe();
    baseDB.run.wipe();

    flash.put("warning", "admin.debug.rankingsWiped");
    return Results.redirect(router.getReverseRoute(DebugController.class, "debug"));
  }
  @FilterWith({XSRFFilter.class, AdminFilter.class})
  public Result delTarget(Context context, @Params("id[]") String[] ids) {
    FlashScope flash = context.getFlashScope();
    Group group = context.getAttribute("group", Group.class);

    // TODO FIX ME locking until database modification done
    if (taskManager.isGoogleRunning()) {
      flash.error("admin.google.errorTaskRunning");
      return Results.redirect(
          router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
    }

    if (ids == null || ids.length == 0) {
      flash.error("error.noWebsiteSelected");
      return Results.redirect(
          router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
    }

    for (String id : ids) {
      GoogleTarget target = null;
      try {
        target = getTarget(context, Integer.parseInt(id));
      } catch (Exception ex) {
        target = null;
      }

      if (target == null) {
        flash.error("error.invalidWebsite");
        return Results.redirect(
            router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
      }

      googleDB.targetSummary.deleteByTarget(target.getId());
      googleDB.rank.deleteByTarget(group.getId(), target.getId());
      googleDB.target.delete(target.getId());
    }

    return Results.redirect(
        router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
  }
  @FilterWith({XSRFFilter.class, AdminFilter.class})
  public Result delEvent(Context context, @Param("day") String day) {
    FlashScope flash = context.getFlashScope();
    Group group = context.getAttribute("group", Group.class);

    Event event = new Event();
    event.setGroupId(group.getId());
    try {
      event.setDay(LocalDate.parse(day));
    } catch (Exception ex) {
    }
    if (event.getDay() == null) {
      flash.error("error.invalidDate");
      return Results.redirect(
          router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
    }

    baseDB.event.delete(event);
    flash.success("google.group.eventDeleted");
    return Results.redirect(
        router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
  }
Esempio n. 12
0
  @Override
  public void init(Router router) {

    router.GET().route("/").with(ApplicationController.class, "choice");
    router.GET().route("/acesUp").with(ApplicationController.class, "acesUp");
    router.GET().route("/SPacesUp").with(ApplicationController.class, "SPacesUp");

    router.GET().route("/game").with(ApplicationController.class, "gameGet");
    router.GET().route("/SPgame").with(ApplicationController.class, "SPgameGet");

    router.POST().route("/dealGame").with(ApplicationController.class, "dealPost");
    router.POST().route("/SPdealGame").with(ApplicationController.class, "SPdealPost");

    router
        .POST()
        .route("/moveCard/{columnFrom}/{columnTo}")
        .with(ApplicationController.class, "moveCard");
    router
        .POST()
        .route("/SPmoveCard/{columnFrom}/{columnTo}")
        .with(ApplicationController.class, "SPmoveCard");

    router.POST().route("/removeCard/{column}").with(ApplicationController.class, "removeCard");
    router.POST().route("/SPremoveCard/{column}").with(ApplicationController.class, "SPremoveCard");

    ///////////////////////////////////////////////////////////////////////
    // Assets (pictures / javascript)
    ///////////////////////////////////////////////////////////////////////
    router
        .GET()
        .route("/assets/webjars/{fileName: .*}")
        .with(AssetsController.class, "serveWebJars");
    router.GET().route("/assets/{fileName: .*}").with(AssetsController.class, "serveStatic");

    ///////////////////////////////////////////////////////////////////////
    // Index / Catchall shows index page
    ///////////////////////////////////////////////////////////////////////
    //        router.GET().route("/.*").with(ApplicationController.class, "index");
  }
Esempio n. 13
0
  @Override
  public void init(Router router) {

    router.GET().route("/").with(ApplicationController.class, "index");
    router.POST().route("/contactForm").with(ApplicationController.class, "SearchProcess");
    router.GET().route("/updateOnto").with(ApplicationController.class, "updateOnto");
    router.POST().route("/updateOnto").with(ApplicationController.class, "update");

    ///////////////////////////////////////////////////////////////////////
    // Assets (pictures / javascript)
    ///////////////////////////////////////////////////////////////////////
    router
        .GET()
        .route("/assets/webjars/{fileName: .*}")
        .with(AssetsController.class, "serveWebJars");
    router.GET().route("/assets/{fileName: .*}").with(AssetsController.class, "serveStatic");

    ///////////////////////////////////////////////////////////////////////
    // Index / Catchall shows index page
    ///////////////////////////////////////////////////////////////////////
    router.GET().route("/.*").with(ApplicationController.class, "index");
  }
  @FilterWith({XSRFFilter.class, AdminFilter.class})
  public Result addEvent(
      Context context,
      @Param("day") String day,
      @Param("title") String title,
      @Param("description") String description,
      @Param("redir-search") Integer redirSearchId,
      @Param("redir-target") Integer redirTargetId) {
    FlashScope flash = context.getFlashScope();
    Group group = context.getAttribute("group", Group.class);

    Event event = new Event();
    event.setGroupId(group.getId());
    try {
      event.setDay(LocalDate.parse(day));
    } catch (Exception ex) {
    }

    if (event.getDay() == null) {
      flash.error("error.invalidDate");
      return Results.redirect(
          router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
    }

    if (Validator.isEmpty(title)) {
      flash.error("error.invalidTitle");
      return Results.redirect(
          router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
    }

    if (baseDB.event.find(group, event.getDay()) != null) {
      flash.error("google.group.alreadyEventForThisDate");
      return Results.redirect(
          router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
    }

    event.setTitle(title);
    event.setDescription(Jsoup.clean(description == null ? "" : description, Whitelist.basic()));

    if (!baseDB.event.insert(event)) {
      flash.error("error.internalError");
      return Results.redirect(
          router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
    }

    flash.success("google.group.eventInserted");
    if (redirSearchId != null) {
      return Results.redirect(
          router.getReverseRoute(
              GoogleSearchController.class,
              "search",
              "groupId",
              group.getId(),
              "searchId",
              redirSearchId));
    }
    if (redirTargetId != null) {
      return Results.redirect(
          router.getReverseRoute(
              GoogleTargetController.class,
              "target",
              "groupId",
              group.getId(),
              "targetId",
              redirTargetId));
    }

    return Results.redirect(
        router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
  }
Esempio n. 15
0
  @FilterWith(XSRFFilter.class)
  public Result dryRun(
      Context context, @Param("startDate") String start, @Param("endDate") String end) {
    long _start = System.currentTimeMillis();
    FlashScope flash = context.getFlashScope();

    LocalDate startDate = null;
    LocalDate endDate = null;

    try {
      startDate = LocalDate.parse(start);
      endDate = LocalDate.parse(end);
    } catch (Exception ex) {
    }

    if (startDate == null || endDate == null || startDate.isAfter(endDate)) {
      flash.error("error.invalidDate");
      return Results.redirect(router.getReverseRoute(DebugController.class, "debug"));
    }

    Run lastRun = baseDB.run.findLast(Module.GOOGLE, null, null);
    if (lastRun != null && lastRun.getDay().isAfter(startDate)) {
      flash.error("error.invalidDate");
      return Results.redirect(router.getReverseRoute(DebugController.class, "debug"));
    }

    LocalDate date = LocalDate.from(startDate);

    GoogleSettings ggOptions = googleDB.options.get();

    int minPauseBetweenPageSec = ggOptions.getMinPauseBetweenPageSec();
    int maxPauseBetweenPageSec = ggOptions.getMaxPauseBetweenPageSec();
    ggOptions.setMinPauseBetweenPageSec(0);
    ggOptions.setMaxPauseBetweenPageSec(0);
    googleDB.options.update(ggOptions);

    try {
      while (date.isBefore(endDate)) {
        LOG.debug("dry run {}", date);
        if (!taskManager.startGoogleTask(
            new Run(Run.Mode.MANUAL, Module.GOOGLE, date.atTime(13, 37, 00)))) {
          LOG.error("can't startGoogleTask");
          flash.error("can't startGoogleTask");
          return Results.redirect(router.getReverseRoute(DebugController.class, "debug"));
        }
        taskManager.joinGoogleTask();
        date = date.plusDays(1);
      }
    } catch (Exception ex) {
      LOG.error("an error occured", ex);
      flash.error("an error occured");
      return Results.redirect(router.getReverseRoute(DebugController.class, "debug"));
    } finally {
      ggOptions.setMinPauseBetweenPageSec(minPauseBetweenPageSec);
      ggOptions.setMaxPauseBetweenPageSec(maxPauseBetweenPageSec);
      googleDB.options.update(ggOptions);
    }

    LOG.debug(
        "dry run timing : {}",
        DurationFormatUtils.formatDurationHMS(System.currentTimeMillis() - _start));
    flash.success("ok");
    return Results.redirect(router.getReverseRoute(DebugController.class, "debug"));
  }
  @FilterWith(XSRFFilter.class)
  public Result update(
      Context context,
      @Param("targetDisplayMode") String targetDisplayMode,
      @Param("searchDisplayMode") String searchDispayMode,
      @Param("pages") Integer pages,
      @Param("result-per-page") Integer resultPerPage,
      @Param("min-pause") Integer minPause,
      @Param("max-pause") Integer maxPause,
      @Param("maxThreads") Integer maxThreads,
      @Param("fetchRetry") Integer fetchRetry,
      @Param("tld") String tld,
      @Param("datacenter") String datacenter,
      @Param("device") Integer device,
      @Param("local") String local,
      @Param("custom") String custom) {
    FlashScope flash = context.getFlashScope();

    GoogleSettings defaultOptions = new GoogleSettings();
    GoogleSettings options = googleDB.options.get();

    if (pages != null && resultPerPage != null) {
      if (pages * resultPerPage > 1000 || pages * resultPerPage < 1) {
        flash.error("admin.google.invalidPages");
        return Results.redirect(router.getReverseRoute(GoogleSettingsController.class, "settings"));
      }
      options.setPages(pages);
      options.setResultPerPage(resultPerPage);
    }

    if (minPause != null && maxPause != null) {
      if (minPause > maxPause) {
        flash.error("admin.google.invalidPauseRange");
        return Results.redirect(router.getReverseRoute(GoogleSettingsController.class, "settings"));
      }
      options.setMinPauseBetweenPageSec(minPause);
      options.setMaxPauseBetweenPageSec(maxPause);
    }

    if (fetchRetry != null) {
      options.setFetchRetry(fetchRetry);
    }

    if (maxThreads != null) {
      options.setMaxThreads(maxThreads);
    }

    if (!Validator.isEmpty(tld)) {
      if (!Validator.isGoogleTLD(tld)) {
        flash.error("admin.google.invalidTLD");
        return Results.redirect(router.getReverseRoute(GoogleSettingsController.class, "settings"));
      }
      options.setDefaultTld(tld);
    } else {
      options.setDefaultTld(defaultOptions.getDefaultTld());
    }

    if (!Validator.isEmpty(datacenter)) {
      if (!Validator.isIPv4(datacenter)) {
        flash.error("error.invalidIP");
        return Results.redirect(router.getReverseRoute(GoogleSettingsController.class, "settings"));
      }
      options.setDefaultDatacenter(datacenter);
    } else {
      options.setDefaultDatacenter(defaultOptions.getDefaultDatacenter());
    }

    if (device != null && device == 1) {
      options.setDefaultDevice(GoogleDevice.SMARTPHONE);
    } else {
      options.setDefaultDevice(GoogleDevice.DESKTOP);
    }

    if (Validator.isNotEmpty(local)) {
      options.setDefaultLocal(local);
    } else {
      options.setDefaultLocal(defaultOptions.getDefaultLocal());
    }

    if (Validator.isNotEmpty(custom)) {
      options.setDefaultCustomParameters(custom);
    } else {
      options.setDefaultCustomParameters(defaultOptions.getDefaultCustomParameters());
    }

    googleDB.options.update(options);

    flash.success("label.settingsUpdated");
    return Results.redirect(router.getReverseRoute(GoogleSettingsController.class, "settings"));
  }
  @FilterWith({XSRFFilter.class, AdminFilter.class})
  public Result addTarget(
      Context context,
      @Param("target-radio") String targetType,
      @Params("name[]") String[] names,
      @Params("pattern[]") String[] patterns) {
    FlashScope flash = context.getFlashScope();
    Group group = context.getAttribute("group", Group.class);

    if (targetType == null
        || names == null
        || names.length == 0
        || patterns == null
        || patterns.length == 0
        || names.length != patterns.length) {
      flash.error("error.invalidParameters");
      return Results.redirect(
          router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
    }

    Set<GoogleTarget> targets = new HashSet<>();
    for (int i = 0; i < names.length; i++) {
      String name = names[i];
      String pattern = patterns[i];

      if (name != null) {
        name = name.replaceAll("(^\\s+)|(\\s+$)", "");
      }

      if (pattern != null) {
        pattern = pattern.replaceAll("(^\\s+)|(\\s+$)", "");
      }

      if (Validator.isEmpty(name)) {
        flash.error("error.invalidName");
        return Results.redirect(
            router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
      }

      PatternType type = null;
      try {
        type = PatternType.valueOf(targetType);
      } catch (Exception ex) {
        flash.error("error.invalidTargetType");
        return Results.redirect(
            router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
      }

      if (PatternType.DOMAIN.equals(type) || PatternType.SUBDOMAIN.equals(type)) {
        try {
          pattern = IDN.toASCII(pattern);
        } catch (Exception ex) {
          pattern = null;
        }
      }

      if (!GoogleTarget.isValidPattern(type, pattern)) {
        flash.error("error.invalidPattern");
        return Results.redirect(
            router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
      }

      targets.add(new GoogleTarget(group.getId(), name, type, pattern));
    }

    if (googleDB.target.insert(targets) < 1) {
      flash.error("error.internalError");
      return Results.redirect(
          router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
    }
    googleDB.serpRescan.rescan(null, targets, getSearches(context), true);

    Run runningGoogleTask = taskManager.getRunningGoogleTask();
    if (runningGoogleTask != null) {
      flash.put(
          "warning",
          msg.get(
                  "google.group.websiteInsertedWhileRun",
                  context,
                  Optional.absent(),
                  runningGoogleTask.getId())
              .or(""));
    } else {
      flash.success("google.group.websiteInserted");
    }

    return Results.redirect(
        router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
  }
  @FilterWith({XSRFFilter.class, AdminFilter.class})
  public Result addSearch(
      Context context,
      @Params("keyword[]") String[] keywords,
      @Params("tld[]") String tlds[],
      @Params("datacenter[]") String[] datacenters,
      @Params("device[]") Integer[] devices,
      @Params("local[]") String[] locals,
      @Params("custom[]") String[] customs) {
    FlashScope flash = context.getFlashScope();
    Group group = context.getAttribute("group", Group.class);

    if (keywords == null
        || tlds == null
        || datacenters == null
        || devices == null
        || locals == null
        || customs == null
        || keywords.length != tlds.length
        || keywords.length != datacenters.length
        || keywords.length != devices.length
        || keywords.length != locals.length
        || keywords.length != customs.length) {
      flash.error("error.invalidParameters");
      return Results.redirect(
          router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
    }

    Set<GoogleSearch> searches = new HashSet<>();

    for (int i = 0; i < keywords.length; i++) {
      GoogleSearch search = new GoogleSearch();

      if (keywords[i].isEmpty()) {
        flash.error("admin.google.keywordEmpty");
        return Results.redirect(
            router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
      }
      search.setKeyword(keywords[i]);

      if (!Validator.isGoogleTLD(tlds[i])) {
        flash.error("admin.google.invalidTLD");
        return Results.redirect(
            router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId()));
      }
      search.setTld(tlds[i]);

      if (!datacenters[i].isEmpty()) {
        if (!Validator.isIPv4(datacenters[i])) {
          flash.error("error.invalidIP");
          return Results.redirect(
              router.getReverseRoute(
                  GoogleGroupController.class, "view", "groupId", group.getId()));
        }
        search.setDatacenter(datacenters[i]);
      }

      if (devices[i] != null && devices[i] >= 0 && devices[i] < GoogleDevice.values().length) {
        search.setDevice(GoogleDevice.values()[devices[i]]);
      } else {
        search.setDevice(GoogleDevice.DESKTOP);
      }

      if (!Validator.isEmpty(locals[i])) {
        search.setLocal(locals[i]);
      }

      if (!Validator.isEmpty(customs[i])) {
        search.setCustomParameters(customs[i]);
      }

      searches.add(search);
    }

    List<GoogleSearch> knownSearches = new ArrayList<>();
    synchronized (searchLock) {
      for (GoogleSearch search : searches) {
        int id = googleDB.search.getId(search);
        if (id > 0) {
          search.setId(id);
          knownSearches.add(search);
        }
      }
      googleDB.search.insert(searches, group.getId());
    }

    googleDB.serpRescan.rescan(null, getTargets(context), knownSearches, false);

    flash.success("google.group.searchInserted");
    return Results.redirect(
        router.getReverseRoute(GoogleGroupController.class, "view", "groupId", group.getId())
            + "#tab-searches");
  }