view src/nabble/model/SiteGlobal.java @ 6:c4ed473452d4

better https support
author Franklin Schmidt <fschmidt@gmail.com>
date Mon, 22 Jul 2019 05:37:46 -0400
parents 7ecd1a4ef557
children 04d4c291484b
line wrap: on
line source

package nabble.model;

import fschmidt.db.DbDatabase;
import fschmidt.db.DbNull;
import fschmidt.db.DbObject;
import fschmidt.db.DbObjectFactory;
import fschmidt.db.DbRecord;
import fschmidt.db.DbTable;
import fschmidt.db.Listener;
import fschmidt.db.LongKey;
import fschmidt.util.java.DateUtils;
import fschmidt.util.java.ObjectUtils;
import nabble.view.lib.Jtp;
import nabble.view.lib.SiteDeleteMail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;


final class SiteGlobal implements DbObject<LongKey,SiteGlobal> {
	private static final Logger logger = LoggerFactory.getLogger(SiteGlobal.class);

	final SiteKey siteKey;
	private final DbRecord<LongKey,SiteGlobal> record;
	private String customDomain;
	private Date deleteDate;
	private int activity;
	private boolean isEmbarrassing = false;
	private String remoteAddr = null; // IP of the user who created the site
	private String baseUrl;

	SiteGlobal() {
		record = table.newRecord(this);
		record.insert();
		this.siteKey = SiteKey.getInstance(getId());
	}

	SiteGlobal(long siteId) {
		record = table.newRecord(this);
		record.fields().put("site_id", siteId );
		record.insert();
		this.siteKey = SiteKey.getInstance(getId());
	}

	private SiteGlobal(LongKey key,ResultSet rs)
		throws SQLException
	{
		record = table.newRecord(this,key);
		this.siteKey = SiteKey.getInstance(getId());
		customDomain = rs.getString("custom_domain");
		if( customDomain != null )
			customDomain = customDomain.intern();
		deleteDate = rs.getDate("delete_date");
		activity = rs.getInt("activity");
		isEmbarrassing = rs.getBoolean("is_embarrassing");
		remoteAddr = rs.getString("remote_addr");
	}

	public DbRecord<LongKey,SiteGlobal> getDbRecord() {
		return record;
	}

	public long getId() {
		return record.getPrimaryKey().value();
	}

	private DbTable<LongKey,SiteGlobal> table() {
		return record.getDbTable();
	}

	private DbDatabase db() {
		return table().getDbDatabase();
	}

	SiteImpl site() {
		return siteKey.site();
	}

	static DbTable<LongKey,SiteGlobal> table = Db.dbGlobal().newTable(
		"site_global",
		Db.dbGlobal().newIdentityLongKeySetter("site_id"),
		new DbObjectFactory<LongKey, SiteGlobal>() {
			public SiteGlobal makeDbObject(LongKey key,ResultSet rs,String tableName)
				throws SQLException
			{
				return new SiteGlobal(key,rs);
			}
		}
	);
	static {
		table.getPostUpdateListeners().add(new Listener<SiteGlobal>() {
			public void event(SiteGlobal siteGlobal) {
				SiteImpl.postUpdateListeners.event(siteGlobal.site());
			}
		} );
/*
		// for debugging
		table.getPreDeleteListeners().add(new Listener<SiteGlobal>() {
			public void event(SiteGlobal siteGlobal) {
				logger.error("deleting "+siteGlobal,new Exception());
			}
		} );
*/
	}

	static SiteGlobal getSiteGlobal(long siteId) {
		return table.findByPrimaryKey(new LongKey(siteId));
	}

	static SiteGlobal getSiteGlobal(ResultSet rs)
		throws SQLException
	{
		return table.getDbObject(rs);
	}

	public void setCustomDomain(String customDomain) {
		if( customDomain != null )
			customDomain = customDomain.toLowerCase();
		this.customDomain = customDomain;
		record.fields().put("custom_domain", DbNull.fix(customDomain) );
		if( !db().isInTransaction() )
			record.update();
//		calcBaseUrl();
	}

	public String getCustomDomain() {
		return customDomain;
	}

	public String getBaseUrl() {
		if( baseUrl == null ) {
			String domain = customDomain != null ? customDomain : Jtp.getDefaultBaseUrl(siteKey.site());
			baseUrl = Init.scheme(domain) + "://" + domain;
		}
		return baseUrl;
	}
/*
	void calcBaseUrl() {
		baseUrl = "http://" +
			(customDomain != null ? customDomain : Jtp.getDefaultBaseUrl(siteKey.site()));
	}
*/


	private static final Map<String,Long> domainMap = new WeakHashMap<String,Long>();

	static Long getSiteIdFromDomain(String customDomain) {
		Long siteId;
		synchronized(domainMap) {
			siteId = domainMap.get(customDomain);
			if( siteId == null ) {
				try {
					Connection con = Db.dbGlobal().getConnection();
					try {
						PreparedStatement stmt = con.prepareStatement(
							"select site_id from site_global where custom_domain = ?"
						);
						stmt.setString(1,customDomain);
						ResultSet rs = stmt.executeQuery();
						try {
							if( !rs.next() )
								return null;
							siteId = rs.getLong("site_id");
						} finally {
							rs.close();
							stmt.close();
						}
					} finally {
						con.close();
					}
				} catch(SQLException e) {
					throw new RuntimeException(e);
				}
				domainMap.put( customDomain.intern(), siteId );
			}
		}
		return siteId;
	}




	public int getActivity() {
		return activity;
	}

	void setActivity(int activity) {
		this.activity = activity;
		record.fields().put( "activity", activity );
		if( !db().isInTransaction() )
			record.update();
	}


	public Date getDeleteDate() {
		return deleteDate;
	}

	private void setDeleteDate(Date deleteDate) {
		if( deleteDate==null )
			throw new NullPointerException();
		this.deleteDate = deleteDate;
		record.fields().put("delete_date",deleteDate);
		record.update();
	}

	public void clearDeleteDate() {
		record.fields().put("delete_date",DbNull.TIMESTAMP);
		record.fields().put("activity",ViewCount.initialActivity);
		record.update();
	}

	private static final boolean deleteInactiveSites = Init.hasDaemons && Init.get("deleteInactiveSites",false);
	private static final int daysToDeletion = Init.get("daysToDeletion",30);

	private static void deleteInactiveSites() {
		logger.error("Starting deleteInactiveSites");
		List<SiteGlobal> sitesToDelete = new ArrayList<SiteGlobal>();
		try {
			Date deletionDate = DateUtils.addDays(new Date(),daysToDeletion);
			Connection con = Db.dbGlobal().getConnection();
			try {
				{
					Statement stmt = con.createStatement();
					ResultSet rs = stmt.executeQuery(
						"select * from site_global"
						+" where delete_date is null and activity=0"
					);
					int count = 0;
					while( rs.next() ) {
						SiteGlobal siteGlobal = SiteGlobal.getSiteGlobal(rs);
						try {
							SiteImpl site = siteGlobal.site();
							siteGlobal.setDeleteDate(deletionDate);
							count++;
							for( UserImpl user : site.getPosters() ) {
								if( !user.isRegistered() )
									continue;
								// Send an email if site has more than one node
								if (site.getRootNode().getDescendantCount() > 1) {
									SiteDeleteMail.send(user,site,daysToDeletion);
									logger.info("Site deletion email sent to " + user.getEmail() + " for " + site);
								} else
									logger.info("Site scheduled for deletion: " + site);
							}
						} catch(UpdatingException e) {
							logger.error("Couldn't schedule for deletion: " + e);
						}
						if( Executors.isShuttingDown() )
							return;
					}
					rs.close();
					stmt.close();
					logger.error("Sites scheduled for deletion = " + count);
				}
				{
					Statement stmt = con.createStatement();
					ResultSet rs = stmt.executeQuery(
						"select * from site_global"
						+" where delete_date < now()"
					);
					while( rs.next() ) {
						SiteGlobal siteGlobal = SiteGlobal.getSiteGlobal(rs);
						sitesToDelete.add(siteGlobal);
					}
					rs.close();
					stmt.close();
				}
			} finally {
				con.close();
			}
		} catch(SQLException e) {
			throw new RuntimeException(e);
		}
		for( SiteGlobal siteGlobal : sitesToDelete ) {
			try {
				Site site = siteGlobal.site();
				logger.error("Deleting inactive site ID=" + site.getId() + " (" + site.getRootNode().getSubject() + " / " + site.getRootNode().getDescendantCount() + " nodes)");
				site.delete();
			} catch(UpdatingException e) {
				logger.error("Couldn't delete inactive site: " + e);
			} catch(RuntimeException e) {
				logger.error("couldn't delete inactive site "+siteGlobal,e);
			}
		}
		logger.error("Finished deleteInactiveSites");
	}

	static {
		if( deleteInactiveSites ) {
			Executors.runDaily(new Runnable(){public void run(){
				deleteInactiveSites();
			}});
		}
	}


	public boolean isEmbarrassing() {
		return isEmbarrassing;
	}

	public void setEmbarrassing(boolean isEmbarrassing) {
		this.isEmbarrassing = isEmbarrassing;
		record.fields().put( "is_embarrassing", DbNull.fix(isEmbarrassing) );
		if( !db().isInTransaction() )
			record.update();
	}

	public String toString() {
		return "siteGlobal-"+getId();
	}

	@Override public boolean equals(Object obj) {
		return this==obj || obj instanceof SiteGlobal && record.isInDb() && ((SiteGlobal)obj).getId()==getId();
	}

	@Override public int hashCode() {
		return (int)getId();
	}


	boolean setRemoteAddr(String remoteAddr) {
		this.remoteAddr = remoteAddr;
		record.fields().put( "remote_addr", DbNull.fix(remoteAddr) );
		record.update();
		return true;
	}

}