view src/nabble/modules/ad/Ad.java @ 0:7ecd1a4ef557

add content
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 21 Mar 2019 19:15:52 -0600
parents
children
line wrap: on
line source

package nabble.modules.ad;

import fschmidt.db.DbDatabase;
import fschmidt.db.DbExpression;
import fschmidt.db.DbNull;
import fschmidt.db.DbRecord;
import fschmidt.db.NoKey;
import nabble.model.Db;
import nabble.model.ExtensionFactory;
import nabble.model.ModelHome;
import nabble.model.Site;
import nabble.model.ViewCount;
import nabble.naml.compiler.Template;
import nabble.naml.compiler.TemplatePrintWriter;
import nabble.naml.namespaces.BasicNamespace;
import nabble.view.web.template.NabbleNamespace;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;


public final class Ad {
	private static final Logger logger = LoggerFactory.getLogger(Ad.class);

	private static final String AD_MODULE_TASK = "ad_free";

	private static final ExtensionFactory<Site,Ad> FACTORY = new ExtensionFactory<Site,Ad>() {

		private final Set<Long> adFreeSites = Collections.newSetFromMap(new ConcurrentHashMap<Long,Boolean>());

		public String getName() {
			return AdModule.INSTANCE.getName();
		}

		public Class<Ad> extensionClass() {
			return Ad.class;
		}

		public Ad construct(Site site) {
			return null;
		}

		public Ad construct(Site site,ResultSet rs)
			throws SQLException
		{
			boolean isSafe = rs.getBoolean("is_safe");
			int credits = rs.getInt("ad_free");
			if( credits > 0 && adFreeSites.add(site.getId()) )
				site.addTask(AD_MODULE_TASK);
			boolean isCreditsForUsersOnly = rs.getBoolean("ad_credits_for_users");
			return new Ad(site,isSafe,credits,isCreditsForUsersOnly);
		}

		public Serializable getExportData(Site site) {
			throw new UnsupportedOperationException();
		}

		public void saveExportData(Site site,Serializable s) {
			throw new UnsupportedOperationException();
		}
	};

	static {
		ModelHome.addSiteExtensionFactory(FACTORY);
		ViewCount.addCalculateActivityListener(new Runnable(){public void run(){
			try {
				for( Site site : ModelHome.getSitesForTask(AD_MODULE_TASK) ) {
					Ad ad = Ad.of(site);
					int views;
					{
						Connection con = Db.dbGlobal().getConnection();
						String field = ad.isCreditsForUsersOnly ? "user_views" : "views";
						PreparedStatement stmt = con.prepareStatement(
							"select " + field + " from site_global where site_id = ?"
						);
						stmt.setLong(1,site.getId());
						ResultSet rs = stmt.executeQuery();
						rs.next();
						views = rs.getInt(field);
						rs.close();
						stmt.close();
						con.close();
						if( views > 0 && !ad.wasCreatedRecently() ) {
							ad.decCredits(views);
						} else {
							site.addTask(AD_MODULE_TASK);
						}
					}
					if( ad.getCredits() > 0 ) {
						Connection con = site.getDb().getConnection();
						PreparedStatement stmt = con.prepareStatement(
							"update site set monthly_views = monthly_views*29/30 + ?"
						);
						stmt.setInt(1,views);
						stmt.executeUpdate();
						stmt.close();
						con.close();
					}
				}
			} catch(SQLException e) {
				logger.error("",e);
				throw new RuntimeException(e);
			}
		}});
	}

	static void init() {}

	public static Ad of(Site site) {
		return site.getExtension(FACTORY);
	}


	private final Site site;
	private boolean isSafe;
	private int credits = 0;
	private boolean isCreditsForUsersOnly;

	Ad(Site site,boolean isSafe,int credits,boolean isCreditsForUsersOnly) {
		this.site = site;
		this.isSafe = isSafe;
		this.credits = credits;
		this.isCreditsForUsersOnly = isCreditsForUsersOnly;
	}

	public boolean isSafe() {
		return isSafe;
	}

	public void setSafe(boolean isSafe) {
		DbRecord<NoKey,?> record = site.getDbRecord();
		this.isSafe = isSafe;
		record.fields().put( "is_safe", isSafe );
//		if( !isSafe ) {
//			record.fields().put( "when_created", DbExpression.NOW );
//			record.fields().put( "ad_credits_for_users", false );
//		}
		if (!site.getDb().isInTransaction()) {
			record.update();
		}
	}

	public int getCredits() {
		return credits;
	}

	public void setCredits(int credits) {
		if( credits < 0 )
			credits = 0;
		DbRecord<NoKey,?> record = site.getDbRecord();
		this.credits = credits;
		record.fields().put( "ad_free", DbNull.fix(credits) );
		DbDatabase db = site.getDb();
		if( !db.isInTransaction() )
			record.update();
		if( credits > 0 )
			site.addTask(AD_MODULE_TASK);
	}

	public void incCredits(int n) {
		setCredits(this.credits + n);
	}

	private void decCredits(int n) {
		setCredits(this.credits - n);

		// notify user?
		// I'm supposing that everyday we will deduct n credits, so he has one more day to buy new ones
		// I test if he has more than 0 credits to avoid send emails to everyone that doesn't have or buy credits
		if( this.credits < n && this.credits > 0) {  // condition here
			Template template = site.getTemplate( "ad_notice",
				BasicNamespace.class, NabbleNamespace.class
			);
			template.run( TemplatePrintWriter.NULL, Collections.<String,Object>emptyMap(),
				new BasicNamespace(template),
				new NabbleNamespace(site)
			);
		}
	}

	public boolean isPaid() {
		return false;
	}

	public boolean isCreditsForUsersOnly() {
		return isCreditsForUsersOnly;
	}

	private static long ONE_DAY = 24 * 60 * 60 * 1000L; // 1 day
	private static long LIMIT_DAYS = 6 * 30 * ONE_DAY; // 6 months

	boolean wasCreatedRecently() {
		long whenCreated = site.getWhenCreated().getTime();
		long now = new Date().getTime();
		return now < whenCreated + LIMIT_DAYS;
	}

 	long lastDayWithoutAds() {
		return site.getWhenCreated().getTime() + LIMIT_DAYS;
	}

}