Merge branch 'stable-2.16' into stable-3.0 * stable-2.16: Upgrade bazlets to latest stable-2.16 to build with 2.16.20 API Change-Id: I9563d33d749defe45d5a4bc8dfdfe0d7827c5f59
diff --git a/BUILD b/BUILD index ca6a1cd..ab1c177 100644 --- a/BUILD +++ b/BUILD
@@ -6,6 +6,7 @@ manifest_entries = [ "Gerrit-PluginName: messageoftheday", "Gerrit-Module: com.googlesource.gerrit.plugins.messageoftheday.Module", + "Gerrit-HttpModule: com.googlesource.gerrit.plugins.messageoftheday.HttpModule", "Implementation-Title: Plugin messageoftheday", "Implementation-URL: https://gerrit-review.googlesource.com/#/admin/projects/plugins/messageoftheday", ],
diff --git a/WORKSPACE b/WORKSPACE index a954b47..cb54686 100644 --- a/WORKSPACE +++ b/WORKSPACE
@@ -3,7 +3,7 @@ load("//:bazlets.bzl", "load_bazlets") load_bazlets( - commit = "c40247e30381ddc4a90ef99d749a9161ac4d064b", + commit = "15eae2ee5cd524a204bd62c3d59bfd0ce86916ec", #local_path = "/home/<user>/projects/bazlets", )
diff --git a/src/main/java/com/googlesource/gerrit/plugins/messageoftheday/GetMessage.java b/src/main/java/com/googlesource/gerrit/plugins/messageoftheday/GetMessage.java new file mode 100644 index 0000000..c0181a5 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/messageoftheday/GetMessage.java
@@ -0,0 +1,120 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.googlesource.gerrit.plugins.messageoftheday; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.google.common.base.Strings; +import com.google.gerrit.extensions.annotations.PluginData; +import com.google.gerrit.extensions.annotations.PluginName; +import com.google.gerrit.extensions.restapi.RestReadView; +import com.google.gerrit.server.config.ConfigResource; +import com.google.gerrit.server.config.SitePaths; +import com.google.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; +import org.eclipse.jgit.errors.ConfigInvalidException; +import org.eclipse.jgit.storage.file.FileBasedConfig; +import org.eclipse.jgit.util.FS; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GetMessage implements RestReadView<ConfigResource> { + private static final String SECTION_MESSAGE = "message"; + private static final String KEY_ID = "id"; + private static final String KEY_STARTS_AT = "startsAt"; + private static final String KEY_EXPIRES_AT = "expiresAt"; + + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd:HHmm"); + + private static final Logger log = LoggerFactory.getLogger(GetMessage.class); + + private final File cfgFile; + private final Path dataDirPath; + + private volatile FileBasedConfig cfg; + + @Inject + public GetMessage( + @PluginName String pluginName, @PluginData Path dataDirPath, SitePaths sitePaths) { + this.dataDirPath = dataDirPath; + this.cfgFile = sitePaths.etc_dir.resolve(pluginName + ".config").toFile(); + } + + @Override + public MessageOfTheDayInfo apply(ConfigResource rsrc) { + MessageOfTheDayInfo motd = new MessageOfTheDayInfo(); + cfg = new FileBasedConfig(cfgFile, FS.DETECTED); + try { + cfg.load(); + } catch (ConfigInvalidException | IOException e) { + return null; + } + + motd.id = cfg.getString(SECTION_MESSAGE, null, KEY_ID); + if (Strings.isNullOrEmpty(motd.id)) { + log.warn("id not defined, no message will be shown"); + return null; + } + + try { + motd.expiresAt = DATE_FORMAT.parse(cfg.getString(SECTION_MESSAGE, null, KEY_EXPIRES_AT)); + } catch (ParseException | NullPointerException e) { + log.warn("expiresAt not defined, no message will be shown"); + return null; + } + + try { + motd.html = new String(Files.readAllBytes(dataDirPath.resolve(motd.id + ".html")), UTF_8); + } catch (IOException e1) { + log.warn( + String.format( + "No HTML-file was found for message %s, no message will be shown", motd.id)); + return null; + } + + try { + String startsAt = cfg.getString(SECTION_MESSAGE, null, KEY_STARTS_AT); + motd.startsAt = Strings.isNullOrEmpty(startsAt) ? new Date() : DATE_FORMAT.parse(startsAt); + } catch (ParseException e) { + motd.startsAt = new Date(); + } + + if (motd.startsAt.compareTo(new Date()) > 0 || motd.expiresAt.compareTo(new Date()) < 0) { + return null; + } + + motd.redisplay = getRedisplay(); + + return motd; + } + + private Date getRedisplay() { + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + cal.add(Calendar.DAY_OF_MONTH, 1); + return cal.getTime(); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/messageoftheday/HttpModule.java b/src/main/java/com/googlesource/gerrit/plugins/messageoftheday/HttpModule.java new file mode 100644 index 0000000..d10983a --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/messageoftheday/HttpModule.java
@@ -0,0 +1,28 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.googlesource.gerrit.plugins.messageoftheday; + +import com.google.gerrit.extensions.registration.DynamicSet; +import com.google.gerrit.extensions.webui.JavaScriptPlugin; +import com.google.gerrit.extensions.webui.WebUiPlugin; +import com.google.inject.AbstractModule; + +public class HttpModule extends AbstractModule { + @Override + protected void configure() { + DynamicSet.bind(binder(), WebUiPlugin.class) + .toInstance(new JavaScriptPlugin("gr-messageoftheday.html")); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/messageoftheday/MessageOfTheDayImpl.java b/src/main/java/com/googlesource/gerrit/plugins/messageoftheday/MessageOfTheDayImpl.java deleted file mode 100644 index 83adccc..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/messageoftheday/MessageOfTheDayImpl.java +++ /dev/null
@@ -1,99 +0,0 @@ -// Copyright (C) 2016 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package com.googlesource.gerrit.plugins.messageoftheday; - -import static java.nio.charset.StandardCharsets.UTF_8; - -import com.google.common.base.MoreObjects; -import com.google.common.base.Strings; -import com.google.gerrit.extensions.annotations.PluginData; -import com.google.gerrit.extensions.annotations.PluginName; -import com.google.gerrit.extensions.systemstatus.MessageOfTheDay; -import com.google.gerrit.server.config.PluginConfigFactory; -import com.google.inject.Inject; -import com.google.inject.Singleton; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.text.SimpleDateFormat; -import java.util.Date; -import org.eclipse.jgit.lib.Config; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Singleton -class MessageOfTheDayImpl extends MessageOfTheDay { - private static final Logger log = LoggerFactory.getLogger(MessageOfTheDayImpl.class); - - private final File data; - private final String id; - private final String startsAt; - private final String expiresAt; - private final String msg; - - @Inject - public MessageOfTheDayImpl( - PluginConfigFactory configFactory, @PluginName String myName, @PluginData File data) { - this.data = data; - Config cfg = configFactory.getGlobalPluginConfig(myName); - id = cfg.getString("message", null, "id"); - String configuredStartsAt = Strings.emptyToNull(cfg.getString("message", null, "startsAt")); - startsAt = MoreObjects.firstNonNull(configuredStartsAt, now()); - expiresAt = cfg.getString("message", null, "expiresAt"); - msg = message(); - } - - @Override - public String getHtmlMessage() { - if (Strings.isNullOrEmpty(id)) { - return null; - } - - if (Strings.isNullOrEmpty(expiresAt)) { - log.warn("expiresAt not defined, no message will be shown"); - return null; - } - - if (now().compareTo(startsAt) < 0 || now().compareTo(expiresAt) > 0) { - return null; - } - - return msg; - } - - @Override - public String getMessageId() { - return id; - } - - private String message() { - if (Strings.isNullOrEmpty(id)) { - return null; - } - - Path p = new File(data, id + ".html").toPath(); - try { - return new String(Files.readAllBytes(p), UTF_8); - } catch (IOException e) { - log.warn("Couldn't read content of the mesage with id = " + id, e); - return null; - } - } - - private static String now() { - return new SimpleDateFormat("yyyyMMdd:HHmm").format(new Date()); - } -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/messageoftheday/MessageOfTheDayInfo.java b/src/main/java/com/googlesource/gerrit/plugins/messageoftheday/MessageOfTheDayInfo.java new file mode 100644 index 0000000..eed52ce --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/messageoftheday/MessageOfTheDayInfo.java
@@ -0,0 +1,31 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.googlesource.gerrit.plugins.messageoftheday; + +import java.util.Date; + +/** REST API representation of a "message of the day". */ +public class MessageOfTheDayInfo { + /** The ID of the message. */ + public String id; + /** The time from which on the message will be displayed. */ + public Date startsAt; + /** The time from which on the message will not be displayed anymore. */ + public Date expiresAt; + /** The date and time the message will be displayed again after being dismissed by the user. */ + public Date redisplay; + /** The message in HTML-format. */ + public String html; +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/messageoftheday/Module.java b/src/main/java/com/googlesource/gerrit/plugins/messageoftheday/Module.java index c9ea760..1164004 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/messageoftheday/Module.java +++ b/src/main/java/com/googlesource/gerrit/plugins/messageoftheday/Module.java
@@ -14,13 +14,20 @@ package com.googlesource.gerrit.plugins.messageoftheday; -import com.google.gerrit.extensions.registration.DynamicSet; -import com.google.gerrit.extensions.systemstatus.MessageOfTheDay; +import static com.google.gerrit.server.config.ConfigResource.CONFIG_KIND; + +import com.google.gerrit.extensions.restapi.RestApiModule; import com.google.inject.AbstractModule; class Module extends AbstractModule { @Override protected void configure() { - DynamicSet.bind(binder(), MessageOfTheDay.class).to(MessageOfTheDayImpl.class); + install( + new RestApiModule() { + @Override + protected void configure() { + get(CONFIG_KIND, "message").to(GetMessage.class); + } + }); } }
diff --git a/src/main/resources/Documentation/rest-api-config.md b/src/main/resources/Documentation/rest-api-config.md new file mode 100644 index 0000000..86d923c --- /dev/null +++ b/src/main/resources/Documentation/rest-api-config.md
@@ -0,0 +1,57 @@ +@PLUGIN@ - /config/ REST API +============================ + +This page describes the REST endpoints that are added by the @PLUGIN@ +plugin. + +Please also take note of the general information on the +[REST API](../../../Documentation/rest-api.html). + +<a id="config-endpoints"> Config Endpoints +------------------------------------------ + +### <a id="get-menus"> Get Menus +_GET /config/server/@PLUGIN@~message/_ + +Gets the message of the day. + +#### Request + +``` + GET /config/server/@PLUGIN@~message/ HTTP/1.0 +``` + +As response a [MessageOfTheDayInfo](./rest-api-config.md#MessageOfTheDayInfo) entity +is returned that contains the message and associated metadata. + +#### Response + +``` + HTTP/1.1 200 OK + Content-Disposition: attachment + Content-Type: application/json;charset=UTF-8 + + )]}' + { + "id": "hello", + "starts_at": "Feb 4, 2020 5:53:00 PM", + "expires_at": "Dec 30, 2020 6:00:00 PM", + "redisplay": "Feb 5, 2020 1:00:00 AM", + "html": "hello you!" + } +``` + +### MessageOfTheDayInfo + +The `MessageOfTheDayInfo` entity contains information about the message of the day. + +* `id`: ID of the message. +* `starts_at`: Date, when the message will be first displayed +* `expires_at`: Date, after which the message will not be displayed anymore +* `redisplay`: Date, after which will the message be displayed again after dismissal +* `html`: String, containing the HTML-formatted message + + +[Back to @PLUGIN@ documentation index][index] + +[index]: index.html
diff --git a/src/main/resources/static/gr-messageoftheday-banner.html b/src/main/resources/static/gr-messageoftheday-banner.html new file mode 100644 index 0000000..102645d --- /dev/null +++ b/src/main/resources/static/gr-messageoftheday-banner.html
@@ -0,0 +1,38 @@ +<!-- +@license +Copyright (C) 2020 The Android Open Source Project + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> + +<dom-module id="gr-messageoftheday-banner"> + <template> + <style include="shared-styles"> + #container { + background-color: lightyellow; + display: flex; + height: fit-content; + justify-content: space-between; + padding: 1em; + } + </style> + <div id="container" hidden$="[[_hidden]]"> + <div id="message"></div> + <gr-button id="dismissMessageBtn" + link + on-tap="_handleDismissMessage">Dismiss</gr-button> + </div> + <gr-rest-api-interface id="restAPI"></gr-rest-api-interface> + </template> + <script src="gr-messageoftheday-banner.js"></script> +</dom-module>
diff --git a/src/main/resources/static/gr-messageoftheday-banner.js b/src/main/resources/static/gr-messageoftheday-banner.js new file mode 100644 index 0000000..536c05d --- /dev/null +++ b/src/main/resources/static/gr-messageoftheday-banner.js
@@ -0,0 +1,54 @@ +/** + * @license + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +(function() { + 'use strict'; + + Polymer({ + is: 'gr-messageoftheday-banner', + + properties: { + _message: Object, + _hidden: { + type: Boolean, + value: true, + }, + }, + + attached() { + this.plugin.restApi() + .get(`/config/server/${this.plugin.getPluginName()}~message`) + .then(message => { + if (!message || !message.html) { + return; + } + this._message = message; + this._isHidden(); + this.$.message.innerHTML = this._message.html; + }); + }, + + _handleDismissMessage() { + document.cookie = + `msg-${this._message.id}=1; expires=${this._message.redisplay}`; + this._hidden = true; + }, + + _isHidden() { + this._hidden = window.util.getCookie(`msg-${this._message.id}`) === '1'; + }, + }); +})();
diff --git a/src/main/resources/static/gr-messageoftheday.html b/src/main/resources/static/gr-messageoftheday.html new file mode 100644 index 0000000..8758502 --- /dev/null +++ b/src/main/resources/static/gr-messageoftheday.html
@@ -0,0 +1,27 @@ +<!-- +@license +Copyright (C) 2020 The Android Open Source Project + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> + +<link rel="import" + href="./gr-messageoftheday-banner.html"> + +<dom-module id="gr-messageoftheday"> + <script> + Gerrit.install(plugin => { + plugin.registerCustomComponent("banner", "gr-messageoftheday-banner"); + }); + </script> +</dom-module>