Mercurial Hosting > nabble
annotate src/nabble/view/web/app/Addons.java @ 25:ea1d2e6e2a49
semiprivate
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Thu, 18 Jun 2020 19:26:15 -0600 |
parents | e0c501fb5229 |
children | 5ea557eece1f |
rev | line source |
---|---|
0 | 1 |
2 package nabble.view.web.app; | |
3 | |
4 import fschmidt.db.DbDatabase; | |
5 import nabble.model.Node; | |
6 import nabble.model.Site; | |
7 import nabble.model.User; | |
8 import nabble.view.lib.Jtp; | |
9 import nabble.view.lib.Permissions; | |
10 import nabble.view.lib.Shared; | |
11 | |
12 import javax.servlet.ServletException; | |
13 import javax.servlet.http.HttpServlet; | |
14 import javax.servlet.http.HttpServletRequest; | |
15 import javax.servlet.http.HttpServletResponse; | |
16 import java.io.IOException; | |
17 import java.io.PrintWriter; | |
18 import java.util.ArrayList; | |
19 import java.util.LinkedHashMap; | |
20 import java.util.List; | |
21 import java.util.Map; | |
22 | |
23 | |
24 public final class Addons extends HttpServlet { | |
25 | |
26 private static class ModuleInfo { | |
27 String moduleName; | |
28 String name; | |
29 String description; | |
30 } | |
31 | |
32 private static Map<String, List<ModuleInfo>> modulesByCategory = new LinkedHashMap<String, List<ModuleInfo>>(); | |
33 | |
34 private static String firstTab; | |
35 | |
36 private static void addModule(String category, String moduleName, String name, String description) { | |
37 if (firstTab == null) | |
38 firstTab = category; | |
39 List<ModuleInfo> list = modulesByCategory.get(category); | |
40 if (list == null) { | |
41 list = new ArrayList<ModuleInfo>(); | |
42 modulesByCategory.put(category, list); | |
43 } | |
44 ModuleInfo info = new ModuleInfo(); | |
45 info.moduleName = moduleName; | |
46 info.name = name; | |
47 info.description = description; | |
48 list.add(info); | |
49 } | |
50 | |
51 static { | |
52 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."); | |
53 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>"); | |
54 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>"); | |
55 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>"); | |
56 | |
57 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."); | |
58 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."); | |
59 addModule("Content", "content_smart_cache", "Smart application pages", | |
60 "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. "+ | |
61 "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. "+ | |
62 "Other users (without access) will only view the public contents. "+ | |
63 "<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)."); | |
64 addModule("Content", "content_news_summary", "Custom summary for Newspaper", | |
65 "If you use the Newspaper application type, you can use this add-on to define custom snippets for your posts "+ | |
66 "(the snippet is the text that shows on the front page of the app, immediately below the title of the post). " + | |
67 "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.\" "+ | |
68 "The text between the tags is the snippet to be displayed on the news page and will NOT appear on the post page." | |
69 ); | |
70 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."); | |
25 | 71 addModule("Content", "semiprivate", "Restrict to registered users", "Only allow registered users to view the forum. This has no effect for new forums which are restricted by default."); |
0 | 72 |
73 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)."); | |
74 | |
75 addModule("Mailing List Archives", "expire_old_threads", "Lock old threads", "This add-on prevents new replies to old threads, which could be confusing to the mailing list users. Users that try to reply to an old thread will see a message that suggests them to create a new topic instead. By default, a thread is locked if it was created more than 365 days ago. You can change this number by tweaking the \"thread_expiration_days\" macro. "); | |
76 | |
77 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)."); | |
78 | |
79 addModule("Responsiveness", "responsive", "Responsive layout", "Add-on that improves the responsiveness of Nabble apps and make pages more readable on small screens."); | |
80 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)."); | |
81 | |
82 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."); | |
83 | |
84 addModule("Work", "workgroup", "Workgroup", | |
85 "This feature allows a team to work integrated with a forum. " + | |
86 "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." + | |
87 "Each topic represents a task that holds the discussion about the work to be accomplished.<br/>" + | |
88 "<a href=\"http://nabble-support.1.n2.nabble.com/Workgroups-td1559166.html\">Learn more</a>" | |
89 ); | |
90 | |
91 addModule("Voting & Survey", "poll", "Polls", "Allows you to add polls/surveys to your posts and collect votes from your visitors. " + | |
92 "You will find options to add a new poll when you create a new topic or reply to a post." + | |
93 "By default, only administrators can create polls. If you want to let other groups create polls, just modify the Create_poll permission. "); | |
94 } | |
95 | |
96 protected void service(HttpServletRequest request,HttpServletResponse response) | |
97 throws ServletException, IOException | |
98 { | |
99 Site site = Jtp.getSite(request); | |
100 if (site == null) { | |
101 response.sendError(HttpServletResponse.SC_NOT_FOUND, "No application match the \"<i>" + request.getHeader("host") + "</i>\" domain."); | |
102 return; | |
103 } | |
104 | |
19
18cf4872fd7f
remove anonymous posting
Franklin Schmidt <fschmidt@gmail.com>
parents:
0
diff
changeset
|
105 User user = Jtp.getUser(request); |
0 | 106 if (user == null) { |
107 response.sendRedirect(site.getBaseUrl() + Jtp.loginPath(site,null,response.encodeURL("/forum/Addons.jtp?site="+site.getId())) ); | |
108 return; | |
109 } | |
110 | |
111 boolean isSiteAdmin = Permissions.isInGroup(user, Permissions.ADMINISTRATORS_GROUP); | |
112 boolean isSysAdmin = Permissions.isSysAdmin(user); | |
113 if (!isSiteAdmin && !isSysAdmin) { | |
114 Jtp.login("Only administrators can proceed in this area.", request, response); | |
115 return; | |
116 } | |
117 | |
118 boolean isSave = "save".equals(request.getParameter("action")); | |
119 | |
120 String errorMsg = null; | |
121 if (isSave && "POST".equals(request.getMethod())) { | |
122 DbDatabase db = site.getDb(); | |
123 db.beginTransaction(); | |
124 try { | |
125 site = site.getGoodCopy(); | |
126 for( Map.Entry<String,List<ModuleInfo>> entry : modulesByCategory.entrySet() ) { | |
127 for (ModuleInfo info : entry.getValue()) { | |
128 boolean isEnabled = "y".equals(request.getParameter(info.moduleName)); | |
129 site.setModuleEnabled(info.moduleName, isEnabled); | |
130 } | |
131 } | |
132 | |
133 db.commitTransaction(); | |
134 Jtp.sendRedirect(request,response,Jtp.path(site.getRootNode())); | |
135 return; | |
136 } finally { | |
137 db.endTransaction(); | |
138 } | |
139 } | |
140 Node rootNode = site.getRootNode(); | |
141 PrintWriter out = response.getWriter(); | |
142 | |
143 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 " ); | |
144 Shared.title(request, response, "Extras & add-ons"); | |
145 out.print( "\n " ); | |
146 style(out); | |
147 out.print( "\n " ); | |
148 js(out); | |
149 out.print( "\n </head>\n <body>\n " ); | |
150 Shared.minHeader(request,response, rootNode); | |
151 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 " ); | |
152 Shared.errorMessage(request, response, errorMsg, null); | |
153 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 " ); | |
154 for( Map.Entry<String,List<ModuleInfo>> entry : modulesByCategory.entrySet() ) { | |
155 out.print( "\n <li id=\"tab_" ); | |
156 out.print( (elementId(entry.getKey())) ); | |
157 out.print( "\" " ); | |
158 out.print( (entry.getKey().equals(firstTab)?"class=\"selected shaded-bg-color\"":"") ); | |
159 out.print( ">" ); | |
160 out.print( (entry.getKey()) ); | |
161 out.print( "</li>\n " ); | |
162 } | |
163 out.print( "\n </ul>\n </td>\n <td class=\"details shaded-bg-color\">\n " ); | |
164 for( Map.Entry<String,List<ModuleInfo>> entry : modulesByCategory.entrySet() ) { | |
165 out.print( "\n <div id=\"div_" ); | |
166 out.print( (elementId(entry.getKey())) ); | |
167 out.print( "\" " ); | |
168 out.print( (entry.getKey().equals(firstTab)?"":"style=\"display:none\"") ); | |
169 out.print( ">\n " ); | |
170 for (ModuleInfo info : entry.getValue()) { | |
171 out.print( "\n " ); | |
172 boolean isChecked = site.isModuleEnabled(info.moduleName); | |
173 out.print( "\n <div class=\"addon-option\">\n <input id=\"_" ); | |
174 out.print( (info.moduleName) ); | |
175 out.print( "\" type=\"checkbox\" name=\"" ); | |
176 out.print( (info.moduleName) ); | |
177 out.print( "\" value=\"y\" " ); | |
178 out.print( (isChecked?"checked=\"true\"":"") ); | |
179 out.print( "/>\n <label for=\"_" ); | |
180 out.print( (info.moduleName) ); | |
181 out.print( "\">" ); | |
182 out.print( (info.name) ); | |
183 out.print( "</label>\n " ); | |
184 if (info.description != null && info.description.length() > 0) { | |
185 out.print( "\n <div class=\"weak-color\" style=\"margin:.25em 1.8em 1.4em\">" ); | |
186 out.print( (info.description) ); | |
187 out.print( "</div>\n " ); | |
188 } | |
189 out.print( "\n </div>\n " ); | |
190 } | |
191 out.print( "\n </div>\n " ); | |
192 } | |
193 out.print( "\n </td>\n </tr>\n </table>\n <input type=\"submit\" class=\"toolbar action-button\" value=\"Save Changes\"/>\n or <a href=\"" ); | |
194 out.print( (Jtp.path(rootNode)) ); | |
195 out.print( "\">Cancel</a>\n </form>\n\n " ); | |
196 Shared.footer(request, response); | |
197 out.print( "\n " ); | |
198 Shared.analytics(request, response); | |
199 out.print( "\n </body>\n</html>\n" ); | |
200 | |
201 } | |
202 | |
203 private static String elementId(String name) { | |
204 return name.replaceAll(" ","_").replaceAll("&",""); | |
205 } | |
206 | |
207 private static void js(PrintWriter out) { | |
208 | |
209 out.print( "\n<script type=\"text/javascript\">\n var selectedTab = '" ); | |
210 out.print( (firstTab) ); | |
211 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" ); | |
212 | |
213 } | |
214 | |
215 private static void style(PrintWriter out) { | |
216 | |
217 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" ); | |
218 | |
219 } | |
220 } | |
221 |