@TraceCall
  @Override
  public void destroyPage(Context ctx, long pageId, boolean destroyAssociated) {
    checkUpdatePagePermission(ctx, pageId);
    String sql;

    SQLExecutor se = getSqlExecutor();
    if (destroyAssociated) {
      sql =
          new SQLBuilder.Select()
              .select("associated_id", "free_circle_ids")
              .from(pageTable)
              .where("destroyed_time=0 AND page_id = ${v(page_id)}", "page_id", pageId)
              .toString();
      Record pageRec = se.executeRecord(sql, null);
      if (MapUtils.isNotEmpty(pageRec)) {
        long associatedId = pageRec.getInt("associated_id");
        long[] freeCircleIds =
            StringUtils2.splitIntArray(pageRec.getString("free_circle_ids"), ",");
        long[] allCircleIds =
            associatedId > 0 ? ArrayUtils.add(freeCircleIds, 0, associatedId) : freeCircleIds;
        for (long circleId : allCircleIds) {
          GlobalLogics.getGroup()
              .updateGroupSimple(ctx, circleId, new Record(), Record.of("page_id", 0L));
        }
      }
    }

    sql =
        new SQLBuilder.Update()
            .update(pageTable)
            .value("destroyed_time", DateUtils.nowMillis())
            .where("page_id=${v(page_id)}", "page_id", pageId)
            .toString();

    se.executeUpdate(sql);
  }
  @TraceCall
  @Override
  public Record updatePage(
      Context ctx, Record pageRec, boolean withAssociated, boolean checkPermission) {
    long pageId = pageRec.checkGetInt("page_id");
    if (checkPermission) {
      checkUpdatePagePermission(ctx, pageId);
    }
    long now = DateUtils.nowMillis();
    String sql =
        new SQLBuilder.Update()
            .update(pageTable)
            .value("updated_time", now)
            .valueIf(
                pageRec.containsKey("email_domain1"),
                "email_domain1",
                pageRec.getString("email_domain1"))
            .valueIf(
                pageRec.containsKey("email_domain2"),
                "email_domain2",
                pageRec.getString("email_domain2"))
            .valueIf(
                pageRec.containsKey("email_domain3"),
                "email_domain3",
                pageRec.getString("email_domain3"))
            .valueIf(
                pageRec.containsKey("email_domain4"),
                "email_domain4",
                pageRec.getString("email_domain4"))
            .valueIf(pageRec.containsKey("type"), "type", pageRec.getString("type"))
            .valueIf(pageRec.containsKey("name"), "name", pageRec.getString("name"))
            .valueIf(pageRec.containsKey("name_en"), "name_en", pageRec.getString("name_en"))
            .valueIf(pageRec.containsKey("address"), "address", pageRec.getString("address"))
            .valueIf(
                pageRec.containsKey("address_en"), "address_en", pageRec.getString("address_en"))
            .valueIf(pageRec.containsKey("email"), "email", pageRec.getString("email"))
            .valueIf(pageRec.containsKey("website"), "website", pageRec.getString("website"))
            .valueIf(pageRec.containsKey("tel"), "tel", pageRec.getString("tel"))
            .valueIf(pageRec.containsKey("fax"), "fax", pageRec.getString("fax"))
            .valueIf(pageRec.containsKey("zip_code"), "zip_code", pageRec.getString("zip_code"))
            .valueIf(
                pageRec.containsKey("small_logo_url"),
                "small_logo_url",
                pageRec.getString("small_logo_url"))
            .valueIf(pageRec.containsKey("logo_url"), "logo_url", pageRec.getString("logo_url"))
            .valueIf(
                pageRec.containsKey("large_logo_url"),
                "large_logo_url",
                pageRec.getString("large_logo_url"))
            .valueIf(
                pageRec.containsKey("small_cover_url"),
                "small_cover_url",
                pageRec.getString("small_cover_url"))
            .valueIf(pageRec.containsKey("cover_url"), "cover_url", pageRec.getString("cover_url"))
            .valueIf(
                pageRec.containsKey("large_cover_url"),
                "large_cover_url",
                pageRec.getString("large_cover_url"))
            .valueIf(
                pageRec.containsKey("description"), "description", pageRec.getString("description"))
            .valueIf(
                pageRec.containsKey("description_en"),
                "description_en",
                pageRec.getString("description_en"))
            .valueIf(
                withAssociated && pageRec.containsKey("associated_id"),
                "associated_id",
                pageRec.getInt("associated_id"))
            .valueIf(
                withAssociated && pageRec.containsKey("free_circle_ids"),
                "free_circle_ids",
                pageRec.getString("free_circle_ids"))
            .where("destroyed_time=0 AND page_id=${v(page_id)}", "page_id", pageId)
            .toString();

    SQLExecutor se = getSqlExecutor();
    long n = se.executeUpdate(sql);
    if (n == 0) throw new ServerException(WutongErrors.PAGE_ILLEGAL, "Illegal page " + pageId);

    return getPage(ctx, pageId);
  }
  @TraceCall
  @Override
  public Record createPage(Context ctx, Record pageRec) {
    long viewerId = ctx.getViewerId();
    GlobalLogics.getAccount().checkUserIds(ctx, Long.toString(viewerId));
    long associatedId = pageRec.checkGetInt("associated_id");
    //        if (associatedId > 0) {
    //            int userType = Constants.getUserTypeById(associatedId);
    //            if (userType == Constants.PUBLIC_CIRCLE_OBJECT || userType ==
    // Constants.EVENT_OBJECT) {
    //                // TODO: group exists?
    //            } else if (userType == Constants.USER_OBJECT) {
    //                // TODO: user exists?
    //            } else {
    //                throw new ServerException(WutongErrors.PAGE_ILLEGAL_ASSOCIATED_ID);
    //            }
    //        }

    long now = DateUtils.nowMillis();
    String sql =
        new SQLBuilder.Insert()
            .insertIgnoreInto(pageTable)
            .values(
                new Record()
                    .set("created_time", now)
                    .set("updated_time", now)
                    .set("destroyed_time", 0L)
                    .set("email_domain1", pageRec.getString("email_domain1"))
                    .set("email_domain2", pageRec.getString("email_domain2"))
                    .set("email_domain3", pageRec.getString("email_domain3"))
                    .set("email_domain4", pageRec.getString("email_domain4"))
                    .set("type", pageRec.getString("type"))
                    .set("name", pageRec.getString("name"))
                    .set("name_en", pageRec.getString("name_en"))
                    .set("email", pageRec.getString("email"))
                    .set("website", pageRec.getString("website"))
                    .set("tel", pageRec.getString("tel"))
                    .set("fax", pageRec.getString("fax"))
                    .set("zip_code", pageRec.getString("zip_code"))
                    .set("small_logo_url", pageRec.getString("small_logo_url"))
                    .set("logo_url", pageRec.getString("logo_url"))
                    .set("large_logo_url", pageRec.getString("large_logo_url"))
                    .set("small_cover_url", pageRec.getString("small_cover_url"))
                    .set("cover_url", pageRec.getString("cover_url"))
                    .set("large_cover_url", pageRec.getString("large_cover_url"))
                    .set("description", pageRec.getString("description"))
                    .set("description_en", pageRec.getString("description_en"))
                    .set("creator", viewerId)
                    .set("associated_id", associatedId)
                    .set("free_circle_ids", pageRec.getString("free_circle_ids")))
            .toString();

    SQLExecutor se = getSqlExecutor();
    ObjectHolder<Long> idHolder = new ObjectHolder<Long>(0L);
    se.executeUpdate(sql, idHolder);
    if (idHolder.value == 0L)
      throw new ServerException(WutongErrors.PAGE_SERVICE_ERROR_CODE, "Create page error");

    GlobalLogics.getFriendship().followPage(ctx, ctx.getViewerId(), idHolder.value);
    return getPage(ctx, idHolder.value);
  }