CtanSite3Resource.java

/*
 * Copyright © 2022-2025 The CTAN Team and individual authors
 *
 * This file is distributed under the 3-clause BSD license.
 * See file LICENSE for details.
 */
package org.ctan.site.resources.site;

import java.util.List;
import java.util.stream.Collectors;

import org.ctan.site.CtanConfiguration;
import org.ctan.site.stores.AuthorStore;
import org.ctan.site.stores.MessageStore;
import org.ctan.site.stores.PkgStore;
import org.ctan.site.stores.TopicStore;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import io.dropwizard.hibernate.UnitOfWork;
import jakarta.annotation.security.PermitAll;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import lombok.Builder;
import lombok.Getter;
import lombok.NonNull;

/**
 * The class <code>CtanSite3Resource</code> contains the controller for the site
 * resource.
 *
 * @author <a href="mailto:gene@ctan.org">Gerd Neugebauer</a>
 */
@Path("/3.0/site")
@Produces(MediaType.APPLICATION_JSON)
public class CtanSite3Resource {

    /**
     * The class <code>CtanMotd</code> contains the transport object for a motd.
     */
    @Getter
    @Builder
    @SuppressFBWarnings(value = "EI_EXPOSE_REP")
    protected static class CtanMotd {

        private long id;

        private String text;

        private String title;

        private String type;
    }

    /**
     * The class <code>CtanSiteConfigTo</code> contains the transport object for
     * the configuration resource.
     */
    @Getter
    @Builder
    @SuppressFBWarnings(value = "EI_EXPOSE_REP")
    protected static class CtanSiteConfigTo {

        private String name;

        private String version;

        private String[] languages;

        private List<CtanMotd> motd;

        private Long motdHash;

        private Long authors;

        private Long pkgs;

        private Long topics;
    }

    /**
     * The field <code>messageStore</code> contains the message store.
     */
    private MessageStore messageStore;

    /**
     * The field <code>service</code> contains the underlying service.
     */
    private CtanConfiguration config;

    /**
     * The field <code>authorStore</code> contains the author store.
     */
    private @NonNull AuthorStore authorStore;

    /**
     * The field <code>pkgStore</code> contains the package store.
     */
    private @NonNull PkgStore pkgStore;

    /**
     * The field <code>topicStore</code> contains the topic store.
     */
    private @NonNull TopicStore topicStore;

    /**
     * This is the constructor for the class <code>CtanSite3Resource</code>.
     *
     * @param config the CTAN configuration
     * @param messageStore the message store
     * @param authorStore the author store
     * @param pkgStore the package store
     * @param topicStore the topic store
     */
    @SuppressFBWarnings(value = {"CT_CONSTRUCTOR_THROW", "EI_EXPOSE_REP2"})
    public CtanSite3Resource(@NonNull CtanConfiguration config,
        @NonNull MessageStore messageStore,
        @NonNull AuthorStore authorStore,
        @NonNull PkgStore pkgStore,
        @NonNull TopicStore topicStore) {

        this.topicStore = topicStore;
        this.pkgStore = pkgStore;
        this.authorStore = authorStore;
        this.config = config;
        this.messageStore = messageStore;
    }

    /**
     * The method <code>getConfig</code> provides means to retrieve the
     * configuration of the site.
     *
     * @return the configuration
     */
    @GET
    @Path("/config")
    @PermitAll
    @UnitOfWork(value = "siteDb")
    public CtanSiteConfigTo getConfig() {

        var motd = messageStore.findAllCurrent();
        var ctan = config.getCtan();
        var motdHash = motd.stream()
            .map(it -> it.getId() & 0xffff)
            .reduce(0L, Long::sum);
        return CtanSiteConfigTo.builder()
            .name(config.getAppName())
            .version(config.getVersion())
            .languages(ctan.getLanguages())
            .authors(authorStore.count())
            .pkgs(pkgStore.count())
            .topics(topicStore.count())
            .motd(motd.stream()
                .map((var m) -> CtanMotd.builder()
                    .id(m.getId())
                    .text(m.getTextEn())
                    .title(m.getTitleEn())
                    .type(m.getType().toString())
                    .build())
                .collect(Collectors.toList()))
            .motdHash(motdHash)
            .build();
    }
}