view src/nabble/view/web/app/Addons.java @ 47:72765b66e2c3

remove mailing list code
author Franklin Schmidt <fschmidt@gmail.com>
date Fri, 18 Jun 2021 17:44:24 -0600
parents 5ea557eece1f
children 4674ed7d56df
line wrap: on
line source


package nabble.view.web.app;

import fschmidt.db.DbDatabase;
import nabble.model.Node;
import nabble.model.Site;
import nabble.model.User;
import nabble.view.lib.Jtp;
import nabble.view.lib.Permissions;
import nabble.view.lib.Shared;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;


public final class Addons extends HttpServlet {

	private static class ModuleInfo {
		String moduleName;
		String name;
		String description;
	}

	private static Map<String, List<ModuleInfo>> modulesByCategory = new LinkedHashMap<String, List<ModuleInfo>>();

	private static String firstTab;

	private static void addModule(String category, String moduleName, String name, String description) {
		if (firstTab == null)
			firstTab = category;
		List<ModuleInfo> list = modulesByCategory.get(category);
		if (list == null) {
			list = new ArrayList<ModuleInfo>();
			modulesByCategory.put(category, list);
		}
		ModuleInfo info = new ModuleInfo();
		info.moduleName = moduleName;
		info.name = name;
		info.description = description;
		list.add(info);
	}

	static {
		addModule("Social", "social_dropdown_links", "Social dropdown links", "Show social links under the \"More\" menu of posts. With these links, users will be able to easily post to Twitter, Facebook, Delicious, Stumble Upon, LinkedIn, Google Bookmarks and Digg, which helps promoting your site.");
		addModule("Social", "social_google_plus_one", "Google +1 button", "Show the Google +1 button on the top of the topic page.<br/><a href=\"http://www.google.com/+1/button/\" rel=\"nofollow\">Learn more</a>");
		addModule("Social", "social_facebook_like", "Facebook like button", "Show the Facebook Like button on the top of the topic page. <br/><a href=\"http://developers.facebook.com/docs/reference/plugins/like/\" rel=\"nofollow\">Learn more</a>");
		addModule("Social",  "social_tweet", "Tweet button", "Show Twitter / Tweet button on the top of the topic page. <br/><a href=\"http://twitter.com/about/resources/tweetbutton\" rel=\"nofollow\">Learn more</a>");

		addModule("Content",  "content_noindex", "Hide contents from search engines", "Select this checkbox if you want to prevent Google and other search engines from indexing the contents of this application.");
		addModule("Content",  "content_open_links_in_new_window", "Open links in new window", "Links posted by users will open in a different tab or window.");
		addModule("Content",  "content_smart_cache", "Smart application pages",
			"If your application has private sub-forums (or any other private sub-app), you can use this feature to make app pages always display the contents that the user can view. "+
			"In other words, if a user has access to a private sub-forum, he/she will be able to view the private contents from the top-level app. "+
			"Other users (without access) will only view the public contents. "+
			"<b>Note</b>: this feature may slow down your app pages a little bit because the system must generate them from scratch for each user. You will probably not notice any difference if your application is small (e.g., less than 5,000 topics).");
		addModule("Content",  "content_news_summary", "Custom summary for Newspaper",
			"If you use the Newspaper application type, you can use this add-on to define custom snippets for your posts "+
			"(the snippet is the text that shows on the front page of the app, immediately below the title of the post). " +
			"You can specify the snippet directly in the post message like this: \"{summary_start} Here is your summary text {summary_end} Here is the post message.\" "+
			"The text between the tags is the snippet to be displayed on the news page and will NOT appear on the post page."
		);
		addModule("Content",  "forum_avatars", "Show avatars on forum page", "Shows the avatar for the first and last post of each topic on the forum page.");
		addModule("Content",  "semiprivate", "Restrict to registered users", "Only allow registered users to view the forum.");

		addModule("Email & Notifications",  "email_registration_notification", "Notify me when someone registers", "When a user completes the registration process, an email is sent to all administrators with the details of the user (e.g., username, email, link to profile page).");

		addModule("Privacy & Law",  "cookie_policy", "Cookie Law Compliance Solution", "Add-on for obtaining a user's explicit consent for the use of cookies on their browsers. This is required by some countries (mainly UK and EU) and visitors must explicitly agree with the E-Privacy Directive before having cookies read from/written to their browsers. The consent is requested just once. By default, the consent is requested to UK visitors only, but you can change the list of countries with NAML (i.e., override the <i>cookie_countries</i> macro).");

		addModule("Responsiveness",  "responsive", "Responsive layout", "Add-on that improves the responsiveness of Nabble apps and make pages more readable on small screens.");
		addModule("Responsiveness",  "mobile", "Better new post interface for mobile users", "Add-on that provides a better \"new topic\" and \"reply\" interfaces for mobile users. Posting new messages from cell phones (or any device with a small screen) will be easier with this module. Only mobile users will see the optimized pages (other users will still see the default new topic and reply pages).");

		addModule("Navigation",  "thread_navigation", "Show links to next/previous threads", "This add-on adds \"Previous Thread\" and \"Next Thread\" links to the top of each thread page. Navigation through the threads becomes easier since users don't have to return to the front page in order to visit other threads.");

		addModule("Work", "workgroup", "Workgroup",
			"This feature allows a team to work integrated with a forum. " +
			"Basically, a user can assign a topic to another user with a priority that ranges from 1 (highest) to 5 (lowest).This feature allows a team to work integrated with a forum." +
			"Each topic represents a task that holds the discussion about the work to be accomplished.<br/>" +
			"<a href=\"http://nabble-support.1.n2.nabble.com/Workgroups-td1559166.html\">Learn more</a>"
		);

		addModule("Voting & Survey",  "poll", "Polls", "Allows you to add polls/surveys to your posts and collect votes from your visitors. " +
				"You will find options to add a new poll when you create a new topic or reply to a post." +
				"By default, only administrators can create polls. If you want to let other groups create polls, just modify the Create_poll permission. ");
	}

	protected void service(HttpServletRequest request,HttpServletResponse response)
		throws ServletException, IOException
	{
		Site site = Jtp.getSite(request);
		if (site == null) {
			response.sendError(HttpServletResponse.SC_NOT_FOUND, "No application match the \"<i>" + request.getHeader("host") + "</i>\" domain.");
			return;
		}

		User user = Jtp.getUser(request);
		if (user == null) {
			response.sendRedirect(site.getBaseUrl() + Jtp.loginPath(site,null,response.encodeURL("/forum/Addons.jtp?site="+site.getId())) );
			return;
		}

		boolean isSiteAdmin = Permissions.isInGroup(user, Permissions.ADMINISTRATORS_GROUP);
		boolean isSysAdmin = Permissions.isSysAdmin(user);
		if (!isSiteAdmin && !isSysAdmin) {
			Jtp.login("Only administrators can proceed in this area.", request, response);
			return;
		}

		boolean isSave = "save".equals(request.getParameter("action"));

		String errorMsg = null;
		if (isSave && "POST".equals(request.getMethod())) {
			DbDatabase db = site.getDb();
			db.beginTransaction();
			try {
				site = site.getGoodCopy();
				for( Map.Entry<String,List<ModuleInfo>> entry : modulesByCategory.entrySet() ) {
					for (ModuleInfo info : entry.getValue()) {
						boolean isEnabled = "y".equals(request.getParameter(info.moduleName));
						site.setModuleEnabled(info.moduleName, isEnabled);
					}
				}

				db.commitTransaction();
				Jtp.sendRedirect(request,response,Jtp.path(site.getRootNode()));
				return;
			} finally {
				db.endTransaction();
			}
		}
		Node rootNode = site.getRootNode();
		PrintWriter out = response.getWriter();
		
		out.print( "\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n	<head>\n		<META NAME=\"robots\" CONTENT=\"noindex,nofollow\">\n		" );
 Shared.title(request, response, "Extras & add-ons"); 
		out.print( "\n		" );
 style(out); 
		out.print( "\n		" );
 js(out); 
		out.print( "\n	</head>\n	<body>\n		" );
 Shared.minHeader(request,response, rootNode); 
		out.print( "\n\n		<div style=\"padding:.5em 0 .5em 60px;background:url('/images/box.png') 0 5px no-repeat;min-height:40px\">\n			<div class=\"big-title second-font\">Extras & Add-ons</div>\n			<div class=\"weak-color\">\n				Select below the extra features and add-ons for your Nabble application.\n			</div>\n		</div>\n\n		" );
 Shared.errorMessage(request, response, errorMsg, null); 
		out.print( "\n\n		<form method=\"post\" action=\"/app/Addons.jtp\" accept-charset=\"UTF-8\">\n			<input type=\"hidden\" name=\"action\" value=\"save\"/>\n			<table class=\"vertical-control\">\n				<tr>\n					<td>\n						<ul class=\"vertical-control\">\n							" );
 for( Map.Entry<String,List<ModuleInfo>> entry : modulesByCategory.entrySet() ) { 
		out.print( "\n							<li id=\"tab_" );
		out.print( (elementId(entry.getKey())) );
		out.print( "\" " );
		out.print( (entry.getKey().equals(firstTab)?"class=\"selected shaded-bg-color\"":"") );
		out.print( ">" );
		out.print( (entry.getKey()) );
		out.print( "</li>\n							" );
 } 
		out.print( "\n						</ul>\n					</td>\n					<td class=\"details shaded-bg-color\">\n						" );
 for( Map.Entry<String,List<ModuleInfo>> entry : modulesByCategory.entrySet() ) { 
		out.print( "\n						<div id=\"div_" );
		out.print( (elementId(entry.getKey())) );
		out.print( "\" " );
		out.print( (entry.getKey().equals(firstTab)?"":"style=\"display:none\"") );
		out.print( ">\n							" );
 for (ModuleInfo info : entry.getValue()) { 
		out.print( "\n								" );
 boolean isChecked = site.isModuleEnabled(info.moduleName); 
		out.print( "\n								<div class=\"addon-option\">\n									<input id=\"_" );
		out.print( (info.moduleName) );
		out.print( "\" type=\"checkbox\" name=\"" );
		out.print( (info.moduleName) );
		out.print( "\" value=\"y\" " );
		out.print( (isChecked?"checked=\"true\"":"") );
		out.print( "/>\n									<label for=\"_" );
		out.print( (info.moduleName) );
		out.print( "\">" );
		out.print( (info.name) );
		out.print( "</label>\n									" );
 if (info.description != null && info.description.length() > 0) { 
		out.print( "\n									<div class=\"weak-color\" style=\"margin:.25em 1.8em 1.4em\">" );
		out.print( (info.description) );
		out.print( "</div>\n									" );
 } 
		out.print( "\n								</div>\n							" );
 } 
		out.print( "\n						</div>\n						" );
 } 
		out.print( "\n					</td>\n				</tr>\n			</table>\n			<input type=\"submit\" class=\"toolbar action-button\" value=\"Save Changes\"/>\n			or <a href=\"" );
		out.print( (Jtp.path(rootNode)) );
		out.print( "\">Cancel</a>\n		</form>\n\n		" );
 Shared.footer(request, response); 
		out.print( "\n		" );
 Shared.analytics(request, response); 
		out.print( "\n	</body>\n</html>\n" );

	}

	private static String elementId(String name) {
		return name.replaceAll(" ","_").replaceAll("&","");
	}

	private static void js(PrintWriter out) {
		
		out.print( "\n<script type=\"text/javascript\">\n	var selectedTab = '" );
		out.print( (firstTab) );
		out.print( "';\n	$(document).ready(function() {\n		var $li = $('ul.vertical-control li');\n		$li.click(function() {\n			var $this = $(this);\n			if ($this.hasClass('selected'))\n				return;\n			$('#tab_'+selectedTab).removeClass('selected shaded-bg-color');\n			$('#div_'+selectedTab).hide();\n			selectedTab = $this.attr('id').substring(4);\n			$('#tab_'+selectedTab).addClass('selected shaded-bg-color');\n			$('#div_'+selectedTab).show();\n			Nabble.resizeFrames();\n		});\n		$li.hover(function() {\n			var $this = $(this);\n			if ($this.hasClass('selected'))\n				return;\n			$this.addClass('light-bg-color');\n		}, function() {\n			var $this = $(this);\n			$this.removeClass('light-bg-color');\n		});\n	});\n</script>\n" );

	}

	private static void style(PrintWriter out) {
		
		out.print( "\n<style type=\"text/css\">\n	input { vertical-align:-10%; }\n	label {\n		font-weight: bold;\n		cursor: pointer;\n	}\n\n	div.addon-option {\n		margin: 0 0 .5em;\n	}\n	table.vertical-control {\n		margin: 1em 0;\n		width:100%;\n		border-collapse:collapse;\n	}\n	table.vertical-control td {\n		padding:0;\n		vertical-align:top;\n	}\n	table.vertical-control td.details {\n		width:85%;\n		padding:1em .8em .8em;\n	}\n	ul.vertical-control {\n		width:100%;\n		list-style-type:none;\n		padding:0;\n		margin:0;\n	}\n	ul.vertical-control li {\n		padding: .3em 0 .3em 1em;\n		font-weight:bold;\n		white-space:nowrap;\n		cursor:pointer;\n		border-top-left-radius:5px;\n		border-bottom-left-radius:5px;\n		-moz-border-radius-topleft:5px;\n		-moz-border-radius-bottomleft:5px;\n	}\n	ul.vertical-control li.selected {\n		cursor:text;\n		text-shadow:1px 1px 0 white;\n	}\n</style>\n" );

	}
}