Skip to content
This repository has been archived by the owner on Jun 9, 2021. It is now read-only.

Commit

Permalink
Admin GUI in place
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasbjerre committed Mar 28, 2015
1 parent 1ba6fed commit 9e5b6db
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 75 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>se.bjurr.prnfs</groupId>
<artifactId>prnfs</artifactId>
<artifactId>pull-request-notifier-for-stash</artifactId>
<version>1.0-SNAPSHOT</version>
<organization>
<name>Tomas Bjerre</name>
<url>http://bjurr.se/</url>
</organization>
<name>prnfs</name>
<name>pull-request-notifier-for-stash</name>
<description>This is the Pull Request Notifier for Atlassian Stash. See https://github.com/tomasbjerre/pull-request-notifier-for-stash for documentation and source code.</description>
<packaging>atlassian-plugin</packaging>
<scm>
Expand Down
15 changes: 11 additions & 4 deletions src/main/java/se/bjurr/prnfs/admin/ConfigResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import se.bjurr.prnfs.settings.ValidationException;

import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory;
Expand All @@ -34,7 +37,7 @@
public class ConfigResource {
private final PluginSettingsFactory pluginSettingsFactory;
private final TransactionTemplate transactionTemplate;

private static final Logger logger = LoggerFactory.getLogger(ConfigResource.class);
private final UserManager userManager;

public ConfigResource(UserManager userManager, PluginSettingsFactory pluginSettingsFactory,
Expand Down Expand Up @@ -92,7 +95,7 @@ public UserManager getUserManager() {
}

private boolean isAdminLoggedIn(HttpServletRequest request) {
UserProfile user = userManager.getRemoteUser(request);
final UserProfile user = userManager.getRemoteUser(request);
if (user == null) {
return false;
}
Expand All @@ -115,14 +118,18 @@ public Response post(final AdminFormValues config, @Context HttpServletRequest r
*/
try {
getPrnfsNotification(config);
} catch (ValidationException e) {
} catch (final ValidationException e) {
return status(BAD_REQUEST).entity(new AdminFormError(e.getField(), e.getError())).build();
}

transactionTemplate.execute(new TransactionCallback<Object>() {
@Override
public Object doInTransaction() {
storeSettings(pluginSettingsFactory.createGlobalSettings(), config);
try {
storeSettings(pluginSettingsFactory.createGlobalSettings(), config);
} catch (final ValidationException e) {
logger.error("", e);
}
return null;
}
});
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/se/bjurr/prnfs/settings/PrnfsNotification.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@ public class PrnfsNotification {

public PrnfsNotification(List<PullRequestAction> triggers, String password, String url, String user)
throws ValidationException {
this.password = password;
if (nullToEmpty(url).isEmpty()) {
this.password = nullToEmpty(password).trim();
if (nullToEmpty(url).trim().isEmpty()) {
throw new ValidationException("url", "URL not set!");
}
try {
new URL(url);
} catch (Exception e) {
} catch (final Exception e) {
throw new ValidationException("url", "URL not valid!");
}
this.url = url;
this.user = user;
this.user = nullToEmpty(user).trim();
this.triggers = checkNotNull(triggers);
}

Expand Down
61 changes: 38 additions & 23 deletions src/main/java/se/bjurr/prnfs/settings/SettingsStorage.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static com.google.common.base.Optional.fromNullable;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.find;
import static com.google.common.collect.Iterables.removeIf;
import static com.google.common.collect.Iterables.tryFind;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newTreeMap;
Expand Down Expand Up @@ -39,12 +40,18 @@ public class SettingsStorage {
private static final Gson gson = new Gson();
private static final Logger logger = LoggerFactory.getLogger(SettingsStorage.class);

private static final String STORAGE_KEY = AdminFormValues.class.getName() + "_2";

private static Random random = new Random(currentTimeMillis());

public static void deleteSettings(PluginSettings pluginSettings, String id) {
Map<String, AdminFormValues> map = getNotificationsMap(pluginSettings);
final Map<String, AdminFormValues> map = getNotificationsMap(pluginSettings);
map.remove(id);
storeNotificationsMap(pluginSettings, map);
try {
storeNotificationsMap(pluginSettings, map);
} catch (final ValidationException e) {
logger.error("", e);
}
}

@VisibleForTesting
Expand All @@ -57,8 +64,8 @@ public static String formIdentifierGnerator() {
}

private static Map<String, AdminFormValues> getNotificationsMap(PluginSettings pluginSettings) {
Map<String, AdminFormValues> allNotificationsMap = newTreeMap();
for (AdminFormValues a : getSettingsAsFormValues(pluginSettings)) {
final Map<String, AdminFormValues> allNotificationsMap = newTreeMap();
for (final AdminFormValues a : getSettingsAsFormValues(pluginSettings)) {
if (tryFind(a, predicate(FORM_IDENTIFIER_NAME)).isPresent()) {
allNotificationsMap.put(find(a, predicate(FORM_IDENTIFIER_NAME)).get(VALUE), a);
}
Expand All @@ -67,61 +74,69 @@ private static Map<String, AdminFormValues> getNotificationsMap(PluginSettings p
}

public static PrnfsNotification getPrnfsNotification(AdminFormValues a) throws ValidationException {
Optional<Map<String, String>> urlOpt = Iterables.tryFind(a, predicate("url"));
final Optional<Map<String, String>> urlOpt = Iterables.tryFind(a, predicate("url"));
if (!urlOpt.isPresent()) {
throw new ValidationException("url", "URL not set");
}
PrnfsNotificationBuilder prnfsNotificationBuilder = prnfsNotificationBuilder().withUser("").withPassword("")
final PrnfsNotificationBuilder prnfsNotificationBuilder = prnfsNotificationBuilder().withUser("").withPassword("")
.withUrl(urlOpt.get().get(VALUE));
Iterable<Map<String, String>> events = filter(a, predicate("events"));
for (Map<String, String> event : events) {
final Iterable<Map<String, String>> events = filter(a, predicate("events"));
for (final Map<String, String> event : events) {
prnfsNotificationBuilder.withTrigger(PullRequestAction.valueOf(event.get(VALUE)));
}
return prnfsNotificationBuilder.build();
}

public static PrnfsSettings getPrnfsSettings(PluginSettings pluginSettings) throws ValidationException {
PrnfsSettingsBuilder prnfsSettingsBuilder = prnfsSettingsBuilder();
for (AdminFormValues a : getSettingsAsFormValues(pluginSettings)) {
final PrnfsSettingsBuilder prnfsSettingsBuilder = prnfsSettingsBuilder();
for (final AdminFormValues a : getSettingsAsFormValues(pluginSettings)) {
prnfsSettingsBuilder.withNotification(getPrnfsNotification(a));
}
return prnfsSettingsBuilder.build();
}

public static List<AdminFormValues> getSettingsAsFormValues(PluginSettings settings) {
List<AdminFormValues> toReturn = newArrayList();
final List<AdminFormValues> toReturn = newArrayList();
try {
if (!fromNullable(settings.get(AdminFormValues.class.getName())).isPresent()) {
if (!fromNullable(settings.get(STORAGE_KEY)).isPresent()) {
return toReturn;
}
@SuppressWarnings("unchecked")
List<String> settingsList = newArrayList((List<String>) settings.get(AdminFormValues.class.getName()));
for (String storedJson : settingsList) {
final List<String> settingsList = newArrayList((List<String>) settings.get(STORAGE_KEY));
for (final String storedJson : settingsList) {
toReturn.add(gson.fromJson(storedJson, AdminFormValues.class));
}
} catch (Exception e) {
} catch (final Exception e) {
logger.error("Unable to deserialize settings", e);
}
return toReturn;
}

private static void storeNotificationsMap(PluginSettings pluginSettings,
Map<String, AdminFormValues> allNotificationsMap) {
List<String> toStore = newArrayList();
for (AdminFormValues adminFormValues : allNotificationsMap.values()) {
Map<String, AdminFormValues> allNotificationsMap) throws ValidationException {
final List<String> toStore = newArrayList();
for (final AdminFormValues adminFormValues : allNotificationsMap.values()) {
final Optional<Map<String, String>> formIdOpt = tryFind(adminFormValues, predicate(FORM_IDENTIFIER_NAME));
if (!formIdOpt.isPresent() || formIdOpt.get().get(VALUE).trim().isEmpty()) {
throw new ValidationException(FORM_IDENTIFIER_NAME, "Not set!");
}
toStore.add(new Gson().toJson(adminFormValues));
}
pluginSettings.put(AdminFormValues.class.getName(), toStore);
pluginSettings.put(STORAGE_KEY, toStore);
}

public static void storeSettings(PluginSettings pluginSettings, final AdminFormValues config) {
Map<String, AdminFormValues> allNotificationsMap = getNotificationsMap(pluginSettings);
public static void storeSettings(PluginSettings pluginSettings, final AdminFormValues config)
throws ValidationException {
final Map<String, AdminFormValues> allNotificationsMap = getNotificationsMap(pluginSettings);

if (!tryFind(config, predicate(FORM_IDENTIFIER_NAME)).isPresent()) {
String generatedIdentifier = formIdentifierGnerator();
final Optional<Map<String, String>> formIdOpt = tryFind(config, predicate(FORM_IDENTIFIER_NAME));
if (!formIdOpt.isPresent() || formIdOpt.get().get(VALUE).trim().isEmpty()) {
final String generatedIdentifier = formIdentifierGnerator();
removeIf(config, predicate(FORM_IDENTIFIER_NAME));
config.add(new ImmutableMap.Builder<String, String>().put(NAME, FORM_IDENTIFIER_NAME)
.put(VALUE, generatedIdentifier).build());
}

allNotificationsMap.put(find(config, predicate(FORM_IDENTIFIER_NAME)).get(VALUE), config);

storeNotificationsMap(pluginSettings, allNotificationsMap);
Expand Down
17 changes: 17 additions & 0 deletions src/main/resources/admin.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,21 @@ legend {

.right {
float: right;
}

.error {
font-weight: bold;
color: red;
}

input[type="text"] {
width: 100%;
}

.prnfs > form {
margin: 10px 0 0 0;
}

.prnfs-template {
display:none;
}
88 changes: 70 additions & 18 deletions src/main/resources/admin.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,74 @@
(function ($) {
var url = AJS.contextPath() + "/rest/prnfs-admin/1.0/";
$(document).ready(function() {
$(".trigger").submit(function(e) {
e.preventDefault();
AJS.$.ajax({
url: url,
type: "POST",
contentType: "application/json",
data: JSON.stringify(AJS.$(".trigger").serializeArray(), null, 2),
processData: false
});
});
var config_resource = AJS.contextPath() + "/rest/prnfs-admin/1.0/";
$(document).ready(function() {
function setEvents() {
$('input[name="delete"]').click(function(e) {
var $form = $(this).closest('form');
var formIdentifier = $('input[name="FORM_IDENTIFIER"]',$form).val();
$.ajax({
url: config_resource + formIdentifier,
dataType: "json",
type: "DELETE",
error: function(xhr, data, error) {
console.log(xhr);
console.log(data);
console.log(error);
},
success: function(data, text, xhr) {
$form.remove();
}
});
});

$('input[name="save"]').click(function(e) {
var $form = $(this).closest('form');
$(".post",$form).html("Saving...");
$.ajax({
url: config_resource,
dataType: "json",
type: "POST",
contentType: "application/json",
data: JSON.stringify($form.serializeArray(), null, 2),
processData: false,
error: function(xhr, data, error) {
$.each(xhr.responseJSON, function(field,errorString) {
$(".error."+field,$form).html(errorString);
$(".post",$form).html("There were errors, form not saved!");
});
},
success: function(data, text, xhr) {
getAll();
}
});
});
}

function addNewForm() {
var $template = $(".prnfs-template").clone();
$('input[name="delete"]',$template).remove();
$(".prnfs").append($template.html());
}

$.ajax({
url: url,
dataType: "json"
}).done(function(config) {

function getAll() {
$.ajax({
url: config_resource,
dataType: "json"
}).done(function(configs) {
$(".prnfs").html("");
$.each(configs, function(index, config) {
var $template = $(".prnfs-template").clone();
$.each(config, function(fieldIndex,field_map) {
$('input[type="text"][name="'+field_map.name+'"]', $template).attr('value', field_map.value);
$('input[type="hidden"][name="'+field_map.name+'"]', $template).attr('value', field_map.value);
$('input[type="checkbox"][name="'+field_map.name+'"][value="'+field_map.value+'"]', $template).attr('checked','checked');
});
$(".prnfs").append($template.html());
});
});
addNewForm();
setEvents();
});
}

getAll();
});
})(AJS.$ || jQuery);
40 changes: 27 additions & 13 deletions src/main/resources/admin.vm
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,28 @@
<head>
<title>Pull Request Notifier for Stash Admin</title>
<meta name="decorator" content="atl.admin">
$webResourceManager.requireResource("se.bjurr.prnfs.prnfs:resources")
$webResourceManager.requireResource("se.bjurr.prnfs.pull-request-notifier-for-stash:resources")
</head>
<body>
<div>
<div class="description">
You can use variables when invoking the URL.
<ul>
<li><b>${ID}</b> - Pull Request ID</li>
<li><b>${FROM_REPO}</b> - From repository</li>
<li><b>${FROM_COMMIT}</b> - From commit</li>
<li><b>${TO_REPO}</b> - To repository</li>
<li><b>${TO_COMMIT}</b> - To commit</li>
</ul>
</div>
</div>

<div class="prnfs">
</div>

<div class="prnfs-template">
<form class="trigger">
<input type="hidden" name="FORM_IDENTIFIER">
<div>
<fieldset>
<legend>Triggers</legend>
Expand Down Expand Up @@ -45,23 +63,19 @@
<div>
<fieldset>
<legend>Invoke URL</legend>
<div class="description">
You can use variables:
<ul>
<li><b>${ID}</b> - Pull Request ID</li>
<li><b>${FROM_REPO}</b> - From repository</li>
<li><b>${FROM_COMMIT}</b> - From commit</li>
<li><b>${TO_REPO}</b> - To repository</li>
<li><b>${TO_COMMIT}</b> - To commit</li>
</ul>
</div>
<label for="user">URL</label>
<input type="text" name="url" size="50">
<input type="text" name="url">
<div class="error url"></div>
</fieldset>
</div>
<div>
<input type="submit" name="save"/>
<fieldset>
<input type="button" name="save" value="Save"/>
<input type="button" name="delete" value="Remove"/>
<span class="post"></span>
</fieldset>
</div>
</form>
</div>
</body>
</html>
Loading

0 comments on commit 9e5b6db

Please sign in to comment.