001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.petstore.console.ops;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import java.util.*;
022
023import org.apache.juneau.commons.beanquery.*;
024import org.apache.juneau.petstore.console.*;
025import org.apache.juneau.petstore.console.pages.*;
026import org.apache.juneau.http.*;
027import org.apache.juneau.petstore.service.*;
028import org.apache.juneau.rest.server.*;
029import org.apache.juneau.console.datatables.*;
030import org.apache.juneau.console.datatables.adapter.*;
031import org.apache.juneau.rest.server.view.*;
032import org.apache.juneau.rest.server.view.freemarker.*;
033
034/**
035 * Audit log: a read-only, server-mode table over the store's audit trail.
036 *
037 * <p>
038 * The table's {@code at} column takes a timestamp range as a column search value; the query layer parses the ISO-8601
039 * instants.
040 *
041 * <h5 class='section'>Example:</h5>
042 * <p class='bjava'>
043 *    <jc>// What the table sends as the "at" column search to show one day:</jc>
044 *    <js>"$between(2026-09-30T00:00:00Z,2026-10-01T00:00:00Z)"</js>
045 *
046 *    <ja>@RestPost</ja>(path=<js>"/query"</js>)
047 *    <jk>public</jk> DataTablesResults&lt;AuditEntry&gt; query(<ja>@Content</ja> DataTablesRequest <jv>req</jv>) {
048 *       <jk>try</jk> (<jk>var</jk> <jv>s</jv> = store().queryAudit()) {
049 *          <jk>return</jk> DataTablesQuery.<jsm>run</jsm>(<jv>req</jv>, <jv>s</jv>);
050 *       }
051 *    }
052 * </p>
053 */
054@Rest(path="/audit", title="Audit")
055@SuppressWarnings({
056   "java:S110" // Inheritance depth comes from the BasicRestServlet hierarchy, not this page.
057})
058public class AuditRest extends PetstoreConsolePage {
059
060   private static final long serialVersionUID = 1L;
061
062   private static final int ROWS_CAP = 200;
063
064   /**
065    * Renders the Audit page.
066    *
067    * @param req The request; {@code ?builder} renders the builder twin.
068    * @return The page view.
069    */
070   @RestGet(path="/")
071   public View page(RestRequest req) {
072      return builder(req) ? twin(req, OpsPageBuilders.audit()) : FreemarkerView.of("audit.ftlh");
073   }
074
075   /**
076    * Server-mode DataTables query over the audit trail.
077    *
078    * @param req The DataTables request.
079    * @return One page of audit entries, or a 200 {@code error} envelope for a malformed search expression.
080    */
081   @RestPost(path="/query")
082   public DataTablesResults<AuditEntry> query(@Content DataTablesRequest req) {
083      try (var s = store().queryAudit()) {
084         return DataTablesQuery.run(req, s);
085      } catch (BeanQuerySyntaxException e) {
086         return DataTablesResults.error(req.getDraw(), e.getMessage());
087      }
088   }
089
090   /**
091    * @return The newest audit entries first, capped at {@value #ROWS_CAP}.
092    */
093   @RestGet(path="/rows")
094   public List<AuditEntry> rows() {
095      var all = tl(store().getAudit());
096      Collections.reverse(all);
097      return all.size() > ROWS_CAP ? all.subList(0, ROWS_CAP) : all;
098   }
099}