view src/nabble/view/web/template/ServletNamespace.java @ 24:e0c501fb5229

remove trk
author Franklin Schmidt <fschmidt@gmail.com>
date Sun, 14 Jun 2020 17:56:59 -0600
parents 18cf4872fd7f
children
line wrap: on
line source

package nabble.view.web.template;

import fschmidt.util.java.HtmlUtils;
import fschmidt.util.servlet.JtpContext;
import fschmidt.util.servlet.ServletUtils;
import nabble.model.DailyNumber;
import nabble.model.ModelException;
import nabble.model.Node;
import nabble.model.Person;
import nabble.model.Site;
import nabble.model.User;
import nabble.model.ViewCount;
import nabble.naml.compiler.Command;
import nabble.naml.compiler.CommandSpec;
import nabble.naml.compiler.Encoder;
import nabble.naml.compiler.ExitException;
import nabble.naml.compiler.IPrintWriter;
import nabble.naml.compiler.Interpreter;
import nabble.naml.compiler.Namespace;
import nabble.naml.compiler.ScopedInterpreter;
import nabble.naml.namespaces.CommandDoc;
import nabble.naml.namespaces.TemplateException;
import nabble.view.lib.Jtp;
import nabble.view.lib.MyJtpServlet;
import nabble.view.lib.Shared;
import nabble.view.web.user.OnlineStatus;
import nabble.view.lib.Recaptcha;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


@Namespace (
	name = "servlet",
	global = true
)
public final class ServletNamespace extends RequestNamespace {
	private static final Logger logger = LoggerFactory.getLogger(ServletNamespace.class);

	public final HttpServletResponse response;
	private final NabbleNamespace nabbleNs;
	private UserNamespace visitorNs = null;

	public ServletNamespace(HttpServletRequest request, HttpServletResponse response) {
		super(request);
		this.response = response;
		this.nabbleNs = NabbleNamespace.current();
	}

	public final JtpContext jtpContext() {
		return MyJtpServlet.getJtpContext();
	}

	private Site site() {
		return nabbleNs.site();
	}

	private UserNamespace visitorNamespace()
		throws ServletException
	{
		if( visitorNs == null ) {
			if(Jtp.isCached(request,response) )
				throw new RuntimeException("can't get visitor on cached page");
			Person visitor = Jtp.getUser(request);
			visitorNs = new UserNamespace(visitor);
		}
		return visitorNs;
	}

	@Command public void dont_cache(IPrintWriter out,Interpreter interp) {
		Jtp.dontCache(response);
	}

	@Command public void default_host_name(IPrintWriter out,Interpreter interp) {
		out.print(Jtp.getDefaultHost());
	}

	public Person getVisitor()
		throws ServletException
	{
		return visitorNamespace().person();
	}

	public User getVisitorUser()
		throws ServletException
	{
		Person visitor = getVisitor();
		return !(visitor instanceof User) ? null : (User)visitor;
	}


	public static final CommandSpec visitor = CommandSpec.DO;

	@Command public void visitor(IPrintWriter out,ScopedInterpreter<UserNamespace> interp)
		throws ServletException
	{
		out.print( interp.getArg(visitorNamespace(),"do") );
	}


	private Map<String,FieldNamespace> fields;

	public static final CommandSpec field = new CommandSpec.Builder()
		.scopedParameters("do")
		.dotParameter("do")
		.parameters("name")
		.build()
	;

	@Command public void field(IPrintWriter out,ScopedInterpreter<FieldNamespace> interp) {
		String name = interp.getArgString("name");
		if (fields == null)
			fields = new HashMap<String,FieldNamespace>();
		FieldNamespace field = fields.get(name);
		if( field == null ) {
			field = new FieldNamespace(name);
			field.setValue(request);
			FieldNamespace f = fields.put(name,field);
			if( f != null )
				throw new RuntimeException("field named '"+name+"' already defined");
		}
		out.print( interp.getArg(field,"do") );
	}

	public static final CommandSpec redirect_to = CommandSpec.NO_OUTPUT()
		.dotParameter("url")
		.build()
	;

	@Command public void redirect_to(IPrintWriter out,Interpreter interp)
		throws IOException
	{
		interp.setEncoder(Encoder.TEXT);
		String redirectUrl = interp.getArgString("url").trim();
		Jtp.sendRedirect(request,response,redirectUrl);
		throw new ExitException();
	}

	public static final CommandSpec redirect_with_notice = new CommandSpec.Builder()
		.parameters("url")
		.dotParameter("notice")
		.build()
	;

	@Command public void redirect_with_notice(IPrintWriter out,Interpreter interp)
		throws IOException, ServletException
	{
		String notice = interp.getArgString("notice").trim();
		notice = notice.replaceAll("(\n|\r|\t)","");
		notice = HtmlUtils.javascriptStringEncode(notice);
		String redirectUrl = interp.getArgString("url").trim();
		Shared.javascriptRedirect(request, response, redirectUrl, "Nabble.setVar('notice','" + notice + "');");
		throw new ExitException();
	}

	public static final CommandSpec profile_update_with_redirection_to = CommandSpec.NO_OUTPUT()
		.dotParameter("url")
		.build()
	;

	@Command public void profile_update_with_redirection_to(IPrintWriter out,Interpreter interp)
			throws IOException, ServletException
	{
		StringBuffer js = new StringBuffer();
		String userId = ServletUtils.getCookieValue(request,"userId");
		if (Jtp.isInteger(userId)) {
			Person visitor = site().getUser(Long.valueOf(userId));
			if (visitor != null && visitor instanceof User) {
				User user = (User) visitor;
				String name = user.getName();
				String passcookie = user.getPasscookie();
				ServletUtils.setCookie(request, response, "username", HtmlUtils.urlEncode(name), true, null);
				ServletUtils.setCookie(request, response, "password", HtmlUtils.urlEncode(passcookie), true, null);
				js.append("if (parent.nabbleinfo) {");
				js.append("Nabble.setCookie('username','").append(HtmlUtils.javascriptStringEncode(HtmlUtils.urlEncode(name))).append("');");
				js.append("Nabble.setCookie('password','").append(HtmlUtils.javascriptStringEncode(HtmlUtils.urlEncode(passcookie))).append("');");
				js.append("}");
			}
		}
		String redirectUrl = interp.getArgString("url").trim();
		Shared.javascriptRedirect(request, response, redirectUrl, js.toString());
		throw new ExitException();
	}

	public static final CommandSpec send_http_error = new CommandSpec.Builder()
		.parameters("code")
		.dotParameter("text")
		.build()
	;

	@Command public void send_http_error(IPrintWriter out,Interpreter interp)
		throws IOException
	{
		String text = interp.getArgString("text").trim();
		int code = interp.getArgAsInt("code");
		response.sendError(code, text);
		throw new ExitException();
	}


	@Command public void set_visitor_online(IPrintWriter out,Interpreter interp)
		throws ServletException
	{
		User visitor = Jtp.getUser(request);
		OnlineStatus.setOnline(request, visitor, site());
	}

	public static final CommandSpec author_is_online = new CommandSpec.Builder()
		.parameters("search_id")
		.build()
	;

	@Command public void author_is_online(IPrintWriter out,Interpreter interp) {
		String authorId = interp.getArgString("search_id");
		out.print( OnlineStatus.isOnline(authorId, site()) );
	}


	public static final CommandSpec nabble_html = new CommandSpec.Builder()
		.scopedParameters("do","output")
		.build()
	;
	@CommandDoc(
		"Commands in \"do\" call \"put_in_head\" and print to the body at the same time.  Commands in \"output\" can't do this.  The \"output\" is the final output."
	)
	@Command public void nabble_html(IPrintWriter out,ScopedInterpreter<HtmlNamespace> interp) {
		HtmlNamespace ns = new HtmlNamespace(interp);
		out.print( interp.getArg(ns,"output") );
	}


	public static final CommandSpec check_user = new CommandSpec.Builder()
		.dotParameter("user_id")
		.outputtedParameters()
		.build()
	;

	@Command public void check_user(IPrintWriter out,Interpreter interp)
		throws ServletException
	{
		String userId = interp.getArgString("user_id");
		if( site().getUser(Jtp.parseLong(request,userId)) == null )
			throw Jtp.servletException(request,"user not found: "+userId);
	}


	public static final CommandSpec do_login = new CommandSpec.Builder()
		.parameters("email","password")
		.optionalParameters("nextUrl")
		.build()
	;

	@Command public void do_login(IPrintWriter out,Interpreter interp)
		throws IOException, ServletException
	{
		String email = interp.getArgString("email").trim();
		String password = interp.getArgString("password");
		String nextUrl = interp.getArgString("nextUrl");
		if( nextUrl == null )
			nextUrl = "/";
		User user = site().getUserFromEmail(email);
		if( user != null && user.isRegistered() && user.checkPassword(password) ) {
			Jtp.doLogin(request,response,user,true);
			DailyNumber.logins.inc();

			Shared.javascriptRedirect(request,response, nextUrl);
			throw new ExitException();
		}
	}

	public static final CommandSpec registration = CommandSpec.DO()
		.parameters("email","password","user_name")
		.optionalParameters("next_url")
		.build()
	;

	@Command public void registration(IPrintWriter out,ScopedInterpreter<RegistrationNamespace> interp)
		throws IOException, ServletException, ModelException
	{
		String email = interp.getArgString("email").trim();
		String userName = interp.getArgString("user_name");
		String password = interp.getArgString("password");
		String nextUrl = interp.getArgString("next_url");
		if( nextUrl == null )
			nextUrl = "/";
		out.print( interp.getArg(new RegistrationNamespace(site(), email,password,userName,nextUrl),"do") );
	}

	public static final CommandSpec check_captcha = CommandSpec.NO_OUTPUT;

	@Command public void check_captcha(IPrintWriter out, Interpreter interp)
		throws ModelException.InvalidRecaptcha, IOException
	{
		Recaptcha.check(request);
	}

	@Command public void do_logout(IPrintWriter out,Interpreter interp) {
		Jtp.logout(request,response);
	}

	public static final CommandSpec set_response_header = new CommandSpec.Builder()
		.parameters("name","value")
		.outputtedParameters()
		.build()
	;

	@Command public void set_response_header(IPrintWriter out,Interpreter interp) {
		response.setHeader( interp.getArgString("name"), interp.getArgString("value") );
	}

	@Command public void remote_address(IPrintWriter out,Interpreter interp) {
		out.print(Jtp.getClientIpAddr(request));
	}

	public static final CommandSpec increment_node_view_count = new CommandSpec.Builder()
		.parameters("node_id")
		.build()
	;

	@Command public void increment_node_view_count(IPrintWriter out,Interpreter interp)
		throws ServletException
	{
		Site site = NabbleNamespace.current().site();
		long nodeId = interp.getArgAsLong("node_id");
		boolean isUser = getVisitor() instanceof User;
		ViewCount.inc(site,nodeId,isUser);
	}


	public static final CommandSpec get_node_from_request_parameter = CommandSpec.DO;

	@Command public void get_node_from_request_parameter(IPrintWriter out,ScopedInterpreter<NodeNamespace> interp)
		throws IOException, ServletException, TemplateException
	{
		Node node = site().getNode( Jtp.getLong(request, "node") );
		if( node == null ) {
			throw TemplateException.newInstance("node_not_found");
		}
		out.print( interp.getArg(new NodeNamespace(node),"do") );
	}

	public static final CommandSpec get_user_from_parameter = CommandSpec.DO;

	@Command public void get_user_from_parameter(IPrintWriter out,ScopedInterpreter<UserNamespace> interp)
		throws IOException, ServletException
	{
		String userId = Jtp.getString(request,"user");
		Person person = site().getPerson(userId);
		if( person == null ) {
			response.sendError(HttpServletResponse.SC_NOT_FOUND, "User not found.");
			throw new ExitException();
		}
		out.print( interp.getArg(new UserNamespace(person),"do") );
	}


	Set<String> cacheEvents = null;

	public void cache(String event) {
		if( cacheEvents != null )
			cacheEvents.add(event);
	}

	public static final CommandSpec uncache_for = CommandSpec.NO_OUTPUT()
		.scopedParameters("do")
		.dotParameter("do")
		.optionalParameters("do")
		.build()
	;

	@Command public void uncache_for(IPrintWriter out,ScopedInterpreter<CacheNamespace> interp) {
		if( visitorNs != null )
			throw new RuntimeException("can't cache page that depends on visitor");
		CacheNamespace ns = new CacheNamespace();
		try {
			interp.getArgString(ns,"do");
			cacheEvents = ns.events;
			request.setAttribute(Jtp.CACHED,"yes");
		} catch(CacheNamespace.DontCache e) {}
	}

	public static final CommandSpec set_anonymous_name = CommandSpec.NO_OUTPUT()
		.parameters("name")
		.build()
	;

	@Command public void set_anonymous_name(IPrintWriter out,Interpreter interp)
		throws ServletException
	{
		Person visitor = getVisitor();
		String anonymousName = interp.getArgString("name");
		if( visitor instanceof User
			|| anonymousName == null
			|| anonymousName.trim().length() == 0
			|| !"POST".equals(request.getMethod())  // ???
		)
			return;
		try {
			visitor.setName(anonymousName);
		} catch(ModelException e) {
			throw new RuntimeException(e);
		}
        ServletUtils.setCookie(request, response, "anonymousName", HtmlUtils.urlEncode(anonymousName), true, null);
	}


	public static final CommandSpec get_registration = CommandSpec.DO()
		.parameters("registration_key","email")
		.build()
	;

	@Command public void get_registration(IPrintWriter out,ScopedInterpreter<UserNamespace> interp)
		throws ModelException
	{
		String key = interp.getArgString("registration_key");
		String email = interp.getArgString("email");
		User user = site().getRegistration(key);
		if (user==null || !user.getEmail().equalsIgnoreCase(email)) {
			logger.error("Registration failed: url="+ServletUtils.getCurrentURL(request)+" email="+email+" user="+(user==null?"null":user.getEmail())+" key="+key+" user-agent="+request.getHeader("user-agent"));
			out.print((String)null);
			return;
		}
		out.print( interp.getArg(new UserNamespace(user),"do") );
	}

	public static final CommandSpec get_next_url_from_registration = new CommandSpec.Builder()
		.parameters("registration_key")
		.build()
	;

	@Command public void get_next_url_from_registration(IPrintWriter out,Interpreter interp) {
		String key = interp.getArgString("registration_key");
		String nextUrl = site().getNextUrl(key);
		if( nextUrl==null )
			nextUrl = "/";
		out.print(nextUrl);
	}

	@Command public void visitor_ip_address(IPrintWriter out,Interpreter interp) {
		out.print(Jtp.getClientIpAddr(request));
	}

}