GuestBook.java
/*
* Copyright (C) 2012-2026Gerd Neugebauer
*
* This file is distributed under the 3-clause BSD license.
* See file LICENSE for details.
*/
package org.ctan.site.domain.site;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import org.apache.lucene.index.CorruptIndexException;
import org.ctan.site.domain.AbstractEntity;
import org.ctan.site.domain.account.User;
import org.ctan.site.services.search.base.IndexType;
import org.ctan.site.services.search.base.IndexingSession;
import org.ctan.site.services.search.base.IndexingSession.IndexArgs;
import org.ctan.site.services.search.base.Searchable;
import com.fasterxml.jackson.annotation.JsonFormat;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder.Default;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
/**
* This domain class represents an entry in the guest book.
*
* @author <a href="mailto:gene@ctan.org">Gerd Neugebauer</a>
*/
@Entity
@Table(name = "guestbook")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
@EqualsAndHashCode(callSuper = false)
@SuppressFBWarnings(value = "EI_EXPOSE_REP")
public class GuestBook extends AbstractEntity implements Searchable {
/**
* The field <code>title</code> contains the title of the guest book item.
*/
@Column(length = 128, nullable = false)
private String title;
/**
* The field <code>text</code> contains the text body of the guest book
* item.
*/
@Column(length = 2048, nullable = false)
private String text;
/**
* The field <code>name</code> contains the optional name of the author.
*/
@Column(length = 128, nullable = true)
private String name;
/**
* The field <code>email</code> contains the optional email address of the
* guest book item.
*/
@Column(length = 255, nullable = true)
private String email;
/**
* The field <code>hideEmail</code> contains the indicator to hide the email
* address.
*/
@Column(name = "hide_email")
private boolean hideEmail;
/**
* The field <code>hidden</code> contains the indicator to hide the complete
* item. This is used for spurious items.
*/
@Column
@Default
private boolean hidden = false;
/**
* The field <code>user</code> contains the optional user who has created
* the item.
*/
@ManyToOne
private User user;
/**
* The field <code>dateCreated</code> contains the time stamp when the item
* has been created.
*/
@Column(name = "date_created")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm")
@Default
private LocalDateTime dateCreated = LocalDateTime.now();
/**
* The field <code>lastUpdated</code> contains the time stamp when the item
* has been updated.
*/
@Column(name = "last_updated")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm")
@Default
private LocalDateTime lastUpdated = LocalDateTime.now();
/**
* The field <code>parent</code> contains the reference to the parent item.
*/
@ManyToOne
@Default
private GuestBook parent = null;
// static hasMany = [ followup: Guestbook ]
// static constraints = {
// lastUpdated()
// hidden()
// title maxSize: 128
// text blank: false, maxSize: 2048
// name nullable: true, maxSize: 128
// email nullable: true, maxSize: 255
// hideEmail()
// user nullable: true
// parent nullable: true
// dateCreated()
// }
/**
* The method <code>getIndexType</code> provides means to name the
* indexType.
*
* @return the index type
*/
public IndexType getIndexType() {
return IndexType.GUESTBOOK;
}
/**
* {@inheritDoc}
*
* @see org.ctan.site.services.search.base.Searchable#indexPath()
*/
@Override
public String indexPath() {
return "/guestbook/" + getId();
}
/**
* The method <code>toMap</code> provides means to get the instance as an
* immutable Map.
*
* @return the Map
*/
public Map<String, Object> toMap() {
Map<String, Object> map = new HashMap<>();
map.put("id", getId());
map.put("title", title);
map.put("text", text);
map.put("hidden", hidden);
map.put("hideEmail", hideEmail);
map.put("name", name);
if (user != null) {
if (user.getShowName()) {
map.put("name", user.getName());
}
map.put("account", user.getAccount());
}
map.put("created", String.format("%tF", dateCreated));
return map;
}
/**
* {@inheritDoc}
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return text.length() < 24 ? text : text.substring(0, 24) + "...";
}
/**
* This method <code>toUrl</code> returns the URL for the search index.
*
* @return the URL
*/
public String toUrl() {
return "/guestbook/item/" + getId();
}
/**
* {@inheritDoc}
*
* @see org.ctan.site.services.search.base.Searchable#updateIndex(org.ctan.site.services.search.base.IndexingSession,
* java.lang.String)
*/
@Override
public void updateIndex(IndexingSession session, String locale)
throws CorruptIndexException,
IOException {
session.updateIndex(indexPath(),
IndexArgs.builder()
.display(title)
.locale(locale)
.type(IndexType.GUESTBOOK)
.title(title)
.content(new String[]{
title,
text
})
.build());
}
}